Decompiled source of hololive English Advent v1.0.0

AdventSuit.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using GameNetcodeStuff;
using HarmonyLib;
using ModelReplacement;
using ModelReplacement.AvatarBodyUpdater;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace AdventSuit;

public enum AttentionKind
{
	Player,
	Enemy,
	Item
}
public struct AttentionCandidate
{
	public int Key;

	public AttentionKind Kind;

	public float Distance;

	public bool Speaking;

	public bool Eligible;

	public AttentionCandidate(int key, AttentionKind kind, float distance, bool speaking = true, bool eligible = true)
	{
		Key = key;
		Kind = kind;
		Distance = distance;
		Speaking = speaking;
		Eligible = eligible;
	}
}
public sealed class AdventAttentionSelection
{
	private float lastSpeech;

	private float selectedAt;

	public int CurrentKey { get; private set; }

	public bool HasTarget { get; private set; }

	public AttentionKind CurrentKind { get; private set; }

	public void Reset()
	{
		HasTarget = false;
		CurrentKey = 0;
		lastSpeech = (selectedAt = 0f);
	}

	public int Choose(IList<AttentionCandidate> candidates, float now, float pauseHold = 1.2f)
	{
		AttentionCandidate attentionCandidate = default(AttentionCandidate);
		AttentionCandidate c = default(AttentionCandidate);
		AttentionCandidate c2 = default(AttentionCandidate);
		bool flag = false;
		bool flag2 = false;
		bool flag3 = false;
		foreach (AttentionCandidate candidate in candidates)
		{
			if (!candidate.Eligible || float.IsNaN(candidate.Distance) || float.IsInfinity(candidate.Distance) || candidate.Distance < 0f)
			{
				continue;
			}
			if (HasTarget && candidate.Key == CurrentKey && candidate.Kind == CurrentKind)
			{
				attentionCandidate = candidate;
				flag = true;
			}
			if (candidate.Kind == AttentionKind.Player)
			{
				if (candidate.Speaking && (!flag2 || candidate.Distance < c.Distance))
				{
					c = candidate;
					flag2 = true;
				}
			}
			else if (!flag3 || candidate.Kind < c2.Kind || (candidate.Kind == c2.Kind && candidate.Distance < c2.Distance))
			{
				c2 = candidate;
				flag3 = true;
			}
		}
		if (flag && attentionCandidate.Kind == AttentionKind.Player && attentionCandidate.Speaking)
		{
			lastSpeech = now;
		}
		if (flag2)
		{
			if (flag && attentionCandidate.Kind == AttentionKind.Player && attentionCandidate.Speaking && (now - selectedAt < 0.65f || c.Distance >= attentionCandidate.Distance * 0.7f))
			{
				return CurrentKey;
			}
			return Select(c, now);
		}
		if (flag && attentionCandidate.Kind == AttentionKind.Player && now - lastSpeech <= Mathf.Clamp(pauseHold, 0f, 5f))
		{
			return CurrentKey;
		}
		if (flag3)
		{
			if (flag && attentionCandidate.Kind == c2.Kind && attentionCandidate.Kind != AttentionKind.Player && (now - selectedAt < 1.5f || c2.Distance >= attentionCandidate.Distance * 0.7f))
			{
				return CurrentKey;
			}
			return Select(c2, now);
		}
		Reset();
		return 0;
	}

	private int Select(AttentionCandidate c, float now)
	{
		if (!HasTarget || c.Key != CurrentKey || c.Kind != CurrentKind)
		{
			selectedAt = now;
		}
		HasTarget = true;
		CurrentKey = c.Key;
		CurrentKind = c.Kind;
		if (c.Kind == AttentionKind.Player && c.Speaking)
		{
			lastSpeech = now;
		}
		return CurrentKey;
	}

	public static bool InView(Vector3 origin, Vector3 forward, Vector3 point, float radius)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: 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_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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_002d: 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_0038: 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_0046: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = point - origin;
		float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
		if (sqrMagnitude < 0.0225f || sqrMagnitude > radius * radius)
		{
			return false;
		}
		Vector3 val2 = Vector3.ProjectOnPlane(val, Vector3.up);
		Vector3 val3 = Vector3.ProjectOnPlane(forward, Vector3.up);
		if (Vector3.Angle(val2, val3) <= 65f)
		{
			return Mathf.Abs(Mathf.Atan2(val.y, ((Vector3)(ref val2)).magnitude) * 57.29578f) <= 60f;
		}
		return false;
	}

	public static bool ActiveSpeech(bool speaking, float amplitude)
	{
		if (speaking && !float.IsNaN(amplitude) && !float.IsInfinity(amplitude))
		{
			return amplitude >= 0.002f;
		}
		return false;
	}

	public static bool Visible(Vector3 origin, Vector3 point, int mask, Transform observer, Transform model, Transform target, RaycastHit[] hits)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: 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_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: 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 val = point - origin;
		float magnitude = ((Vector3)(ref val)).magnitude;
		if (magnitude < 0.05f)
		{
			return true;
		}
		int num = Physics.RaycastNonAlloc(origin, val / magnitude, hits, magnitude, mask, (QueryTriggerInteraction)1);
		if (num == hits.Length)
		{
			return false;
		}
		for (int i = 0; i < num; i++)
		{
			Transform transform = ((RaycastHit)(ref hits[i])).transform;
			if (Object.op_Implicit((Object)(object)transform) && (!Object.op_Implicit((Object)(object)observer) || !transform.IsChildOf(observer)) && (!Object.op_Implicit((Object)(object)model) || !transform.IsChildOf(model)) && (!Object.op_Implicit((Object)(object)target) || !transform.IsChildOf(target)))
			{
				return false;
			}
		}
		return true;
	}
}
public sealed class AdventAttention
{
	private sealed class ItemRenderer
	{
		public GrabbableObject Item;

		public Renderer Renderer;
	}

	private readonly AdventAttentionSelection selection = new AdventAttentionSelection();

	private readonly List<AttentionCandidate> candidates = new List<AttentionCandidate>(64);

	private readonly Dictionary<int, Object> objects = new Dictionary<int, Object>();

	private readonly RaycastHit[] hits = (RaycastHit[])(object)new RaycastHit[24];

	private static EnemyAI[] enemies = (EnemyAI[])(object)new EnemyAI[0];

	private static GrabbableObject[] items = (GrabbableObject[])(object)new GrabbableObject[0];

	private static float nextSceneScan;

	private static StartOfRound scene;

	private static readonly Dictionary<int, ItemRenderer> itemRenderers = new Dictionary<int, ItemRenderer>();

	private static readonly HashSet<int> aliveItems = new HashSet<int>();

	private static readonly List<int> staleItems = new List<int>();

	private Object target;

	private float nextScan;

	public void Reset()
	{
		selection.Reset();
		target = null;
		nextScan = 0f;
	}

	private static void ScanScene(float now)
	{
		if ((Object)(object)scene != (Object)(object)StartOfRound.Instance)
		{
			scene = StartOfRound.Instance;
			nextSceneScan = 0f;
			itemRenderers.Clear();
		}
		if (now < nextSceneScan)
		{
			return;
		}
		nextSceneScan = now + 1f;
		enemies = AdventSceneCache.Enemies(now);
		items = Object.FindObjectsByType<GrabbableObject>((FindObjectsSortMode)0);
		aliveItems.Clear();
		GrabbableObject[] array = items;
		foreach (GrabbableObject val in array)
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				aliveItems.Add(((Object)val).GetInstanceID());
			}
		}
		staleItems.Clear();
		foreach (KeyValuePair<int, ItemRenderer> itemRenderer in itemRenderers)
		{
			if (!aliveItems.Contains(itemRenderer.Key))
			{
				staleItems.Add(itemRenderer.Key);
			}
		}
		foreach (int staleItem in staleItems)
		{
			itemRenderers.Remove(staleItem);
		}
	}

	internal static void ClearSceneCache()
	{
		scene = null;
		nextSceneScan = 0f;
		enemies = (EnemyAI[])(object)new EnemyAI[0];
		items = (GrabbableObject[])(object)new GrabbableObject[0];
		itemRenderers.Clear();
		aliveItems.Clear();
		staleItems.Clear();
	}

	private static Vector3 Point(Object value)
	{
		//IL_003d: 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_0022: 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_0031: 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_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		PlayerControllerB val = (PlayerControllerB)(object)((value is PlayerControllerB) ? value : null);
		if (val != null)
		{
			if (!Object.op_Implicit((Object)(object)val.playerEye))
			{
				return ((Component)val).transform.position + Vector3.up * 1.6f;
			}
			return val.playerEye.position;
		}
		EnemyAI val2 = (EnemyAI)(object)((value is EnemyAI) ? value : null);
		if (val2 != null)
		{
			if (!Object.op_Implicit((Object)(object)val2.eye))
			{
				return ((Component)val2).transform.position + Vector3.up;
			}
			return val2.eye.position;
		}
		GrabbableObject val3 = (GrabbableObject)(object)((value is GrabbableObject) ? value : null);
		if (val3 != null)
		{
			int instanceID = ((Object)val3).GetInstanceID();
			if (!itemRenderers.TryGetValue(instanceID, out var value2) || (Object)(object)value2.Item != (Object)(object)val3)
			{
				value2 = new ItemRenderer
				{
					Item = val3,
					Renderer = ((Component)val3).GetComponentInChildren<Renderer>()
				};
				itemRenderers[instanceID] = value2;
			}
			if (!Object.op_Implicit((Object)(object)value2.Renderer))
			{
				return ((Component)val3).transform.position;
			}
			Bounds bounds = value2.Renderer.bounds;
			return ((Bounds)(ref bounds)).center;
		}
		return Vector3.zero;
	}

	private void Add(Component value, AttentionKind kind, Vector3 origin, Vector3 forward, float range, bool speaking, PlayerControllerB owner, Transform model)
	{
		//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_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_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Point((Object)(object)value);
		if (AdventAttentionSelection.InView(origin, forward, val, range))
		{
			int mask = (Object.op_Implicit((Object)(object)StartOfRound.Instance) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-5));
			if (AdventAttentionSelection.Visible(origin, val, mask, ((Component)owner).transform, model, value.transform, hits))
			{
				int instanceID = ((Object)value).GetInstanceID();
				objects[instanceID] = (Object)(object)value;
				candidates.Add(new AttentionCandidate(instanceID, kind, Vector3.Distance(origin, val), speaking));
			}
		}
	}

	public bool Resolve(PlayerControllerB owner, Transform model, Vector3 origin, Vector3 forward, float now, out Vector3 direction)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		direction = forward;
		if (!Object.op_Implicit((Object)(object)owner) || owner.isPlayerDead || !owner.isPlayerControlled || !Object.op_Implicit((Object)(object)StartOfRound.Instance))
		{
			Reset();
			return false;
		}
		if (now >= nextScan)
		{
			nextScan = now + 0.1f;
			candidates.Clear();
			objects.Clear();
			ScanScene(now);
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val == (Object)(object)owner) && val.isPlayerControlled && !val.isPlayerDead && ((Component)val).gameObject.activeInHierarchy)
				{
					bool flag = AdventVoiceActivity.IsSpeaking(val);
					if (flag || (selection.HasTarget && selection.CurrentKind == AttentionKind.Player && selection.CurrentKey == ((Object)val).GetInstanceID()))
					{
						Add((Component)(object)val, AttentionKind.Player, origin, forward, Plugin.TalkingPlayersRange.Value, flag, owner, model);
					}
				}
			}
			EnemyAI[] array = enemies;
			foreach (EnemyAI val2 in array)
			{
				if (Object.op_Implicit((Object)(object)val2) && !val2.isEnemyDead && ((Behaviour)val2).isActiveAndEnabled)
				{
					Add((Component)(object)val2, AttentionKind.Enemy, origin, forward, Plugin.EnemiesRange.Value, speaking: false, owner, model);
				}
			}
			GrabbableObject[] array2 = items;
			foreach (GrabbableObject val3 in array2)
			{
				if (Object.op_Implicit((Object)(object)val3) && !val3.isHeld && !val3.isPocketed && !val3.isHeldByEnemy && ((Behaviour)val3).isActiveAndEnabled)
				{
					Add((Component)(object)val3, AttentionKind.Item, origin, forward, Plugin.ItemsRange.Value, speaking: false, owner, model);
				}
			}
			int key = selection.Choose(candidates, now, Plugin.SpeechPauseHold.Value);
			target = ((selection.HasTarget && objects.TryGetValue(key, out var value)) ? value : null);
		}
		if (!Object.op_Implicit(target))
		{
			return false;
		}
		Object obj = target;
		PlayerControllerB val4 = (PlayerControllerB)(object)((obj is PlayerControllerB) ? obj : null);
		if (val4 == null || (val4.isPlayerControlled && !val4.isPlayerDead))
		{
			Object obj2 = target;
			EnemyAI val5 = (EnemyAI)(object)((obj2 is EnemyAI) ? obj2 : null);
			if (val5 == null || !val5.isEnemyDead)
			{
				Object obj3 = target;
				GrabbableObject val6 = (GrabbableObject)(object)((obj3 is GrabbableObject) ? obj3 : null);
				if (val6 == null || (!val6.isHeld && !val6.isPocketed && !val6.isHeldByEnemy))
				{
					direction = Point(target) - origin;
					return ((Vector3)(ref direction)).sqrMagnitude > 1E-06f;
				}
			}
		}
		target = null;
		selection.Reset();
		nextScan = 0f;
		return false;
	}
}
internal static class AdventVoiceActivity
{
	private static object comms;

