Decompiled source of BarberFixes v1.3.0

BarberFixes.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LobbyCompatibility.Enums;
using LobbyCompatibility.Features;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BarberFixes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fixes some major issues with Barbers")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0+b219f5a3a6dab73c227a5d9f3d11a0c4f27afdbb")]
[assembly: AssemblyProduct("BarberFixes")]
[assembly: AssemblyTitle("BarberFixes")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BarberFixes
{
	internal static class LobbyCompatibility
	{
		internal static void Init()
		{
			PluginHelper.RegisterPlugin("butterystancakes.lethalcompany.barberfixes", Version.Parse("1.3.0"), (CompatibilityLevel)2, (VersionStrictness)0);
		}
	}
	[BepInPlugin("butterystancakes.lethalcompany.barberfixes", "Barber Fixes", "1.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal const string PLUGIN_GUID = "butterystancakes.lethalcompany.barberfixes";

		internal const string PLUGIN_NAME = "Barber Fixes";

		internal const string PLUGIN_VERSION = "1.3.0";

		private const string GUID_VENT_SPAWN_FIX = "butterystancakes.lethalcompany.ventspawnfix";

		private const string GUID_LOBBY_COMPATIBILITY = "BMX.LobbyCompatibility";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<bool> configDrumrollFromAll;

		internal static ConfigEntry<bool> configApplySpawningSettings;

		internal static ConfigEntry<int> configMaxCount;

		internal static ConfigEntry<int> configSpawnInGroupsOf;

		internal static bool CAN_SPAWN_IN_GROUPS;

		private void Awake()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			if (Chainloader.PluginInfos.ContainsKey("butterystancakes.lethalcompany.ventspawnfix"))
			{
				CAN_SPAWN_IN_GROUPS = true;
				Logger.LogInfo((object)"CROSS-COMPATIBILITY - VentSpawnFix detected");
			}
			if (Chainloader.PluginInfos.ContainsKey("BMX.LobbyCompatibility"))
			{
				Logger.LogInfo((object)"CROSS-COMPATIBILITY - Lobby Compatibility detected");
				LobbyCompatibility.Init();
			}
			configApplySpawningSettings = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "ApplySpawningSettings", false, "The rest of the \"Spawning\" section's settings are only applied if this is enabled. You should enable this only if you aren't using something else to configure enemy variables! (i.e. Clay Surgeon Overhaul, Lethal Quantities)");
			configMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("(Host only) How many Barbers are allowed to spawn?\nIn v62+, this is set to 1. In v55-v61, this was set to 8.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			configSpawnInGroupsOf = ((BaseUnityPlugin)this).Config.Bind<int>("Spawning", "SpawnInGroupsOf", 1, new ConfigDescription("(Host only) When a Barber spawns, should additional Barbers attempt to spawn?\nIn v56+, this is set to 1. In v55, this was set to 2.\nNOTE: This REQUIRES VentSpawnFix to work!", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
			configDrumrollFromAll = ((BaseUnityPlugin)this).Config.Bind<bool>("Music", "DrumrollFromAll", false, "If true, all Barbers will play the drumroll audio before they \"jump\". If false, only the master Barber will drumroll.\nThis is false in vanilla, although whether that's by design or a bug is unclear.");
			if (!((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "OnlyOneBarber", true, "Legacy setting, doesn't work").Value && configMaxCount.Value == 1)
			{
				configMaxCount.Value = 8;
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "SpawnInPairs", false, "Legacy setting, doesn't work").Value && configSpawnInGroupsOf.Value == 1)
			{
				configSpawnInGroupsOf.Value = 2;
			}
			((BaseUnityPlugin)this).Config.Remove(((BaseUnityPlugin)this).Config["Spawning", "OnlyOneBarber"].Definition);
			((BaseUnityPlugin)this).Config.Remove(((BaseUnityPlugin)this).Config["Spawning", "SpawnInPairs"].Definition);
			((BaseUnityPlugin)this).Config.Save();
			new Harmony("butterystancakes.lethalcompany.barberfixes").PatchAll();
			Logger.LogInfo((object)"Barber Fixes v1.3.0 loaded");
		}
	}
	[HarmonyPatch]
	internal class BarberFixesPatches
	{
		private static readonly MethodInfo OBJECT_DESTROY = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null);

		private static readonly FieldInfo MUSIC_AUDIO_2 = AccessTools.Field(typeof(ClaySurgeonAI), "musicAudio2");

		private static readonly FieldInfo ON_HOUR_CHANGED = AccessTools.Field(typeof(TimeOfDay), "onHourChanged");

		[HarmonyPatch(typeof(ClaySurgeonAI), "ChooseMasterSurgeon")]
		[HarmonyPrefix]
		private static bool PreChooseMasterSurgeon(ClaySurgeonAI __instance, ref bool ___isMaster)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			if (!((NetworkBehaviour)__instance).IsServer)
			{
				return false;
			}
			ClaySurgeonAI[] array = Object.FindObjectsByType<ClaySurgeonAI>((FindObjectsSortMode)0);
			if (array.Length == 1)
			{
				__instance.master = __instance;
			}
			else
			{
				__instance.master = ((IEnumerable<ClaySurgeonAI>)array).FirstOrDefault((Func<ClaySurgeonAI, bool>)((ClaySurgeonAI barber) => (Object)(object)barber.master == (Object)(object)barber));
				if ((Object)(object)__instance.master == (Object)null)
				{
					__instance.master = __instance;
				}
			}
			if ((Object)(object)__instance.master == (Object)(object)__instance)
			{
				___isMaster = true;
				DanceClock.Start(__instance.startingInterval, __instance.endingInterval);
			}
			__instance.master.SendDanceBeat = new SimpleEvent();
			for (int i = 0; i < array.Length; i++)
			{
				if (!__instance.master.allClaySurgeons.Contains(array[i]))
				{
					__instance.master.allClaySurgeons.Add(array[i]);
				}
				if ((Object)(object)array[i] != (Object)(object)__instance.master)
				{
					array[i].master = __instance.master;
					array[i].ListenToMasterSurgeon();
				}
			}
			__instance.master.SyncMasterClaySurgeonClientRpc();
			return false;
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "ListenToMasterSurgeon")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransListenToMasterSurgeon(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			Label? label = null;
			for (int i = 0; i < list.Count; i++)
			{
				if (!label.HasValue)
				{
					if (list[i].opcode == OpCodes.Brtrue)
					{
						label = (Label)list[i].operand;
						Plugin.Logger.LogDebug((object)"Transpiler (ListenToMasterSurgeon): Allow when \"listeningToMasterSurgeon\" is already true");
					}
					list.RemoveAt(i--);
					continue;
				}
				if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == OBJECT_DESTROY && list[i - 2].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 2].operand == MUSIC_AUDIO_2)
				{
					list.RemoveRange(i - 3, 4);
					Plugin.Logger.LogDebug((object)"Transpiler (ListenToMasterSurgeon): Don't destroy \"musicAudio2\" (causes NRE)");
					i -= 3;
				}
				if (list[i].labels.Contains(label.Value))
				{
					list[i].labels.Remove(label.Value);
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "SyncMasterClaySurgeonClientRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransSyncMasterClaySurgeonClientRpc(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && list[i].operand.ToString().Contains("AddListener") && list[i - 4].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 4].operand == ON_HOUR_CHANGED)
				{
					list.RemoveRange(i - 5, 6);
					Plugin.Logger.LogDebug((object)"Transpiler (SyncMasterClaySurgeonClientRpc): Don't add listener to \"onHourChanged\"");
					i -= 5;
					list.InsertRange(i, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[5]
					{
						new CodeInstruction(OpCodes.Ldarg_0, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(ClaySurgeonAI), "startingInterval")),
						new CodeInstruction(OpCodes.Ldarg_0, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(ClaySurgeonAI), "endingInterval")),
						new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DanceClock), "Start", (Type[])null, (Type[])null))
					}));
					Plugin.Logger.LogDebug((object)"Transpiler (SyncMasterClaySurgeonClientRpc): Use new \"DanceClock\"");
				}
				else if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == OBJECT_DESTROY && list[i - 2].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 2].operand == MUSIC_AUDIO_2)
				{
					list.RemoveRange(i - 6, 7);
					Plugin.Logger.LogDebug((object)"Transpiler (SyncMasterClaySurgeonClientRpc): Don't destroy \"musicAudio2\" (causes NRE)");
					i -= 6;
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "OnDestroy")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ClaySurgeonAITransOnDestroy(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && list[i].operand.ToString().Contains("RemoveListener") && list[i - 4].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 4].operand == ON_HOUR_CHANGED)
				{
					list.RemoveRange(i - 5, 6);
					Plugin.Logger.LogDebug((object)"Transpiler (ClaySurgeonAI.OnDestroy): Don't remove listener from \"onHourChanged\"");
					i -= 5;
					list.Insert(i, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DanceClock), "Stop", (Type[])null, (Type[])null)));
					Plugin.Logger.LogDebug((object)"Transpiler (ClaySurgeonAI.OnDestroy): Use new \"DanceClock\"");
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "KillPlayerClientRpc")]
		[HarmonyPostfix]
		private static void ClaySurgeonAIPostKillPlayerClientRpc(ClaySurgeonAI __instance, ref bool ___isMaster, ref float ___beatTimer, ref float ___snareIntervalTimer)
		{
			if (((NetworkBehaviour)__instance).IsOwner & ___isMaster)
			{
				___beatTimer = Mathf.Min(___beatTimer, 4f + __instance.snareOffset);
				___snareIntervalTimer = ___beatTimer - __instance.snareOffset;
			}
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "PlayMusic")]
		[HarmonyPostfix]
		private static void ClaySurgeonAIPostPlayMusic(ClaySurgeonAI __instance, float ___snareIntervalTimer)
		{
			if (___snareIntervalTimer != 100f || !Plugin.configDrumrollFromAll.Value)
			{
				return;
			}
			foreach (ClaySurgeonAI allClaySurgeon in __instance.allClaySurgeons)
			{
				if ((Object)(object)allClaySurgeon != (Object)(object)__instance)
				{
					allClaySurgeon.musicAudio.PlayOneShot(allClaySurgeon.snareDrum);
					WalkieTalkie.TransmitOneShotAudio(allClaySurgeon.musicAudio, allClaySurgeon.snareDrum, 1f);
				}
			}
		}

		[HarmonyPatch(typeof(RoundManager), "AdvanceHourAndSpawnNewBatchOfEnemies")]
		[HarmonyPrefix]
		private static void PreAdvanceHourAndSpawnNewBatchOfEnemies(RoundManager __instance)
		{
			if (!((NetworkBehaviour)__instance).IsServer || !Plugin.configApplySpawningSettings.Value)
			{
				return;
			}
			EnemyType val = ((IEnumerable<SpawnableEnemyWithRarity>)__instance.currentLevel.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)delegate(SpawnableEnemyWithRarity enemy)
			{
				EnemyType enemyType3 = enemy.enemyType;
				return ((enemyType3 != null) ? ((Object)enemyType3).name : null) == "ClaySurgeon";
			})?.enemyType;
			if ((Object)(object)val == (Object)null)
			{
				val = ((IEnumerable<SpawnableEnemyWithRarity>)__instance.currentLevel.OutsideEnemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)delegate(SpawnableEnemyWithRarity enemy)
				{
					EnemyType enemyType2 = enemy.enemyType;
					return ((enemyType2 != null) ? ((Object)enemyType2).name : null) == "ClaySurgeon";
				})?.enemyType ?? ((IEnumerable<SpawnableEnemyWithRarity>)__instance.currentLevel.DaytimeEnemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)delegate(SpawnableEnemyWithRarity enemy)
				{
					EnemyType enemyType = enemy.enemyType;
					return ((enemyType != null) ? ((Object)enemyType).name : null) == "ClaySurgeon";
				})?.enemyType;
				if ((Object)(object)val != (Object)null && !Plugin.CAN_SPAWN_IN_GROUPS)
				{
					Plugin.CAN_SPAWN_IN_GROUPS = true;
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				int value = Plugin.configSpawnInGroupsOf.Value;
				if (value > 1 && !Plugin.CAN_SPAWN_IN_GROUPS)
				{
					Plugin.Logger.LogWarning((object)"Config setting \"SpawnInGroupsOf\" is greater than 1, but VentSpawnFix was not detected. Enemies spawning from vents in groups is unsupported by vanilla, so this setting won't work!");
				}
				else if (Plugin.configMaxCount.Value < value)
				{
					Plugin.Logger.LogWarning((object)"Config setting \"SpawnInGroupsOf\" exceeds \"MaxCount\" and will be capped.");
					value = Plugin.configMaxCount.Value;
				}
				if (val.spawnInGroupsOf != value)
				{
					Plugin.Logger.LogDebug((object)$"ClaySurgeon.spawnInGroupsOf: {val.spawnInGroupsOf} -> {value}");
					val.spawnInGroupsOf = value;
				}
				int value2 = Plugin.configMaxCount.Value;
				if (val.MaxCount != value2)
				{
					Plugin.Logger.LogDebug((object)$"ClaySurgeon.MaxCount: {val.MaxCount} -> {value2}");
					val.MaxCount = value2;
				}
			}
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "Start")]
		[HarmonyPostfix]
		private static void ClaySurgeonAIPostStart(ClaySurgeonAI __instance, ref float ___snareIntervalTimer)
		{
			((EnemyAI)__instance).agent.speed = 0f;
			___snareIntervalTimer = 100f;
			EnemyAICollisionDetect componentInChildren = ((Component)__instance).GetComponentInChildren<EnemyAICollisionDetect>();
			GameObject val = ((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null);
			if ((Object)(object)val != (Object)null && !Object.op_Implicit((Object)(object)val.GetComponent<Rigidbody>()))
			{
				Rigidbody obj = val.AddComponent<Rigidbody>();
				obj.isKinematic = true;
				obj.collisionDetectionMode = (CollisionDetectionMode)3;
			}
		}

		[HarmonyPatch(typeof(ClaySurgeonAI), "OnCollideWithPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ClaySurgeonAITransOnCollideWithPlayer(IEnumerable<CodeInstruction> instructions)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			list.InsertRange(list.Count - 1, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Ldc_R4, (object)0f),
				new CodeInstruction(OpCodes.Stfld, (object)AccessTools.Field(typeof(ClaySurgeonAI), "timeSinceSnip"))
			}));
			Plugin.Logger.LogDebug((object)"Transpiler (ClaySurgeonAI.OnCollideWithPlayer): Set cooldown for local client immediately");
			return list;
		}
	}
	public class DanceClock
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Tick;
		}

		private static bool ticking;

		private static float startingInterval = 2.75f;

		private static float endingInterval = 1.25f;

		internal static void Start(float start, float end)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (!ticking)
			{
				ticking = true;
				startingInterval = start;
				endingInterval = end;
				UnityEvent onHourChanged = TimeOfDay.Instance.onHourChanged;
				object obj = <>O.<0>__Tick;
				if (obj == null)
				{
					UnityAction val = Tick;
					<>O.<0>__Tick = val;
					obj = (object)val;
				}
				onHourChanged.AddListener((UnityAction)obj);
			}
		}

		public static void Tick()
		{
			float currentInterval = Mathf.Lerp(startingInterval, endingInterval, (float)TimeOfDay.Instance.hour / (float)TimeOfDay.Instance.numberOfHours);
			ClaySurgeonAI[] array = Object.FindObjectsByType<ClaySurgeonAI>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].currentInterval = currentInterval;
			}
		}

		internal static void Stop()
		{
			//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: Expected O, but got Unknown
			if (ticking)
			{
				ticking = false;
				UnityEvent onHourChanged = TimeOfDay.Instance.onHourChanged;
				object obj = <>O.<0>__Tick;
				if (obj == null)
				{
					UnityAction val = Tick;
					<>O.<0>__Tick = val;
					obj = (object)val;
				}
				onHourChanged.RemoveListener((UnityAction)obj);
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "BarberFixes";

		public const string PLUGIN_NAME = "BarberFixes";

		public const string PLUGIN_VERSION = "1.3.0";
	}
}
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => _items.Length;

	T IReadOnlyList<T>.this[int index] => _items[index];

	int ICollection<T>.Count => _items.Length;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlyArray(T[] items)
	{
		_items = items;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return ((IEnumerable)_items).GetEnumerator();
	}

	void ICollection.CopyTo(Array array, int index)
	{
		((ICollection)_items).CopyTo(array, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return ((IList)_items).Contains(value);
	}

	int IList.IndexOf(object value)
	{
		return ((IList)_items).IndexOf(value);
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return ((IEnumerable<T>)_items).GetEnumerator();
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return ((ICollection<T>)_items).Contains(item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		((ICollection<T>)_items).CopyTo(array, arrayIndex);
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		return ((IList<T>)_items).IndexOf(item);
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}