Decompiled source of Cats v2.13.0

Cats.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Cats;

public enum Rarity
{
	Common,
	Uncommon,
	Rare,
	Custom
}
public class MaterialVariants : MonoBehaviour
{
	public Material[] variants;

	[HideInInspector]
	public int currentVariant;
}
public class ChargeGlow : MonoBehaviour
{
	public Renderer[] glowRenderers;

	public Color chargingColor = new Color(0.3f, 0.6f, 1f) * 2f;

	private static readonly FieldInfo _stateCurrent = AccessTools.Field(typeof(ItemGun), "stateCurrent");

	private static readonly FieldInfo _stateTimer = AccessTools.Field(typeof(ItemGun), "stateTimer");

	private static readonly FieldInfo _stateTimeMax = AccessTools.Field(typeof(ItemGun), "stateTimeMax");

	private ItemGun _gun;

	private void Awake()
	{
		_gun = ((Component)this).GetComponent<ItemGun>();
	}

	private void Update()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Invalid comparison between Unknown and I4
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Invalid comparison between Unknown and I4
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		if (glowRenderers == null || glowRenderers.Length == 0 || (Object)(object)_gun == (Object)null)
		{
			return;
		}
		State val = (State)_stateCurrent.GetValue(_gun);
		float num3;
		if ((int)val == 2)
		{
			float num = (float)_stateTimer.GetValue(_gun);
			float num2 = (float)_stateTimeMax.GetValue(_gun);
			num3 = Mathf.Clamp01(num / Mathf.Max(num2, 0.01f));
		}
		else
		{
			num3 = (((int)val == 3) ? 1f : 0f);
		}
		Color val2 = Color.Lerp(Color.black, chargingColor, num3);
		Renderer[] array = glowRenderers;
		foreach (Renderer val3 in array)
		{
			if (!((Object)(object)val3 == (Object)null))
			{
				val3.material.EnableKeyword("_EMISSION");
				val3.material.SetColor("_EmissionColor", val2);
			}
		}
	}
}
public class FightPull : MonoBehaviour
{
	public float radius = 3f;

	public float pullForce = 10f;

	public float damping = 5f;

	private static readonly FieldInfo _hasRigidbody = AccessTools.Field(typeof(Enemy), "HasRigidbody");

	private static readonly FieldInfo _enemyRigidbody = AccessTools.Field(typeof(Enemy), "Rigidbody");

	private static readonly FieldInfo _rb = AccessTools.Field(typeof(EnemyRigidbody), "rb");

	private static readonly FieldInfo _disableFollowPositionTimer = AccessTools.Field(typeof(EnemyRigidbody), "disableFollowPositionTimer");

	private void FixedUpdate()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, radius);
		HashSet<Rigidbody> hashSet = new HashSet<Rigidbody>();
		CatsPlugin.Log.LogDebug((object)$"[Cats] FightPull tick - {array.Length} colliders in range");
		Collider[] array2 = array;
		foreach (Collider val in array2)
		{
			Rigidbody val2 = val.attachedRigidbody;
			Enemy componentInParent = ((Component)val).GetComponentInParent<Enemy>();
			if ((Object)(object)componentInParent != (Object)null && (bool)_hasRigidbody.GetValue(componentInParent))
			{
				object value = _enemyRigidbody.GetValue(componentInParent);
				val2 = (Rigidbody)_rb.GetValue(value);
				_disableFollowPositionTimer.SetValue(value, 0.2f);
			}
			if ((Object)(object)val2 == (Object)null || !hashSet.Add(val2))
			{
				CatsPlugin.Log.LogDebug((object)("[Cats]   " + ((Object)val).name + " -> no usable rigidbody or dupe"));
				continue;
			}
			if (val2.isKinematic)
			{
				val2.isKinematic = false;
			}
			Vector3 val3 = ((Component)this).transform.position - val2.position;
			float magnitude = ((Vector3)(ref val3)).magnitude;
			CatsPlugin.Log.LogDebug((object)$"[Cats]   {((Object)val2).name} mass={val2.mass} dist={magnitude:F2} kinematic={val2.isKinematic}");
			if (magnitude > 0.3f)
			{
				val2.AddForce(((Vector3)(ref val3)).normalized * pullForce, (ForceMode)0);
			}
			val2.velocity = Vector3.Lerp(val2.velocity, Vector3.zero, damping * Time.fixedDeltaTime);
		}
	}
}
public class FightCloud : MonoBehaviour
{
	public GameObject[] limbs;

	public float popDuration = 0.08f;

	public float holdDuration = 0.28f;

	public float retractDuration = 0.07f;

	public float minDelay = 0.15f;

	public float maxDelay = 0.5f;

	public float spawnRadius = 0.5f;

	private void Start()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		if (limbs == null)
		{
			return;
		}
		GameObject[] array = limbs;
		foreach (GameObject val in array)
		{
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 localPosition = val.transform.localPosition;
				Vector3 val2;
				if (!(((Vector3)(ref localPosition)).sqrMagnitude > 0.0001f))
				{
					val2 = Vector3.up;
				}
				else
				{
					localPosition = val.transform.localPosition;
					val2 = ((Vector3)(ref localPosition)).normalized;
				}
				Vector3 val3 = val2;
				val.transform.localPosition = Vector3.zero;
				((MonoBehaviour)this).StartCoroutine(PopLoop(val.transform, val3 * spawnRadius));
			}
		}
	}

	private IEnumerator PopLoop(Transform t, Vector3 poppedPos)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		while (true)
		{
			yield return (object)new WaitForSeconds(Random.Range(minDelay, maxDelay));
			float elapsed = 0f;
			while (elapsed < popDuration)
			{
				elapsed += Time.deltaTime;
				t.localPosition = Vector3.Lerp(Vector3.zero, poppedPos, elapsed / popDuration);
				yield return null;
			}
			t.localPosition = poppedPos;
			yield return (object)new WaitForSeconds(holdDuration);
			elapsed = 0f;
			while (elapsed < retractDuration)
			{
				elapsed += Time.deltaTime;
				t.localPosition = Vector3.Lerp(poppedPos, Vector3.zero, elapsed / retractDuration);
				yield return null;
			}
			t.localPosition = Vector3.zero;
		}
	}
}
[Flags]
public enum SpawnLevel
{
	None = 0,
	Museum = 1,
	ArenaRace = 2,
	Wizard = 4,
	Manor = 8,
	Arctic = 0x10
}
public class CatRarity : MonoBehaviour
{
	public Rarity rarity;

	public SpawnLevel spawnLevels;

	public bool noDisplayName;

	public string defaultName;
}
public class HolidaySpawn : MonoBehaviour
{
	[Tooltip("Turn the guarantee off without removing the component.")]
	public bool guaranteeEnabled = true;

	[Tooltip("At least this many of this valuable will be in every qualifying level.")]
	[Range(1f, 10f)]
	public int minimumCount = 1;

	[Tooltip("Chance (0-1) the guarantee applies on a given level. 1 = every level.")]
	[Range(0f, 1f)]
	public float chance = 1f;

	[Tooltip("Levels the guarantee applies on. None = every level.")]
	public SpawnLevel levels;

	[Tooltip("First level of a run the guarantee applies on (1 = the very first level).")]
	[Min(1f)]
	public int startLevel = 1;

	[Tooltip("Count copies the game already spawned naturally toward the minimum. Off = always spawn minimumCount extra.")]
	public bool countNaturalSpawns = true;

	[Tooltip("If no free volume of this valuable's own size is left, allow it to use a bigger one.")]
	public bool allowLargerVolumes = true;

	[Tooltip("Lower numbers get first pick of free volumes when several guaranteed valuables compete.")]
	public int priority;
}
public class BananipEffects : MonoBehaviour
{
	public float pitchMultiplier = 1.7f;

	public float pitchOscillation = 0.4f;

	public float pitchOscillationSpeed = 3f;

	public float pupilMultiplier = 3f;

	private static readonly FieldInfo _voiceFetchedField = AccessTools.Field(typeof(PlayerAvatar), "voiceChatFetched");

	private static readonly FieldInfo _voiceChatField = AccessTools.Field(typeof(PlayerAvatar), "voiceChat");

	private void Update()
	{
		PhysGrabObject component = ((Component)this).GetComponent<PhysGrabObject>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		foreach (PhysGrabber item in component.playerGrabbing)
		{
			if ((Object)(object)item == (Object)null || (Object)(object)item.playerAvatar == (Object)null)
			{
				continue;
			}
			PlayerAvatar playerAvatar = item.playerAvatar;
			if (!(_voiceFetchedField == null) && (bool)_voiceFetchedField.GetValue(playerAvatar))
			{
				object? obj = _voiceChatField?.GetValue(playerAvatar);
				PlayerVoiceChat val = (PlayerVoiceChat)((obj is PlayerVoiceChat) ? obj : null);
				if (!((Object)(object)val == (Object)null))
				{
					val.OverridePitch(pitchMultiplier, 0.1f, 0.3f, 0.2f, pitchOscillation, pitchOscillationSpeed);
					val.OverrideHearSelf(0f, 0.2f);
				}
			}
		}
	}
}
public class YarnBallDuctTaped : MonoBehaviour
{
	public GameObject grenadePrefab;

	public int spawnCount = 3;

	public Sound soundExplosion;

	public Sound soundExplosionGlobal;

	private ParticleScriptExplosion particleScriptExplosion;

	private PhotonView photonView;

	private ItemGrenade itemGrenade;

	private string _networkPath;

	private static readonly FieldInfo _activatorField = AccessTools.Field(typeof(ItemGrenade), "activatorPlayerAvatar");

	private static readonly FieldInfo _clientNonKinField = AccessTools.Field(typeof(PhysGrabObject), "clientNonKinematic");

	private static readonly FieldInfo _isSpawnedField = AccessTools.Field(typeof(ItemGrenade), "isSpawnedGrenade");

	private static readonly FieldInfo _tickTimeField = AccessTools.Field(typeof(ItemGrenade), "tickTime");

	private static readonly MethodInfo _setActivatorMethod = AccessTools.Method(typeof(ItemGrenade), "SetActivator", (Type[])null, (Type[])null);

	private static readonly FieldInfo _causingHurtField = AccessTools.Field(typeof(ParticleScriptExplosion), "playerCausingHurtOverride");