	private static readonly Dictionary<int, float> retry = new Dictionary<int, float>();

	private static readonly Dictionary<int, object> states = new Dictionary<int, object>();

	internal static bool IsSpeaking(PlayerControllerB player)
	{
		object obj = AdventFace.Read(player, "voicePlayerState") ?? AdventFace.Read(AdventFace.Read(player, "currentVoiceChatIngameSettings"), "_playerState");
		int instanceID = ((Object)player).GetInstanceID();
		if (obj == null && states.TryGetValue(instanceID, out var value))
		{
			obj = value;
		}
		if (obj == null && (!retry.TryGetValue(instanceID, out var value2) || Time.unscaledTime >= value2))
		{
			retry[instanceID] = Time.unscaledTime + 1f;
			comms = AdventFace.Read(StartOfRound.Instance, "voiceChatModule");
			if (comms != null)
			{
				string text = (((NetworkBehaviour)player).IsOwner ? (AdventFace.Read(comms, "LocalPlayerName") as string) : (AdventFace.Read(player, "voicePlayerName") as string));
				if (!string.IsNullOrEmpty(text))
				{
					try
					{
						obj = AdventRuntimeMembers.CallString(comms, "FindPlayer", text);
						if (obj != null)
						{
							states[instanceID] = obj;
						}
					}
					catch
					{
					}
				}
			}
		}
		bool value3;
		bool flag = AdventRuntimeMembers.TryRead<bool>(obj, "IsSpeaking", out value3) && value3;
		if (AdventRuntimeMembers.TryRead<bool>(obj, "IsConnected", out var value4) && !value4)
		{
			return false;
		}
		if (!AdventRuntimeMembers.TryRead<float>(obj, "Amplitude", out var value5))
		{
			return flag;
		}
		return AdventAttentionSelection.ActiveSpeech(flag, value5);
	}

	internal static void Clear()
	{
		comms = null;
		retry.Clear();
		states.Clear();
	}
}
[DefaultExecutionOrder(600)]
public sealed class AdventBijouAccessories : MonoBehaviour
{
	private SkinnedMeshRenderer[] crown;

	private SkinnedMeshRenderer[] ornaments;

	public bool CrownShown { get; private set; } = true;

	public bool OrnamentsShown { get; private set; } = true;

	public void Initialize()
	{
		if (crown == null)
		{
			SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
			crown = componentsInChildren.Where((SkinnedMeshRenderer r) => ((Object)r).name == "AdventBijouCrown").ToArray();
			ornaments = componentsInChildren.Where((SkinnedMeshRenderer r) => ((Object)r).name == "AdventBijouOrnaments").ToArray();
		}
	}

	public void Apply(bool showCrown, bool showOrnaments)
	{
		Initialize();
		SkinnedMeshRenderer[] array;
		if (CrownShown != showCrown)
		{
			CrownShown = showCrown;
			array = crown;
			foreach (SkinnedMeshRenderer val in array)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					((Renderer)val).enabled = showCrown;
				}
			}
		}
		if (OrnamentsShown == showOrnaments)
		{
			return;
		}
		OrnamentsShown = showOrnaments;
		array = ornaments;
		foreach (SkinnedMeshRenderer val2 in array)
		{
			if (Object.op_Implicit((Object)(object)val2))
			{
				((Renderer)val2).enabled = showOrnaments;
			}
		}
	}

	public void EnforceVisibility()
	{
		if (CrownShown && OrnamentsShown)
		{
			return;
		}
		SkinnedMeshRenderer[] array;
		if (!CrownShown)
		{
			array = crown;
			foreach (SkinnedMeshRenderer val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && ((Renderer)val).enabled)
				{
					((Renderer)val).enabled = false;
				}
			}
		}
		if (OrnamentsShown)
		{
			return;
		}
		array = ornaments;
		foreach (SkinnedMeshRenderer val2 in array)
		{
			if (Object.op_Implicit((Object)(object)val2) && ((Renderer)val2).enabled)
			{
				((Renderer)val2).enabled = false;
			}
		}
	}

	private void LateUpdate()
	{
		EnforceVisibility();
	}
}
public static class AdventBijouControl
{
	private sealed class State
	{
		public bool Crown;

		public bool Ornaments;
	}

	private static readonly Dictionary<PlayerControllerB, AdventBijouAccessories> models = new Dictionary<PlayerControllerB, AdventBijouAccessories>();

	private static readonly Dictionary<PlayerControllerB, State> settings = new Dictionary<PlayerControllerB, State>();

	public static void Bind(PlayerControllerB player, GameObject model, string character)
	{
		if (character != "KosekiBijou" || !Object.op_Implicit((Object)(object)player))
		{
			return;
		}
		AdventBijouAccessories component = model.GetComponent<AdventBijouAccessories>();
		if (Object.op_Implicit((Object)(object)component))
		{
			models[player] = component;
			if (!settings.ContainsKey(player))
			{
				settings[player] = new State
				{
					Crown = Plugin.BijouCrownShown.Value,
					Ornaments = Plugin.BijouOrnamentsShown.Value
				};
			}
			component.Apply(CrownShown(player), OrnamentsShown(player));
		}
	}

	public static bool CrownShown(PlayerControllerB player)
	{
		if (Object.op_Implicit((Object)(object)player) && !((NetworkBehaviour)player).IsOwner)
		{
			return AdventExpressionNetwork.BijouCrownShown(player.playerClientId);
		}
		if (Object.op_Implicit((Object)(object)player) && settings.TryGetValue(player, out var value))
		{
			return value.Crown;
		}
		return true;
	}

	public static bool OrnamentsShown(PlayerControllerB player)
	{
		if (Object.op_Implicit((Object)(object)player) && !((NetworkBehaviour)player).IsOwner)
		{
			return AdventExpressionNetwork.BijouOrnamentsShown(player.playerClientId);
		}
		if (Object.op_Implicit((Object)(object)player) && settings.TryGetValue(player, out var value))
		{
			return value.Ornaments;
		}
		return true;
	}

	public static void Tick()
	{
		//IL_0077: 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_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		Keyboard current = Keyboard.current;
		foreach (KeyValuePair<PlayerControllerB, AdventBijouAccessories> model in models)
		{
			PlayerControllerB key = model.Key;
			if (!Object.op_Implicit((Object)(object)key) || !Object.op_Implicit((Object)(object)model.Value))
			{
				continue;
			}
			if (((NetworkBehaviour)key).IsOwner && current != null && !key.isTypingChat && !key.inTerminalMenu && settings.TryGetValue(key, out var value))
			{
				if ((int)Plugin.BijouCrownKey.Value != 0 && ((ButtonControl)current[Plugin.BijouCrownKey.Value]).wasPressedThisFrame)
				{
					value.Crown = !value.Crown;
				}
				if ((int)Plugin.BijouOrnamentsKey.Value != 0 && ((ButtonControl)current[Plugin.BijouOrnamentsKey.Value]).wasPressedThisFrame)
				{
					value.Ornaments = !value.Ornaments;
				}
			}
			model.Value.Apply(CrownShown(key), OrnamentsShown(key));
		}
	}

	public static void Clear()
	{
		models.Clear();
		settings.Clear();
	}
}
[DefaultExecutionOrder(600)]
public sealed class AdventClawToggle : MonoBehaviour
{
	public string Character;

	private SkinnedMeshRenderer[] renderers;

	public bool Shown { get; private set; } = true;

	public void Initialize()
	{
		if (renderers == null)
		{
			renderers = (from r in ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where ((Object)r).name == "AdventClaws"
				select r).ToArray();
		}
	}

	public void Apply(bool shown)
	{
		Initialize();
		if (Shown == shown)
		{
			return;
		}
		Shown = shown;
		SkinnedMeshRenderer[] array = renderers;
		foreach (SkinnedMeshRenderer val in array)
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				((Renderer)val).enabled = shown;
			}
		}
	}

	public void EnforceVisibility()
	{
		if (Shown)
		{
			return;
		}
		SkinnedMeshRenderer[] array = renderers;
		foreach (SkinnedMeshRenderer val in array)
		{
			if (Object.op_Implicit((Object)(object)val) && ((Renderer)val).enabled)
			{
				((Renderer)val).enabled = false;
			}
		}
	}

	private void LateUpdate()
	{
		EnforceVisibility();
	}
}
public static class AdventClawControl
{
	private sealed class Entry
	{
		public AdventClawToggle Body;

