Decompiled source of Fellow Droid v1.0.1

FellowDroid.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FellowDroid
{
	internal static class Cfg
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<bool> CopyNameTag;

		public static ConfigEntry<bool> KeepDisguiseAfterTransform;

		public static ConfigEntry<float> Scale;

		public static void Bind(ConfigFile c)
		{
			Enabled = c.Bind<bool>("General", "Enabled", true, "Master switch for the whole mod. Off means the droid stays exactly as Wesleys Enemies made it.");
			CopyNameTag = c.Bind<bool>("General", "CopyNameTag", true, "Show the stolen player name above the droid, exactly the way real player names show up. Turn it off if a fake name feels like too much.");
			KeepDisguiseAfterTransform = c.Bind<bool>("General", "KeepDisguiseAfterTransform", true, "Keep the stolen look after the droid turns into its second form. On by default: the copied outfit is not visible on that form anyway, but the copied colours are, and the creature staying the player's colour reads better than it snapping back to a stock one. Turn it off for a completely plain fight.");
			Scale = c.Bind<float>("General", "Scale", 1f, "Size correction for the copied cosmetics. The droid rig matches the player rig, so 1.0 should be right; raise or lower it only if things sit visibly too big or too small.");
		}
	}
	internal class Disguise : MonoBehaviour
	{
		private static readonly List<int> UsedThisLevel = new List<int>();

		private static object lastLevel;

		private static Transform holder;

		private const string DecorationFolder = "HeadDecorations";

		private const string WorldFollower = "WorldDecorationFollower";

		private static int albedoId;

		private static int emissionId;

		private static int fresnelId;

		private static bool shaderIdsReady;

		private readonly List<GameObject> spawned = new List<GameObject>();

		private readonly List<GameObject> created = new List<GameObject>();

		private readonly List<Renderer> tinted = new List<Renderer>();

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

		private readonly List<Renderer> hiddenParts = new List<Renderer>();

		private Transform worldAnchor;

		private NameTag nameTag;

		private Component droid;

		private PhotonView view;

		private static readonly string[] BodyParts = new string[12]
		{
			"head_top", "head_bot", "body_top", "body_bot", "arm_l", "arm_r", "leg_l", "leg_r", "eye_l", "eye_r",
			"pupil_l", "pupil_r"
		};

		internal static void OnDroidSpawn(Component lostDroid)
		{
			if ((Object)(object)lostDroid == (Object)null)
			{
				return;
			}
			Disguise disguise = lostDroid.GetComponent<Disguise>();
			if ((Object)(object)disguise == (Object)null)
			{
				disguise = lostDroid.gameObject.AddComponent<Disguise>();
				disguise.droid = lostDroid;
				disguise.view = lostDroid.GetComponent<PhotonView>();
				if ((Object)(object)disguise.view != (Object)null)
				{
					disguise.view.RefreshRpcMonoBehaviourCache();
				}
			}
			disguise.TakeOff();
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			EnsureLevel();
			int num = ChooseVictim();
			if (num < 0)
			{
				Plugin.Log.LogInfo((object)"Fellow Droid: некого копировать, дроид остался обычным.");
				return;
			}
			UsedThisLevel.Add(num);
			if (SemiFunc.IsMultiplayer() && (Object)(object)disguise.view != (Object)null)
			{
				disguise.view.RPC("FellowDroidWearRPC", (RpcTarget)0, new object[1] { num });
			}
			else
			{
				disguise.WearRPC(num);
			}
		}

		internal static void OnDroidTransform(Component lostDroid)
		{
			if (!((Object)(object)lostDroid == (Object)null) && !Cfg.KeepDisguiseAfterTransform.Value)
			{
				Disguise component = lostDroid.GetComponent<Disguise>();
				if ((Object)(object)component != (Object)null)
				{
					component.TakeOff();
				}
			}
		}

		private void OnDestroy()
		{
			TakeOff();
		}

		private static void EnsureLevel()
		{
			object instance = LevelGenerator.Instance;
			if (instance != lastLevel)
			{
				UsedThisLevel.Clear();
				lastLevel = instance;
			}
		}

		private static int ChooseVictim()
		{
			GameDirector instance = GameDirector.instance;
			if ((Object)(object)instance == (Object)null || instance.PlayerList == null)
			{
				return -1;
			}
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			foreach (PlayerAvatar player in instance.PlayerList)
			{
				if (!((Object)(object)player == (Object)null) && !((Object)(object)player.photonView == (Object)null))
				{
					int viewID = player.photonView.ViewID;
					list.Add(viewID);
					if (!player.isDisabled)
					{
						list2.Add(viewID);
					}
				}
			}
			return Victims.Pick(list2, list, UsedThisLevel, (int count) => Random.Range(0, count));
		}

		private static PlayerAvatar FindPlayer(int viewId)
		{
			GameDirector instance = GameDirector.instance;
			if ((Object)(object)instance == (Object)null || instance.PlayerList == null)
			{
				return null;
			}
			foreach (PlayerAvatar player in instance.PlayerList)
			{
				if ((Object)(object)player != (Object)null && (Object)(object)player.photonView != (Object)null && player.photonView.ViewID == viewId)
				{
					return player;
				}
			}
			return null;
		}

		[PunRPC]
		private void FellowDroidWearRPC(int viewId)
		{
			WearRPC(viewId);
		}

		private void WearRPC(int viewId)
		{
			PlayerAvatar val = FindPlayer(viewId);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Fellow Droid: игрок " + viewId + " не найден, маскировки не будет."));
			}
			else
			{
				Wear(val);
			}
		}

		private void Wear(PlayerAvatar victim)
		{
			TakeOff();
			if ((Object)(object)victim.playerAvatarVisuals == (Object)null || (Object)(object)victim.playerCosmetics == (Object)null)
			{
				return;
			}
			if ((Object)(object)GameplayManager.instance != (Object)null && !GameplayManager.instance.cosmetics)
			{
				Plugin.Log.LogInfo((object)"Fellow Droid: в лобби выключена косметика, дроид остался обычным.");
				return;
			}
			Transform transform = ((Component)victim.playerAvatarVisuals).transform;
			Transform val = RigRoot();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Fellow Droid: у дроида не нашёлся узел [RIG], маскировки не будет.");
				return;
			}
			EnsureShaderIds();
			HideSameParts(transform, val);
			List<Cosmetic> cosmeticEquipped = victim.playerCosmetics.cosmeticEquipped;
			if (cosmeticEquipped != null)
			{
				foreach (Cosmetic item in cosmeticEquipped)
				{
					if (!((Object)(object)item == (Object)null))
					{
						if (!((Component)item).gameObject.activeInHierarchy)
						{
							Plugin.Log.LogInfo((object)("Fellow Droid: вещь \"" + ((Object)item).name + "\" на игроке выключена, пропускаем."));
						}
						else
						{
							TryWear(((Component)item).transform, null, transform, val, victim);
						}
					}
				}
			}
			WearDecorations(transform, val, victim);
			Recolor(victim);
			WearNameTag(victim, transform, val);
			Plugin.Log.LogInfo((object)("Fellow Droid: дроид надел " + spawned.Count + " вещей игрока " + victim.playerName + "."));
		}

		private void WearNameTag(PlayerAvatar victim, Transform sourceRoot, Transform targetRoot)
		{
			if (!Cfg.CopyNameTag.Value)
			{
				return;
			}
			Transform val = null;
			if ((Object)(object)victim.playerAvatarVisuals != (Object)null)
			{
				val = RigMirror.Mirror(sourceRoot, targetRoot, victim.playerAvatarVisuals.headLookAtTransform, created);
			}
			if ((Object)(object)val == (Object)null)
			{
				val = targetRoot;
				Transform[] componentsInChildren = ((Component)targetRoot).GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					if (((Object)val2).name == "code_head_top")
					{
						val = val2;
						break;
					}
				}
			}
			nameTag = NameTag.Create(victim.playerName, val, ((Component)this).GetComponentInParent<EnemyParent>());
			if ((Object)(object)nameTag == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Fellow Droid: подпись над головой создать не вышло.");
			}
		}

		private void HideSameParts(Transform sourceRoot, Transform targetRoot)
		{
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			Renderer[] componentsInChildren = ((Component)sourceRoot).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				string text = BodyPart(((Object)val).name);
				if (text != null)
				{
					if (!list.Contains(text))
					{
						list.Add(text);
					}
					if (val.enabled && ((Component)val).gameObject.activeInHierarchy && !list2.Contains(text))
					{
						list2.Add(text);
					}
				}
			}
			componentsInChildren = ((Component)targetRoot).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				string text2 = BodyPart(((Object)val2).name);
				if (text2 != null && val2.enabled && list.Contains(text2) && !list2.Contains(text2))
				{
					val2.enabled = false;
					hiddenParts.Add(val2);
				}
			}
		}

		private static string BodyPart(string meshName)
		{
			if (meshName == null || !meshName.StartsWith("mesh_"))
			{
				return null;
			}
			string text = meshName.Substring("mesh_".Length);
			if (text.EndsWith("_sphere"))
			{
				text = text.Substring(0, text.Length - "_sphere".Length);
			}
			else if (text.EndsWith("_flat"))
			{
				text = text.Substring(0, text.Length - "_flat".Length);
			}
			string[] bodyParts = BodyParts;
			foreach (string text2 in bodyParts)
			{
				if (text == text2)
				{
					return text;
				}
			}
			return null;
		}

		private void WearDecorations(Transform sourceRoot, Transform targetRoot, PlayerAvatar victim)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			Transform[] componentsInChildren = ((Component)sourceRoot).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name != "HeadDecorations")
				{
					continue;
				}
				bool flag = InWorldSpace(val);
				foreach (Transform item in val)
				{
					Transform val2 = item;
					if (flag ? ((Component)val2).gameObject.activeSelf : ((Component)val2).gameObject.activeInHierarchy)
					{
						Transform parent = (flag ? WorldAnchorOn(targetRoot) : null);
						TryWear(val2, parent, sourceRoot, targetRoot, victim);
					}
				}
			}
		}

		private Transform WorldAnchorOn(Transform targetRoot)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)worldAnchor != (Object)null)
			{
				return worldAnchor;
			}
			GameObject val = new GameObject("FellowDroidWorldDecorations");
			val.transform.SetParent(targetRoot, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
			val.AddComponent<WorldAnchor>().Root = targetRoot;
			created.Add(val);
			worldAnchor = val.transform;
			return worldAnchor;
		}

		private static bool InWorldSpace(Transform node)
		{
			Transform val = node;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name == "WorldDecorationFollower")
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private void TryWear(Transform source, Transform parent, Transform sourceRoot, Transform targetRoot, PlayerAvatar victim)
		{
			try
			{
				if ((Object)(object)parent == (Object)null)
				{
					parent = RigMirror.Mirror(sourceRoot, targetRoot, source.parent, created);
					if ((Object)(object)parent == (Object)null)
					{
						Plugin.Log.LogWarning((object)("Fellow Droid: вещи \"" + ((Object)source).name + "\" не нашлось места на дроиде (на игроке она висит на " + (((Object)(object)source.parent == (Object)null) ? "null" : ((Object)source.parent).name) + ")."));
						return;
					}
				}
				Attach(source, parent, sourceRoot, targetRoot, victim);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Fellow Droid: вещь \"" + ((Object)source).name + "\" надеть не вышло: " + ex));
			}
		}

		private Transform RigRoot()
		{
			EnemyParent componentInParent = ((Component)this).GetComponentInParent<EnemyParent>();
			Transform[] componentsInChildren = ((Component)(((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : ((Component)this).transform)).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == "[RIG]")
				{
					return val.parent;
				}
			}
			return null;
		}

		private void Attach(Transform source, Transform parent, Transform sourceRoot, Transform targetRoot, PlayerAvatar victim)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject, Holder());
			((Object)val).name = ((Object)source).name;
			Strip(val);
			RemapBones(val, sourceRoot, targetRoot);
			Tint(val, victim);
			val.transform.SetParent(parent, false);
			val.transform.localPosition = source.localPosition;
			val.transform.localRotation = source.localRotation;
			val.transform.localScale = source.localScale * Cfg.Scale.Value;
			SetLayer(val, DroidLayer());
			MatchLighting(val);
			spawned.Add(val);
		}

		private int DroidLayer()
		{
			Renderer[] array = Patches.RenderersOf(droid);
			if (array != null)
			{
				Renderer[] array2 = array;
				foreach (Renderer val in array2)
				{
					if ((Object)(object)val != (Object)null)
					{
						return ((Component)val).gameObject.layer;
					}
				}
			}
			return ((Component)this).gameObject.layer;
		}

		private void MatchLighting(GameObject clone)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			Renderer val = null;
			Renderer[] array = Patches.RenderersOf(droid);
			Renderer[] array2;
			if (array != null)
			{
				array2 = array;
				foreach (Renderer val2 in array2)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						val = val2;
						break;
					}
				}
			}
			array2 = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in array2)
			{
				val3.SetPropertyBlock((MaterialPropertyBlock)null);
				val3.probeAnchor = null;
				if (!((Object)(object)val == (Object)null))
				{
					val3.renderingLayerMask = val.renderingLayerMask;
					val3.lightProbeUsage = val.lightProbeUsage;
					val3.reflectionProbeUsage = val.reflectionProbeUsage;
					val3.shadowCastingMode = val.shadowCastingMode;
					val3.receiveShadows = val.receiveShadows;
				}
			}
		}

		private static void SetLayer(GameObject go, int layer)
		{
			Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).gameObject.layer = layer;
			}
		}

		private static Transform Holder()
		{
			//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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if ((Object)(object)holder == (Object)null)
			{
				GameObject val = new GameObject("FellowDroidHolder");
				val.SetActive(false);
				((Object)val).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)val);
				holder = val.transform;
			}
			return holder;
		}

		private static void Strip(GameObject clone)
		{
			Collider[] componentsInChildren = clone.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			MonoBehaviour[] componentsInChildren2 = clone.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren2)
			{
				if (!((Object)(object)val == (Object)null) && !(val is PlayerMaterial))
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		private void RemapBones(GameObject clone, Transform sourceRoot, Transform targetRoot)
		{
			SkinnedMeshRenderer[] componentsInChildren = clone.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			foreach (SkinnedMeshRenderer val in componentsInChildren)
			{
				Transform[] bones = val.bones;
				bool flag = false;
				for (int j = 0; j < bones.Length; j++)
				{
					Transform val2 = bones[j];
					if (!((Object)(object)val2 == (Object)null) && !val2.IsChildOf(clone.transform))
					{
						Transform val3 = RigMirror.Mirror(sourceRoot, targetRoot, val2, created);
						if ((Object)(object)val3 != (Object)null)
						{
							bones[j] = val3;
							flag = true;
						}
					}
				}
				if (flag)
				{
					val.bones = bones;
				}
				Transform rootBone = val.rootBone;
				if ((Object)(object)rootBone != (Object)null && !rootBone.IsChildOf(clone.transform))
				{
					Transform val4 = RigMirror.Mirror(sourceRoot, targetRoot, rootBone, created);
					if ((Object)(object)val4 != (Object)null)
					{
						val.rootBone = val4;
					}
				}
			}
		}

		private static void Tint(GameObject clone, PlayerAvatar victim)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected I4, but got Unknown
			int[] colorsEquipped = victim.playerCosmetics.colorsEquipped;
			PlayerMaterial[] componentsInChildren = clone.GetComponentsInChildren<PlayerMaterial>(true);
			foreach (PlayerMaterial val in componentsInChildren)
			{
				if (!((Object)(object)((Component)val).GetComponent<Renderer>() == (Object)null))
				{
					val.Setup();
					int num = (int)val.cosmeticType;
					int index = ((colorsEquipped != null && num >= 0 && num < colorsEquipped.Length) ? colorsEquipped[num] : 0);
					val.ColorSet(albedoId, emissionId, fresnelId, SafeColor(index));
				}
			}
		}

		private void Recolor(PlayerAvatar victim)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected I4, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] array = Patches.RenderersOf(droid);
			if (array == null)
			{
				return;
			}
			int[] colorsEquipped = victim.playerCosmetics.colorsEquipped;
			Renderer[] array2 = array;
			foreach (Renderer val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					int num = (int)SlotFor(((Object)val).name);
					int index = ((colorsEquipped != null && num >= 0 && num < colorsEquipped.Length) ? colorsEquipped[num] : 0);
					Color color = MetaManager.instance.colors[SafeColor(index)].color;
					Material material = val.material;
					Color color2 = material.GetColor(albedoId);
					tinted.Add(val);
					tintedWas.Add(color2);
					material.SetColor(albedoId, new Color(color.r, color.g, color.b, color2.a));
				}
			}
		}

		private static CosmeticType SlotFor(string meshName)
		{
			return (CosmeticType)(BodyPart(meshName) switch
			{
				"head_top" => 5, 
				"head_bot" => 6, 
				"body_top" => 7, 
				"body_bot" => 8, 
				"arm_l" => 10, 
				"arm_r" => 9, 
				"leg_l" => 12, 
				"leg_r" => 11, 
				_ => 7, 
			});
		}

		private static int SafeColor(int index)
		{
			MetaManager instance = MetaManager.instance;
			if ((Object)(object)instance == (Object)null || instance.colors == null || instance.colors.Count == 0)
			{
				return 0;
			}
			if (index < 0 || index >= instance.colors.Count)
			{
				return 0;
			}
			return index;
		}

		private static void EnsureShaderIds()
		{
			if (!shaderIdsReady)
			{
				albedoId = Shader.PropertyToID("_AlbedoColor");
				emissionId = Shader.PropertyToID("_EmissionColor");
				fresnelId = Shader.PropertyToID("_FresnelColor");
				shaderIdsReady = true;
			}
		}

		private void TakeOff()
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			for (int num = spawned.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)spawned[num] != (Object)null)
				{
					Object.Destroy((Object)(object)spawned[num]);
				}
			}
			spawned.Clear();
			for (int num2 = created.Count - 1; num2 >= 0; num2--)
			{
				if ((Object)(object)created[num2] != (Object)null)
				{
					Object.Destroy((Object)(object)created[num2]);
				}
			}
			created.Clear();
			for (int i = 0; i < tinted.Count; i++)
			{
				if ((Object)(object)tinted[i] != (Object)null)
				{
					tinted[i].material.SetColor(albedoId, tintedWas[i]);
				}
			}
			tinted.Clear();
			tintedWas.Clear();
			for (int j = 0; j < hiddenParts.Count; j++)
			{
				if ((Object)(object)hiddenParts[j] != (Object)null)
				{
					hiddenParts[j].enabled = true;
				}
			}
			hiddenParts.Clear();
			worldAnchor = null;
			if ((Object)(object)nameTag != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)nameTag).gameObject);
			}
			nameTag = null;
		}
	}
	internal class NameTag : MonoBehaviour
	{
		private const float ViewDistance = 15f;

		private const float ViewRadius = 0.25f;

		private const float ShowTime = 0.5f;

		private const float CheckEvery = 0.25f;

		private const float HeadOffset = 0.35f;

		private RectTransform rect;

		private TextMeshProUGUI text;

		private Transform head;

		private EnemyParent owner;

		private Vector3 followTarget;

		private float showTimer;

		private float checkTimer;

		internal static NameTag Create(string playerName, Transform head, EnemyParent owner)
		{
			//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_00be: Unknown result type (might be due to invalid IL or missing references)
			WorldSpaceUIParent instance = WorldSpaceUIParent.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.playerNamePrefab == (Object)null || (Object)(object)head == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(instance.playerNamePrefab, ((Component)instance).transform);
			WorldSpaceUIPlayerName component = val.GetComponent<WorldSpaceUIPlayerName>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			NameTag nameTag = val.AddComponent<NameTag>();
			nameTag.rect = val.GetComponent<RectTransform>();
			nameTag.text = val.GetComponentInChildren<TextMeshProUGUI>(true);
			nameTag.head = head;
			nameTag.owner = owner;
			nameTag.followTarget = head.position;
			if ((Object)(object)nameTag.text != (Object)null)
			{
				((TMP_Text)nameTag.text).text = playerName;
				((Graphic)nameTag.text).color = new Color(1f, 1f, 1f, 0f);
			}
			return nameTag;
		}

		private void LateUpdate()
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_0179: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)head == (Object)null || (Object)(object)rect == (Object)null || (Object)(object)text == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			if (Allowed())
			{
				checkTimer -= Time.deltaTime;
				if (checkTimer <= 0f)
				{
					checkTimer = 0.25f;
					if (LookedAt())
					{
						showTimer = 0.5f;
					}
				}
			}
			else
			{
				showTimer = 0f;
			}
			bool flag = showTimer > 0f;
			Color val = default(Color);
			((Color)(ref val))..ctor(1f, 1f, 1f, flag ? 0.5f : 0f);
			((Graphic)text).color = Color.Lerp(((Graphic)text).color, val, Time.deltaTime * (flag ? 5f : 20f));
			if (flag)
			{
				showTimer -= Time.deltaTime;
			}
			followTarget = Vector3.Lerp(followTarget, head.position, Time.deltaTime * 30f);
			Vector3 val2 = followTarget + Vector3.up * 0.35f;
			rect.anchoredPosition = Vector2.op_Implicit(SemiFunc.UIWorldToCanvasPosition(val2));
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				((TMP_Text)text).fontSize = 20f - Vector3.Distance(val2, ((Component)main).transform.position);
			}
		}

		private static bool Allowed()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if ((Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2)
			{
				return false;
			}
			if ((Object)(object)Map.Instance != (Object)null && Map.Instance.Active)
			{
				return false;
			}
			if ((Object)(object)GameplayManager.instance == (Object)null || !GameplayManager.instance.playerNames)
			{
				return false;
			}
			if ((Object)(object)SpectateCamera.instance != (Object)null)
			{
				return false;
			}
			return true;
		}

		private bool LookedAt()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return false;
			}
			Vector3 position = ((Component)main).transform.position;
			RaycastHit[] array = Physics.SphereCastAll(position, 0.25f, ((Component)main).transform.forward, 15f, -1, (QueryTriggerInteraction)2);
			RaycastHit val3 = default(RaycastHit);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<EnemyParent>() != (Object)(object)owner))
				{
					int num = LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct()) - LayerMask.GetMask(new string[1] { "Player" });
					Vector3 val2 = position - ((RaycastHit)(ref val)).point;
					if (!Physics.Raycast(((RaycastHit)(ref val)).point, val2, ref val3, ((Vector3)(ref val2)).magnitude, num, (QueryTriggerInteraction)2))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal static class Patches
	{
		private const string TypeName = "WesleysEnemies.AI.LostDroid";

		private static FieldInfo renderersField;

		internal static bool TryPatch(Harmony harmony)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("WesleysEnemies.AI.LostDroid");
			if (type == null)
			{
				return false;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "PickRandomVariantRPC", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(type, "TransformImpulseRPC", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.Log.LogWarning((object)"Fellow Droid: в WesleysEnemies.AI.LostDroid не нашлись PickRandomVariantRPC или TransformImpulseRPC. Похоже, чужой мод обновился и переименовал их.");
				return false;
			}
			renderersField = AccessTools.Field(type, "renderers");
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Patches), "AfterPickVariant", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Patches), "AfterTransformImpulse", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			return true;
		}

		internal static Renderer[] RenderersOf(Component lostDroid)
		{
			if (renderersField == null || (Object)(object)lostDroid == (Object)null)
			{
				return null;
			}
			return renderersField.GetValue(lostDroid) as Renderer[];
		}

		private static void AfterPickVariant(object __instance)
		{
			try
			{
				Disguise.OnDroidSpawn((Component)((__instance is Component) ? __instance : null));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Fellow Droid: не удалось надеть маскировку: " + ex));
			}
		}

		private static void AfterTransformImpulse(object __instance)
		{
			try
			{
				Disguise.OnDroidTransform((Component)((__instance is Component) ? __instance : null));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Fellow Droid: не удалось снять маскировку: " + ex));
			}
		}
	}
	[BepInPlugin("sweet.fellowdroid", "Fellow Droid", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "sweet.fellowdroid";

		public const string Name = "Fellow Droid";

		public const string Version = "1.0.1";

		internal static ManualLogSource Log;

		private static Harmony harmony;

		private void Awake()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg.Bind(((BaseUnityPlugin)this).Config);
			if (!Cfg.Enabled.Value)
			{
				Log.LogInfo((object)"Fellow Droid disabled in config, patches not applied.");
				return;
			}
			harmony = new Harmony("sweet.fellowdroid");
			if (!Patches.TryPatch(harmony))
			{
				Log.LogWarning((object)"Fellow Droid: мод Wesleys Enemies не найден, делать нечего.");
			}
			else
			{
				Log.LogInfo((object)"Fellow Droid 1.0.1 loaded.");
			}
		}
	}
	internal static class RigMirror
	{
		internal static string Path(Transform root, Transform node)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)node == (Object)null)
			{
				return null;
			}
			List<string> list = new List<string>();
			Transform val = node;
			while ((Object)(object)val != (Object)(object)root)
			{
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list.ToArray());
		}

		internal static Transform Mirror(Transform sourceRoot, Transform targetRoot, Transform sourceNode, List<GameObject> created)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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)
			if ((Object)(object)sourceRoot == (Object)null || (Object)(object)targetRoot == (Object)null || (Object)(object)sourceNode == (Object)null)
			{
				return null;
			}
			if ((Object)(object)sourceNode == (Object)(object)sourceRoot)
			{
				return targetRoot;
			}
			List<Transform> list = new List<Transform>();
			Transform val = sourceNode;
			while ((Object)(object)val != (Object)(object)sourceRoot)
			{
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				list.Add(val);
				val = val.parent;
			}
			list.Reverse();
			Transform val2 = targetRoot;
			for (int i = 0; i < list.Count; i++)
			{
				Transform val3 = list[i];
				Transform val4 = ChildAt(val2, ((Object)val3).name, Occurrence(val3));
				if ((Object)(object)val4 == (Object)null && i + 1 < list.Count)
				{
					Transform val5 = list[i + 1];
					if ((Object)(object)ChildAt(val2, ((Object)val5).name, Occurrence(val5)) != (Object)null)
					{
						continue;
					}
				}
				if ((Object)(object)val4 == (Object)null)
				{
					GameObject val6 = new GameObject(((Object)val3).name);
					val4 = val6.transform;
					val4.SetParent(val2, false);
					val4.localPosition = val3.localPosition;
					val4.localRotation = val3.localRotation;
					val4.localScale = val3.localScale;
					created?.Add(val6);
				}
				val2 = val4;
			}
			return val2;
		}

		private static int Occurrence(Transform node)
		{
			Transform parent = node.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if ((Object)(object)child == (Object)(object)node)
				{
					return num;
				}
				if (((Object)child).name == ((Object)node).name)
				{
					num++;
				}
			}
			return num;
		}

		private static Transform ChildAt(Transform parent, string name, int occurrence)
		{
			int num = 0;
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (!(((Object)child).name != name))
				{
					if (num == occurrence)
					{
						return child;
					}
					num++;
				}
			}
			return null;
		}
	}
	internal static class Victims
	{
		internal static int Pick(IList<int> alive, IList<int> all, ICollection<int> used, Func<int, int> roll)
		{
			List<int> list = Free(alive, used);
			if (list.Count == 0)
			{
				list = Copy(alive);
			}
			if (list.Count == 0)
			{
				list = Free(all, used);
			}
			if (list.Count == 0)
			{
				list = Copy(all);
			}
			if (list.Count == 0)
			{
				return -1;
			}
			int num = roll(list.Count);
			if (num < 0)
			{
				num = 0;
			}
			if (num >= list.Count)
			{
				num = list.Count - 1;
			}
			return list[num];
		}

		private static List<int> Free(IList<int> from, ICollection<int> used)
		{
			List<int> list = new List<int>();
			if (from == null)
			{
				return list;
			}
			foreach (int item in from)
			{
				if (used == null || !used.Contains(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static List<int> Copy(IList<int> from)
		{
			if (from != null)
			{
				return new List<int>(from);
			}
			return new List<int>();
		}
	}
	internal class WorldAnchor : MonoBehaviour
	{
		internal Transform Root;

		private void LateUpdate()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Root == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			((Component)this).transform.position = Root.position;
			((Component)this).transform.rotation = Quaternion.Euler(0f, Root.eulerAngles.y, 0f);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}