	private static readonly FieldInfo _fullRuckusField = AccessTools.Field(typeof(ParticleScriptExplosion), "playerHitFullRuckusOverride");

	private void Start()
	{
		particleScriptExplosion = ((Component)this).GetComponent<ParticleScriptExplosion>();
		photonView = ((Component)this).GetComponent<PhotonView>();
		itemGrenade = ((Component)this).GetComponent<ItemGrenade>();
		foreach (KeyValuePair<string, GameObject> prefab in NetworkPrefabs.Prefabs)
		{
			if ((Object)(object)prefab.Value != (Object)null && ((Object)prefab.Value).name.Contains("Yarn Ball Grenade"))
			{
				_networkPath = prefab.Key;
				break;
			}
		}
	}

	public void Explosion()
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		PlayerAvatar val = (PlayerAvatar)(((Object)(object)itemGrenade != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
		int activatorViewId = (((Object)(object)val != (Object)null) ? val.photonView.ViewID : (-1));
		Vector3 val2 = default(Vector3);
		for (int i = 0; i < spawnCount; i++)
		{
			((Vector3)(ref val2))..ctor(Random.Range(-0.3f, 0.3f), 0.2f * (float)i, Random.Range(-0.3f, 0.3f));
			Vector3 val3 = ((Component)this).transform.position + val2;
			GameObject val4 = null;
			if (!SemiFunc.IsMultiplayer())
			{
				if ((Object)(object)grenadePrefab != (Object)null)
				{
					val4 = Object.Instantiate<GameObject>(grenadePrefab, val3, Quaternion.identity);
				}
			}
			else if (SemiFunc.IsMasterClient() && _networkPath != null)
			{
				val4 = PhotonNetwork.Instantiate(_networkPath, val3, Quaternion.identity, (byte)0, (object[])null);
			}
			if ((Object)(object)val4 == (Object)null)
			{
				continue;
			}
			ItemGrenade component = val4.GetComponent<ItemGrenade>();
			if ((Object)(object)component != (Object)null)
			{
				_isSpawnedField?.SetValue(component, true);
				_tickTimeField?.SetValue(component, Random.Range(1.5f, 3f));
				if ((Object)(object)val != (Object)null)
				{
					_setActivatorMethod?.Invoke(component, new object[1] { val });
				}
			}
			((MonoBehaviour)CatsPlugin.Instance).StartCoroutine(ActivateNextFrame(val4, activatorViewId));
		}
		if ((Object)(object)particleScriptExplosion != (Object)null)
		{
			if ((Object)(object)val != (Object)null)
			{
				_causingHurtField?.SetValue(particleScriptExplosion, val);
			}
			_fullRuckusField?.SetValue(particleScriptExplosion, true);
			particleScriptExplosion.Spawn(((Component)this).transform.position, 0.6f, 30, 60, 2f, false, true, 1f, 0f);
		}
		soundExplosion.Play(((Component)this).transform.position, 1f, 1f, 1f, 1f);
		soundExplosionGlobal.Play(((Component)this).transform.position, 1f, 1f, 1f, 1f);
	}

	private static IEnumerator ActivateNextFrame(GameObject go, int activatorViewId)
	{
		yield return null;
		if ((Object)(object)go == (Object)null)
		{
			yield break;
		}
		ItemToggle component = go.GetComponent<ItemToggle>();
		if ((Object)(object)component != (Object)null)
		{
			component.ToggleItem(true, activatorViewId);
		}
		yield return null;
		if (!((Object)(object)go == (Object)null))
		{
			PhysGrabObject component2 = go.GetComponent<PhysGrabObject>();
			if ((Object)(object)component2 != (Object)null)
			{
				_clientNonKinField?.SetValue(component2, true);
			}
			Rigidbody component3 = go.GetComponent<Rigidbody>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.isKinematic = false;
				Vector3 val = Quaternion.Euler((float)Random.Range(-30, 30), (float)Random.Range(-180, 180), 0f) * Vector3.forward;
				component3.velocity = val * Random.Range(4f, 8f);
				component3.angularVelocity = Random.insideUnitSphere * Random.Range(3f, 6f);
			}
		}
	}
}
public class StrungUp : MonoBehaviour
{
	public float slowMultiplier = 0.3f;

	public float slowDuration = 3f;

	public float enemySlowSpeed = 0.5f;

	private ParticleSystem _ps;

	private List<ParticleCollisionEvent> _events = new List<ParticleCollisionEvent>();

	private void Awake()
	{
		_ps = ((Component)this).GetComponent<ParticleSystem>();
	}

	private void OnParticleCollision(GameObject other)
	{
		ParticlePhysicsExtensions.GetCollisionEvents(_ps, other, _events);
		PlayerController componentInParent = other.GetComponentInParent<PlayerController>();
		if ((Object)(object)componentInParent != (Object)null)
		{
			componentInParent.OverrideSpeed(slowMultiplier, slowDuration, -1f);
			return;
		}
		EnemyNavMeshAgent val = other.GetComponentInParent<EnemyNavMeshAgent>();
		if ((Object)(object)val == (Object)null)
		{
			EnemyRigidbody componentInParent2 = other.GetComponentInParent<EnemyRigidbody>();
			if ((Object)(object)componentInParent2 != (Object)null && (Object)(object)componentInParent2.enemy != (Object)null)
			{
				val = ((Component)componentInParent2.enemy).GetComponentInChildren<EnemyNavMeshAgent>();
			}
		}
		if ((Object)(object)val != (Object)null)
		{
			val.OverrideAgent(enemySlowSpeed, 8f, slowDuration);
		}
	}
}
public class ScriptYarnString : MonoBehaviour
{
	public ParticleSystem[] particles;

	public Material[] particleMaterials;

	public void Explosion()
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		Material val = null;
		MaterialVariants componentInChildren = ((Component)this).GetComponentInChildren<MaterialVariants>();
		if ((Object)(object)componentInChildren != (Object)null && particleMaterials != null && componentInChildren.currentVariant < particleMaterials.Length)
		{
			val = particleMaterials[componentInChildren.currentVariant];
		}
		ParticleSystem[] array = particles;
		foreach (ParticleSystem val2 in array)
		{
			if (!((Object)(object)val2 == (Object)null))
			{
				((Component)val2).transform.position = ((Component)this).transform.position;
				((Component)val2).transform.SetParent((Transform)null);
				((Component)val2).gameObject.SetActive(true);
				if ((Object)(object)val != (Object)null)
				{
					((Renderer)((Component)val2).GetComponent<ParticleSystemRenderer>()).material = val;
				}
				val2.Stop(true);
				val2.Play();
			}
		}
	}
}
public class Billboard : MonoBehaviour
{
	public float lifetime;

	private void Start()
	{
		if (lifetime > 0f)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject, lifetime);
		}
	}

	private void LateUpdate()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		Camera main = Camera.main;
		if ((Object)(object)main != (Object)null)
		{
			((Component)this).transform.rotation = ((Component)main).transform.rotation;
		}
	}
}
public class BestExtractingDevice : MonoBehaviour
{
	public float healRate = 3f;

	public int healAmount = 5;

	public int batteryDrainPerHeal = 10;

	private static readonly FieldInfo _isTumbling = AccessTools.Field(typeof(PlayerAvatar), "isTumbling");

	private static readonly FieldInfo _tumble = AccessTools.Field(typeof(PlayerAvatar), "tumble");

	private static readonly FieldInfo _tumblePhysGrabObject = AccessTools.Field(typeof(PlayerTumble), "physGrabObject");

	private static readonly FieldInfo _health = AccessTools.Field(typeof(PlayerHealth), "health");

	private static readonly FieldInfo _maxHealth = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

	private ItemBattery itemBattery;

	private PhotonView photonView;

	private Transform inCart;

	private float healTimer;

	private void Start()
	{
		itemBattery = ((Component)this).GetComponent<ItemBattery>();
		photonView = ((Component)this).GetComponent<PhotonView>();
		inCart = ((Component)this).transform.Find("In Cart");
	}