		public AdventClawToggle View;

		public string Character;
	}

	private static readonly Dictionary<PlayerControllerB, Entry> models = new Dictionary<PlayerControllerB, Entry>();

	private static readonly Dictionary<PlayerControllerB, bool> settings = new Dictionary<PlayerControllerB, bool>();

	public static void Bind(PlayerControllerB player, GameObject model, string character)
	{
		AdventClawToggle component = model.GetComponent<AdventClawToggle>();
		if (Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)component))
		{
			component.Initialize();
			models[player] = new Entry
			{
				Body = component,
				Character = character
			};
			if (!settings.ContainsKey(player))
			{
				settings[player] = Plugin.ClawsShown.Value;
			}
			component.Apply(Shown(player, character));
		}
	}

	public static void AttachViews(AdventBody owner)
	{
		if (!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)((BodyReplacementBase)owner).controller) || !models.TryGetValue(((BodyReplacementBase)owner).controller, out var value))
		{
			return;
		}
		object obj = AdventRuntimeMembers.Read(AdventRuntimeMembers.Read(owner, "viewModelAvatar"), "replacementViewModel");
		GameObject val = (GameObject)((obj is GameObject) ? obj : null);
		if (Object.op_Implicit((Object)(object)val))
		{
			value.View = val.GetComponent<AdventClawToggle>();
			if (Object.op_Implicit((Object)(object)value.View))
			{
				value.View.Apply(Shown(((BodyReplacementBase)owner).controller, value.Character));
			}
		}
	}

	public static bool Shown(PlayerControllerB player, string character)
	{
		if (Object.op_Implicit((Object)(object)player) && !((NetworkBehaviour)player).IsOwner)
		{
			return AdventExpressionNetwork.ClawsShown(player.playerClientId, character);
		}
		bool value = default(bool);
		return !Object.op_Implicit((Object)(object)player) || !settings.TryGetValue(player, out value) || value;
	}

	public static void Tick()
	{
		//IL_006b: 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)
		Keyboard current = Keyboard.current;
		foreach (KeyValuePair<PlayerControllerB, Entry> model in models)
		{
			PlayerControllerB key = model.Key;
			Entry value = model.Value;
			if (Object.op_Implicit((Object)(object)key) && Object.op_Implicit((Object)(object)value.Body))
			{
				if (((NetworkBehaviour)key).IsOwner && current != null && !key.isTypingChat && !key.inTerminalMenu && (int)Plugin.ClawKey.Value != 0 && ((ButtonControl)current[Plugin.ClawKey.Value]).wasPressedThisFrame)
				{
					settings[key] = !Shown(key, value.Character);
				}
				bool shown = Shown(key, value.Character);
				value.Body.Apply(shown);
				if (Object.op_Implicit((Object)(object)value.View))
				{
					value.View.Apply(shown);
				}
			}
		}
	}

	public static void Clear()
	{
		models.Clear();
		settings.Clear();
	}
}
public enum AdventExpression : byte
{
	Neutral,
	Frightened,
	Hurt,
	Happy,
	Surprised,
	VeryHappy,
	Dead,
	CrazySmile,
	IntenseCrazySmile,
	Crying,
	Excited,
	Worried,
	BigGrin
}
public struct AdventExpressionContext
{
	public bool Dead;

	public bool Critical;

	public bool EnemyNear;

	public bool Fear;

	public bool Chased;

	public bool Dancing;

	public bool Driving;

	public bool WeaponHeld;

	public bool TwinVisibleClose;

	public bool TwinUnsafe;

	public bool TwinDeadNear;

	public bool AdventCorpseVisible;

	public bool Unsafe
	{
		get
		{
			if (!EnemyNear && !Fear)
			{
				return Chased;
			}
			return true;
		}
	}
}
public sealed class AdventExpressionSelection
{
	public string Character;

	private float hurtUntil = -1f;

	private float weaponUntil = -1f;

	private float treasureUntil = -1f;

	private bool surprised = true;

	private int pickups;

	public void Damage(float now)
	{
		hurtUntil = now + 2f;
	}

	public void WeaponUsed(float now)
	{
		weaponUntil = now + 3f;
	}

	public void PickedUp(int value, float now)
	{
		if (value > 100)
		{
			treasureUntil = now + 3.5f;
			surprised = pickups++ % 2 == 0;
		}
	}

	public AdventExpression Choose(AdventExpressionContext c, float now)
	{
		if (c.Dead)
		{
			return AdventExpression.Dead;
		}
		if (c.Critical || now < hurtUntil)
		{
			return AdventExpression.Hurt;
		}
		bool flag = Character == "FuwawaAbyssgard" || Character == "MococoAbyssgard";
		if (c.Unsafe || (flag && c.TwinVisibleClose && c.TwinUnsafe))
		{
			return AdventExpression.Frightened;
		}
		if (flag && c.TwinDeadNear)
		{
			return AdventExpression.Crying;
		}
		if (Character == "NerissaRavencroft" && c.AdventCorpseVisible)
		{
			return AdventExpression.Worried;
		}
		if (now < weaponUntil)
		{
			if (Character == "ShioriNovella")
			{
				return AdventExpression.IntenseCrazySmile;
			}
			if (Character == "KosekiBijou")
			{
				return AdventExpression.BigGrin;
			}
		}
		if (c.Driving)
		{
			if (Character == "ShioriNovella")
			{
				return AdventExpression.CrazySmile;
			}
			if (Character == "KosekiBijou")
			{
				return AdventExpression.Excited;
			}
		}
		if (now < treasureUntil)
		{
			if (!surprised)
			{
				return AdventExpression.VeryHappy;
			}
			return AdventExpression.Surprised;
		}
		if (c.Dancing)
		{
			return AdventExpression.Happy;
		}
		if (flag && c.TwinVisibleClose && !c.TwinUnsafe)
		{
			return AdventExpression.Happy;
		}
		if (Character == "ShioriNovella" && c.WeaponHeld)
		{
			return AdventExpression.CrazySmile;
		}
		return AdventExpression.Neutral;
	}
}
public struct AdventExpressionWeight
{
	public string Shape;

	public float Weight;

	public bool Eyes;

	public bool Mouth;

	public AdventExpressionWeight(string shape, float weight, bool eyes = false, bool mouth = false)
	{
		Shape = "expr_" + shape;
		Weight = weight;
		Eyes = eyes;
		Mouth = mouth;
	}
}
public static class AdventExpressionProfiles
{
	private static readonly AdventExpressionWeight[][] Profiles = new AdventExpressionWeight[13][]
	{
		new AdventExpressionWeight[0],
		new AdventExpressionWeight[4]
		{
			B("worry", 0.75f),
			B("brow_up", 0.25f),
			E("surprise", 0.85f),
			M("triangle", 0.6f)
		},
		new AdventExpressionWeight[4]
		{
			B("worry", 0.85f),
			B("serious", 0.25f),
			E("focus", 0.45f),
			M("clench", 0.8f)
		},
		new AdventExpressionWeight[3]
		{
			B("happy_brows", 0.45f),
			E("smile_eyes", 0.65f),
			M("smile", 0.85f)
		},
		new AdventExpressionWeight[3]
		{
			B("brow_up", 0.65f),
			E("surprise", 0.9f),
			M("o", 0.65f)
		},
		new AdventExpressionWeight[3]
		{
			B("happy_brows", 0.65f),
			E("smile_eyes", 0.85f),
			M("laugh", 0.85f)
		},
		new AdventExpressionWeight[2]
		{
			B("worry", 0.7f),
			M("clench", 0.55f)
		},
		new AdventExpressionWeight[4]
		{
			B("angry", 0.3f),
			E("focus", 0.35f),
			E("small_pupils", 0.25f),
			M("crazy", 0.8f)
		},
		new AdventExpressionWeight[4]
		{
			B("angry", 0.45f),
			E("surprise", 0.3f),
			E("small_pupils", 0.65f),
			M("crazy", 1f)
		},
		new AdventExpressionWeight[5]
		{
			B("worry", 1f),
			E("relaxed", 0.4f),
			M("mouth_down", 0.75f),
			B("tears", 1f),
			B("sad_ears", 0.65f)
		},
		new AdventExpressionWeight[3]
		{
			B("brow_up", 0.4f),
			E("surprise", 0.4f),
			M("grin", 0.9f)
		},
		new AdventExpressionWeight[3]
		{
			B("worry", 0.9f),
			E("surprise", 0.2f),
			M("mouth_down", 0.4f)
		},
		new AdventExpressionWeight[3]
		{
			B("angry", 0.15f),
			E("focus", 0.3f),
			M("grin", 1f)
		}
	};

	private static AdventExpressionWeight B(string n, float w)
	{
		return new AdventExpressionWeight(n, w);
	}

	private static AdventExpressionWeight E(string n, float w)
	{
		return new AdventExpressionWeight(n, w, eyes: true);
	}

	private static AdventExpressionWeight M(string n, float w)
	{
		return new AdventExpressionWeight(n, w, eyes: false, mouth: true);
	}

	public static AdventExpressionWeight[] Weights(AdventExpression state)
	{
		return Profiles[(uint)state];
	}
}
public sealed class AdventExpressionMixer
{
	private sealed class Binding
	{
		public SkinnedMeshRenderer Renderer;

		public int[] Indices;

		public int Blink;

		public int Open;

		public int Round;
	}

	private readonly List<string> shapes = new List<string>();

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

	private readonly List<Binding> bindings = new List<Binding>();

	private float[] values;

	private float[] target;

	private bool[] eyes;

	private bool[] mouth;

	private float death;

	public AdventExpressionMixer(GameObject model)
	{
		foreach (AdventExpression value in Enum.GetValues(typeof(AdventExpression)))
		{
			AdventExpressionWeight[] array = AdventExpressionProfiles.Weights(value);
			for (int i = 0; i < array.Length; i++)
			{
				AdventExpressionWeight adventExpressionWeight = array[i];
				if (!slots.ContainsKey(adventExpressionWeight.Shape))
				{
					slots[adventExpressionWeight.Shape] = shapes.Count;
					shapes.Add(adventExpressionWeight.Shape);
				}
			}
		}
		values = new float[shapes.Count];
		target = new float[shapes.Count];
		eyes = new bool[shapes.Count];
		mouth = new bool[shapes.Count];
		foreach (AdventExpression value2 in Enum.GetValues(typeof(AdventExpression)))
		{
			AdventExpressionWeight[] array = AdventExpressionProfiles.Weights(value2);
			for (int i = 0; i < array.Length; i++)
			{
				AdventExpressionWeight adventExpressionWeight2 = array[i];
				int num = slots[adventExpressionWeight2.Shape];
				eyes[num] |= adventExpressionWeight2.Eyes;
				mouth[num] |= adventExpressionWeight2.Mouth;
			}
		}
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			if (Object.op_Implicit((Object)(object)val.sharedMesh))
			{
				Binding binding = new Binding
				{
					Renderer = val,
					Indices = new int[shapes.Count],
					Blink = val.sharedMesh.GetBlendShapeIndex("blink"),
					Open = val.sharedMesh.GetBlendShapeIndex("speech_open"),
					Round = val.sharedMesh.GetBlendShapeIndex("speech_round")
				};
				for (int j = 0; j < shapes.Count; j++)
				{
					binding.Indices[j] = val.sharedMesh.GetBlendShapeIndex(shapes[j]);
				}
				bindings.Add(binding);
			}
		}
	}

	public void Step(AdventExpression state, float delta, bool immediate = false)
	{
		Array.Clear(target, 0, target.Length);
		AdventExpressionWeight[] array = AdventExpressionProfiles.Weights(state);
		for (int i = 0; i < array.Length; i++)
		{
			AdventExpressionWeight adventExpressionWeight = array[i];
			target[slots[adventExpressionWeight.Shape]] = adventExpressionWeight.Weight;
		}
		float num = ((immediate || state == AdventExpression.Dead) ? 1f : (1f - Mathf.Exp((0f - Mathf.Min(delta, 0.1f)) * 13f)));
		death = Mathf.Lerp(death, (float)((state == AdventExpression.Dead) ? 1 : 0), num);
		for (int j = 0; j < values.Length; j++)
		{
			values[j] = Mathf.Lerp(values[j], target[j], num);
		}
		foreach (Binding binding in bindings)
		{
			if (!Object.op_Implicit((Object)(object)binding.Renderer))
			{
				continue;
			}
			float num2 = ((binding.Blink < 0) ? 0f : (binding.Renderer.GetBlendShapeWeight(binding.Blink) / 100f));
			float num3 = ((binding.Open < 0) ? 0f : (binding.Renderer.GetBlendShapeWeight(binding.Open) / 85f));
			if (death > 0.001f)
			{
				num2 = death;
				if (binding.Blink >= 0)
				{
					binding.Renderer.SetBlendShapeWeight(binding.Blink, death * 100f);
				}
				if (binding.Open >= 0)
				{
					binding.Renderer.SetBlendShapeWeight(binding.Open, 0f);
				}
				if (binding.Round >= 0)
				{
					binding.Renderer.SetBlendShapeWeight(binding.Round, 0f);
				}
				num3 = 0f;
			}
			for (int k = 0; k < values.Length; k++)
			{
				if (binding.Indices[k] >= 0)
				{
					float num4 = values[k];
					if (eyes[k])
					{
						num4 *= 1f - num2;
					}
					if (mouth[k])
					{
						num4 *= 1f - num3 * 0.55f;
					}
					binding.Renderer.SetBlendShapeWeight(binding.Indices[k], num4 * 100f);
				}
			}
		}
	}
}
[DefaultExecutionOrder(280)]
public sealed class AdventDeathFace : MonoBehaviour
{
	private AdventExpressionMixer mixer;

	public void Initialize()
	{
		mixer = new AdventExpressionMixer(((Component)this).gameObject);
		mixer.Step(AdventExpression.Dead, 0f, immediate: true);
	}

	private void LateUpdate()
	{
		if (mixer == null)
		{
			Initialize();
		}
		mixer.Step(AdventExpression.Dead, Time.deltaTime, immediate: true);
	}
}
public sealed class AdventEyeGlow : MonoBehaviour
{
	private sealed class Slot
	{
		public SkinnedMeshRenderer Renderer;

		public Material[] Original;

		public Material[] Glow;
	}

	private readonly List<Slot> slots = new List<Slot>();

	private readonly List<Material> owned = new List<Material>();

	private static readonly Dictionary<Material, Material> originals = new Dictionary<Material, Material>();

	private bool initialized;

	public bool Enabled { get; private set; }

	public int EyeMaterials { get; private set; }

	public void Initialize()
	{
		//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_00b9: Expected O, but got Unknown
		if (initialized)
		{
			return;
		}
		initialized = true;
		SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
			Material[] array = (Material[])sharedMaterials.Clone();
			bool flag = false;
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				Material val2 = sharedMaterials[j];
				if (Object.op_Implicit((Object)(object)val2))
				{
					if (originals.TryGetValue(val2, out var value))
					{
						val2 = (sharedMaterials[j] = value);
					}
					if (((Object)val2).name.StartsWith("ShioriNovella_Material_05", StringComparison.Ordinal) || ((Object)val2).name.StartsWith("ShioriNovella_Material_06", StringComparison.Ordinal))
					{
						Material val3 = new Material(val2)
						{
							name = ((Object)val2).name + " - Amber iris glow"
						};
						val3.SetFloat("_GflYellowEyeGlow", 2.6f);
						val3.SetFloat("_GflEmissionUnlit", 1f);
						array[j] = val3;
						owned.Add(val3);
						originals[val3] = val2;
						EyeMaterials++;
						flag = true;
					}
				}
			}
			if (flag)
			{
				slots.Add(new Slot
				{
					Renderer = val,
					Original = sharedMaterials,
					Glow = array
				});
				((Renderer)val).sharedMaterials = sharedMaterials;
			}
		}
	}

	public void Apply(bool enabled)
	{
		Initialize();
		if (Enabled == enabled)
		{
			return;
		}
		Enabled = enabled;
		foreach (Slot slot in slots)
		{
			if (Object.op_Implicit((Object)(object)slot.Renderer))
			{
				((Renderer)slot.Renderer).sharedMaterials = (enabled ? slot.Glow : slot.Original);
			}
		}
	}

	private void OnDestroy()
	{
		foreach (Slot slot in slots)
		{
			if (Object.op_Implicit((Object)(object)slot.Renderer))
			{
				((Renderer)slot.Renderer).sharedMaterials = slot.Original;
			}
		}
		foreach (Material item in owned)
		{
			originals.Remove(item);
			if (Object.op_Implicit((Object)(object)item))
			{
				Object.Destroy((Object)(object)item);
			}
		}
	}
}
public static class AdventEyeGlowControl
{
	private static readonly Dictionary<PlayerControllerB, AdventEyeGlow> models = new Dictionary<PlayerControllerB, AdventEyeGlow>();

	private static readonly Dictionary<PlayerControllerB, bool> settings = new Dictionary<PlayerControllerB, bool>();

	public static void Bind(PlayerControllerB player, GameObject model, string character)
	{
		if (!(character != "ShioriNovella") && Object.op_Implicit((Object)(object)player))
		{
			AdventEyeGlow adventEyeGlow = model.GetComponent<AdventEyeGlow>() ?? model.AddComponent<AdventEyeGlow>();
			adventEyeGlow.Initialize();
			models[player] = adventEyeGlow;
			if (!settings.ContainsKey(player))
			{
				settings[player] = Plugin.YellowEyeGlow.Value;
			}
			adventEyeGlow.Apply(Enabled(player));
		}
	}

	public static bool Enabled(PlayerControllerB player)
	{
		if (Object.op_Implicit((Object)(object)player))
		{
			if (!((NetworkBehaviour)player).IsOwner)
			{
				return AdventExpressionNetwork.EyeGlow(player.playerClientId);
			}
			bool value;
			return settings.TryGetValue(player, out value) && value;
		}
		return false;
	}

	public static void Tick()
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		Keyboard current = Keyboard.current;
		foreach (KeyValuePair<PlayerControllerB, AdventEyeGlow> model in models)
		{
			if (Object.op_Implicit((Object)(object)model.Key) && Object.op_Implicit((Object)(object)model.Value))
			{
				PlayerControllerB key = model.Key;
				if (((NetworkBehaviour)key).IsOwner && current != null && !key.isTypingChat && !key.inTerminalMenu && (int)Plugin.EyeGlowKey.Value != 0 && ((ButtonControl)current[Plugin.EyeGlowKey.Value]).wasPressedThisFrame)
				{
					settings[key] = !Enabled(key);
				}
				model.Value.Apply(Enabled(key));
			}
		}
	}

	public static void Clear()
	{
		models.Clear();
		settings.Clear();
	}
}
public static class AdventFirstPersonMesh
{
	private sealed class Entry
	{
		public Mesh Mesh;

		public int[] BoneIndices;

		public int[] MaterialSlots;
	}

	private static readonly Dictionary<Mesh, Entry> Cache = new Dictionary<Mesh, Entry>();

	public static int CachedMeshes => Cache.Count;