	[PunRPC]
	private void RemoveBatteryBars(int bars)
	{
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			itemBattery.RemoveFullBar(bars);
		}
	}

	private void Update()
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Expected O, but got Unknown
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Expected O, but got Unknown
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		if (!SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.RunIsShop() || (Object)(object)inCart == (Object)null || (Object)(object)itemBattery == (Object)null || itemBattery.batteryLife <= 0f)
		{
			return;
		}
		healTimer += Time.deltaTime;
		if (healTimer < healRate)
		{
			return;
		}
		healTimer = 0f;
		Bounds val = default(Bounds);
		((Bounds)(ref val))..ctor(inCart.position, inCart.localScale);
		foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
		{
			if (!(bool)_isTumbling.GetValue(player))
			{
				continue;
			}
			int num = (int)_health.GetValue(player.playerHealth);
			int num2 = (int)_maxHealth.GetValue(player.playerHealth);
			if (num >= num2)
			{
				continue;
			}
			PlayerTumble val2 = (PlayerTumble)_tumble.GetValue(player);
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			PhysGrabObject val3 = (PhysGrabObject)_tumblePhysGrabObject.GetValue(val2);
			if (!((Object)(object)val3 == (Object)null) && ((Bounds)(ref val)).Contains(val3.centerPoint))
			{
				player.playerHealth.HealOther(healAmount, true);
				int num3 = Mathf.Max(1, Mathf.RoundToInt((float)batteryDrainPerHeal / (100f / (float)itemBattery.batteryBars)));
				if (SemiFunc.IsMultiplayer())
				{
					photonView.RPC("RemoveBatteryBars", (RpcTarget)2, new object[1] { num3 });
				}
				else
				{
					itemBattery.RemoveFullBar(num3);
				}
			}
		}
	}
}
[BepInPlugin("eberk30.cats", "Cats", "2.12.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class CatsPlugin : BaseUnityPlugin
{
	public static CatsPlugin Instance;

	internal static ManualLogSource Log;

	public static ConfigEntry<bool> ControlledSpawning;

	public static ConfigEntry<int> SpawnCount;

	public static ConfigEntry<int> CommonWeight;

	public static ConfigEntry<int> UncommonWeight;

	public static ConfigEntry<int> RareWeight;

	public static ConfigEntry<int> CustomWeight;

	public static ConfigEntry<float> BananipSpeedMultiplier;

	public static ConfigEntry<float> BananipVignetteIntensity;

	public static ConfigEntry<float> BananipLensDistortionIntensity;

	public static ConfigEntry<float> BananipFovPulseAmount;

	public static ConfigEntry<float> BananipFovPulseSpeed;

	public static ConfigEntry<float> BananipJoltInterval;

	public static ConfigEntry<float> BananipJoltStrength;

	internal static readonly Dictionary<string, ConfigEntry<string>> DisplayNames = new Dictionary<string, ConfigEntry<string>>();

	internal static readonly Dictionary<string, string> DefaultNames = new Dictionary<string, string>();

	internal static readonly HashSet<string> CatPrefabNames = new HashSet<string>();

	private static readonly string[] _displayNameCats = new string[19]
	{
		"Alien Cat", "Black Cat", "Blue Point", "Calico", "Cyberpunk Cat", "Galaxy Cat", "Gray Tabby", "Munchkin", "Orange Tabby", "Pallas Cat",
		"Photosynthesis Cat", "Pink Cat", "Russian Blue", "Scottish Fold", "Siamese", "Sphynx", "Tortoise", "Tuxedo", "White Cat"
	};

	private static bool _fightCloudRegistered;

	internal static readonly string[] _extraNetworkPrefabNames = new string[2] { "Cat Staff Fight Cloud", "Blue Orb Impact" };

	public static NetworkedEvent ShareNamesEvent;

	public static NetworkedEvent AssignNamesEvent;

	public static NetworkedEvent RequestConfigsEvent;

	public static NetworkedEvent AssignVariantsEvent;

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

	internal static readonly Dictionary<int, string> AssignedNames = new Dictionary<int, string>();

	internal static readonly Dictionary<int, int> AssignedVariants = new Dictionary<int, int>();

	private static Dictionary<string, HashSet<int>> _prevLevelVariants = new Dictionary<string, HashSet<int>>();

	private static Dictionary<string, HashSet<int>> _thisLevelVariants = new Dictionary<string, HashSet<int>>();

	private static bool _sentThisLevel = false;

	private static string _lastLevel = "";

	private void Awake()
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Expected O, but got Unknown
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Expected O, but got Unknown
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Expected O, but got Unknown
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Expected O, but got Unknown
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Expected O, but got Unknown
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Expected O, but got Unknown
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Expected O, but got Unknown
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_025b: Expected O, but got Unknown
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0298: Expected O, but got Unknown
		//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Expected O, but got Unknown
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Expected O, but got Unknown
		//IL_034f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0359: Expected O, but got Unknown
		//IL_036a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0374: Expected O, but got Unknown
		//IL_0385: Unknown result type (might be due to invalid IL or missing references)
		//IL_038f: Expected O, but got Unknown
		//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		ControlledSpawning = ((BaseUnityPlugin)this).Config.Bind<bool>("Controlled Spawning", "Controlled Spawning", false, "Take over spawning. On = Control spawning using count/weight settings below; Off = let the game spawn cats normally.");
		SpawnCount = ((BaseUnityPlugin)this).Config.Bind<int>("Controlled Spawning", "Spawn Count", 3, new ConfigDescription("How many cats appear per level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
		CommonWeight = ((BaseUnityPlugin)this).Config.Bind<int>("Controlled Spawning", "Common Weight", 90, new ConfigDescription("Relative spawn weight for Common rarity cats. Higher = more frequent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		UncommonWeight = ((BaseUnityPlugin)this).Config.Bind<int>("Controlled Spawning", "Uncommon Weight", 60, new ConfigDescription("Relative spawn weight for Uncommon rarity cats. Higher = more frequent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		RareWeight = ((BaseUnityPlugin)this).Config.Bind<int>("Controlled Spawning", "Rare Weight", 20, new ConfigDescription("Relative spawn weight for Rare rarity cats. Higher = more frequent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		CustomWeight = ((BaseUnityPlugin)this).Config.Bind<int>("Controlled Spawning", "Custom Weight", 50, new ConfigDescription("Relative spawn weight for Custom rarity cats. Higher = more frequent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		BananipSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "Speed Multiplier", 1.8f, new ConfigDescription("Movement speed multiplier while holding the Bananip.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
		BananipVignetteIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "Vignette Intensity", 0.8f, new ConfigDescription("Peak vignette darkness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		BananipLensDistortionIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "Lens Distortion Intensity", 1f, new ConfigDescription("Peak lens distortion amount.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		BananipFovPulseAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "FOV Pulse Amount", 20f, new ConfigDescription("Degrees the FOV pulses up and down.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
		BananipFovPulseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "FOV Pulse Speed", 1.6f, new ConfigDescription("Oscillations per second for FOV and vignette pulse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
		BananipJoltInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "Jolt Interval", 4f, new ConfigDescription("Seconds between random movement jolts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
		BananipJoltStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Bananip", "Jolt Strength", 15f, new ConfigDescription("Force applied per jolt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
		string[] displayNameCats = _displayNameCats;
		foreach (string text in displayNameCats)
		{
			DisplayNames[text] = ((BaseUnityPlugin)this).Config.Bind<string>("Cat Names", text, "", "Name shown when holding " + text + ". Comma-separate for random pick: Bob, Bill. Leave blank for no name.");
		}
		ShareNamesEvent = new NetworkedEvent("ShareNames", (Action<EventData>)OnShareNames);
		AssignNamesEvent = new NetworkedEvent("AssignNames", (Action<EventData>)OnAssignNames);
		RequestConfigsEvent = new NetworkedEvent("RequestConfigs", (Action<EventData>)OnRequestConfigs);
		AssignVariantsEvent = new NetworkedEvent("AssignVariants", (Action<EventData>)OnAssignVariants);
		((MonoBehaviour)Instance).StartCoroutine(BakeWhenReady());
		new Harmony("eberk30.cats").PatchAll();
	}

	private static IEnumerator BakeWhenReady()
	{
		while (Valuables.RegisteredValuables.Count == 0)
		{
			yield return (object)new WaitForSeconds(0.5f);
		}
		BakeItemAttributesIntoCatPrefabs();
	}

	private static void RegisterFightCloudPrefab()
	{
		string[] extraNetworkPrefabNames = _extraNetworkPrefabNames;
		for (int i = 0; i < extraNetworkPrefabNames.Length; i++)
		{
			RegisterNetworkPrefabByName(extraNetworkPrefabNames[i]);
		}
	}

	private static void RegisterNetworkPrefabByName(string name)
	{
		Log.LogDebug((object)("[Cats] RegisterNetworkPrefabByName(" + name + ") — searching loaded bundles"));
		try
		{
			GameObject val = null;
			foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
			{
				val = allLoadedAssetBundle.LoadAsset<GameObject>(name);
				if ((Object)(object)val != (Object)null)
				{
					Log.LogDebug((object)("[Cats] found " + name + " in bundle: " + ((Object)allLoadedAssetBundle).name));
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				string text = Directory.GetFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "*.repobundle").FirstOrDefault();
				if (text != null)
				{
					AssetBundle val2 = AssetBundle.LoadFromFile(text);
					if ((Object)(object)val2 != (Object)null)
					{
						val = val2.LoadAsset<GameObject>(name);
					}
					Log.LogDebug((object)$"[Cats] loaded {text} fresh from disk, found {name}={(Object)(object)val != (Object)null}");
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)("[Cats] " + name + " not found in any loaded bundle — rebuild the .repobundle in Unity"));
				return;
			}
			NetworkPrefabs.RegisterNetworkPrefab(val);
			Log.LogDebug((object)("[Cats] registered " + name + " as network prefab"));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("[Cats] RegisterNetworkPrefabByName(" + name + ") threw: " + ex.Message));
		}
	}

	internal static void BakeItemAttributesIntoCatPrefabs()
	{
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Expected O, but got Unknown
		bool flag = Chainloader.PluginInfos.ContainsKey("eberk30.genesis");
		foreach (PrefabRef registeredValuable in Valuables.RegisteredValuables)
		{
			if (!NetworkPrefabs.Prefabs.TryGetValue(((PrefabRef<GameObject>)(object)registeredValuable).ResourcePath, out var value) || (Object)(object)value == (Object)null)
			{
				continue;
			}
			CatRarity component = value.GetComponent<CatRarity>();
			if ((Object)(object)component == (Object)null || (flag && ((PrefabRef<GameObject>)(object)registeredValuable).PrefabName == "Genesis") || !CatPrefabNames.Add(((PrefabRef<GameObject>)(object)registeredValuable).PrefabName))
			{
				continue;
			}
			if ((Object)(object)value.GetComponent<ItemAttributes>() == (Object)null)
			{
				value.AddComponent<ItemAttributes>();
			}
			if (!component.noDisplayName)
			{
				if (!string.IsNullOrEmpty(component.defaultName))
				{
					DefaultNames[((PrefabRef<GameObject>)(object)registeredValuable).PrefabName] = component.defaultName;
					((BaseUnityPlugin)Instance).Config.Remove(new ConfigDefinition("Cat Names", ((PrefabRef<GameObject>)(object)registeredValuable).PrefabName));
					DisplayNames.Remove(((PrefabRef<GameObject>)(object)registeredValuable).PrefabName);
				}
				else
				{
					DisplayNames[((PrefabRef<GameObject>)(object)registeredValuable).PrefabName] = ((BaseUnityPlugin)Instance).Config.Bind<string>("Cat Names", ((PrefabRef<GameObject>)(object)registeredValuable).PrefabName, "", "Name shown when holding " + ((PrefabRef<GameObject>)(object)registeredValuable).PrefabName + ". Comma-separate for random pick: Bob, Bill. Leave blank for no name.");
				}
			}
			Log.LogDebug((object)$"[Cats] baked {((PrefabRef<GameObject>)(object)registeredValuable).PrefabName} rarity={component.rarity}");
		}
		if (!_fightCloudRegistered && CatPrefabNames.Count > 0)
		{
			_fightCloudRegistered = true;
			RegisterFightCloudPrefab();
		}
	}

	internal static string GetCatType(string name)
	{
		foreach (string catPrefabName in CatPrefabNames)
		{
			if (name.Contains(catPrefabName))
			{
				return catPrefabName;
			}
		}
		return null;
	}

	internal static bool IsCat(string name)
	{
		return GetCatType(name) != null;
	}

	internal static SpawnLevel CurrentSpawnLevel()
	{
		return ((Object)RunManager.instance.levelCurrent).name switch
		{
			"Level - Museum" => SpawnLevel.Museum, 
			"Level - Arena Race" => SpawnLevel.ArenaRace, 
			"Level - Wizard" => SpawnLevel.Wizard, 
			"Level - Manor" => SpawnLevel.Manor, 
			"Level - Arctic" => SpawnLevel.Arctic, 
			_ => SpawnLevel.None, 
		};
	}

	internal static int PickVariant(string typeKey, int count)
	{
		HashSet<int> exclude = new HashSet<int>();
		if (_prevLevelVariants.TryGetValue(typeKey, out var value))
		{
			exclude.UnionWith(value);
		}
		if (_thisLevelVariants.TryGetValue(typeKey, out var value2))
		{
			exclude.UnionWith(value2);
		}
		int[] array = ((exclude.Count >= count) ? Enumerable.Range(0, count).ToArray() : (from i in Enumerable.Range(0, count)
			where !exclude.Contains(i)
			select i).ToArray());
		int num = array[Random.Range(0, array.Length)];
		if (!_thisLevelVariants.TryGetValue(typeKey, out var value3))
		{
			value3 = (_thisLevelVariants[typeKey] = new HashSet<int>());
		}
		value3.Add(num);
		return num;
	}

	private static void OnShareNames(EventData photonEvent)
	{
		if (photonEvent.CustomData is string text)
		{
			_receivedConfigs[photonEvent.Sender] = text;
			Log.LogDebug((object)$"[Cats] got config from actor {photonEvent.Sender} ({text.Length} bytes)");
		}
	}

	private static void OnRequestConfigs(EventData photonEvent)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		Log.LogDebug((object)$"[Cats] received config request (isMaster={SemiFunc.IsMasterClientOrSingleplayer()})");
		if (!SemiFunc.IsMasterClientOrSingleplayer())
		{
			ShareNamesEvent.RaiseEvent((object)PackConfig(), NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
			Log.LogDebug((object)"[Cats] replied with config");
		}
	}

	private static void OnAssignNames(EventData photonEvent)
	{
		if (!(photonEvent.CustomData is string text))
		{
			return;
		}
		string[] array = text.Split(new char[1] { '|' });
		foreach (string text2 in array)
		{
			int num = text2.IndexOf('=');
			if (num >= 0)
			{
				if (!int.TryParse(text2.Substring(0, num), out var result))
				{
					Log.LogWarning((object)("[Cats] couldn't parse viewID: " + text2));
				}
				else
				{
					AssignedNames[result] = text2.Substring(num + 1);
				}
			}
		}
		ValuableObject[] array2 = Object.FindObjectsOfType<ValuableObject>();
		foreach (ValuableObject val in array2)
		{
			PhotonView component = ((Component)val).GetComponent<PhotonView>();
			if (!((Object)(object)component == (Object)null) && AssignedNames.TryGetValue(component.ViewID, out var value))
			{
				ItemAttributes component2 = ((Component)val).GetComponent<ItemAttributes>();
				if ((Object)(object)component2 != (Object)null && (Object)(object)component2.item != (Object)null)
				{
					component2.item.itemName = value;
				}
			}
		}
	}

	private static void OnAssignVariants(EventData photonEvent)
	{
		if (!(photonEvent.CustomData is string text))
		{
			return;
		}
		string[] array = text.Split(new char[1] { '|' });
		foreach (string text2 in array)
		{
			int num = text2.IndexOf('=');
			if (num >= 0 && int.TryParse(text2.Substring(0, num), out var result) && int.TryParse(text2.Substring(num + 1), out var result2))
			{
				AssignedVariants[result] = result2;
			}
		}
		ItemAttributes[] array2 = Object.FindObjectsOfType<ItemAttributes>();
		foreach (ItemAttributes val in array2)
		{
			MaterialVariants componentInChildren = ((Component)val).GetComponentInChildren<MaterialVariants>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				continue;
			}
			PhotonView component = ((Component)val).GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null || !AssignedVariants.TryGetValue(component.ViewID, out var value) || componentInChildren.variants == null || value >= componentInChildren.variants.Length)
			{
				continue;
			}
			Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>();
			if (componentsInChildren.Length == 0)
			{
				continue;
			}
			Renderer[] array3 = componentsInChildren;
			for (int j = 0; j < array3.Length; j++)
			{
				array3[j].material = componentInChildren.variants[value];
			}
			if (!componentInChildren.variants[value].HasProperty("_FresnelScale"))
			{
				ItemLight[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<ItemLight>();
				foreach (ItemLight val2 in componentsInChildren2)
				{
					array3 = componentsInChildren;
					foreach (Renderer obj in array3)
					{
						MeshRenderer val3 = (MeshRenderer)(object)((obj is MeshRenderer) ? obj : null);
						if ((Object)(object)val3 != (Object)null)
						{
							val2.meshRenderers.Remove(val3);
						}
					}
				}
			}
			FixIcon(val);
		}
	}

	internal static void FixIcon(ItemAttributes ia)
	{
		if (Convert.ToInt32(Traverse.Create((object)ia).Field("iconState").GetValue()) != 2 || (Object)(object)ia.icon == (Object)null || (Object)(object)ia.icon != (Object)(object)Traverse.Create((object)ia).Field("generatedIcon").GetValue<Sprite>() || !AssignedVariants.TryGetValue(((Component)ia).GetComponent<PhotonView>().ViewID, out var value))
		{
			return;
		}
		string key = ((Object)((Component)ia).gameObject).name.Replace("(Clone)", "") + "#" + value;
		if (!Traverse.Create<ItemAttributes>().Field("iconCache").GetValue<Dictionary<string, Sprite>>()
			.TryGetValue(key, out var value2) || !((Object)(object)value2 == (Object)(object)ia.icon))
		{
			Log.LogDebug((object)$"[Cats] icon for {((Object)((Component)ia).gameObject).name} isn't skin {value}, redoing it");
			ia.icon = null;
			Traverse.Create((object)ia).Field("generatedIcon").SetValue((object)null);
			Traverse.Create((object)ia).Field("iconState").SetValue(Enum.ToObject(AccessTools.Field(typeof(ItemAttributes), "iconState").FieldType, 1));
			if (((Component)ia).gameObject.activeInHierarchy)
			{
				Traverse.Create((object)ia).Method("OnEnable", Array.Empty<object>()).GetValue();
			}
		}
	}

	private static string PackConfig()
	{
		return string.Join("|", DisplayNames.Select((KeyValuePair<string, ConfigEntry<string>> kvp) => kvp.Key + "=" + kvp.Value.Value));
	}

	internal static void TrySendConfig()
	{
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		RunManager instance = RunManager.instance;
		object obj;
		if (instance == null)
		{
			obj = null;
		}
		else
		{
			Level levelCurrent = instance.levelCurrent;
			obj = ((levelCurrent != null) ? ((Object)levelCurrent).name : null);
		}
		if (obj == null)
		{
			obj = "";
		}
		Room currentRoom = PhotonNetwork.CurrentRoom;
		string text = (string?)obj + "|" + ((currentRoom != null) ? currentRoom.Name : null);
		if (text != _lastLevel)
		{
			_lastLevel = text;
			_sentThisLevel = false;
			AssignedNames.Clear();
			AssignedVariants.Clear();
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				_receivedConfigs.Clear();
				_prevLevelVariants = _thisLevelVariants;
				_thisLevelVariants = new Dictionary<string, HashSet<int>>();
			}
		}
		if (!_sentThisLevel && PhotonNetwork.InRoom)
		{
			_sentThisLevel = true;
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				_receivedConfigs[PhotonNetwork.LocalPlayer.ActorNumber] = PackConfig();
				Log.LogDebug((object)"[Cats] host stored own config");
			}
			else
			{
				ShareNamesEvent.RaiseEvent((object)PackConfig(), NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
				Log.LogDebug((object)"[Cats] client sent config to master");
			}
		}
	}

	private static List<string> GetNames(string serialized, string catType)
	{
		List<string> list = new List<string>();
		string text = catType + "=";
		string[] array = serialized.Split(new char[1] { '|' });
		foreach (string text2 in array)
		{
			if (!text2.StartsWith(text))
			{
				continue;
			}
			string[] array2 = text2.Substring(text.Length).Split(new char[1] { ',' });
			for (int j = 0; j < array2.Length; j++)
			{
				string text3 = array2[j].Trim();
				if (text3.Length > 0)
				{
					list.Add(text3);
				}
			}
			break;
		}
		return list;
	}

	internal IEnumerator AssignCatNames()
	{
		yield return null;
		int num = PhotonNetwork.PlayerList.Length - 1;
		Log.LogDebug((object)$"[Cats] requesting configs from {num} other player(s)");
		RequestConfigsEvent.RaiseEvent((object)"", NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
		float waited = 0f;
		int expected = PhotonNetwork.PlayerList.Length;
		while (_receivedConfigs.Count < expected && waited < 8f)
		{
			yield return null;
			waited += Time.deltaTime;
		}
		if (waited >= 8f)
		{
			Log.LogWarning((object)$"[Cats] timed out waiting for name configs ({_receivedConfigs.Count}/{expected})");
		}
		StringBuilder stringBuilder = new StringBuilder();
		ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>();
		foreach (ValuableObject val in array)
		{
			string catType = GetCatType(((Object)((Component)val).gameObject).name);
			if (catType == null)
			{
				continue;
			}
			PhotonView component = ((Component)val).GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null)
			{
				continue;
			}
			List<string> list = new List<string>();
			foreach (string value2 in _receivedConfigs.Values)
			{
				list.AddRange(GetNames(value2, catType));
			}
			if (list.Count != 0)
			{
				string value = list[Random.Range(0, list.Count)];
				AssignedNames[component.ViewID] = value;
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('|');
				}
				stringBuilder.Append(component.ViewID).Append('=').Append(value);
			}
		}
		if (stringBuilder.Length > 0)
		{
			AssignNamesEvent.RaiseEvent((object)stringBuilder.ToString(), NetworkingEvents.RaiseAll, SendOptions.SendReliable);
		}
	}
}
[HarmonyPatch(typeof(ValuableObject), "Start")]
internal static class AttributesPatch
{
	[HarmonyPostfix]
	private static void Postfix(ValuableObject __instance)
	{
		if (CatsPlugin.IsCat(((Object)((Component)__instance).gameObject).name) && !((Object)(object)((Component)__instance).gameObject.GetComponent<ItemAttributes>() != (Object)null))
		{
			((Component)__instance).gameObject.AddComponent<ItemAttributes>();
		}
	}
}
[HarmonyPatch(typeof(ItemAttributes), "Awake")]
internal static class AwakePatch
{
	[HarmonyPrefix]
	private static void Prefix(ItemAttributes __instance)
	{
		if (CatsPlugin.CatPrefabNames.Count == 0)
		{
			CatsPlugin.BakeItemAttributesIntoCatPrefabs();
		}
		string catType = CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name);
		if (catType == null)
		{
			return;
		}
		CatsPlugin.TrySendConfig();
		if ((Object)(object)__instance.item == (Object)null)
		{
			__instance.item = ScriptableObject.CreateInstance<Item>();
			__instance.item.value = ScriptableObject.CreateInstance<Value>();
		}
		PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
		if ((Object)(object)component != (Object)null && CatsPlugin.AssignedNames.TryGetValue(component.ViewID, out var value))
		{
			__instance.item.itemName = value;
			return;
		}
		if (CatsPlugin.DefaultNames.TryGetValue(catType, out var value2))
		{
			__instance.item.itemName = value2;
			return;
		}
		ConfigEntry<string> value3;
		string[] array = (from s in (CatsPlugin.DisplayNames.TryGetValue(catType, out value3) ? value3.Value : "").Split(new char[1] { ',' })
			select s.Trim() into s
			where s.Length > 0
			select s).ToArray();
		__instance.item.itemName = ((array.Length != 0) ? array[Random.Range(0, array.Length)] : "");
	}

	[HarmonyPostfix]
	private static void Postfix(ItemAttributes __instance)
	{
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		string catType = CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name);
		PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		MaterialVariants componentInChildren = ((Component)__instance).GetComponentInChildren<MaterialVariants>();
		if ((Object)(object)componentInChildren == (Object)null || componentInChildren.variants == null || componentInChildren.variants.Length == 0)
		{
			return;
		}
		Renderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Renderer>();
		if (componentsInChildren.Length == 0)
		{
			return;
		}
		bool flag = false;
		if (CatsPlugin.AssignedVariants.TryGetValue(component.ViewID, out var value))
		{
			Renderer[] array = componentsInChildren;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].material = componentInChildren.variants[value];
			}
			flag = true;
		}
		else if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			value = CatsPlugin.PickVariant(catType ?? ((Object)((Component)__instance).gameObject).name, componentInChildren.variants.Length);
			CatsPlugin.AssignedVariants[component.ViewID] = value;
			Renderer[] array = componentsInChildren;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].material = componentInChildren.variants[value];
			}
			CatsPlugin.AssignVariantsEvent.RaiseEvent((object)(component.ViewID + "=" + value), NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			flag = true;
		}
		if (flag)
		{
			componentInChildren.currentVariant = value;
			string text = ((Object)((Component)__instance).gameObject).name.Replace("(Clone)", "").ToLowerInvariant() + "#" + value;
			string path = Path.Combine(Application.persistentDataPath, "Cache", "Icons", "Items", text + ".png");
			if (File.Exists(path))
			{
				File.Delete(path);
			}
		}
	}
}
[HarmonyPatch(typeof(ItemAttributes), "GenerateIcon")]
internal static class IconVariantPatch
{
	[HarmonyPostfix]
	private static void Postfix(ItemAttributes __instance, ref IEnumerator __result)
	{
		if (!((Object)(object)((Component)__instance).GetComponentInChildren<MaterialVariants>() == (Object)null) || !((Object)(object)((Component)__instance).GetComponentInChildren<TrailRenderer>(true) == (Object)null))
		{
			__result = Wrap(__instance, __result);
		}
	}

	private static IEnumerator Wrap(ItemAttributes ia, IEnumerator inner)
	{
		GameObject go = ((Component)ia).gameObject;
		PhotonView pv = ((Component)ia).GetComponent<PhotonView>();
		TrailRenderer[] trails = ((Component)ia).GetComponentsInChildren<TrailRenderer>(true);
		while (true)
		{
			string name = ((Object)go).name;
			if ((Object)(object)pv != (Object)null && CatsPlugin.AssignedVariants.TryGetValue(pv.ViewID, out var value))
			{
				((Object)go).name = name + "#" + value;
			}
			TrailRenderer[] array = trails;
			foreach (TrailRenderer val in array)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					((Renderer)val).forceRenderingOff = true;
				}
			}
			bool flag;
			try
			{
				flag = inner.MoveNext();
			}
			finally
			{
				((Object)go).name = name;
				array = trails;
				foreach (TrailRenderer val2 in array)
				{
					if (Object.op_Implicit((Object)(object)val2))
					{
						((Renderer)val2).forceRenderingOff = false;
						val2.Clear();
					}
				}
			}
			if (!flag)
			{
				break;
			}
			yield return inner.Current;
		}
		if ((Object)(object)pv != (Object)null)
		{
			CatsPlugin.FixIcon(ia);
		}
	}
}
[HarmonyPatch(typeof(ItemAttributes), "Start")]
internal static class StartPatch
{
	[HarmonyPrefix]
	private static void Prefix(ItemAttributes __instance)
	{
		if (CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name) != null)
		{
			CatsPlugin.TrySendConfig();
			if (!((Object)(object)__instance.item != (Object)null))
			{
				Item val = ScriptableObject.CreateInstance<Item>();
				val.value = ScriptableObject.CreateInstance<Value>();
				val.itemName = "";
				__instance.item = val;
			}
		}
	}

	[HarmonyPostfix]
	private static void Postfix(ItemAttributes __instance)
	{
		if (CatsPlugin.GetCatType(((Object)((Component)__instance).gameObject).name) != null)
		{
			ItemManager instance = ItemManager.instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.spawnedItems.Remove(__instance);
			}
		}
	}
}
[HarmonyPatch(typeof(BatteryVisualLogic), "BatteryBarsSet")]
internal static class BatteryBarsPatch
{
	[HarmonyPrefix]
	private static bool Prefix(BatteryVisualLogic __instance)
	{
		if ((Object)(object)__instance.batteryBarPrefab != (Object)null)
		{
			return true;
		}
		BatteryVisualLogic[] array = Object.FindObjectsOfType<BatteryVisualLogic>();
		foreach (BatteryVisualLogic val in array)
		{
			if ((Object)(object)val != (Object)(object)__instance && (Object)(object)val.batteryBarPrefab != (Object)null)
			{
				__instance.batteryBarPrefab = val.batteryBarPrefab;
				return true;
			}
		}
		return false;
	}
}
internal static class TreatBuffs
{
	internal const float QuietRadiusMultiplier = 0.5f;

	internal const float SpeedMultiplier = 1.5f;

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

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

	private static bool _fastPending;

	private static bool _fastActive;

	private static PlayerController _boosted;

	private static readonly FieldInfo _steamID = AccessTools.Field(typeof(PlayerAvatar), "steamID");

	private static readonly FieldInfo _isLocal = AccessTools.Field(typeof(PlayerAvatar), "isLocal");

	private static readonly FieldInfo _origMove = AccessTools.Field(typeof(PlayerController), "playerOriginalMoveSpeed");

	private static readonly FieldInfo _origSprint = AccessTools.Field(typeof(PlayerController), "playerOriginalSprintSpeed");

	private static readonly FieldInfo _origCrouch = AccessTools.Field(typeof(PlayerController), "playerOriginalCrouchSpeed");

	internal static bool IsTreat(ItemHealthPack hp, out bool quiet)
	{
		Item val = ((Component)hp).GetComponent<ItemAttributes>()?.item;
		string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : "");
		quiet = text.Contains("Meoffin");
		if (!quiet)
		{
			return text.Contains("Catcake");
		}
		return true;
	}

	internal static bool IsQuiet(PlayerAvatar pa)
	{
		string text = (((Object)(object)pa != (Object)null) ? (_steamID.GetValue(pa) as string) : null);
		if (text != null)
		{
			return _quietActive.Contains(text);
		}
		return false;
	}

	internal static void Grant(PlayerAvatar pa, bool quiet)
	{
		if ((Object)(object)pa == (Object)null)
		{
			return;
		}
		bool flag = SemiFunc.RunIsLevel();
		string text = _steamID.GetValue(pa) as string;
		if (quiet)
		{
			if (text != null)
			{
				(flag ? _quietActive : _quietPending).Add(text);
			}
		}
		else if ((bool)_isLocal.GetValue(pa))
		{
			if (flag)
			{
				_fastActive = true;
				ApplySpeed(PlayerController.instance);
			}
			else
			{
				_fastPending = true;
			}
		}
		CatsPlugin.Log.LogInfo((object)("[Cats] " + (quiet ? "Meoffin" : "Catcake") + " eaten by " + text + " - " + (flag ? "active for this level" : "queued for next level")));
	}

	internal static void OnLevelStart(PlayerController pc)
	{
		_quietActive.Clear();
		_fastActive = false;
		if (SemiFunc.RunIsLevel())
		{
			_quietActive.UnionWith(_quietPending);
			_quietPending.Clear();
			_fastActive = _fastPending;
			_fastPending = false;
			if (_fastActive)
			{
				ApplySpeed(pc);
			}
		}
	}

	private static void ApplySpeed(PlayerController pc)
	{
		if (!((Object)(object)pc == (Object)null) && !((Object)(object)pc == (Object)(object)_boosted))
		{
			_boosted = pc;
			_origMove.SetValue(pc, (float)_origMove.GetValue(pc) * 1.5f);
			_origSprint.SetValue(pc, (float)_origSprint.GetValue(pc) * 1.5f);
			_origCrouch.SetValue(pc, (float)_origCrouch.GetValue(pc) * 1.5f);
			pc.MoveSpeed *= 1.5f;
			pc.SprintSpeed *= 1.5f;
			pc.CrouchSpeed *= 1.5f;
		}
	}
}
[HarmonyPatch(typeof(ItemHealthPack), "UsedRPC")]
internal static class TreatUsedPatch
{
	private static readonly FieldInfo _used = AccessTools.Field(typeof(ItemHealthPack), "used");