	private static HashSet<Transform> ArmBones(GameObject model)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		Animator componentInChildren = model.GetComponentInChildren<Animator>(true);
		if (!Object.op_Implicit((Object)(object)componentInChildren) || !componentInChildren.isHuman)
		{
			throw new InvalidOperationException("Advent first-person avatar must be humanoid.");
		}
		HashSet<Transform> hashSet = new HashSet<Transform>();
		HumanBodyBones[] array = new HumanBodyBones[6];
		RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
		HumanBodyBones[] array2 = (HumanBodyBones[])(object)array;
		foreach (HumanBodyBones val in array2)
		{
			Transform boneTransform = componentInChildren.GetBoneTransform(val);
			if (Object.op_Implicit((Object)(object)boneTransform))
			{
				Transform[] componentsInChildren = ((Component)boneTransform).GetComponentsInChildren<Transform>(true);
				foreach (Transform item in componentsInChildren)
				{
					hashSet.Add(item);
				}
			}
		}
		return hashSet;
	}

	public static void Prime(GameObject model)
	{
		HashSet<Transform> arms = ArmBones(model);
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Get(componentsInChildren[i], arms);
		}
	}

	public static IEnumerator PrimeIncremental(GameObject model)
	{
		HashSet<Transform> arms = ArmBones(model);
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Get(componentsInChildren[i], arms);
			yield return null;
		}
	}

	private static bool Allowed(BoneWeight weight, bool[] bones)
	{
		if ((((BoneWeight)(ref weight)).weight0 <= 0f || bones[((BoneWeight)(ref weight)).boneIndex0]) && (((BoneWeight)(ref weight)).weight1 <= 0f || bones[((BoneWeight)(ref weight)).boneIndex1]) && (((BoneWeight)(ref weight)).weight2 <= 0f || bones[((BoneWeight)(ref weight)).boneIndex2]))
		{
			if (!(((BoneWeight)(ref weight)).weight3 <= 0f))
			{
				return bones[((BoneWeight)(ref weight)).boneIndex3];
			}
			return true;
		}
		return false;
	}

	private static Entry Get(SkinnedMeshRenderer renderer, HashSet<Transform> arms)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Expected O, but got Unknown
		Mesh sharedMesh = renderer.sharedMesh;
		if (!Object.op_Implicit((Object)(object)sharedMesh))
		{
			return null;
		}
		if (Cache.TryGetValue(sharedMesh, out var value))
		{
			return value;
		}
		if (!sharedMesh.isReadable)
		{
			throw new InvalidOperationException("Advent first-person source mesh is not readable: " + ((Object)sharedMesh).name);
		}
		Transform[] bones = renderer.bones;
		bool[] array = new bool[bones.Length];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = Object.op_Implicit((Object)(object)bones[i]) && arms.Contains(bones[i]);
		}
		BoneWeight[] boneWeights = sharedMesh.boneWeights;
		if (boneWeights.Length != sharedMesh.vertexCount)
		{
			throw new InvalidOperationException("Advent arms require four-weight source skinning.");
		}
		bool[] array2 = new bool[sharedMesh.vertexCount];
		for (int j = 0; j < boneWeights.Length; j++)
		{
			array2[j] = Allowed(boneWeights[j], array);
		}
		List<int> list = new List<int>();
		Dictionary<int, int> dictionary = new Dictionary<int, int>();
		List<int[]> list2 = new List<int[]>();
		List<int> list3 = new List<int>();
		for (int k = 0; k < sharedMesh.subMeshCount; k++)
		{
			int[] triangles = sharedMesh.GetTriangles(k);
			List<int> list4 = new List<int>();
			for (int l = 0; l < triangles.Length; l += 3)
			{
				if (!array2[triangles[l]] || !array2[triangles[l + 1]] || !array2[triangles[l + 2]])
				{
					continue;
				}
				for (int m = 0; m < 3; m++)
				{
					int num = triangles[l + m];
					if (!dictionary.TryGetValue(num, out var value2))
					{
						value2 = list.Count;
						dictionary.Add(num, value2);
						list.Add(num);
					}
					list4.Add(value2);
				}
			}
			if (list4.Count > 0)
			{
				list3.Add(k);
				list2.Add(list4.ToArray());
			}
		}
		if (list.Count == 0)
		{
			Cache.Add(sharedMesh, null);
			return null;
		}
		List<int> list5 = new List<int>();
		Dictionary<int, int> dictionary2 = new Dictionary<int, int>();
		BoneWeight[] array3 = (BoneWeight[])(object)new BoneWeight[list.Count];
		for (int n = 0; n < array3.Length; n++)
		{
			BoneWeight val = boneWeights[list[n]];
			int[] array4 = new int[4]
			{
				((BoneWeight)(ref val)).boneIndex0,
				((BoneWeight)(ref val)).boneIndex1,
				((BoneWeight)(ref val)).boneIndex2,
				((BoneWeight)(ref val)).boneIndex3
			};
			float[] array5 = new float[4]
			{
				((BoneWeight)(ref val)).weight0,
				((BoneWeight)(ref val)).weight1,
				((BoneWeight)(ref val)).weight2,
				((BoneWeight)(ref val)).weight3
			};
			for (int num2 = 0; num2 < 4; num2++)
			{
				if (array5[num2] <= 0f)
				{
					array4[num2] = 0;
					continue;
				}
				if (!dictionary2.TryGetValue(array4[num2], out var value3))
				{
					value3 = list5.Count;
					dictionary2.Add(array4[num2], value3);
					list5.Add(array4[num2]);
				}
				array4[num2] = value3;
			}
			((BoneWeight)(ref val)).boneIndex0 = array4[0];
			((BoneWeight)(ref val)).boneIndex1 = array4[1];
			((BoneWeight)(ref val)).boneIndex2 = array4[2];
			((BoneWeight)(ref val)).boneIndex3 = array4[3];
			array3[n] = val;
		}
		Mesh val2 = new Mesh
		{
			name = ((Object)sharedMesh).name + "_AdventFirstPerson",
			indexFormat = (IndexFormat)(list.Count > 65535)
		};
		val2.vertices = Subset(sharedMesh.vertices, list);
		if (sharedMesh.normals.Length == sharedMesh.vertexCount)
		{
			val2.normals = Subset(sharedMesh.normals, list);
		}
		if (sharedMesh.tangents.Length == sharedMesh.vertexCount)
		{
			val2.tangents = Subset(sharedMesh.tangents, list);
		}
		if (sharedMesh.colors32.Length == sharedMesh.vertexCount)
		{
			val2.colors32 = Subset(sharedMesh.colors32, list);
		}
		for (int num3 = 0; num3 < 8; num3++)
		{
			List<Vector4> list6 = new List<Vector4>();
			sharedMesh.GetUVs(num3, list6);
			if (list6.Count == sharedMesh.vertexCount)
			{
				val2.SetUVs(num3, Subset(list6.ToArray(), list));
			}
		}
		val2.boneWeights = array3;
		val2.bindposes = Subset(sharedMesh.bindposes, list5);
		val2.subMeshCount = list2.Count;
		for (int num4 = 0; num4 < list2.Count; num4++)
		{
			val2.SetTriangles(list2[num4], num4, false);
		}
		val2.RecalculateBounds();
		value = new Entry
		{
			Mesh = val2,
			BoneIndices = list5.ToArray(),
			MaterialSlots = list3.ToArray()
		};
		Cache.Add(sharedMesh, value);
		return value;
	}

	private static T[] Subset<T>(T[] source, List<int> indices)
	{
		T[] array = new T[indices.Count];
		for (int i = 0; i < indices.Count; i++)
		{
			array[i] = source[indices[i]];
		}
		return array;
	}

	public static GameObject Convert(GameObject model)
	{
		AdventJacketToggle component = model.GetComponent<AdventJacketToggle>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.PrepareForViewConversion();
		}
		HashSet<Transform> arms = ArmBones(model);
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			Entry entry = Get(val, arms);
			if (entry == null)
			{
				((Renderer)val).enabled = false;
				Remove((Object)(object)val);
				continue;
			}
			Transform[] bones = val.bones;
			Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
			Transform[] array = (Transform[])(object)new Transform[entry.BoneIndices.Length];
			Material[] array2 = (Material[])(object)new Material[entry.MaterialSlots.Length];
			for (int j = 0; j < array.Length; j++)
			{
				array[j] = bones[entry.BoneIndices[j]];
			}
			for (int k = 0; k < array2.Length; k++)
			{
				array2[k] = sharedMaterials[entry.MaterialSlots[k]];
			}
			val.sharedMesh = entry.Mesh;
			val.bones = array;
			((Renderer)val).sharedMaterials = array2;
			val.quality = (SkinQuality)4;
			val.updateWhenOffscreen = true;
			((Renderer)val).shadowCastingMode = (ShadowCastingMode)0;
		}
		StripSimulation(model);
		AdventJacketToggle component2 = model.GetComponent<AdventJacketToggle>();
		if (Object.op_Implicit((Object)(object)component2))
		{
			component2.Rebind();
		}
		return model;
	}

	public static void StripSimulation(GameObject model)
	{
		Collider[] componentsInChildren = model.GetComponentsInChildren<Collider>(true);
		foreach (Collider obj in componentsInChildren)
		{
			obj.enabled = false;
			Remove((Object)(object)obj);
		}
		MonoBehaviour[] componentsInChildren2 = model.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren2)
		{
			switch (((object)val).GetType().FullName)
			{
			case "AdventSuit.AdventLollipopMount":
			case "AdventSuit.AdventSecondaryMotion":
			case "AdventSuit.AdventHeadTracking":
			case "AdventSuit.AdventFootGrounding":
			case "AdventSuit.AdventFace":
			case "AdventSuit.AdventReactionFace":
			case "AdventSuit.AdventDeathFace":
			case "AdventSuit.AdventToonFrame":
			case "JigglePhysics.JiggleRigBuilder":
				((Behaviour)val).enabled = false;
				Remove((Object)(object)val);
				break;
			}
		}
	}

	private static void Remove(Object component)
	{
		if (Application.isPlaying)
		{
			Object.Destroy(component);
		}
		else
		{
			Object.DestroyImmediate(component);
		}
	}

	public static void Clear()
	{
		foreach (Entry value in Cache.Values)
		{
			if (value != null && Object.op_Implicit((Object)(object)value.Mesh))
			{
				Remove((Object)(object)value.Mesh);
			}
		}
		Cache.Clear();
	}
}
public static class AdventFirstPersonPatch
{
	public static void Install(Harmony harmony)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		Type type = typeof(BodyReplacementBase).Assembly.GetType("ModelReplacement.Scripts.MeshHelper", throwOnError: true);
		MethodInfo methodInfo = AccessTools.Method(type, "ConvertModelToViewModel", new Type[1] { typeof(GameObject) }, (Type[])null);
		if (methodInfo == null)
		{
			throw new MissingMethodException(type.FullName, "ConvertModelToViewModel");
		}
		harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(AdventFirstPersonPatch), "BeforeConvert", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(BodyReplacementBase), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AdventFirstPersonPatch), "AfterBodyCreated", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static bool BeforeConvert(GameObject __0, ref GameObject __result)
	{
		if (!Object.op_Implicit((Object)(object)__0) || !((Object)__0).name.StartsWith("Advent_", StringComparison.Ordinal))
		{
			return true;
		}
		__result = AdventFirstPersonMesh.Convert(__0);
		return false;
	}

	private static void AfterBodyCreated(BodyReplacementBase __instance)
	{
		if (__instance is AdventBody)
		{
			object? value = AccessTools.Field(typeof(BodyReplacementBase), "replacementModel").GetValue(__instance);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			object? value2 = AccessTools.Field(typeof(BodyReplacementBase), "replacementModelShadow").GetValue(__instance);
			GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null);
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
			{
				AdventFirstPersonMesh.StripSimulation(val2);
				val2.AddComponent<AdventShadowPose>().Initialize(val);
			}
			AdventOutfitControl.AttachViews(__instance as AdventBody);
			AdventClawControl.AttachViews(__instance as AdventBody);
		}
	}
}
public class AdventFootAlignment : MonoBehaviour
{
	private Transform hip;

	private Transform leftSole;

	private Transform rightSole;

	private Transform playerLeft;

	private Transform playerRight;

	private Vector3 leftReference;

	private Vector3 rightReference;

	private SkinnedMeshRenderer source;

	private bool ready;

	public float LastCorrection { get; private set; }