	private static readonly FieldInfo _togglePlayer = AccessTools.Field(typeof(ItemToggle), "playerTogglePhotonID");

	[HarmonyPostfix]
	private static void Postfix(ItemHealthPack __instance)
	{
		if ((bool)_used.GetValue(__instance) && TreatBuffs.IsTreat(__instance, out var quiet))
		{
			TreatBuffs.Grant(SemiFunc.PlayerAvatarGetFromPhotonID((int)_togglePlayer.GetValue(((Component)__instance).GetComponent<ItemToggle>())), quiet);
		}
	}
}
[HarmonyPatch(typeof(ItemHealthPack), "Update")]
internal static class TreatFullHpPatch
{
	private static readonly FieldInfo _used = AccessTools.Field(typeof(ItemHealthPack), "used");

	private static readonly FieldInfo _togglePlayer = AccessTools.Field(typeof(ItemToggle), "playerTogglePhotonID");

	private static readonly FieldInfo _health = AccessTools.Field(typeof(PlayerHealth), "health");

	private static readonly FieldInfo _maxHealth = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

	private static readonly FieldInfo _instanceName = AccessTools.Field(typeof(ItemAttributes), "instanceName");

	private static readonly MethodInfo _usedRPC = AccessTools.Method(typeof(ItemHealthPack), "UsedRPC", (Type[])null, (Type[])null);