	public void Align(SkinnedMeshRenderer player)
	{
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_026a: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)player))
		{
			return;
		}
		if (!ready || (Object)(object)source != (Object)(object)player)
		{
			source = player;
			Animator component = ((Component)this).GetComponent<Animator>();
			if (!Object.op_Implicit((Object)(object)component) || !component.isHuman)
			{
				return;
			}
			hip = component.GetBoneTransform((HumanBodyBones)0);
			Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(true);
			leftSole = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "AdventSole.L"));
			rightSole = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "AdventSole.R"));
			Transform val = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "EmployeeSoleReference.L"));
			Transform val2 = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "EmployeeSoleReference.R"));
			playerLeft = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "foot.L"));
			playerRight = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "foot.R"));
			ready = Object.op_Implicit((Object)(object)hip) && Object.op_Implicit((Object)(object)leftSole) && Object.op_Implicit((Object)(object)rightSole) && Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)playerLeft) && Object.op_Implicit((Object)(object)playerRight);
			if (!ready)
			{
				return;
			}
			leftReference = val.localPosition;
			rightReference = val2.localPosition;
		}
		float num = Mathf.Min(playerLeft.TransformPoint(leftReference).y, playerRight.TransformPoint(rightReference).y);
		float num2 = Mathf.Min(leftSole.position.y, rightSole.position.y);
		LastCorrection = num - num2;
		if (!float.IsNaN(LastCorrection) && !float.IsInfinity(LastCorrection))
		{
			Transform obj = hip;
			obj.position += Vector3.up * LastCorrection;
		}
	}
}
public class AdventHandAlignment : MonoBehaviour
{
	private class Arm
	{
		public Transform Upper;

		public Transform Lower;

		public Transform Hand;

		public Transform PlayerUpper;

		public Transform PlayerLower;

		public Transform PlayerHand;
	}

	private Arm[] arms;

	private SkinnedMeshRenderer source;

	public void Align(SkinnedMeshRenderer player)
	{
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)player))
		{
			return;
		}
		if (arms == null || (Object)(object)source != (Object)(object)player)
		{
			Animator component = ((Component)this).GetComponent<Animator>();
			if (!Object.op_Implicit((Object)(object)component) || !component.isHuman)
			{
				return;
			}
			source = player;
			arms = new Arm[2];
			for (int i = 0; i < 2; i++)
			{
				bool flag = i == 0;
				string s = (flag ? "L" : "R");
				arms[i] = new Arm
				{
					Upper = component.GetBoneTransform((HumanBodyBones)(flag ? 13 : 14)),
					Lower = component.GetBoneTransform((HumanBodyBones)(flag ? 15 : 16)),
					Hand = component.GetBoneTransform((HumanBodyBones)(flag ? 17 : 18)),
					PlayerUpper = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "arm." + s + "_upper")),
					PlayerLower = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "arm." + s + "_lower")),
					PlayerHand = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "hand." + s))
				};
			}
		}
		Arm[] array = arms;
		foreach (Arm arm in array)
		{
			if (Object.op_Implicit((Object)(object)arm.Upper) && Object.op_Implicit((Object)(object)arm.Lower) && Object.op_Implicit((Object)(object)arm.Hand) && Object.op_Implicit((Object)(object)arm.PlayerUpper) && Object.op_Implicit((Object)(object)arm.PlayerLower) && Object.op_Implicit((Object)(object)arm.PlayerHand))
			{
				Quaternion rotation = arm.Hand.rotation;
				Aim(arm.Upper, arm.Lower, arm.PlayerLower.position - arm.PlayerUpper.position);
				Aim(arm.Lower, arm.Hand, arm.PlayerHand.position - arm.PlayerLower.position);
				arm.Hand.rotation = rotation;
			}
		}
	}

	private static void Aim(Transform joint, Transform end, Vector3 direction)
	{
		//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_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		Vector3 val = end.position - joint.position;
		if (((Vector3)(ref val)).sqrMagnitude > 1E-08f && ((Vector3)(ref direction)).sqrMagnitude > 1E-08f)
		{
			joint.rotation = Quaternion.FromToRotation(val, direction) * joint.rotation;
		}
	}
}
[DefaultExecutionOrder(200)]
public class AdventHeadTracking : MonoBehaviour
{
	public PlayerControllerB Player;

	private readonly AdventAttention attention = new AdventAttention();

	public Quaternion? WorldAimFrame;

	public bool TrackingEnabled = true;

	private Transform neck;

	private Transform head;

	private Quaternion headToLook;

	private Quaternion neckBase;

	private Quaternion headBase;

	private Quaternion neckApplied;

	private Quaternion headApplied;

	private Quaternion neutralNeck;

	private Quaternion neutralHead;

	private bool ready;

	private bool applied;

	private int previousFrame = int.MinValue;

	private float yaw;

	private float pitch;

	private float aimWeight;

	public const float MaximumYaw = 50f;

	public const float MaximumUpPitch = 35f;

	public const float MaximumDownPitch = 45f;

	public const float MaximumCorrection = 55f;

	public const float NeckShare = 0.3f;

	public bool HasAttentionTarget { get; private set; }

	public Vector3 AttentionDirection { get; private set; }

	public float CurrentYaw => yaw;

	public float CurrentPitch => pitch;

	public float LastCorrectionAngle { get; private set; }

	public bool Ready => ready;

	public Vector3 LookForward
	{
		get
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			if (!ready)
			{
				return ((Component)this).transform.forward;
			}
			return head.rotation * headToLook * Vector3.forward;
		}
	}

	public Vector3 LookUp
	{
		get
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			if (!ready)
			{
				return ((Component)this).transform.up;
			}
			return head.rotation * headToLook * Vector3.up;
		}
	}

	private void Awake()
	{
		Initialize();
	}

	private void Initialize()
	{
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: 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_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: 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_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: 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)
		if (ready)
		{
			return;
		}
		Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(true);
		Animator componentInChildren = ((Component)this).GetComponentInChildren<Animator>();
		neck = ((Object.op_Implicit((Object)(object)componentInChildren) && componentInChildren.isHuman) ? componentInChildren.GetBoneTransform((HumanBodyBones)9) : null);
		head = ((Object.op_Implicit((Object)(object)componentInChildren) && componentInChildren.isHuman) ? componentInChildren.GetBoneTransform((HumanBodyBones)10) : null);
		if (!Object.op_Implicit((Object)(object)neck))
		{
			neck = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "DEF-spine.005"));
		}
		if (!Object.op_Implicit((Object)(object)head))
		{
			head = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "DEF-spine.006"));
		}
		ready = Object.op_Implicit((Object)(object)neck) && Object.op_Implicit((Object)(object)head) && head.IsChildOf(neck);
		if (ready)
		{
			Transform val = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "AdventGazeFrame"));
			headToLook = Quaternion.Inverse(head.rotation) * (Object.op_Implicit((Object)(object)val) ? val.rotation : Quaternion.identity);
			neckBase = (neutralNeck = neck.localRotation);
			headBase = (neutralHead = head.localRotation);
		}
	}

	private static bool Finite(float value)
	{
		if (!float.IsNaN(value))
		{
			return !float.IsInfinity(value);
		}
		return false;
	}

	private static bool Finite(Vector3 value)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: 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)
		if (Finite(value.x) && Finite(value.y))
		{
			return Finite(value.z);
		}
		return false;
	}

	private static bool SameRotation(Quaternion a, Quaternion b)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		float num = ((!(Quaternion.Dot(a, b) < 0f)) ? 1 : (-1));
		float num2 = a.x - num * b.x;
		float num3 = a.y - num * b.y;
		float num4 = a.z - num * b.z;
		float num5 = a.w - num * b.w;
		return num2 * num2 + num3 * num3 + num4 * num4 + num5 * num5 < 1E-09f;
	}

	private void RestoreAppliedPose()
	{
		//IL_0017: 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_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		if (ready && applied)
		{
			if (SameRotation(neck.localRotation, neckApplied))
			{
				neck.localRotation = neckBase;
			}
			if (SameRotation(head.localRotation, headApplied))
			{
				head.localRotation = headBase;
			}
			applied = false;
		}
	}

	public void PrepareForAvatarPose()
	{
		RestoreAppliedPose();
	}

	public void StepFromDirection(Vector3 direction, float deltaTime, int frameToken, bool tracking = true)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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)
		//IL_0032: 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_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: 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)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_0219: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_0281: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_0292: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		Initialize();
		if (!ready)
		{
			return;
		}
		RestoreAppliedPose();
		neckBase = neck.localRotation;
		headBase = head.localRotation;
		bool flag = tracking && TrackingEnabled && Finite(direction) && ((Vector3)(ref direction)).sqrMagnitude > 1E-08f;
		Quaternion val = (Quaternion)(((??)WorldAimFrame) ?? ((Component)this).transform.rotation);
		if (previousFrame != frameToken)
		{
			previousFrame = frameToken;
			float num = yaw;
			float num2 = pitch;
			if (flag)
			{
				Vector3 val2 = Quaternion.Inverse(val) * ((Vector3)(ref direction)).normalized;
				num = Mathf.Clamp(Mathf.Atan2(val2.x, val2.z) * 57.29578f, -50f, 50f);
				num2 = Mathf.Clamp(Mathf.Atan2(val2.y, Mathf.Sqrt(val2.x * val2.x + val2.z * val2.z)) * 57.29578f, -45f, 35f);
			}
			float num3 = 1f - Mathf.Exp((0f - Mathf.Clamp(deltaTime, 0f, 0.1f)) * 10f);
			yaw = Mathf.Lerp(yaw, num, num3);
			pitch = Mathf.Lerp(pitch, num2, num3);
			aimWeight = Mathf.Lerp(aimWeight, (float)(flag ? 1 : 0), num3);
		}
		LastCorrectionAngle = 0f;
		if (TrackingEnabled && !(aimWeight < 1E-06f))
		{
			Vector3 val3 = val * Quaternion.Euler(0f - pitch, yaw, 0f) * Vector3.forward;
			Quaternion val4 = Quaternion.FromToRotation(LookForward, val3);
			val4 = Quaternion.RotateTowards(Quaternion.identity, val4, 55f);
			val4 = Quaternion.Slerp(Quaternion.identity, val4, aimWeight);
			LastCorrectionAngle = Quaternion.Angle(Quaternion.identity, val4);
			neck.rotation = Quaternion.Slerp(Quaternion.identity, val4, 0.3f) * neck.rotation;
			head.rotation = Quaternion.Slerp(Quaternion.identity, val4, 0.7f) * head.rotation;
			neckApplied = neck.localRotation;
			headApplied = head.localRotation;
			applied = true;
		}
	}

	public void Step()
	{
		//IL_006b: 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_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		TrackingEnabled = Plugin.HeadTracking.Value;
		bool flag = Object.op_Implicit((Object)(object)Player) && TrackingEnabled && !Player.isPlayerDead && Player.isPlayerControlled;
		Initialize();
		WorldAimFrame = (Object.op_Implicit((Object)(object)Player) ? new Quaternion?(((Component)Player).transform.rotation) : ((Quaternion?)null));
		Vector3 val = (Quaternion)(((??)WorldAimFrame) ?? ((Component)this).transform.rotation) * Vector3.forward;
		Vector3 direction = val;
		HasAttentionTarget = flag && ready && attention.Resolve(Player, ((Component)this).transform, head.position, val, Time.unscaledTime, out direction);
		AttentionDirection = direction;
		if (!flag)
		{
			attention.Reset();
		}
		StepFromDirection(direction, Time.deltaTime, Time.frameCount, HasAttentionTarget);
	}

	public void PrepareNeutralTrackingPose()
	{
		//IL_001c: 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)
		Initialize();
		if (ready)
		{
			RestoreAppliedPose();
			neck.localRotation = neutralNeck;
			head.localRotation = neutralHead;
		}
	}

	private void LateUpdate()
	{
		Step();
	}

	public void ResetAim()
	{
		RestoreAppliedPose();
		yaw = (pitch = (aimWeight = 0f));
		previousFrame = int.MinValue;
		LastCorrectionAngle = 0f;
		HasAttentionTarget = false;
		attention.Reset();
	}

	private void OnDisable()
	{
		ResetAim();
	}
}
public sealed class AdventJacketToggle : MonoBehaviour
{
	private sealed class MaterialSlot
	{
		public SkinnedMeshRenderer Renderer;