	[HarmonyPrefix]
	private static bool Prefix(ItemHealthPack __instance)
	{
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		if (!SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.RunIsShop())
		{
			return true;
		}
		if ((bool)_used.GetValue(__instance) || !TreatBuffs.IsTreat(__instance, out var _))
		{
			return true;
		}
		ItemToggle component = ((Component)__instance).GetComponent<ItemToggle>();
		if (!component.toggleState)
		{
			return true;
		}
		PlayerAvatar val = SemiFunc.PlayerAvatarGetFromPhotonID((int)_togglePlayer.GetValue(component));
		if ((Object)(object)val == (Object)null)
		{
			return true;
		}
		if ((int)_health.GetValue(val.playerHealth) < (int)_maxHealth.GetValue(val.playerHealth))
		{
			return true;
		}
		StatsManager.instance.ItemRemove((string)_instanceName.GetValue(((Component)__instance).GetComponent<ItemAttributes>()));
		if (SemiFunc.IsMultiplayer())
		{
			((Component)__instance).GetComponent<PhotonView>().RPC("UsedRPC", (RpcTarget)0, Array.Empty<object>());
		}
		else
		{
			_usedRPC.Invoke(__instance, new object[1] { (object)default(PhotonMessageInfo) });
		}
		component.ToggleDisable(true);
		return false;
	}
}
[HarmonyPatch(typeof(PlayerController), "Start")]
internal static class TreatLevelPatch
{
	[HarmonyPostfix]
	private static void Postfix(PlayerController __instance)
	{
		TreatBuffs.OnLevelStart(__instance);
	}
}
[HarmonyPatch(typeof(EnemyDirector), "SetInvestigate")]
internal static class HushRadiusPatch
{
	internal static bool Quiet;

	[HarmonyPrefix]
	private static void Prefix(ref float radius)
	{
		if (Quiet)
		{
			radius *= 0.5f;
		}
	}
}
[HarmonyPatch(typeof(PlayerAvatar), "Footstep")]
internal static class HushFootstepPatch
{
	[HarmonyPrefix]
	private static void Prefix(PlayerAvatar __instance)
	{
		HushRadiusPatch.Quiet = TreatBuffs.IsQuiet(__instance);
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		HushRadiusPatch.Quiet = false;
	}
}
[HarmonyPatch(typeof(PlayerAvatar), "LandRPC")]
internal static class HushLandPatch
{
	[HarmonyPrefix]
	private static void Prefix(PlayerAvatar __instance)
	{
		HushRadiusPatch.Quiet = TreatBuffs.IsQuiet(__instance);
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		HushRadiusPatch.Quiet = false;
	}
}
[HarmonyPatch(typeof(PlayerVoiceChat), "Update")]
internal static class HushVoicePatch
{
	private static readonly FieldInfo _playerAvatar = AccessTools.Field(typeof(PlayerVoiceChat), "playerAvatar");

	[HarmonyPrefix]
	private static void Prefix(PlayerVoiceChat __instance)
	{
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			object? value = _playerAvatar.GetValue(__instance);
			HushRadiusPatch.Quiet = TreatBuffs.IsQuiet((PlayerAvatar)((value is PlayerAvatar) ? value : null));
		}
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		HushRadiusPatch.Quiet = false;
	}
}
[HarmonyPatch(typeof(ItemBattery), "BatteryChargeStartRPC")]
internal static class ItemBatteryChargePatch
{
	private static readonly FieldInfo _bvl = AccessTools.Field(typeof(ItemBattery), "batteryVisualLogic");

	private static readonly FieldInfo _isCharging = AccessTools.Field(typeof(ItemBattery), "isCharging");

	[HarmonyPostfix]
	private static void Postfix(ItemBattery __instance)
	{
		if (_bvl.GetValue(__instance) == null)
		{
			_isCharging.SetValue(__instance, false);
		}
	}
}
[HarmonyPatch]
internal static class MultiplayerPoolFallbackPatch
{
	private static MethodBase TargetMethod()
	{
		return AccessTools.Method(AccessTools.TypeByName("MultiplayerPool"), "Instantiate", new Type[3]
		{
			typeof(string),
			typeof(Vector3),
			typeof(Quaternion)
		}, (Type[])null);
	}

	[HarmonyPrefix]
	private static bool Prefix(string prefabId, Vector3 position, Quaternion rotation, ref GameObject __result)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		if (Array.IndexOf(CatsPlugin._extraNetworkPrefabNames, prefabId) < 0)
		{
			return true;
		}
		if (!NetworkPrefabs.Prefabs.TryGetValue(prefabId, out var value) || (Object)(object)value == (Object)null)
		{
			return true;
		}
		__result = Object.Instantiate<GameObject>(value, position, rotation);
		__result.SetActive(false);
		return false;
	}
}
[HarmonyPatch]
internal static class LocalizedAssetCrashGuard
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		return (from m in AccessTools.GetDeclaredMethods(AccessTools.TypeByName("LocalizedAsset"))
			where m.Name == "GetLocalizedString"
			select m).Cast<MethodBase>();
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Exception __exception, ref string __result)
	{
		if (__exception == null)
		{
			return null;
		}
		__result = null;
		return null;
	}
}
[HarmonyPatch(typeof(ItemGunLaser), "Start")]
internal static class CatGunSoundPatch
{
	internal static readonly HashSet<Sound> BuildupSounds = new HashSet<Sound>();

	[HarmonyPostfix]
	private static void Postfix(ItemGunLaser __instance)
	{
		if (((Object)((Component)__instance).gameObject).name == "Cat Gun")
		{
			BuildupSounds.Add(__instance.soundBuildup);
		}
	}
}
[HarmonyPatch(typeof(Sound), "PlayLoop")]
internal static class CatGunPitchPatch
{
	[HarmonyPrefix]
	private static void Prefix(Sound __instance, ref float pitchMultiplier)
	{
		if (CatGunSoundPatch.BuildupSounds.Contains(__instance))
		{
			pitchMultiplier = 1f;
		}
	}
}
[HarmonyPatch(typeof(ItemAttributes), "ShowingInfo")]
internal static class CatNamePatch
{
	private static readonly FieldInfo _promptName = AccessTools.Field(typeof(ItemAttributes), "promptName");

	[HarmonyPostfix]
	private static void Postfix(ItemAttributes __instance)
	{
		if ((Object)(object)__instance.item == (Object)null)
		{
			return;
		}
		string name = ((Object)((Component)__instance).gameObject).name;
		foreach (string catPrefabName in CatsPlugin.CatPrefabNames)
		{
			if (name.Contains(catPrefabName))
			{
				_promptName.SetValue(__instance, __instance.item.itemName);
				break;
			}
		}
	}
}
[HarmonyPatch(typeof(ItemToggle), "ToggleItemLogic")]
internal static class SoundPatch
{
	[HarmonyPostfix]
	private static void Postfix(ItemToggle __instance, bool toggle)
	{
		if (!toggle || !CatsPlugin.IsCat(((Object)((Component)__instance).gameObject).name))
		{
			return;
		}
		PhysGrabObject component = ((Component)__instance).GetComponent<PhysGrabObject>();
		if (!((Object)(object)component == (Object)null) && component.grabbedLocal)
		{
			AudioSource component2 = ((Component)__instance).GetComponent<AudioSource>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.Play();
			}
		}
	}
}
[HarmonyPatch(typeof(PlayerController), "Update")]
internal static class BananipPatch
{
	private static readonly FieldInfo _grabbedField = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

	private static readonly FieldInfo _vigActiveField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideActive");

	private static readonly FieldInfo _vigTimerField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideTimer");

	private static readonly FieldInfo _vigColorField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideColor");

	private static readonly FieldInfo _vigIntensityField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideIntensity");

	private static readonly FieldInfo _vigSmoothnessField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideSmoothness");

	private static readonly FieldInfo _vigLerpField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideLerp");

	private static readonly FieldInfo _vigSpeedInField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideSpeedIn");

	private static readonly FieldInfo _vigSpeedOutField = AccessTools.Field(typeof(PostProcessing), "vignetteOverrideSpeedOut");

	private static readonly FieldInfo _joltImpulseField = AccessTools.Field(typeof(PlayerController), "VelocityImpulse");

	internal static BananipEffects ActiveFx;

	private static float _baseFov;

	private static float _joltTimer;