		public Material[] On;

		public Material[] Off;
	}

	private sealed class Variant
	{
		public Mesh On;

		public Mesh Off;

		public int Removed;
	}

	private sealed class Slot
	{
		public SkinnedMeshRenderer Renderer;

		public Variant Mesh;
	}

	public string Character;

	public string[] JacketMaterials = new string[0];

	public string[] DrawstringBones = new string[0];

	public string[] PhysicsBones = new string[0];

	public Texture CleanBodyTexture;

	private readonly List<MaterialSlot> materialSlots = new List<MaterialSlot>();

	private readonly List<Material> owned = new List<Material>();

	private SkinnedMeshRenderer[] uncovered = (SkinnedMeshRenderer[])(object)new SkinnedMeshRenderer[0];

	private static readonly Dictionary<Mesh, Variant> cache = new Dictionary<Mesh, Variant>();

	private static readonly Dictionary<Mesh, Mesh> originals = new Dictionary<Mesh, Mesh>();

	private static readonly Dictionary<Material, Material> materialOrigins = new Dictionary<Material, Material>();

	private readonly List<Slot> slots = new List<Slot>();

	private AdventSecondaryMotion motion;

	private AdventSecondaryMotion.Node[] allNodes;

	private AdventSecondaryMotion.Node[] uncoveredNodes;

	private bool initialized;

	public bool Shown { get; private set; } = true;

	public int RemovedTriangles => slots.Sum((Slot s) => s.Mesh.Removed);

	private bool MaterialIsJacket(Material m)
	{
		if (Object.op_Implicit((Object)(object)m))
		{
			return JacketMaterials.Any((string n) => ((Object)m).name.StartsWith(n, StringComparison.Ordinal));
		}
		return false;
	}

	private Variant Get(SkinnedMeshRenderer renderer)
	{
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_027a: Unknown result type (might be due to invalid IL or missing references)
		Mesh val = renderer.sharedMesh;
		if (originals.TryGetValue(val, out var value))
		{
			val = value;
		}
		if (cache.TryGetValue(val, out var value2))
		{
			return value2;
		}
		BoneWeight[] boneWeights = val.boneWeights;
		HashSet<int> hashSet = new HashSet<int>(from i in Enumerable.Range(0, renderer.bones.Length)
			where DrawstringBones.Contains(((Object)renderer.bones[i]).name)
			select i);
		bool[] array = new bool[boneWeights.Length];
		for (int num = 0; num < boneWeights.Length; num++)
		{
			BoneWeight val2 = boneWeights[num];
			array[num] = (hashSet.Contains(((BoneWeight)(ref val2)).boneIndex0) ? ((BoneWeight)(ref val2)).weight0 : 0f) + (hashSet.Contains(((BoneWeight)(ref val2)).boneIndex1) ? ((BoneWeight)(ref val2)).weight1 : 0f) + (hashSet.Contains(((BoneWeight)(ref val2)).boneIndex2) ? ((BoneWeight)(ref val2)).weight2 : 0f) + (hashSet.Contains(((BoneWeight)(ref val2)).boneIndex3) ? ((BoneWeight)(ref val2)).weight3 : 0f) > 0.25f;
		}
		Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials;
		int[][] array2 = new int[val.subMeshCount][];
		int num2 = 0;
		for (int num3 = 0; num3 < array2.Length; num3++)
		{
			int[] triangles = val.GetTriangles(num3);
			if (num3 < sharedMaterials.Length && MaterialIsJacket(sharedMaterials[num3]))
			{
				num2 += triangles.Length / 3;
				array2[num3] = new int[0];
				continue;
			}
			List<int> list = new List<int>();
			for (int num4 = 0; num4 < triangles.Length; num4 += 3)
			{
				if (array[triangles[num4]] && array[triangles[num4 + 1]] && array[triangles[num4 + 2]])
				{
					num2++;
					continue;
				}
				list.Add(triangles[num4]);
				list.Add(triangles[num4 + 1]);
				list.Add(triangles[num4 + 2]);
			}
			array2[num3] = list.ToArray();
		}
		if (num2 == 0)
		{
			value2 = new Variant
			{
				On = val,
				Off = val
			};
			cache[val] = value2;
			return value2;
		}
		Mesh val3 = Object.Instantiate<Mesh>(val);
		((Object)val3).name = ((Object)val).name + "_JacketOff";
		for (int num5 = 0; num5 < array2.Length; num5++)
		{
			val3.SetTriangles(array2[num5], num5, false);
		}
		val3.bounds = val.bounds;
		value2 = new Variant
		{
			On = val,
			Off = val3,
			Removed = num2
		};
		cache[val] = value2;
		originals[val3] = val;
		return value2;
	}

	public void Prime()
	{
		SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			if (Object.op_Implicit((Object)(object)val.sharedMesh))
			{
				Get(val);
			}
		}
	}

	public void Initialize()
	{
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Expected O, but got Unknown
		if (initialized)
		{
			return;
		}
		initialized = true;
		uncovered = (from r in ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true)
			where ((Object)r).name == "FuwawaJacketOffSleeves"
			select r).ToArray();
		SkinnedMeshRenderer[] array = uncovered;
		for (int num = 0; num < array.Length; num++)
		{
			((Renderer)array[num]).enabled = !Shown;
		}
		array = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in array)
		{
			if (!Object.op_Implicit((Object)(object)val.sharedMesh))
			{
				continue;
			}
			Variant variant = Get(val);
			if (variant.Removed > 0)
			{
				slots.Add(new Slot
				{
					Renderer = val,
					Mesh = variant
				});
			}
			if (!Object.op_Implicit((Object)(object)CleanBodyTexture))
			{
				continue;
			}
			Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
			for (int num2 = 0; num2 < sharedMaterials.Length; num2++)
			{
				if (materialOrigins.TryGetValue(sharedMaterials[num2], out var value))
				{
					sharedMaterials[num2] = value;
				}
			}
			((Renderer)val).sharedMaterials = sharedMaterials;
			Material[] array2 = (Material[])sharedMaterials.Clone();
			bool flag = false;
			for (int num3 = 0; num3 < sharedMaterials.Length; num3++)
			{
				if (((Object)sharedMaterials[num3]).name.StartsWith("MococoAbyssgard_Material_00") || ((Object)sharedMaterials[num3]).name.StartsWith("MococoAbyssgard_Material_01") || ((Object)sharedMaterials[num3]).name.StartsWith("MococoAbyssgard_Material_03"))
				{
					Material val2 = new Material(sharedMaterials[num3]);
					val2.SetTexture("_BaseColorMap", CleanBodyTexture);
					array2[num3] = val2;
					owned.Add(val2);
					materialOrigins[val2] = sharedMaterials[num3];
					flag = true;
				}
			}
			if (flag)
			{
				materialSlots.Add(new MaterialSlot
				{
					Renderer = val,
					On = sharedMaterials,
					Off = array2
				});
			}
		}
		motion = ((Component)this).GetComponent<AdventSecondaryMotion>();
		if (Object.op_Implicit((Object)(object)motion))
		{
			allNodes = motion.nodes;
			uncoveredNodes = allNodes.Where((AdventSecondaryMotion.Node n) => Object.op_Implicit((Object)(object)n.bone) && !PhysicsBones.Contains(((Object)n.bone).name)).ToArray();
		}
	}

	public void Rebind()
	{
		foreach (MaterialSlot materialSlot in materialSlots)
		{
			if (Object.op_Implicit((Object)(object)materialSlot.Renderer))
			{
				((Renderer)materialSlot.Renderer).sharedMaterials = materialSlot.On;
			}
		}
		foreach (Material item in owned)
		{
			materialOrigins.Remove(item);
			if (Object.op_Implicit((Object)(object)item))
			{
				Object.Destroy((Object)(object)item);
			}
		}
		materialSlots.Clear();
		owned.Clear();
		slots.Clear();
		initialized = false;
		Shown = true;
		Initialize();
	}

	public void PrepareForViewConversion()
	{
		SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			if (Object.op_Implicit((Object)(object)val.sharedMesh) && originals.TryGetValue(val.sharedMesh, out var value))
			{
				val.sharedMesh = value;
			}
		}
	}

	public void Apply(bool shown)
	{
		Initialize();
		if (Shown == shown)
		{
			return;
		}
		Shown = shown;
		foreach (Slot slot in slots)
		{
			if (Object.op_Implicit((Object)(object)slot.Renderer))
			{
				slot.Renderer.sharedMesh = (shown ? slot.Mesh.On : slot.Mesh.Off);
				int blendShapeIndex = slot.Renderer.sharedMesh.GetBlendShapeIndex("jacket_off_fit");
				if (blendShapeIndex >= 0)
				{
					slot.Renderer.SetBlendShapeWeight(blendShapeIndex, (float)((!shown) ? 100 : 0));
				}
			}
		}
		SkinnedMeshRenderer[] array = uncovered;
		foreach (SkinnedMeshRenderer val in array)
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				((Renderer)val).enabled = !shown;
			}
		}
		foreach (MaterialSlot materialSlot in materialSlots)
		{
			if (Object.op_Implicit((Object)(object)materialSlot.Renderer))
			{
				((Renderer)materialSlot.Renderer).sharedMaterials = (shown ? materialSlot.On : materialSlot.Off);
			}
		}
		if (Object.op_Implicit((Object)(object)motion) && ((Behaviour)motion).enabled)
		{
			motion.PrepareForAvatarPose();
			motion.nodes = (shown ? allNodes : uncoveredNodes);
			motion.ResetSimulation();
		}
	}

	private void OnDestroy()
	{
		foreach (MaterialSlot materialSlot in materialSlots)
		{
			if (Object.op_Implicit((Object)(object)materialSlot.Renderer))
			{
				((Renderer)materialSlot.Renderer).sharedMaterials = materialSlot.On;
			}
		}
		foreach (Material item in owned)
		{
			materialOrigins.Remove(item);
			if (Object.op_Implicit((Object)(object)item))
			{
				Object.Destroy((Object)(object)item);
			}
		}
	}

	public static void ClearCache()
	{
		foreach (Variant value in cache.Values)
		{
			if (Object.op_Implicit((Object)(object)value.Off) && (Object)(object)value.Off != (Object)(object)value.On)
			{
				Object.Destroy((Object)(object)value.Off);
			}
		}
		cache.Clear();
		originals.Clear();
		materialOrigins.Clear();
	}
}
public static class AdventOutfitControl
{
	private sealed class Entry
	{
		public AdventJacketToggle Body;