	[HarmonyPostfix]
	private static void Postfix(PlayerController __instance)
	{
		//IL_0342: Unknown result type (might be due to invalid IL or missing references)
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0350: Unknown result type (might be due to invalid IL or missing references)
		//IL_0358: Unknown result type (might be due to invalid IL or missing references)
		//IL_0364: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__instance != (Object)(object)PlayerController.instance)
		{
			return;
		}
		PlayerAvatar playerAvatarScript = __instance.playerAvatarScript;
		BananipEffects bananipEffects = null;
		if ((Object)(object)playerAvatarScript != (Object)null && (Object)(object)playerAvatarScript.physGrabber != (Object)null)
		{
			object? obj = _grabbedField?.GetValue(playerAvatarScript.physGrabber);
			PhysGrabObject val = (PhysGrabObject)((obj is PhysGrabObject) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				bananipEffects = ((Component)val).GetComponent<BananipEffects>();
			}
		}
		BananipEffects activeFx = ActiveFx;
		ActiveFx = bananipEffects;
		PostProcessing instance = PostProcessing.Instance;
		if ((Object)(object)bananipEffects == (Object)null)
		{
			if ((Object)(object)instance != (Object)null)
			{
				_vigActiveField?.SetValue(instance, false);
			}
			if (_baseFov > 0f)
			{
				Camera main = Camera.main;
				if ((Object)(object)main != (Object)null)
				{
					main.fieldOfView = _baseFov;
				}
				_baseFov = 0f;
			}
			return;
		}
		if ((Object)(object)activeFx == (Object)null)
		{
			Camera main2 = Camera.main;
			_baseFov = ((main2 != null) ? main2.fieldOfView : 60f);
			_joltTimer = CatsPlugin.BananipJoltInterval.Value;
			if ((Object)(object)instance != (Object)null)
			{
				_vigLerpField?.SetValue(instance, 0f);
			}
		}
		__instance.OverrideSpeed(CatsPlugin.BananipSpeedMultiplier.Value, 0.2f, -1f);
		playerAvatarScript.OverridePupilSize(bananipEffects.pupilMultiplier, 3, 15f, 0.3f, 4f, 0.6f, 0.2f);
		if ((Object)(object)instance != (Object)null)
		{
			_vigActiveField?.SetValue(instance, true);
			_vigTimerField?.SetValue(instance, 0.2f);
			_vigColorField?.SetValue(instance, Color.black);
			float num = (Mathf.Sin(Time.time * CatsPlugin.BananipFovPulseSpeed.Value) + 1f) * 0.5f;
			float value = CatsPlugin.BananipVignetteIntensity.Value;
			_vigIntensityField?.SetValue(instance, Mathf.Lerp(value * 0.3f, value, num));
			_vigSmoothnessField?.SetValue(instance, 0.8f);
			_vigSpeedInField?.SetValue(instance, 1.5f);
			_vigSpeedOutField?.SetValue(instance, 2f);
			float num2 = Mathf.Abs(Mathf.Sin(Time.time * 2f)) * CatsPlugin.BananipLensDistortionIntensity.Value;
			instance.LensDistortionOverride(num2, 8f, 4f, 0.2f, (GameObject)null);
		}
		Camera main3 = Camera.main;
		if ((Object)(object)main3 != (Object)null && _baseFov > 0f)
		{
			main3.fieldOfView = _baseFov + Mathf.Sin(Time.time * CatsPlugin.BananipFovPulseSpeed.Value) * CatsPlugin.BananipFovPulseAmount.Value;
		}
		_joltTimer -= Time.deltaTime;
		if (_joltTimer <= 0f)
		{
			_joltTimer = CatsPlugin.BananipJoltInterval.Value;
			if (_joltImpulseField != null)
			{
				Vector3 val2 = new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f));
				Vector3 normalized = ((Vector3)(ref val2)).normalized;
				_joltImpulseField.SetValue(__instance, normalized * CatsPlugin.BananipJoltStrength.Value);
			}
		}
	}
}
[HarmonyPatch(typeof(ValuableDirector), "SetupHost")]
internal static class SpawnPatch
{
	internal static readonly Dictionary<Type, Vector3> VolSizes = new Dictionary<Type, Vector3>
	{
		{
			(Type)0,
			new Vector3(0.25f, 0.25f, 0.25f)
		},
		{
			(Type)1,
			new Vector3(0.5f, 0.5f, 0.5f)
		},
		{
			(Type)2,
			new Vector3(0.826f, 1f, 0.826f)
		},
		{
			(Type)3,
			new Vector3(1.25f, 1.5f, 1.25f)
		},
		{
			(Type)4,
			new Vector3(3f, 2.4f, 1.2f)
		},
		{
			(Type)5,
			new Vector3(2.4f, 3f, 1.2f)
		},
		{
			(Type)6,
			new Vector3(1.25f, 3.5f, 1.25f)
		}
	};

	private static int _catsSpawned;

	[HarmonyPostfix]
	private static void Postfix(ValuableDirector __instance)
	{
		try
		{
			PostfixBody(__instance);
		}
		catch (Exception arg)
		{
			CatsPlugin.Log.LogError((object)$"[Cats] SpawnPatch failed: {arg}");
		}
	}

	private static void PostfixBody(ValuableDirector __instance)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		if (!SemiFunc.IsMasterClientOrSingleplayer())
		{
			return;
		}
		RunManager instance = RunManager.instance;
		Level levelCurrent = instance.levelCurrent;
		if ((Object)(object)levelCurrent == (Object)(object)instance.levelMainMenu || (Object)(object)levelCurrent == (Object)(object)instance.levelLobbyMenu || (Object)(object)levelCurrent == (Object)(object)instance.levelLobby || !PhotonNetwork.InRoom)
		{
			return;
		}
		CatsPlugin.TrySendConfig();
		Dictionary<Type, List<Tuple<Vector3, Quaternion>>> dictionary = new Dictionary<Type, List<Tuple<Vector3, Quaternion>>>();
		ValuableVolume[] array = Object.FindObjectsOfType<ValuableVolume>();
		foreach (ValuableVolume val in array)
		{
			if (!dictionary.ContainsKey(val.VolumeType))
			{
				dictionary[val.VolumeType] = new List<Tuple<Vector3, Quaternion>>();
			}
			dictionary[val.VolumeType].Add(Tuple.Create<Vector3, Quaternion>(((Component)val).transform.position, ((Component)val).transform.rotation));
		}
		CatsPlugin.Log.LogDebug((object)$"[Cats] captured {dictionary.Values.Sum((List<Tuple<Vector3, Quaternion>> l) => l.Count)} volumes across {dictionary.Count} types");
		((MonoBehaviour)__instance).StartCoroutine(LevelSpawnFlow(__instance, dictionary, CatsPlugin.ControlledSpawning.Value));
	}

	private static IEnumerator LevelSpawnFlow(ValuableDirector director, Dictionary<Type, List<Tuple<Vector3, Quaternion>>> volumesByType, bool controlled)
	{
		bool nameCats = !controlled;
		if (controlled)
		{
			_catsSpawned = 0;
			yield return SpawnCats(director, volumesByType);
			nameCats = _catsSpawned > 0;
		}
		else
		{
			yield return WaitForValuablesToSettle();
		}
		bool guaranteedCat = false;
		try
		{
			guaranteedCat = GuaranteedSpawns.Ensure(volumesByType);
		}
		catch (Exception arg)
		{
			CatsPlugin.Log.LogError((object)$"[Cats] GuaranteedSpawns failed: {arg}");
		}
		if (guaranteedCat)
		{
			yield return (object)new WaitForSeconds(0.2f);
		}
		if (nameCats || guaranteedCat)
		{
			yield return CatsPlugin.Instance.AssignCatNames();
		}
	}

	private static IEnumerator WaitForValuablesToSettle()
	{
		int prev = -1;
		int stable = 0;
		float waited = 0f;
		while (stable < 3 || waited < 1f)
		{
			yield return (object)new WaitForSeconds(0.2f);
			waited += 0.2f;
			int num = Object.FindObjectsOfType<ValuableObject>().Length;
			if (num == prev)
			{
				stable++;
				continue;
			}
			stable = 0;
			prev = num;
		}
		CatsPlugin.Log.LogDebug((object)$"[Cats] stability check done — {prev} valuables in scene");
	}

	internal static void FilterVolumes(Dictionary<Type, List<Tuple<Vector3, Quaternion>>> volumesByType, IEnumerable<ValuableObject> existing)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		List<Vector3> occupied = new List<Vector3>();
		foreach (ValuableObject item2 in existing)
		{
			if ((Object)(object)item2 != (Object)null)
			{
				occupied.Add(((Component)item2).transform.position);
			}
		}
		foreach (List<Tuple<Vector3, Quaternion>> value in volumesByType.Values)
		{
			value.RemoveAll(delegate(Tuple<Vector3, Quaternion> v)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				Vector3 item = v.Item1;
				for (int i = 0; i < occupied.Count; i++)
				{
					Vector3 val = occupied[i] - item;
					if (((Vector3)(ref val)).sqrMagnitude < 1f)
					{
						return true;
					}
				}
				return false;
			});
		}
		int geoMask = LayerMask.GetMask(new string[1] { "Default" });
		int geoSkipped = 0;
		foreach (KeyValuePair<Type, List<Tuple<Vector3, Quaternion>>> item3 in volumesByType)
		{
			if (!VolSizes.TryGetValue(item3.Key, out var s))
			{
				continue;
			}
			item3.Value.RemoveAll(delegate(Tuple<Vector3, Quaternion> v)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				if (Physics.OverlapBox(v.Item1 + v.Item2 * Vector3.forward * (s.z / 2f) + v.Item2 * Vector3.up * (s.y / 2f) + Vector3.up * 0.01f, s / 2f, v.Item2, geoMask, (QueryTriggerInteraction)1).Length != 0)
				{
					int num = geoSkipped;
					geoSkipped = num + 1;
					return true;
				}
				return false;
			});
		}
		if (geoSkipped > 0)
		{
			CatsPlugin.Log.LogDebug((object)$"[Cats] {geoSkipped} volumes blocked by geometry");
		}
	}

	private static bool IsAllowedOnLevel(CatRarity cr, SpawnLevel currentLevel)
	{
		if (cr.spawnLevels != SpawnLevel.None)
		{
			return (cr.spawnLevels & currentLevel) != 0;
		}
		return true;
	}

	private static IEnumerator SpawnCats(ValuableDirector director, Dictionary<Type, List<Tuple<Vector3, Quaternion>>> volumesByType)
	{
		CatsPlugin.Log.LogDebug((object)"[Cats] SpawnCats coroutine started");
		if (CatsPlugin.CatPrefabNames.Count == 0)
		{
			CatsPlugin.BakeItemAttributesIntoCatPrefabs();
		}
		yield return WaitForValuablesToSettle();
		SpawnLevel currentLevel = CatsPlugin.CurrentSpawnLevel();
		List<PrefabRef> pool = Valuables.RegisteredValuables.Where((PrefabRef v) => CatsPlugin.CatPrefabNames.Contains(((PrefabRef<GameObject>)(object)v).PrefabName) && ((Object)(object)((PrefabRef<GameObject>)(object)v).Prefab == (Object)null || IsAllowedOnLevel(((PrefabRef<GameObject>)(object)v).Prefab.GetComponent<CatRarity>(), currentLevel))).ToList();
		if (pool.Count == 0)
		{
			CatsPlugin.Log.LogWarning((object)"[Cats] cat pool is empty, nothing to spawn");
			yield break;
		}
		ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>();
		int num = 0;
		ValuableObject[] array2 = array;
		foreach (ValuableObject val in array2)
		{
			if (CatsPlugin.IsCat(((Object)((Component)val).gameObject).name))
			{
				PhotonNetwork.Destroy(((Component)val).gameObject);
				num++;
			}
		}
		if (num > 0)
		{
			CatsPlugin.Log.LogDebug((object)$"[Cats] removed {num} naturally spawned cats");
			yield return (object)new WaitForSeconds(0.1f);
			array = Object.FindObjectsOfType<ValuableObject>();
		}
		FilterVolumes(volumesByType, array);
		int num3 = CatsPlugin.CommonWeight.Value + CatsPlugin.UncommonWeight.Value + CatsPlugin.RareWeight.Value + CatsPlugin.CustomWeight.Value;
		if (num3 <= 0)
		{
			CatsPlugin.Log.LogWarning((object)"[Cats] all weights are 0, nothing to spawn");
			yield break;
		}
		List<PrefabRef> list = new List<PrefabRef>();
		List<PrefabRef> list2 = new List<PrefabRef>();
		List<PrefabRef> list3 = new List<PrefabRef>();
		List<PrefabRef> list4 = new List<PrefabRef>();
		foreach (PrefabRef item in pool)
		{
			switch (((PrefabRef<GameObject>)(object)item).Prefab.GetComponent<CatRarity>().rarity)
			{
			case Rarity.Common:
				list.Add(item);
				break;
			case Rarity.Uncommon:
				list2.Add(item);
				break;
			case Rarity.Rare:
				list3.Add(item);
				break;
			case Rarity.Custom:
				list4.Add(item);
				break;
			}
		}
		int value = CatsPlugin.SpawnCount.Value;
		int num4 = 0;
		int num5 = 0;
		while (num4 < value && num5 < 60)
		{
			num5++;
			int num6 = Random.Range(0, num3);
			int value2 = CatsPlugin.CommonWeight.Value;
			int value3 = CatsPlugin.UncommonWeight.Value;
			int value4 = CatsPlugin.RareWeight.Value;
			Rarity rarity = ((num6 >= value2) ? ((num6 < value2 + value3) ? Rarity.Uncommon : ((num6 >= value2 + value3 + value4) ? Rarity.Custom : Rarity.Rare)) : Rarity.Common);
			List<PrefabRef> list5 = rarity switch
			{
				Rarity.Rare => list3, 
				Rarity.Uncommon => list2, 
				Rarity.Common => list, 
				_ => list4, 
			};
			if (list5.Count == 0)
			{
				CatsPlugin.Log.LogDebug((object)$"[Cats] rolled {rarity} but that pool is empty");
				continue;
			}
			PrefabRef val2 = list5[Random.Range(0, list5.Count)];
			ValuableObject val3 = (((Object)(object)((PrefabRef<GameObject>)(object)val2).Prefab != (Object)null) ? ((PrefabRef<GameObject>)(object)val2).Prefab.GetComponent<ValuableObject>() : null);
			if (!((Object)(object)val3 == (Object)null))
			{
				if (!volumesByType.TryGetValue(val3.volumeType, out var value5) || value5.Count == 0)
				{
					CatsPlugin.Log.LogDebug((object)$"[Cats] no volumes left for {((PrefabRef<GameObject>)(object)val2).PrefabName} (type {val3.volumeType})");
					continue;
				}
				int num7 = Random.Range(0, value5.Count);
				CatsPlugin.Log.LogInfo((object)$"[Cats] spawning {((PrefabRef<GameObject>)(object)val2).PrefabName} at volume slot {num7}");
				Valuables.SpawnValuable(val2, value5[num7].Item1, value5[num7].Item2);
				value5.RemoveAt(num7);
				num4++;
			}
		}
		CatsPlugin.Log.LogInfo((object)$"[Cats] spawned {num4}/{value} cats ({num5} attempts)");
		_catsSpawned = num4;
	}
}
internal static class GuaranteedSpawns
{
	private static readonly FieldInfo _levelsCompleted = AccessTools.Field(typeof(RunManager), "levelsCompleted");