		public AdventJacketToggle View;

		public string Character;
	}

	private static readonly Dictionary<PlayerControllerB, Entry> models = new Dictionary<PlayerControllerB, Entry>();

	private static readonly Dictionary<PlayerControllerB, bool> settings = new Dictionary<PlayerControllerB, bool>();

	public static void Bind(PlayerControllerB player, GameObject model, string character)
	{
		AdventJacketToggle component = model.GetComponent<AdventJacketToggle>();
		if (Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)component))
		{
			component.Initialize();
			models[player] = new Entry
			{
				Body = component,
				Character = character
			};
			if (!settings.ContainsKey(player))
			{
				settings[player] = Plugin.JacketShown.Value;
			}
			component.Apply(Shown(player, character));
		}
	}

	public static void AttachViews(AdventBody owner)
	{
		if (!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)((BodyReplacementBase)owner).controller) || !models.TryGetValue(((BodyReplacementBase)owner).controller, out var value))
		{
			return;
		}
		object obj = AdventRuntimeMembers.Read(AdventRuntimeMembers.Read(owner, "viewModelAvatar"), "replacementViewModel");
		GameObject val = (GameObject)((obj is GameObject) ? obj : null);
		if (Object.op_Implicit((Object)(object)val))
		{
			value.View = val.GetComponent<AdventJacketToggle>();
			if (Object.op_Implicit((Object)(object)value.View))
			{
				value.View.Rebind();
				value.View.Apply(Shown(((BodyReplacementBase)owner).controller, value.Character));
			}
		}
	}

	public static bool Shown(PlayerControllerB player, string character)
	{
		if (Object.op_Implicit((Object)(object)player) && !((NetworkBehaviour)player).IsOwner)
		{
			return AdventExpressionNetwork.JacketShown(player.playerClientId, character);
		}
		bool value = default(bool);
		return !Object.op_Implicit((Object)(object)player) || !settings.TryGetValue(player, out value) || value;
	}

	public static void Tick()
	{
		//IL_006b: 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)
		Keyboard current = Keyboard.current;
		foreach (KeyValuePair<PlayerControllerB, Entry> model in models)
		{
			PlayerControllerB key = model.Key;
			Entry value = model.Value;
			if (Object.op_Implicit((Object)(object)key) && Object.op_Implicit((Object)(object)value.Body))
			{
				if (((NetworkBehaviour)key).IsOwner && current != null && !key.isTypingChat && !key.inTerminalMenu && (int)Plugin.JacketKey.Value != 0 && ((ButtonControl)current[Plugin.JacketKey.Value]).wasPressedThisFrame)
				{
					settings[key] = !Shown(key, value.Character);
				}
				bool shown = Shown(key, value.Character);
				value.Body.Apply(shown);
				if (Object.op_Implicit((Object)(object)value.View))
				{
					value.View.Apply(shown);
				}
			}
		}
	}

	public static void Clear()
	{
		models.Clear();
		settings.Clear();
		AdventJacketToggle.ClearCache();
	}
}
[DefaultExecutionOrder(270)]
public sealed class AdventReactionFace : MonoBehaviour
{
	internal static readonly Dictionary<PlayerControllerB, AdventReactionFace> Players = new Dictionary<PlayerControllerB, AdventReactionFace>();

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

	public PlayerControllerB Player;

	public string Character;

	private AdventBody body;

	private AdventExpressionMixer mixer;

	private readonly AdventExpressionSelection selection = new AdventExpressionSelection();

	private readonly HashSet<int> inventory = new HashSet<int>();

	private readonly HashSet<int> currentInventory = new HashSet<int>();

	private int health;

	private float nextContext;

	private AdventExpressionContext context;

	private AdventExpression sent = (AdventExpression)255;

	private bool sentUnsafe;

	private bool sentGlow;

	private bool sentJacket = true;

	private bool sentClaws = true;

	private bool sentCrown = true;

	private bool sentOrnaments = true;

	private float nextHeartbeat;

	private Component customEmotes;

	private float nextEmoteLookup;

	private readonly RaycastHit[] hits = (RaycastHit[])(object)new RaycastHit[24];

	private static Type emoteType;

	private static bool emoteTypeResolved;

	private static EnemyAI[] enemies = (EnemyAI[])(object)new EnemyAI[0];

	private static VehicleController[] vehicles = (VehicleController[])(object)new VehicleController[0];

	private static StartOfRound scene;

	private static float nextSceneScan;

	internal AdventExpression Current { get; private set; }

	public void Initialize(AdventBody owner, PlayerControllerB player, string character)
	{
		body = owner;
		Player = player;
		Character = character;
		selection.Character = character;
		health = player.health;
		SeedInventory();
		mixer = new AdventExpressionMixer(((Component)this).gameObject);
		Players[player] = this;
	}

	private void SeedInventory()
	{
		inventory.Clear();
		if (Player.ItemSlots == null)
		{
			return;
		}
		GrabbableObject[] itemSlots = Player.ItemSlots;
		foreach (GrabbableObject val in itemSlots)
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				inventory.Add(((Object)val).GetInstanceID());
			}
		}
	}

	internal void Damage()
	{
		selection.Damage(Time.unscaledTime);
	}

	internal void WeaponUsed()
	{
		selection.WeaponUsed(Time.unscaledTime);
	}

	private static void Scan(float now)
	{
		if ((Object)(object)scene != (Object)(object)StartOfRound.Instance)
		{
			scene = StartOfRound.Instance;
			nextSceneScan = 0f;
			enemies = (EnemyAI[])(object)new EnemyAI[0];
			vehicles = (VehicleController[])(object)new VehicleController[0];
			CorpseCharacters.Clear();
		}
		if (!(now < nextSceneScan))
		{
			nextSceneScan = now + 1f;
			enemies = AdventSceneCache.Enemies(now);
			vehicles = Object.FindObjectsByType<VehicleController>((FindObjectsSortMode)0);
		}
	}

	internal static bool DangerousNearOrChasing(PlayerControllerB p)
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		EnemyAI[] array = enemies;
		foreach (EnemyAI val in array)
		{
			if (!Object.op_Implicit((Object)(object)val) || val.isEnemyDead || !((Behaviour)val).isActiveAndEnabled)
			{
				continue;
			}
			string name = ((object)val).GetType().Name;
			if (!(name == "DocileLocustBeesAI") && !(name == "DoublewingAI"))
			{
				Vector3 val2 = ((Component)val).transform.position - ((Component)p).transform.position;
				if (((Vector3)(ref val2)).sqrMagnitude <= 36f || ((Object)(object)val.targetPlayer == (Object)(object)p && (val.movingTowardsTargetPlayer || val.currentBehaviourStateIndex > 0)))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static Type OptionalEmoteType()
	{
		if (emoteTypeResolved)
		{
			return emoteType;
		}
		emoteTypeResolved = true;
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			try
			{
				Type type = assembly.GetType("TooManyEmotes.EmoteControllerPlayer", throwOnError: false);
				if (type != null)
				{
					emoteType = type;
					break;
				}
			}
			catch (TypeLoadException)
			{
			}
		}
		return emoteType;
	}

	private bool Dancing()
	{
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		if (Time.unscaledTime >= nextEmoteLookup)
		{
			nextEmoteLookup = Time.unscaledTime + 2f;
			Type type = OptionalEmoteType();
			customEmotes = ((type != null) ? ((Component)Player).GetComponent(type) : null);
		}
		bool value = default(bool);
		if (Object.op_Implicit((Object)(object)customEmotes) && AdventRuntimeMembers.TryRead<bool>(customEmotes, "isPerformingEmote", out value) && value)
		{
			if (AdventRuntimeMembers.TryRead<bool>(AdventRuntimeMembers.Read(customEmotes, "performingEmote"), "isPose", out var value2))
			{
				return !value2;
			}
			return true;
		}
		if (!Player.performingEmote)
		{
			return false;
		}
		if (AdventRuntimeMembers.TryRead<int>(body, "danceNumber", out var value3) && value3 == 1)
		{
			return true;
		}
		if (!Object.op_Implicit((Object)(object)Player.playerBodyAnimator))
		{
			return false;
		}
		AnimatorStateInfo currentAnimatorStateInfo = Player.playerBodyAnimator.GetCurrentAnimatorStateInfo(1);
		return ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Emotes.Emote1");
	}

	private static Transform View(PlayerControllerB p)
	{
		if (!Object.op_Implicit((Object)(object)p.gameplayCamera))
		{
			if (!Object.op_Implicit((Object)(object)p.playerEye))
			{
				return ((Component)p).transform;
			}
			return p.playerEye;
		}
		return ((Component)p.gameplayCamera).transform;
	}

	private bool Sees(PlayerControllerB target, Vector3 point, Transform targetRoot, float radius)
	{
		//IL_000d: 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_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		Transform val = View(Player);
		if (AdventAttentionSelection.InView(val.position, val.forward, point, radius))
		{
			return AdventAttentionSelection.Visible(val.position, point, Object.op_Implicit((Object)(object)StartOfRound.Instance) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-5), ((Component)Player).transform, ((Component)this).transform, targetRoot, hits);
		}
		return false;
	}

	internal static string Id(PlayerControllerB p)
	{
		if (Players.TryGetValue(p, out var value) && Object.op_Implicit((Object)(object)value))
		{
			return value.Character;
		}
		if (CorpseCharacters.TryGetValue(p.playerClientId, out var value2))
		{
			return value2;
		}
		return AdventExpressionNetwork.CharacterOf(p.playerClientId);
	}

	private AdventExpressionContext Gather(float now)
	{
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_029e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
		Scan(now);
		AdventExpressionContext result = new AdventExpressionContext
		{
			Dead = Player.isPlayerDead,
			Critical = (Player.criticallyInjured || Player.health < 10),
			EnemyNear = DangerousNearOrChasing(Player),
			Fear = (((NetworkBehaviour)Player).IsOwner && Object.op_Implicit((Object)(object)StartOfRound.Instance) && (StartOfRound.Instance.fearLevel > 0.01f || StartOfRound.Instance.fearLevelIncreasing)),
			Dancing = Dancing()
		};
		VehicleController[] array = vehicles;
		foreach (VehicleController val in array)
		{
			if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.currentDriver == (Object)(object)Player)
			{
				result.Driving = true;
				break;
			}
		}
		GrabbableObject val2 = (Object.op_Implicit((Object)(object)Player.currentlyHeldObjectServer) ? Player.currentlyHeldObjectServer : Play