	private static string StripClone(string n)
	{
		return n.Replace("(Clone)", "").Trim();
	}

	internal static bool Ensure(Dictionary<Type, List<Tuple<Vector3, Quaternion>>> volumesByType)
	{
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0305: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		if (!SemiFunc.IsMasterClientOrSingleplayer())
		{
			return false;
		}
		if (!SemiFunc.RunIsLevel())
		{
			return false;
		}
		SpawnLevel spawnLevel = CatsPlugin.CurrentSpawnLevel();
		int num = 1;
		if (_levelsCompleted != null && (Object)(object)RunManager.instance != (Object)null)
		{
			num = (int)_levelsCompleted.GetValue(RunManager.instance) + 1;
		}
		List<Tuple<PrefabRef, HolidaySpawn>> list = new List<Tuple<PrefabRef, HolidaySpawn>>();
		HashSet<string> hashSet = new HashSet<string>();
		foreach (PrefabRef registeredValuable in Valuables.RegisteredValuables)
		{
			if (registeredValuable == null || (Object)(object)((PrefabRef<GameObject>)(object)registeredValuable).Prefab == (Object)null || !hashSet.Add(((PrefabRef<GameObject>)(object)registeredValuable).PrefabName))
			{
				continue;
			}
			HolidaySpawn component = ((PrefabRef<GameObject>)(object)registeredValuable).Prefab.GetComponent<HolidaySpawn>();
			if (!((Object)(object)component == (Object)null) && component.guaranteeEnabled && (component.levels == SpawnLevel.None || (component.levels & spawnLevel) != SpawnLevel.None) && num >= component.startLevel)
			{
				if (component.chance < 1f && Random.value >= component.chance)
				{
					CatsPlugin.Log.LogDebug((object)$"[Cats] guaranteed {((PrefabRef<GameObject>)(object)registeredValuable).PrefabName} skipped this level (chance {component.chance:P0})");
				}
				else
				{
					list.Add(Tuple.Create<PrefabRef, HolidaySpawn>(registeredValuable, component));
				}
			}
		}
		if (list.Count == 0)
		{
			return false;
		}
		list.Sort((Tuple<PrefabRef, HolidaySpawn> a, Tuple<PrefabRef, HolidaySpawn> b) => a.Item2.priority.CompareTo(b.Item2.priority));
		ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>();
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		ValuableObject[] array2 = array;
		for (int num2 = 0; num2 < array2.Length; num2++)
		{
			string key = StripClone(((Object)((Component)array2[num2]).gameObject).name);
			dictionary.TryGetValue(key, out var value);
			dictionary[key] = value + 1;
		}
		SpawnPatch.FilterVolumes(volumesByType, array);
		bool result = false;
		foreach (Tuple<PrefabRef, HolidaySpawn> item3 in list)
		{
			PrefabRef item = item3.Item1;
			HolidaySpawn item2 = item3.Item2;
			ValuableObject component2 = ((PrefabRef<GameObject>)(object)item).Prefab.GetComponent<ValuableObject>();
			if ((Object)(object)component2 == (Object)null)
			{
				CatsPlugin.Log.LogWarning((object)("[Cats] " + ((PrefabRef<GameObject>)(object)item).PrefabName + " has HolidaySpawn but no ValuableObject - skipping"));
				continue;
			}
			int value2 = 0;
			if (item2.countNaturalSpawns)
			{
				dictionary.TryGetValue(((PrefabRef<GameObject>)(object)item).PrefabName, out value2);
			}
			int num3 = item2.minimumCount - value2;
			if (num3 <= 0)
			{
				CatsPlugin.Log.LogDebug((object)$"[Cats] guaranteed {((PrefabRef<GameObject>)(object)item).PrefabName} already has {value2}/{item2.minimumCount}");
				continue;
			}
			int num4 = 0;
			for (int num5 = 0; num5 < num3; num5++)
			{
				if (!TryTakeVolume(volumesByType, component2.volumeType, item2.allowLargerVolumes, out var pos, out var rot))
				{
					CatsPlugin.Log.LogWarning((object)$"[Cats] no free volume left for guaranteed {((PrefabRef<GameObject>)(object)item).PrefabName} (type {component2.volumeType}) - placed {num4}/{num3}");
					break;
				}
				Valuables.SpawnValuable(item, pos, rot);
				num4++;
			}
			if (num4 > 0)
			{
				CatsPlugin.Log.LogInfo((object)$"[Cats] guaranteed spawn: {((PrefabRef<GameObject>)(object)item).PrefabName} x{num4} (had {value2}, min {item2.minimumCount})");
				if (CatsPlugin.CatPrefabNames.Contains(((PrefabRef<GameObject>)(object)item).PrefabName))
				{
					result = true;
				}
			}
		}
		return result;
	}

	private static bool TryTakeVolume(Dictionary<Type, List<Tuple<Vector3, Quaternion>>> volumesByType, Type type, bool allowLarger, out Vector3 pos, out Quaternion rot)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		pos = Vector3.zero;
		rot = Quaternion.identity;
		List<Type> list = new List<Type> { type };
		if (allowLarger && SpawnPatch.VolSizes.TryGetValue(type, out var need))
		{
			list.AddRange(from kv in SpawnPatch.VolSizes
				where kv.Key != type && kv.Value.x >= need.x && kv.Value.y >= need.y && kv.Value.z >= need.z
				orderby kv.Value.x * kv.Value.y * kv.Value.z
				select kv.Key);
		}
		foreach (Type item in list)
		{
			if (volumesByType.TryGetValue(item, out var value) && value.Count != 0)
			{
				int index = Random.Range(0, value.Count);
				pos = value[index].Item1;
				rot = value[index].Item2;
				value.RemoveAt(index);
				return true;
			}
		}
		return false;
	}
}