Decompiled source of CHEF Skin Pack v0.2.0

BepInEx/plugins/ChefCollection/Rodanius.Chef.Collection.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using BepInEx;
using Eclipse.AdvancedSkins;
using EntityStates;
using EntityStates.Chef;
using HG.Reflection;
using On.EntityStates.Chef;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

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

[BepInPlugin("rodanius.chef.collection", "CHEF Skin Pack - Collection", "0.2.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class ChefPack : BaseUnityPlugin
{
	[Serializable]
	public sealed class AssetFile
	{
		public string file;

		public string sha256;
	}

	[Serializable]
	public sealed class AssetManifest
	{
		public int schema;

		public string skinId;

		public string revision;

		public string displayName;

		public AssetFile mesh;

		public AssetFile motion;

		public AssetFile albedo;

		public AssetFile normal;

		public AssetFile icon;

		public string[] nativeBoneNames;
	}

	public const string Guid = "rodanius.chef.collection";

	public const string Version = "0.2.0";

	private string SkinId;

	private readonly List<IDisposable> registrations = new List<IDisposable>();

	private static ChefPack instance;

	private string folder;

	private float deadline;

	private bool registered;

	private readonly Dictionary<string, Mesh> fallbackMeshes = new Dictionary<string, Mesh>();

	private GameObject modelPrefab;

	private GameObject displayModelPrefab;

	private Mesh nativeMesh;

	private Material nativeMaterial;

	private AssetManifest manifest;

	private readonly List<AsyncOperationHandle> retainedAssets = new List<AsyncOperationHandle>();

	private static readonly string[] RendererNames = new string[5] { "meshChef", "meshChefPizzaCutter", "meshlChefCleaver", "meshChefOven", "meshChefIceBox" };

	private void Awake()
	{
		instance = this;
		ChefNativeEvents.Install();
		folder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		SystemInitializerInjector.InjectDependency(typeof(SkinCatalog), typeof(ChefPack));
		RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(SyncDisplaySkins));
		MainMenuController.OnMainMenuInitialised += SyncDisplaySkins;
	}

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(SurvivorCatalog)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			yield break;
		}
		instance.deadline = Time.realtimeSinceStartup + 45f;
		IEnumerator routine = instance.Register();
		try
		{
			while (true)
			{
				bool flag;
				try
				{
					flag = routine.MoveNext();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)instance).Logger.LogError((object)("CHEF_PACK_REGISTRATION_FAILED " + ex));
					break;
				}
				if (flag)
				{
					yield return routine.Current;
					continue;
				}
				break;
			}
		}
		finally
		{
			IDisposable disposable = routine as IDisposable;
			if (disposable != null)
			{
				disposable.Dispose();
			}
		}
	}

	private void CheckDeadline()
	{
		if (Time.realtimeSinceStartup > deadline)
		{
			throw new TimeoutException("Chef asset loading timed out; other startup work continues.");
		}
	}

	private byte[] ReadAsset(AssetFile entry)
	{
		if (entry == null || string.IsNullOrWhiteSpace(entry.file) || Path.GetFileName(entry.file) != entry.file || entry.file.Contains("..") || entry.sha256 == null || entry.sha256.Length != 64)
		{
			throw new InvalidDataException("Invalid character asset manifest entry");
		}
		string text = Path.Combine(folder, entry.file);
		if (new FileInfo(text).Length > 67108864)
		{
			throw new InvalidDataException("Chef asset too large");
		}
		byte[] array = File.ReadAllBytes(text);
		using SHA256 sHA = SHA256.Create();
		if (BitConverter.ToString(sHA.ComputeHash(array)).Replace("-", "").ToLowerInvariant() != entry.sha256)
		{
			throw new InvalidDataException("Chef asset hash mismatch: " + entry.file);
		}
		return array;
	}

	private static SkinnedMeshRenderer Exact(GameObject model, string name)
	{
		Transform val = model.transform.Find(name);
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent<SkinnedMeshRenderer>()))
		{
			throw new InvalidOperationException("Missing scoped CHEF renderer " + name);
		}
		return ((Component)val).GetComponent<SkinnedMeshRenderer>();
	}

	private void PrepareTemplate(GameObject model)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		AdvancedSkinModel component = model.GetComponent<AdvancedSkinModel>();
		if (Object.op_Implicit((Object)(object)component) && component.HasNativeSnapshot)
		{
			component.Prepare();
			return;
		}
		SkinnedMeshRenderer val = Exact(model, "meshChef");
		Animator component2 = model.GetComponent<Animator>();
		Vector3 val2 = ((Component)val).transform.localScale - Vector3.one * 100f;
		if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f) && !(Quaternion.Angle(((Component)val).transform.localRotation, Quaternion.Euler(-90f, 0f, 0f)) > 0.1f))
		{
			val2 = ((Component)val).transform.localPosition;
			if (!(((Vector3)(ref val2)).sqrMagnitude > 0.0001f))
			{
				if (!Object.op_Implicit((Object)(object)component2) || val.bones.Length != manifest.nativeBoneNames.Length)
				{
					throw new InvalidOperationException("Chef requires the original CHEF skeleton");
				}
				for (int i = 0; i < val.bones.Length; i++)
				{
					if (!Object.op_Implicit((Object)(object)val.bones[i]) || ((Object)val.bones[i]).name != manifest.nativeBoneNames[i])
					{
						throw new InvalidOperationException("Native bone slot mismatch " + i);
					}
				}
				AdvancedSkinModel val3 = model.GetComponent<AdvancedSkinModel>();
				if (!Object.op_Implicit((Object)(object)val3))
				{
					val3 = model.AddComponent<AdvancedSkinModel>();
				}
				val3.CaptureNativeTemplate(val, component2, nativeMesh, (Material[])(object)new Material[1] { nativeMaterial });
				val3.Prepare();
				return;
			}
		}
		throw new InvalidOperationException("CHEF renderer conversion contract changed");
	}

	private IEnumerator Register()
	{
		string root = folder;
		int[] array = new int[7] { 1, 3, 4, 5, 6, 7, 8 };
		for (int i = 0; i < array.Length; i++)
		{
			int tier = array[i];
			folder = Path.Combine(root, "e" + tier);
			SkinId = "RodaniusChefE" + tier;
			fallbackMeshes.Clear();
			deadline = Time.realtimeSinceStartup + 45f;
			{
				IEnumerator routine = RegisterOne();
				try
				{
					while (true)
					{
						bool flag;
						try
						{
							flag = routine.MoveNext();
						}
						catch (Exception ex)
						{
							((BaseUnityPlugin)this).Logger.LogError((object)("CHEF_PACK_SKIN_FAILED tier=" + tier + " " + ex));
							break;
						}
						if (!flag)
						{
							break;
						}
						yield return routine.Current;
					}
				}
				finally
				{
					IDisposable disposable = routine as IDisposable;
					if (disposable != null)
					{
						disposable.Dispose();
					}
				}
			}
		}
	}

	private IEnumerator RegisterOne()
	{
		manifest = JsonUtility.FromJson<AssetManifest>(File.ReadAllText(Path.Combine(folder, "assets.json")));
		if (manifest == null || manifest.schema != 1 || manifest.skinId != SkinId || string.IsNullOrWhiteSpace(manifest.revision) || manifest.nativeBoneNames == null || manifest.nativeBoneNames.Length != 61)
		{
			throw new InvalidDataException("Invalid character asset identity");
		}
		MotionBank bank;
		using (MemoryStream memoryStream = new MemoryStream(ReadAsset(manifest.motion), writable: false))
		{
			bank = MotionBank.Read((Stream)memoryStream);
		}
		if (bank.SkinId != SkinId)
		{
			throw new InvalidDataException("Motion identity mismatch");
		}
		bank.Find("idle");
		bank.Find("scuttle");
		bank.Find("claw_grip_proof");
		Mesh mesh;
		using (MemoryStream memoryStream2 = new MemoryStream(ReadAsset(manifest.mesh), writable: false))
		{
			mesh = SkinMesh.Read((Stream)memoryStream2, bank);
		}
		Texture2D albedo = new Texture2D(2, 2, (TextureFormat)4, true, false)
		{
			name = "ChefPackAlbedo",
			filterMode = (FilterMode)1,
			anisoLevel = 4
		};
		if (!ImageConversion.LoadImage(albedo, ReadAsset(manifest.albedo), false))
		{
			throw new InvalidDataException("Invalid character albedo");
		}
		mesh.RecalculateTangents();
		Texture2D normal = new Texture2D(2, 2, (TextureFormat)4, true, true)
		{
			name = SkinId + "Normal",
			filterMode = (FilterMode)2,
			anisoLevel = 4
		};
		if (!ImageConversion.LoadImage(normal, ReadAsset(manifest.normal), false))
		{
			throw new InvalidDataException("Invalid CHEF normal texture");
		}
		Texture2D portrait = new Texture2D(2, 2, (TextureFormat)4, false, false)
		{
			name = SkinId + "Portrait"
		};
		if (!ImageConversion.LoadImage(portrait, ReadAsset(manifest.icon), false))
		{
			throw new InvalidDataException("Invalid CHEF portrait");
		}
		GameObject body = BodyCatalog.FindBodyPrefab("ChefBody");
		if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.GetComponent<ModelLocator>()))
		{
			throw new InvalidOperationException("CHEF body unavailable");
		}
		modelPrefab = ((Component)body.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = modelPrefab.GetComponent<ModelSkinController>();
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null || controller.skins.Length == 0)
		{
			throw new InvalidOperationException("Native CHEF skins unavailable");
		}
		if (controller.skins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == SkinId))
		{
			yield break;
		}
		SkinDef baseSkin = controller.skins[0];
		SkinDefParams parameters = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)parameters) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> op = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(op));
			while (!op.IsDone)
			{
				CheckDeadline();
				yield return null;
			}
			parameters = op.Result;
		}
		if (!Object.op_Implicit((Object)(object)parameters))
		{
			throw new InvalidOperationException("Native skin parameters unavailable");
		}
		SkinnedMeshRenderer[] componentsInChildren = modelPrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		SkinnedMeshRenderer target = componentsInChildren.Single((SkinnedMeshRenderer r) => ((Object)r).name == "meshChef");
		MeshReplacement val = ((IEnumerable<MeshReplacement>)parameters.meshReplacements).FirstOrDefault((Func<MeshReplacement, bool>)((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target));
		nativeMesh = val.mesh;
		if (!Object.op_Implicit((Object)(object)nativeMesh) && val.meshAddress != null && ((AssetReference)val.meshAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Mesh> op2 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val.meshAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(op2));
			while (!op2.IsDone)
			{
				CheckDeadline();
				yield return null;
			}
			nativeMesh = op2.Result;
		}
		if (!Object.op_Implicit((Object)(object)nativeMesh))
		{
			nativeMesh = target.sharedMesh;
		}
		if (!Object.op_Implicit((Object)(object)nativeMesh) || nativeMesh.bindposes.Length != 61)
		{
			throw new InvalidOperationException("Native fallback mesh invalid");
		}
		RendererInfo info = parameters.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		nativeMaterial = info.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)nativeMaterial) && info.defaultMaterialAddress != null && ((AssetReference)info.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> op3 = Addressables.LoadAssetAsync<Material>(((AssetReference)info.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(op3));
			while (!op3.IsDone)
			{
				CheckDeadline();
				yield return null;
			}
			nativeMaterial = op3.Result;
		}
		if (!Object.op_Implicit((Object)(object)nativeMaterial) || !Object.op_Implicit((Object)(object)nativeMaterial.shader))
		{
			throw new InvalidOperationException("Native fallback material invalid");
		}
		string[] rendererNames = RendererNames;
		foreach (string name in rendererNames)
		{
			SkinnedMeshRenderer nativeRenderer = Exact(modelPrefab, name);
			MeshReplacement val2 = parameters.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)nativeRenderer);
			Mesh val3 = val2.mesh;
			if (!Object.op_Implicit((Object)(object)val3) && val2.meshAddress != null && ((AssetReference)val2.meshAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<Mesh> op2 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(op2));
				while (!op2.IsDone)
				{
					CheckDeadline();
					yield return null;
				}
				val3 = op2.Result;
			}
			if (!Object.op_Implicit((Object)(object)val3))
			{
				val3 = nativeRenderer.sharedMesh;
			}
			if (!Object.op_Implicit((Object)(object)val3) || val3.bindposes.Length != 61)
			{
				throw new InvalidOperationException("Missing fallback mesh " + name);
			}
			fallbackMeshes.Add(name, val3);
		}
		SurvivorDef val4 = SurvivorCatalog.FindSurvivorDefFromBody(body);
		if (!Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val4.displayPrefab))
		{
			throw new InvalidOperationException("CHEF display unavailable");
		}
		CharacterModel componentInChildren = val4.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (!Object.op_Implicit((Object)(object)componentInChildren))
		{
			throw new InvalidOperationException("CHEF display model unavailable");
		}
		displayModelPrefab = ((Component)componentInChildren).gameObject;
		PrepareTemplate(modelPrefab);
		PrepareTemplate(displayModelPrefab);
		ModelSkinController val5 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
		Material val6 = new Material(nativeMaterial)
		{
			name = "mat" + SkinId
		};
		val6.SetTexture("_MainTex", (Texture)(object)albedo);
		val6.SetColor("_Color", Color.white);
		if (val6.HasProperty("_Cull"))
		{
			val6.SetInt("_Cull", 0);
		}
		val6.SetTexture("_NormalTex", (Texture)(object)normal);
		val6.SetFloat("_NormalStrength", 0.7f);
		val6.SetFloat("_Smoothness", 0.16f);
		val6.SetFloat("_SpecularStrength", 0.15f);
		val6.SetFloat("_SpecularExponent", 8f);
		val6.SetFloat("_EmPower", 0f);
		val6.SetTexture("_EmTex", (Texture)(object)Texture2D.blackTexture);
		val6.DisableKeyword("FLOWMAP");
		val6.SetFloat("_FlowmapOn", 0f);
		val6.SetFloat("_FlowEmissionStrength", 0f);
		val6.DisableKeyword("FORCE_SPEC");
		val6.SetFloat("_ForceSpecOn", 0f);
		val6.DisableKeyword("LIMBREMOVAL");
		val6.SetFloat("_LimbRemovalOn", 0f);
		AdvancedSkinRegistry.Register(new AdvancedSkinDefinition
		{
			Mesh = mesh,
			Motion = bank,
			FallbackClip = "idle",
			AirTransitionSeconds = 0f,
			CreateEffects = (SkinnedMeshRenderer renderer) => (ISkinEffectDriver)(object)new ChefEffects(renderer),
			CreateMotionSource = (Animator animator, MotionBank motion) => (ISkinMotionSource)(object)new ChefMotion(animator, motion)
		});
		Mesh empty = new Mesh
		{
			name = SkinId + "EmptyNativeVisuals"
		};
		empty.vertices = Array.Empty<Vector3>();
		empty.triangles = Array.Empty<int>();
		GameObject[] array = (GameObject[])(object)new GameObject[2] { modelPrefab, displayModelPrefab };
		foreach (GameObject model in array)
		{
			model.AddComponent<ChefNativeVisuals>().Configure(Exact(model, "meshChef"), mesh, empty, (from n in RendererNames.Skip(1)
				select Exact(model, n)).ToArray(), (from n in RendererNames.Skip(1)
				select fallbackMeshes[n]).ToArray());
		}
		info.defaultMaterial = val6;
		info.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val7 = ScriptableObject.CreateInstance<SkinDefParams>();
		val7.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { info };
		val7.meshReplacements = ((IEnumerable<string>)RendererNames).Select((Func<string, MeshReplacement>)((string n) => new MeshReplacement
		{
			renderer = (Renderer)(object)Exact(modelPrefab, n),
			mesh = ((n == "meshChef") ? mesh : empty),
			meshAddress = new AssetReferenceT<Mesh>("")
		})).ToArray();
		SkinDef val8 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val8).name = SkinId;
		val8.nameToken = SkinId.ToUpperInvariant() + "_NAME";
		LanguageAPI.Add(val8.nameToken, manifest.displayName);
		val8.unlockableDef = null;
		val8.rootObject = modelPrefab;
		val8.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val8.skinDefParams = val7;
		val8.icon = Sprite.Create(portrait, new Rect(0f, 0f, (float)((Texture)portrait).width, (float)((Texture)portrait).height), new Vector2(0.5f, 0.5f));
		registrations.Add(AdvancedSkinApplications.Register(val8, mesh));
		val5.skins = (SkinDef[])(controller.skins = controller.skins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { val8 }).ToArray()).Clone();
		registered = true;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("CHEF_PACK_REGISTERED skin=" + SkinId + " revision=" + manifest.revision + " customBones=" + bank.Bones.Length + " unlocked=true audio=not_integrated items=uncalibrated gameplay=untested skills=authored_motion_native_effects_playtest"));
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			if (!Object.op_Implicit((Object)(object)displayModelPrefab))
			{
				throw new InvalidOperationException("Prepared character display was destroyed");
			}
			PrepareTemplate(displayModelPrefab);
			ModelSkinController component = displayModelPrefab.GetComponent<ModelSkinController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Prepared character display controller was removed");
			}
			component.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("CHEF_PACK_DISPLAY_FAILED " + ex));
		}
	}

	private void OnDestroy()
	{
		ChefNativeEvents.Uninstall();
		RoR2Application.onLoad = (Action)Delegate.Remove(RoR2Application.onLoad, new Action(SyncDisplaySkins));
		MainMenuController.OnMainMenuInitialised -= SyncDisplaySkins;
		foreach (IDisposable registration in registrations)
		{
			registration.Dispose();
		}
		registrations.Clear();
		if ((Object)(object)instance == (Object)(object)this)
		{
			instance = null;
		}
	}
}
internal static class ChefActor
{
	internal static CharacterBody Resolve(Component member)
	{
		if (!Object.op_Implicit((Object)(object)member))
		{
			return null;
		}
		CharacterModel componentInParent = member.GetComponentInParent<CharacterModel>();
		if (Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)componentInParent.body) && Object.op_Implicit((Object)(object)componentInParent.body.modelLocator) && (Object)(object)componentInParent.body.modelLocator.modelTransform == (Object)(object)((Component)componentInParent).transform)
		{
			return componentInParent.body;
		}
		AdvancedSkinModel componentInParent2 = member.GetComponentInParent<AdvancedSkinModel>();
		if (!Object.op_Implicit((Object)(object)componentInParent2))
		{
			return null;
		}
		return componentInParent2.AssociatedBody;
	}

	internal static bool Boosted(CharacterBody body)
	{
		if (Object.op_Implicit((Object)(object)body))
		{
			if ((!Object.op_Implicit((Object)(object)Buffs.Boosted) || !body.HasBuff(Buffs.Boosted)) && (!Object.op_Implicit((Object)(object)Buffs.boostedFireEffect) || !body.HasBuff(Buffs.boostedFireEffect)))
			{
				if (Object.op_Implicit((Object)(object)Buffs.boostedFrostEffect))
				{
					return body.HasBuff(Buffs.boostedFrostEffect);
				}
				return false;
			}
			return true;
		}
		return false;
	}
}
public sealed class ChefMotion : ISkinMotionSource, IDisposable
{
	private sealed class Route
	{
		public string Clip;

		public string Group;

		public int Priority;

		public int[] Mask;

		public Route(string c, string g, int p, int[] m = null)
		{
			Clip = c;
			Group = g;
			Priority = p;
			Mask = m;
		}
	}

	private readonly Animator animator;

	private readonly MotionBank bank;

	private readonly Dictionary<string, MotionClip> clips;

	private readonly Dictionary<int, LayerMotionClock> clocks = new Dictionary<int, LayerMotionClock>();

	private readonly List<AnimatorClipInfo> infos = new List<AnimatorClipInfo>();

	private readonly int[] upper;

	private readonly int[] right;

	private readonly int[] left;

	private readonly int[] eyes;

	private readonly ObservedMotionChannel gaitChannel = new ObservedMotionChannel();

	private readonly HashSet<string> floatParameters;

	private double idlePhase;

	private double walkPhase;

	private double deathAt = -1.0;

	private float movement;

	private bool disposed;

	private readonly ChefActionTimeline actionTimeline = new ChefActionTimeline();

	private EntityState sustained;

	private EntityState suppressedState;

	private string sustainedKind;

	private float sustainedStart;

	private CharacterBody trackedBody;

	private EntityStateMachine[] machines = Array.Empty<EntityStateMachine>();

	private readonly HashSet<string> canceledGroups = new HashSet<string>();

	private readonly Dictionary<string, Route> routes = new Dictionary<string, Route>();

	private CharacterBody BindBody()
	{
		CharacterBody val = ChefActor.Resolve((Component)(object)animator);
		if ((Object)(object)val != (Object)(object)trackedBody)
		{
			trackedBody = val;
			machines = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponents<EntityStateMachine>() : Array.Empty<EntityStateMachine>());
			actionTimeline.Clear();
			sustained = null;
			suppressedState = null;
			canceledGroups.Clear();
		}
		return val;
	}

	private EntityState ActiveSecondary()
	{
		return (from m in machines
			where Object.op_Implicit((Object)(object)m) && m.state != null
			select m.state).FirstOrDefault((Func<EntityState, bool>)((EntityState s) => s is Sear || s is IceBox));
	}

	private void OnNativeAction(ChefNativeEvents.Signal signal)
	{
		if (disposed || !Object.op_Implicit((Object)(object)animator) || signal.State == null)
		{
			return;
		}
		CharacterBody val = BindBody();
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)signal.State.outer) || (Object)(object)((Component)signal.State.outer).GetComponent<CharacterBody>() != (Object)(object)val)
		{
			return;
		}
		string kind = signal.Kind;
		double now = Time.time;
		string item = ((kind.StartsWith("fire") || kind.StartsWith("ice")) ? "secondary" : (kind.StartsWith("glaze") ? "glaze" : ((kind == "throw") ? "primary" : "transformation")));
		canceledGroups.Remove(item);
		switch (kind)
		{
		case "fire-start":
		case "ice-start":
			actionTimeline.Remove("secondary");
			suppressedState = null;
			sustained = signal.State;
			sustainedKind = ((kind == "fire-start") ? "sear" : "icebox");
			sustainedStart = Time.time;
			break;
		case "fire-end":
		case "ice-end":
			if (sustained == signal.State)
			{
				sustained = null;
				sustainedKind = null;
			}
			if (ChefActionTimeline.PlayExit(kind, signal.Boosted, signal.Duration))
			{
				actionTimeline.Trigger("secondary", (kind == "fire-end") ? "sear_end" : "icebox_end", now, signal.Duration);
			}
			break;
		case "throw":
			actionTimeline.Trigger("primary", signal.Boosted ? "throw_boost" : "throw", now, signal.Duration);
			break;
		case "fire-burst":
			actionTimeline.Trigger("secondary", "sear_burst", now, signal.Duration);
			break;
		case "ice-burst":
			actionTimeline.Trigger("secondary", "icebox_burst", now, signal.Duration);
			break;
		case "glaze":
			actionTimeline.Trigger("glaze", "glaze_prep", now, signal.Duration);
			break;
		case "glaze-shot":
			actionTimeline.Trigger("glaze", "glaze", now, signal.Duration, 0.18);
			break;
		case "yes-chef":
			actionTimeline.Trigger("transformation", "yes_chef", now, signal.Duration);
			break;
		}
	}

	private void CollectNativeActions(List<NativeMotionCandidate> observed)
	{
		EntityState val = ActiveSecondary();
		if (observed.Any((NativeMotionCandidate c) => c.Motion.Group == "roll" && c.Motion.Samples.Any((WeightedMotion x) => x.Weight > 0f)))
		{
			actionTimeline.Clear();
			suppressedState = val;
			sustained = null;
			string[] array = new string[4] { "primary", "secondary", "glaze", "transformation" };
			foreach (string item in array)
			{
				canceledGroups.Add(item);
			}
			return;
		}
		if (val != null && val != suppressedState && val != sustained)
		{
			actionTimeline.Remove("secondary");
			sustained = val;
			sustainedKind = ((val is IceBox) ? "icebox" : "sear");
			sustainedStart = Time.time - ChefNativeEvents.Number(val, (val is IceBox) ? "fixedAge" : "stopwatch", 0f);
			canceledGroups.Remove("secondary");
		}
		else if (val == null)
		{
			sustained = null;
		}
		if (sustained != null)
		{
			float num2 = Mathf.Max(0.01f, ChefNativeEvents.Number(sustained, "entryDuration", 0.3f));
			float num3 = ((sustainedKind == "sear") ? ChefNativeEvents.Number(sustained, "stopwatch", Time.time - sustainedStart) : (Time.time - sustainedStart));
			double num4;
			string id;
			if (sustainedKind == "sear")
			{
				num4 = ChefActionTimeline.FirePhase(num3, num2, ChefNativeEvents.Number(sustained, "flamethrowerDuration", 1f), ChefNativeEvents.Number(sustained, "exitDuration", 0.3f), ChefNativeEvents.Flag(sustained, "flamethrowerStarted"), ChefNativeEvents.Flag(sustained, "flamethrowerEnded"), ChefNativeEvents.Flag(sustained, "hasBoost") && !ChefNativeEvents.Flag(sustained, "allBoostProjectilesFired"), out id);
				if (id == "sear_loop")
				{
					num4 /= (double)clips[id].Duration;
				}
			}
			else
			{
				bool flag = num3 < num2;
				id = "icebox" + (flag ? "_start" : "_loop");
				num4 = (flag ? (num3 / num2) : ((num3 - num2) / clips[id].Duration));
			}
			observed.Add(Candidate(id, "secondary", 30, -60000, Math.Max(0.0, num4), 1f, upper, "sustained:" + sustainedStart, 1500));
		}
		foreach (ChefActionTimeline.Sample item2 in actionTimeline.Samples(Time.time))
		{
			int num5 = ((item2.Group == "primary") ? 20 : ((item2.Group == "glaze") ? 25 : ((item2.Group == "transformation") ? 60 : 30)));
			int[] mask = ((item2.Group == "primary") ? ((item2.Clip == "throw_boost") ? upper : right) : ((item2.Group == "glaze") ? left : upper));
			observed.Add(Candidate(item2.Clip, item2.Group, num5, -61000 - num5, item2.Phase, item2.Weight, mask, item2.Token, 2000));
		}
	}

	private int[] Mask(Func<string, bool> predicate)
	{
		return (from x in bank.Bones.Select((Bone b, int i) => new { b.Name, i })
			where predicate(x.Name)
			select x.i).ToArray();
	}

	private void Map(string native, string clip, string group, int priority, int[] mask = null)
	{
		routes.Add(native, new Route(clip, group, priority, mask));
	}

	public ChefMotion(Animator animator, MotionBank bank)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		this.animator = animator;
		this.bank = bank;
		clips = bank.Clips.ToDictionary((MotionClip c) => c.Id);
		floatParameters = new HashSet<string>(from p in animator.parameters
			where (int)p.type == 1
			select p.name);
		upper = Mask(delegate(string n)
		{
			switch (n)
			{
			default:
				if (!n.StartsWith("Arm_") && !n.StartsWith("Forearm_") && !n.StartsWith("Tool_") && !n.StartsWith("Wing_"))
				{
					return n.StartsWith("Tail_");
				}
				break;
			case "Body":
			case "Head":
			case "Jaw":
				break;
			}
			return true;
		});
		right = Mask(delegate(string n)
		{
			switch (n)
			{
			default:
				return n.StartsWith("Tail_");
			case "Body":
			case "Head":
			case "Arm_R":
			case "Forearm_R":
			case "Tool_R":
				return true;
			}
		});
		left = Mask(delegate(string n)
		{
			switch (n)
			{
			default:
				return n.StartsWith("Tail_");
			case "Body":
			case "Head":
			case "Arm_L":
			case "Forearm_L":
			case "Tool_L":
				return true;
			}
		});
		eyes = Mask((string n) => n == "Head" || n.StartsWith("Wing_"));
		Map("Chef_SliceAndDice", "throw", "primary", 20, right);
		Map("PrimaryDice1_Return_Start", "recall", "primary", 20, right);
		Map("PrimaryDice1_Return_Hold", "cleaver_hold", "primary", 20, right);
		Map("PrimaryDice1_Return_Catch", "catch", "primary", 20, right);
		Map("PrimaryDice1_Return_All", "catch", "primary", 20, right);
		Map("root|PrimaryDice1_Oops", "flinch", "primary", 20, right);
		Map("ChefGlazeStart", "glaze_prep", "glaze", 25, left);
		Map("Chef_Glaze3Shots", "glaze_boost", "glaze", 25, left);
		Map("Glaze_Glaze3Shot_Exit", "glaze_end", "glaze", 25, left);
		Map("SearBlaze_Prep", "sear_start", "secondary", 30, upper);
		Map("SearBlaze_Loop", "sear_loop", "secondary", 30, upper);
		Map("SearBlaze_Exit", "sear_end", "secondary", 30, upper);
		Map("YesChef", "yes_chef", "transformation", 60, upper);
		string[][] array = new string[3][]
		{
			new string[2] { "Chef_JumpStartTweaked", "jump_start" },
			new string[2] { "Chef_JumpUp", "jump_up" },
			new string[2] { "Chef_JumpDown", "fall" }
		};
		foreach (string[] array2 in array)
		{
			Map(array2[0], array2[1], "airborne", 10);
		}
		array = new string[10][]
		{
			new string[2] { "Rolypoly_Enter", "roll_enter" },
			new string[2] { "Rolypoly_ChargeLoop", "roll_charge" },
			new string[2] { "Chef_RolyPolyStart", "roll_enter" },
			new string[2] { "Chef_RolyPoly", "roll_loop" },
			new string[2] { "ExitRolyPoly", "roll_exit" },
			new string[2] { "Boosted_Rolypoly_Start", "roll_enter" },
			new string[2] { "Boosted_Rolypoly_Loop", "roll_boost" },
			new string[2] { "Chef_RolyPoly_JumpStart", "roll_enter" },
			new string[2] { "Chef_RolyPoly_JumpUp", "roll_charge" },
			new string[2] { "Chef_RolyPoly_JumpDown", "roll_charge" }
		};
		foreach (string[] array3 in array)
		{
			Map(array3[0], array3[1], "roll", 40);
		}
		Map("Chef_JumpLand", "land", "landing", 11);
		Map("Chef_RolyPoly_JumpLand", "roll_exit", "roll-landing", 41);
		string[] array4 = new string[2] { ",Additive", ",Override" };
		foreach (string text in array4)
		{
			Map("OilSpillJump" + text, "oil_jump", "oil", 45);
			Map("OilSpillLoop" + text, "oil_loop", "oil", 45);
			Map("OilSpillLand" + text, "oil_land", "oil", 45);
		}
		Map("Chef_Flinch1", "flinch", "flinch", 70, upper);
		Map("Chef_Flinch2", "flinch", "flinch", 70, upper);
		Map("LobbyIntro", "lobby_intro", "display", 10);
		array4 = new string[3] { "Chef_LobbyIdle", "Chef_LobbyIdleAlternate", "Chef_LobbyIdleAlternate2" };
		foreach (string native in array4)
		{
			Map(native, "lobby_idle", "display", 10);
		}
		foreach (Route value in routes.Values)
		{
			if (!clips.ContainsKey(value.Clip))
			{
				throw new InvalidOperationException("Missing CHEF action " + value.Clip);
			}
			if (value.Mask != null && value.Mask.Length == 0)
			{
				throw new InvalidOperationException("Empty CHEF action mask");
			}
		}
		array4 = new string[16]
		{
			"idle", "scuttle", "sprint", "backpedal", "strafe_left", "strafe_right", "death", "throw_boost", "empowered", "aim_yaw",
			"aim_pitch", "icebox_start", "icebox_loop", "icebox_end", "sear_burst", "icebox_burst"
		};
		foreach (string text2 in array4)
		{
			if (!clips.ContainsKey(text2))
			{
				throw new InvalidOperationException("Missing CHEF motion " + text2);
			}
		}
		ChefNativeEvents.Observed += OnNativeAction;
	}

	private NativeMotionCandidate Candidate(string id, string group, int priority, int layer, double time, float weight, int[] mask = null, string token = null, int rank = 1000)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		//IL_002d: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: 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_008b: Expected O, but got Unknown
		NativeMotionCandidate val = new NativeMotionCandidate();
		val.SourceLayer = layer;
		val.SourceRank = rank;
		MotionLayer val2 = new MotionLayer();
		val2.Group = group;
		val2.Priority = priority;
		val2.Blend = (MotionBlend)0;
		val2.BoneMask = mask;
		val2.Samples = (WeightedMotion[])(object)new WeightedMotion[1]
		{
			new WeightedMotion
			{
				Clip = clips[id],
				Time = Math.Max(0.0, time),
				Weight = Mathf.Clamp01(weight),
				Token = (token ?? group)
			}
		};
		val.Motion = val2;
		return val;
	}

	private void Collect(int layer, AnimatorStateInfo state, MotionOccurrence occurrence, float transition, List<NativeMotionCandidate> result, bool boosted)
	{
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		string layerName = animator.GetLayerName(layer);
		float num = ((layer == 0) ? 1f : Mathf.Clamp01(animator.GetLayerWeight(layer)));
		float num2 = infos.Sum((AnimatorClipInfo x) => Mathf.Max(0f, ((AnimatorClipInfo)(ref x)).weight));
		if (num <= 0f)
		{
			return;
		}
		string text = ((((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireDice")) ? "throw" : ((((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireSliceAndDice")) ? "throw_boost" : null));
		if (text != null)
		{
			if (!canceledGroups.Contains("primary"))
			{
				result.Add(Candidate(text, "primary", 20, -1000 - layer, ((AnimatorStateInfo)(ref state)).normalizedTime, transition * num, (text == "throw_boost") ? upper : right, layer + ":" + occurrence.Serial + ":" + text, layerName.Contains("Override") ? 30 : 20));
			}
		}
		else
		{
			if (num2 <= 1E-06f)
			{
				return;
			}
			foreach (AnimatorClipInfo info in infos)
			{
				AnimatorClipInfo current = info;
				if (Object.op_Implicit((Object)(object)((AnimatorClipInfo)(ref current)).clip) && routes.TryGetValue(((Object)((AnimatorClipInfo)(ref current)).clip).name, out var value) && !canceledGroups.Contains(value.Group))
				{
					string text2 = value.Clip;
					if (((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireDice"))
					{
						text2 = "throw";
						value = new Route(text2, "primary", 20, right);
					}
					else if (((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireSliceAndDice"))
					{
						text2 = "throw_boost";
						value = new Route(text2, "primary", 20, right);
					}
					int rank = (layerName.Contains("Override") ? 30 : (layerName.Contains("Additive") ? 20 : 10));
					int layer2 = -1000 - layer;
					result.Add(Candidate(text2, value.Group, value.Priority, layer2, ((AnimatorStateInfo)(ref state)).normalizedTime, ((AnimatorClipInfo)(ref current)).weight / num2 * transition * num, value.Mask, layer + ":" + occurrence.Serial + ":" + text2, rank));
				}
			}
		}
	}

	public void Observe(List<NativeMotionCandidate> candidates, HashSet<string> replaced)
	{
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f4: 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_0304: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		//IL_031f: Expected O, but got Unknown
		//IL_0324: Expected O, but got Unknown
		//IL_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_035a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0372: Unknown result type (might be due to invalid IL or missing references)
		//IL_0377: Unknown result type (might be due to invalid IL or missing references)
		//IL_0391: Unknown result type (might be due to invalid IL or missing references)
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0385: Unknown result type (might be due to invalid IL or missing references)
		//IL_0396: Unknown result type (might be due to invalid IL or missing references)
		//IL_040c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b9: Expected O, but got Unknown
		//IL_03be: Expected O, but got Unknown
		//IL_053f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0544: Unknown result type (might be due to invalid IL or missing references)
		//IL_044a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0588: Unknown result type (might be due to invalid IL or missing references)
		//IL_058d: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_0638: Unknown result type (might be due to invalid IL or missing references)
		if (disposed || !Object.op_Implicit((Object)(object)animator))
		{
			return;
		}
		MotionBinding[] bindings = bank.Bindings;
		foreach (MotionBinding val in bindings)
		{
			replaced.Add(val.Clip);
		}
		CharacterBody val2 = BindBody();
		bool num = Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.healthComponent) && !val2.healthComponent.alive;
		bool flag = ChefActor.Boosted(val2);
		float num2 = Mathf.Min(Time.deltaTime, 0.1f);
		idlePhase += num2 / clips["idle"].Duration;
		if (num)
		{
			actionTimeline.Clear();
			sustained = null;
			if (deathAt < 0.0)
			{
				deathAt = Time.time;
			}
			candidates.Add(Candidate("death", "death", 1000, -90000, ((double)Time.time - deathAt) / (double)clips["death"].Duration, 1f));
			return;
		}
		deathAt = -1.0;
		Vector3 val3 = Vector3.zero;
		if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.characterMotor) && val2.characterMotor.isGrounded)
		{
			val3 = val2.characterMotor.velocity;
			val3.y = 0f;
			val3 = ((Component)animator).transform.InverseTransformDirection(val3);
		}
		float magnitude = ((Vector3)(ref val3)).magnitude;
		movement = Mathf.MoveTowards(movement, (float)((magnitude > 0.15f) ? 1 : 0), num2 * 6f);
		walkPhase += num2 * Mathf.Min(magnitude / 0.65f, 3.5f);
		string text = ((!(Mathf.Abs(val3.x) > Mathf.Abs(val3.z))) ? ((val3.z < -0.1f) ? "backpedal" : ((Object.op_Implicit((Object)(object)val2) && val2.isSprinting) ? "sprint" : "scuttle")) : ((val3.x < 0f) ? "strafe_left" : "strafe_right"));
		candidates.Add(Candidate("idle", "base-idle", 1, -1, idlePhase, 1f - movement));
		WeightedMotion[] array = gaitChannel.Sample(clips[text], text, walkPhase, (double)Time.time, 0.12f, (string)null, 0, false);
		WeightedMotion[] array2 = array;
		foreach (WeightedMotion obj in array2)
		{
			obj.Weight *= movement;
		}
		candidates.Add(new NativeMotionCandidate
		{
			SourceLayer = -1,
			SourceRank = 1000,
			Motion = new MotionLayer
			{
				Group = "base-gait",
				Priority = 1,
				Blend = (MotionBlend)0,
				Samples = array
			}
		});
		List<NativeMotionCandidate> list = new List<NativeMotionCandidate>();
		AnimatorTransitionInfo animatorTransitionInfo;
		AnimatorStateInfo val4;
		for (int j = 0; j < animator.layerCount; j++)
		{
			bool flag2 = animator.IsInTransition(j);
			float num3;
			if (!flag2)
			{
				num3 = 0f;
			}
			else
			{
				animatorTransitionInfo = animator.GetAnimatorTransitionInfo(j);
				num3 = Mathf.Clamp01(((AnimatorTransitionInfo)(ref animatorTransitionInfo)).normalizedTime);
			}
			float num4 = num3;
			AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(j);
			AnimatorStateInfo val5;
			if (!flag2)
			{
				val4 = default(AnimatorStateInfo);
				val5 = val4;
			}
			else
			{
				val5 = animator.GetNextAnimatorStateInfo(j);
			}
			AnimatorStateInfo state = val5;
			if (!clocks.TryGetValue(j, out var value))
			{
				Dictionary<int, LayerMotionClock> dictionary = clocks;
				int key = j;
				LayerMotionClock val6 = new LayerMotionClock();
				value = val6;
				dictionary[key] = val6;
			}
			value.Observe(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, (double)((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime, flag2, ((AnimatorStateInfo)(ref state)).fullPathHash, (double)((AnimatorStateInfo)(ref state)).normalizedTime, (double)Time.time);
			infos.Clear();
			animator.GetCurrentAnimatorClipInfo(j, infos);
			Collect(j, currentAnimatorStateInfo, value.Current, 1f - num4, list, flag);
			if (flag2)
			{
				infos.Clear();
				animator.GetNextAnimatorClipInfo(j, infos);
				Collect(j, state, value.Next, num4, list, flag);
			}
		}
		CollectNativeActions(list);
		ChefActionTimeline.FilterCanceled(list, canceledGroups);
		candidates.AddRange(NativeMotionComposition.ResolveSources((IEnumerable<NativeMotionCandidate>)list));
		string[][] array3 = new string[2][]
		{
			new string[3] { "AimYaw", "aimYawCycle", "aim_yaw" },
			new string[3] { "AimPitch", "aimPitchCycle", "aim_pitch" }
		};
		foreach (string[] array4 in array3)
		{
			int layerIndex = animator.GetLayerIndex(array4[0]);
			if (layerIndex < 0 || !floatParameters.Contains(array4[1]))
			{
				continue;
			}
			bool flag3 = animator.IsInTransition(layerIndex);
			float num5;
			if (!flag3)
			{
				num5 = 0f;
			}
			else
			{
				animatorTransitionInfo = animator.GetAnimatorTransitionInfo(layerIndex);
				num5 = Mathf.Clamp01(((AnimatorTransitionInfo)(ref animatorTransitionInfo)).normalizedTime);
			}
			float num6 = num5;
			int num7 = Animator.StringToHash(array4[0] + ((array4[0] == "AimYaw") ? ".YawControl" : ".PitchControl"));
			val4 = animator.GetCurrentAnimatorStateInfo(layerIndex);
			float num8 = ((((AnimatorStateInfo)(ref val4)).fullPathHash == num7) ? (1f - num6) : 0f);
			float num9;
			if (flag3)
			{
				val4 = animator.GetNextAnimatorStateInfo(layerIndex);
				if (((AnimatorStateInfo)(ref val4)).fullPathHash == num7)
				{
					num9 = num6;
					goto IL_05d0;
				}
			}
			num9 = 0f;
			goto IL_05d0;
			IL_05d0:
			float num10 = num8 + num9;
			float num11 = Mathf.Clamp01(animator.GetLayerWeight(layerIndex)) * num10;
			if (!(num11 <= 0f))
			{
				NativeMotionCandidate val7 = Candidate(array4[2], array4[0], 80, -70000 - layerIndex, Mathf.Clamp01(animator.GetFloat(array4[1])), num11, upper);
				val7.Motion.Blend = (MotionBlend)1;
				candidates.Add(val7);
			}
		}
		if (flag)
		{
			candidates.Add(Candidate("empowered", "boost-eyes", 5, -80000, Time.time / clips["empowered"].Duration, 1f, eyes));
		}
	}

	public void Dispose()
	{
		disposed = true;
		ChefNativeEvents.Observed -= OnNativeAction;
		actionTimeline.Clear();
		sustained = null;
		trackedBody = null;
		machines = Array.Empty<EntityStateMachine>();
		canceledGroups.Clear();
		clocks.Clear();
		infos.Clear();
	}
}
public sealed class ChefEffects : ISkinEffectDriver, IDisposable
{
	private readonly SkinnedMeshRenderer renderer;

	private Transform tool;

	private Vector3 visibleScale;

	private bool masked;

	private bool disposed;

	private readonly Material original;

	private readonly Material accent;

	private readonly Color originalColor;

	private float boostBlend;

	public ChefEffects(SkinnedMeshRenderer renderer)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected O, but got Unknown
		//IL_0072: 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_0077: Unknown result type (might be due to invalid IL or missing references)
		this.renderer = renderer;
		original = ((Renderer)renderer).sharedMaterial;
		if (!Object.op_Implicit((Object)(object)original))
		{
			throw new InvalidOperationException("Chef material unavailable");
		}
		accent = new Material(original)
		{
			name = "ChefActorAccent"
		};
		originalColor = (original.HasProperty("_Color") ? original.GetColor("_Color") : Color.white);
		((Renderer)renderer).sharedMaterial = accent;
	}

	public void Update()
	{
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		if (disposed || !Object.op_Implicit((Object)(object)renderer))
		{
			return;
		}
		if (!Object.op_Implicit((Object)(object)tool))
		{
			tool = ((IEnumerable<Transform>)renderer.bones).FirstOrDefault((Func<Transform, bool>)((Transform b) => Object.op_Implicit((Object)(object)b) && ((Object)b).name == "Tool_R"));
		}
		CharacterBody val = ChefActor.Resolve((Component)(object)renderer);
		ChefController val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<ChefController>() : null);
		if (Object.op_Implicit((Object)(object)tool))
		{
			visibleScale = tool.localScale;
			masked = false;
			if (Object.op_Implicit((Object)(object)val2) && val2.cleaversAway)
			{
				tool.localScale = Vector3.zero;
				masked = true;
			}
		}
		bool flag = ChefActor.Boosted(val) && (!Object.op_Implicit((Object)(object)val.healthComponent) || val.healthComponent.alive);
		boostBlend = Mathf.MoveTowards(boostBlend, (float)(flag ? 1 : 0), Time.deltaTime * 5f);
		if (Object.op_Implicit((Object)(object)accent) && (Object)(object)((Renderer)renderer).sharedMaterial == (Object)(object)accent)
		{
			bool flag2 = Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)Buffs.boostedFrostEffect) && val.HasBuff(Buffs.boostedFrostEffect);
			accent.SetColor("_Color", Color.Lerp(originalColor, flag2 ? new Color(0.7f, 0.92f, 1f) : new Color(1f, 0.83f, 0.6f), boostBlend * 0.65f));
		}
	}

	public void Dispose()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		if (!disposed)
		{
			disposed = true;
			if (masked && Object.op_Implicit((Object)(object)tool))
			{
				tool.localScale = visibleScale;
			}
			if (Object.op_Implicit((Object)(object)renderer) && (Object)(object)((Renderer)renderer).sharedMaterial == (Object)(object)accent)
			{
				((Renderer)renderer).sharedMaterial = original;
			}
			if (Object.op_Implicit((Object)(object)accent))
			{
				Object.Destroy((Object)(object)accent);
			}
			masked = false;
		}
	}
}
[DefaultExecutionOrder(32001)]
public sealed class ChefNativeVisuals : MonoBehaviour
{
	[SerializeField]
	private SkinnedMeshRenderer target;

	[SerializeField]
	private Mesh custom;

	[SerializeField]
	private Mesh empty;

	[SerializeField]
	private SkinnedMeshRenderer[] companions;

	[SerializeField]
	private Mesh[] originals;

	public void Configure(SkinnedMeshRenderer target, Mesh custom, Mesh empty, SkinnedMeshRenderer[] companions, Mesh[] originals)
	{
		this.target = target;
		this.custom = custom;
		this.empty = empty;
		this.companions = companions;
		this.originals = originals;
	}

	private void LateUpdate()
	{
		if (Object.op_Implicit((Object)(object)target) && companions != null && !((Object)(object)target.sharedMesh == (Object)(object)custom))
		{
			Restore();
		}
	}

	private void Restore()
	{
		if (companions == null)
		{
			return;
		}
		for (int i = 0; i < companions.Length; i++)
		{
			if (Object.op_Implicit((Object)(object)companions[i]) && (Object)(object)companions[i].sharedMesh == (Object)(object)empty)
			{
				companions[i].sharedMesh = originals[i];
			}
		}
	}

	private void OnDestroy()
	{
		Restore();
	}
}
internal static class ChefNativeEvents
{
	internal sealed class Signal
	{
		public EntityState State;

		public string Kind;

		public float Duration;

		public bool Boosted;
	}

	private static bool installed;

	private static readonly Dictionary<string, FieldInfo> fields = new Dictionary<string, FieldInfo>();

	private static bool warned;

	internal static event Action<Signal> Observed;

	internal static float Number(EntityState s, string n, float fallback)
	{
		if (!(Read(s, n) is float num) || float.IsNaN(num) || float.IsInfinity(num))
		{
			return fallback;
		}
		return num;
	}

	internal static bool Flag(EntityState s, string n)
	{
		object obj = Read(s, n);
		bool flag = default(bool);
		int num;
		if (obj is bool)
		{
			flag = (bool)obj;
			num = 1;
		}
		else
		{
			num = 0;
		}
		return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
	}

	private static object Read(EntityState s, string n)
	{
		try
		{
			if (s == null)
			{
				return null;
			}
			string key = ((object)s).GetType().FullName + ":" + n;
			if (!fields.TryGetValue(key, out var value))
			{
				value = ((object)s).GetType().GetField(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				fields[key] = value;
			}
			return (value != null) ? value.GetValue(s) : ((object)s).GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(s);
		}
		catch (Exception)
		{
			if (!warned)
			{
				warned = true;
				Debug.LogWarning((object)"CHEF CHEF presentation observation unavailable; native gameplay preserved.");
			}
			return null;
		}
	}

	private static void Emit(EntityState s, string kind, float duration = 0f, bool boost = false)
	{
		Action<Signal> observed = ChefNativeEvents.Observed;
		if (observed == null)
		{
			return;
		}
		Signal obj = new Signal
		{
			State = s,
			Kind = kind,
			Duration = duration,
			Boosted = boost
		};
		Delegate[] invocationList = observed.GetInvocationList();
		for (int i = 0; i < invocationList.Length; i++)
		{
			Action<Signal> action = (Action<Signal>)invocationList[i];
			try
			{
				action(obj);
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
		}
	}

	internal static void Install()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Expected O, but got Unknown
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Expected O, but got Unknown
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Expected O, but got Unknown
		if (!installed)
		{
			installed = true;
			Dice.PlayThrowAnims += new hook_PlayThrowAnims(Throw);
			Sear.OnEnter += new hook_OnEnter(FireEnter);
			Sear.OnExit += new hook_OnExit(FireExit);
			Sear.FireBoostedFireball += new hook_FireBoostedFireball(FireBurst);
			IceBox.OnEnter += new hook_OnEnter(IceEnter);
			IceBox.OnExit += new hook_OnExit(IceExit);
			IceBox.FireBoostedIceCube += new hook_FireBoostedIceCube(IceBurst);
			Glaze.OnEnter += new hook_OnEnter(Glaze);
			Glaze.FireGrenade += new hook_FireGrenade(GlazeShot);
			YesChef.OnEnter += new hook_OnEnter(YesChef);
		}
	}

	internal static void Uninstall()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Expected O, but got Unknown
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Expected O, but got Unknown
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Expected O, but got Unknown
		if (installed)
		{
			installed = false;
			Dice.PlayThrowAnims -= new hook_PlayThrowAnims(Throw);
			Sear.OnEnter -= new hook_OnEnter(FireEnter);
			Sear.OnExit -= new hook_OnExit(FireExit);
			Sear.FireBoostedFireball -= new hook_FireBoostedFireball(FireBurst);
			IceBox.OnEnter -= new hook_OnEnter(IceEnter);
			IceBox.OnExit -= new hook_OnExit(IceExit);
			IceBox.FireBoostedIceCube -= new hook_FireBoostedIceCube(IceBurst);
			Glaze.OnEnter -= new hook_OnEnter(Glaze);
			Glaze.FireGrenade -= new hook_FireGrenade(GlazeShot);
			YesChef.OnEnter -= new hook_OnEnter(YesChef);
			ChefNativeEvents.Observed = null;
			fields.Clear();
		}
	}

	private static void Throw(orig_PlayThrowAnims orig, Dice self, float duration)
	{
		orig.Invoke(self, duration);
		Emit((EntityState)(object)self, "throw", duration, Flag((EntityState)(object)self, "hasBoost"));
	}

	private static void FireEnter(orig_OnEnter orig, Sear self)
	{
		orig.Invoke(self);
		Emit((EntityState)(object)self, "fire-start");
	}

	private static void FireExit(orig_OnExit orig, Sear self)
	{
		bool flag = Flag((EntityState)(object)self, "flamethrowerEnded");
		orig.Invoke(self);
		Emit((EntityState)(object)self, "fire-end", flag ? 0f : Number((EntityState)(object)self, "exitDuration", 0.3f));
	}

	private static void FireBurst(orig_FireBoostedFireball orig, Sear self, string muzzle)
	{
		orig.Invoke(self, muzzle);
		Emit((EntityState)(object)self, "fire-burst", 0.32f);
	}

	private static void IceEnter(orig_OnEnter orig, IceBox self)
	{
		orig.Invoke(self);
		Emit((EntityState)(object)self, "ice-start");
	}

	private static void IceExit(orig_OnExit orig, IceBox self)
	{
		bool boost = Flag((EntityState)(object)self, "hasBoost");
		orig.Invoke(self);
		Emit((EntityState)(object)self, "ice-end", Number((EntityState)(object)self, "exitDuration", 0.3f), boost);
	}

	private static void IceBurst(orig_FireBoostedIceCube orig, IceBox self)
	{
		orig.Invoke(self);
		Emit((EntityState)(object)self, "ice-burst", 0.65f, boost: true);
	}

	private static void Glaze(orig_OnEnter orig, Glaze self)
	{
		orig.Invoke(self);
		Emit((EntityState)(object)self, "glaze", Number((EntityState)(object)self, "duration", 1f));
	}

	private static void GlazeShot(orig_FireGrenade orig, Glaze self, string muzzle)
	{
		orig.Invoke(self, muzzle);
		Emit((EntityState)(object)self, "glaze-shot", 0.3f);
	}

	private static void YesChef(orig_OnEnter orig, YesChef self)
	{
		orig.Invoke(self);
		Emit((EntityState)(object)self, "yes-chef", Number((EntityState)(object)self, "duration", 1f));
	}
}
internal sealed class ChefActionTimeline
{
	internal sealed class Sample
	{
		public string Group;

		public string Clip;

		public string Token;

		public double Phase;

		public float Weight;
	}

	private sealed class Pulse
	{
		public string Clip;

		public double Start;

		public double Duration;

		public double StartPhase;

		public long Serial;
	}

	private readonly Dictionary<string, Pulse> pulses = new Dictionary<string, Pulse>();

	private long serial;

	internal void Trigger(string group, string clip, double now, double duration, double startPhase = 0.0)
	{
		if (!double.IsNaN(now) && !double.IsInfinity(now) && !double.IsNaN(duration) && !double.IsInfinity(duration) && !(duration <= 0.0))
		{
			pulses[group] = new Pulse
			{
				Clip = clip,
				Start = now,
				Duration = Math.Max(0.06, duration),
				StartPhase = Math.Max(0.0, Math.Min(1.0, startPhase)),
				Serial = ++serial
			};
		}
	}

	internal IEnumerable<Sample> Samples(double now)
	{
		List<string> list = new List<string>();
		List<Sample> list2 = new List<Sample>();
		foreach (KeyValuePair<string, Pulse> pulse in pulses)
		{
			Pulse value = pulse.Value;
			double num = now - value.Start;
			if (num < 0.0 || num >= value.Duration)
			{
				list.Add(pulse.Key);
				continue;
			}
			list2.Add(new Sample
			{
				Group = pulse.Key,
				Clip = value.Clip,
				Phase = value.StartPhase + (1.0 - value.StartPhase) * num / value.Duration,
				Weight = (float)Math.Min(1.0, (value.Duration - num) / Math.Min(0.08, value.Duration * 0.2)),
				Token = pulse.Key + ":" + value.Serial
			});
		}
		foreach (string item in list)
		{
			pulses.Remove(item);
		}
		return list2;
	}

	internal static bool PlayExit(string kind, bool boosted, double duration)
	{
		if (duration > 0.0)
		{
			return !(kind == "ice-end" && boosted);
		}
		return false;
	}

	internal static double FirePhase(double elapsed, double entry, double flame, double exit, bool started, bool ended, bool boostWaiting, out string id)
	{
		entry = Math.Max(0.01, entry);
		exit = Math.Max(0.01, exit);
		if (ended)
		{
			id = "sear_end";
			return Math.Max(0.0, (elapsed - entry - flame) / exit);
		}
		if (elapsed < entry || !started || boostWaiting)
		{
			id = "sear_start";
			return Math.Max(0.0, Math.Min(1.0, elapsed / entry));
		}
		id = "sear_loop";
		return Math.Max(0.0, elapsed - entry);
	}

	internal static void FilterCanceled(List<NativeMotionCandidate> observed, HashSet<string> canceled)
	{
		observed.RemoveAll((NativeMotionCandidate c) => canceled.Contains(c.Motion.Group));
	}

	internal void Remove(string group)
	{
		pulses.Remove(group);
	}

	internal void Clear()
	{
		pulses.Clear();
	}
}

BepInEx/plugins/ChefCrabRangoon/Eclipse.Chef.E2.CrabRangoon.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using BepInEx;
using Eclipse.AdvancedSkins;
using EclipseSkinRuntimeFix;
using EntityStates;
using EntityStates.Chef;
using HG.Reflection;
using On.EntityStates.Chef;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: AssemblyVersion("0.0.0.0")]
namespace EclipseSkinRuntimeFix
{
	internal static class NativeRenderers
	{
		private static readonly HashSet<string> NativePaths = new HashSet<string>(StringComparer.Ordinal)
		{
			"mdlLoader/PilotFemaleMesh", "mdlLoader/LoaderMechMesh", "mdlLoader/PilotFemaleFoldedOverJumpsuit", "mdlFalseSon/FalseSon_Body", "mdlFalseSon/FalseSon_Cloth", "mdlFalseSon/L_FalseSon_Weapon", "mdlSeeker/meshSeekerBody", "mdlSeeker/meshSeekerCloth", "mdlSeeker/meshSeekerGlass", "mdlChef/meshChef",
			"mdlChef/meshChefPizzaCutter", "mdlChef/meshlChefCleaver", "mdlChef/meshChefOven", "mdlChef/meshChefIceBox", "mdlCroco/CrocoMesh", "mdlCroco/CrocoSpineMesh", "mdlHuntress/HuntressMesh", "mdlHuntress/BowMesh", "mdlHuntress/HuntressScarfMesh", "mdlHuntress (1)/HuntressMesh",
			"mdlHuntress (1)/BowMesh", "mdlHuntress (1)/HuntressScarfMesh", "mdlMerc/MercMesh", "mdlMerc/MercSwordMesh", "mdlTreebot/TreebotBotMesh", "mdlTreebot/TreebotRootMesh", "mdlTreebot/TreebotLeafletMesh", "mdlTreebot/TreebotFlowerMesh", "mdlVoidSurvivor/mdlVoidSurvivorBody", "mdlVoidSurvivor/mdlVoidSurvivorHead",
			"mdlVoidSurvivor/mdlVoidSurvivorMetal", "mdlVoidSurvivor/metalcollar.001", "mdlBandit2/BanditArmature/ROOT/base/MainWeapon/BanditShotgunMesh", "mdlBandit2/BanditArmature/SideWeapon/SideWeaponSpinner/BanditPistolMesh", "mdlBandit2/Bandit2AccessoriesMesh"
		};

		public static T[] GetSkinRenderers<T>(this Component owner, bool inactive = false, SkinDefParams parameters = null) where T : Renderer
		{
			return owner.gameObject.GetSkinRenderers<T>(inactive, parameters);
		}

		public static T[] GetSkinRenderers<T>(this GameObject owner, bool inactive = false, SkinDefParams parameters = null) where T : Renderer
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: 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)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			T[] componentsInChildren = owner.GetComponentsInChildren<T>(inactive);
			CharacterModel val = owner.GetComponent<CharacterModel>() ?? owner.GetComponentInParent<CharacterModel>();
			ModelSkinController val2 = owner.GetComponent<ModelSkinController>() ?? (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<ModelSkinController>() : null);
			HashSet<Renderer> skinRefs = new HashSet<Renderer>();
			SkinDefParams val3 = parameters;
			if (!Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val2) && val2.skins != null && val2.skins.Length != 0 && Object.op_Implicit((Object)(object)val2.skins[0]))
			{
				val3 = val2.skins[0].skinDefParams;
			}
			if (Object.op_Implicit((Object)(object)val3))
			{
				if (val3.rendererInfos != null)
				{
					RendererInfo[] rendererInfos = val3.rendererInfos;
					foreach (RendererInfo val4 in rendererInfos)
					{
						if (Object.op_Implicit((Object)(object)val4.renderer))
						{
							skinRefs.Add(val4.renderer);
						}
					}
				}
				if (val3.meshReplacements != null)
				{
					MeshReplacement[] meshReplacements = val3.meshReplacements;
					foreach (MeshReplacement val5 in meshReplacements)
					{
						if (Object.op_Implicit((Object)(object)val5.renderer))
						{
							skinRefs.Add(val5.renderer);
						}
					}
				}
			}
			HashSet<Renderer> modelRefs = new HashSet<Renderer>();
			if (Object.op_Implicit((Object)(object)val) && val.baseRendererInfos != null)
			{
				RendererInfo[] rendererInfos = val.baseRendererInfos;
				foreach (RendererInfo val6 in rendererInfos)
				{
					if (Object.op_Implicit((Object)(object)val6.renderer))
					{
						modelRefs.Add(val6.renderer);
					}
				}
			}
			return Select(componentsInChildren, (T x) => ((Object)(object)x).name, (T x) => skinRefs.Contains((Renderer)(object)x), (T x) => modelRefs.Contains((Renderer)(object)x), (T x) => Path(((Component)(object)x).transform, owner.transform), (T x) => IsKnownNativePath(Path(((Component)(object)x).transform, owner.transform)));
		}

		internal static T[] Select<T>(T[] found, Func<T, string> name, Func<T, bool> skin, Func<T, bool> model, Func<T, string> path, Func<T, bool> contract = null)
		{
			HashSet<T> hashSet = new HashSet<T>();
			if (contract == null)
			{
				contract = (T x) => false;
			}
			bool flag = found.Any(skin) || found.Any(model) || found.Any(contract);
			foreach (IGrouping<string, T> item in found.GroupBy(name))
			{
				T[] array = item.ToArray();
				if (array.Length == 1)
				{
					if (!flag || skin(array[0]) || model(array[0]) || contract(array[0]))
					{
						hashSet.Add(array[0]);
					}
					continue;
				}
				T[] array2 = array.Where(skin).ToArray();
				T[] array3 = array.Where(model).ToArray();
				T[] array4 = ((array2.Length == 1) ? ((array3.Length == 0 || array3.Contains(array2[0])) ? array2 : new T[0]) : ((array2.Length <= 1) ? array3 : array2.Where(((IEnumerable<T>)array3).Contains<T>).ToArray()));
				if (array2.Length == 0 && array3.Length == 0)
				{
					T[] array5 = array.Where(contract).ToArray();
					if (array5.Length != 0)
					{
						if (array5.Length != 1)
						{
							throw new InvalidOperationException("ECLIPSE_RENDERER_PATH_AMBIGUOUS " + string.Join(";", array.Select(path)));
						}
						hashSet.Add(array5[0]);
						Debug.Log((object)("ECLIPSE_RENDERER_NATIVE_PATH name=" + item.Key + " native=" + path(array5[0])));
						continue;
					}
				}
				if (array2.Length == 0 && array3.Length == 0 && flag)
				{
					Debug.Log((object)("ECLIPSE_RENDERER_FOREIGN_DUPLICATES name=" + item.Key + " ignored=" + array.Length));
					continue;
				}
				if (array4.Length != 1)
				{
					throw new InvalidOperationException("ECLIPSE_RENDERER_AMBIGUOUS name=" + item.Key + " candidates=" + string.Join(";", array.Select(path)) + " skinRefs=" + array2.Length + " modelRefs=" + array3.Length);
				}
				hashSet.Add(array4[0]);
				Debug.Log((object)("ECLIPSE_RENDERER_RESOLVED name=" + item.Key + " native=" + path(array4[0]) + " ignoredDuplicates=" + (array.Length - 1)));
			}
			return found.Where(hashSet.Contains).ToArray();
		}

		internal static bool IsKnownNativePath(string path)
		{
			if (path == null)
			{
				return false;
			}
			int num = path.IndexOf('/');
			if (num < 0)
			{
				return false;
			}
			string text = path.Substring(0, num);
			if (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - 7);
			}
			return NativePaths.Contains(text + path.Substring(num));
		}

		private static string Path(Transform t, Transform root)
		{
			List<string> list = new List<string>();
			Transform val = t;
			while (Object.op_Implicit((Object)(object)val))
			{
				list.Add(((Object)val).name);
				if ((Object)(object)val == (Object)(object)root)
				{
					break;
				}
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}
	}
}
namespace EclipsePlaytestChefE2
{
	internal sealed class CrabActionTimeline
	{
		internal sealed class Sample
		{
			public string Group;

			public string Clip;

			public string Token;

			public double Phase;

			public float Weight;
		}

		private sealed class Pulse
		{
			public string Clip;

			public double Start;

			public double Duration;

			public double StartPhase;

			public long Serial;
		}

		private readonly Dictionary<string, Pulse> pulses = new Dictionary<string, Pulse>();

		private long serial;

		internal void Trigger(string group, string clip, double now, double duration, double startPhase = 0.0)
		{
			if (!double.IsNaN(now) && !double.IsInfinity(now) && !double.IsNaN(duration) && !double.IsInfinity(duration) && !(duration <= 0.0))
			{
				pulses[group] = new Pulse
				{
					Clip = clip,
					Start = now,
					Duration = Math.Max(0.06, duration),
					StartPhase = Math.Max(0.0, Math.Min(1.0, startPhase)),
					Serial = ++serial
				};
			}
		}

		internal IEnumerable<Sample> Samples(double now)
		{
			List<string> list = new List<string>();
			List<Sample> list2 = new List<Sample>();
			foreach (KeyValuePair<string, Pulse> pulse in pulses)
			{
				Pulse value = pulse.Value;
				double num = now - value.Start;
				if (num < 0.0 || num >= value.Duration)
				{
					list.Add(pulse.Key);
					continue;
				}
				list2.Add(new Sample
				{
					Group = pulse.Key,
					Clip = value.Clip,
					Phase = value.StartPhase + (1.0 - value.StartPhase) * num / value.Duration,
					Weight = (float)Math.Min(1.0, (value.Duration - num) / Math.Min(0.08, value.Duration * 0.2)),
					Token = pulse.Key + ":" + value.Serial
				});
			}
			foreach (string item in list)
			{
				pulses.Remove(item);
			}
			return list2;
		}

		internal static bool PlayExit(string kind, bool boosted, double duration)
		{
			if (duration > 0.0)
			{
				return !(kind == "ice-end" && boosted);
			}
			return false;
		}

		internal static double FirePhase(double elapsed, double entry, double flame, double exit, bool started, bool ended, bool boostWaiting, out string id)
		{
			entry = Math.Max(0.01, entry);
			exit = Math.Max(0.01, exit);
			if (ended)
			{
				id = "sear_end";
				return Math.Max(0.0, (elapsed - entry - flame) / exit);
			}
			if (elapsed < entry || !started || boostWaiting)
			{
				id = "sear_start";
				return Math.Max(0.0, Math.Min(1.0, elapsed / entry));
			}
			id = "sear_loop";
			return Math.Max(0.0, elapsed - entry);
		}

		internal static void FilterCanceled(List<NativeMotionCandidate> observed, HashSet<string> canceled)
		{
			observed.RemoveAll((NativeMotionCandidate c) => canceled.Contains(c.Motion.Group));
		}

		internal void Remove(string group)
		{
			pulses.Remove(group);
		}

		internal void Clear()
		{
			pulses.Clear();
		}
	}
	internal static class CrabNativeEvents
	{
		internal sealed class Signal
		{
			public EntityState State;

			public string Kind;

			public float Duration;

			public bool Boosted;
		}

		private static bool installed;

		private static readonly Dictionary<string, FieldInfo> fields = new Dictionary<string, FieldInfo>();

		private static bool warned;

		internal static event Action<Signal> Observed;

		internal static float Number(EntityState s, string n, float fallback)
		{
			if (!(Read(s, n) is float num) || float.IsNaN(num) || float.IsInfinity(num))
			{
				return fallback;
			}
			return num;
		}

		internal static bool Flag(EntityState s, string n)
		{
			object obj = Read(s, n);
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static object Read(EntityState s, string n)
		{
			try
			{
				if (s == null)
				{
					return null;
				}
				string key = ((object)s).GetType().FullName + ":" + n;
				if (!fields.TryGetValue(key, out var value))
				{
					value = ((object)s).GetType().GetField(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					fields[key] = value;
				}
				return (value != null) ? value.GetValue(s) : ((object)s).GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(s);
			}
			catch (Exception)
			{
				if (!warned)
				{
					warned = true;
					Debug.LogWarning((object)"CHEF crab presentation observation unavailable; native gameplay preserved.");
				}
				return null;
			}
		}

		private static void Emit(EntityState s, string kind, float duration = 0f, bool boost = false)
		{
			Action<Signal> observed = CrabNativeEvents.Observed;
			if (observed == null)
			{
				return;
			}
			Signal obj = new Signal
			{
				State = s,
				Kind = kind,
				Duration = duration,
				Boosted = boost
			};
			Delegate[] invocationList = observed.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<Signal> action = (Action<Signal>)invocationList[i];
				try
				{
					action(obj);
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		internal static void Install()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			if (!installed)
			{
				installed = true;
				Dice.PlayThrowAnims += new hook_PlayThrowAnims(Throw);
				Sear.OnEnter += new hook_OnEnter(FireEnter);
				Sear.OnExit += new hook_OnExit(FireExit);
				Sear.FireBoostedFireball += new hook_FireBoostedFireball(FireBurst);
				IceBox.OnEnter += new hook_OnEnter(IceEnter);
				IceBox.OnExit += new hook_OnExit(IceExit);
				IceBox.FireBoostedIceCube += new hook_FireBoostedIceCube(IceBurst);
				Glaze.OnEnter += new hook_OnEnter(Glaze);
				Glaze.FireGrenade += new hook_FireGrenade(GlazeShot);
				YesChef.OnEnter += new hook_OnEnter(YesChef);
			}
		}

		internal static void Uninstall()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			if (installed)
			{
				installed = false;
				Dice.PlayThrowAnims -= new hook_PlayThrowAnims(Throw);
				Sear.OnEnter -= new hook_OnEnter(FireEnter);
				Sear.OnExit -= new hook_OnExit(FireExit);
				Sear.FireBoostedFireball -= new hook_FireBoostedFireball(FireBurst);
				IceBox.OnEnter -= new hook_OnEnter(IceEnter);
				IceBox.OnExit -= new hook_OnExit(IceExit);
				IceBox.FireBoostedIceCube -= new hook_FireBoostedIceCube(IceBurst);
				Glaze.OnEnter -= new hook_OnEnter(Glaze);
				Glaze.FireGrenade -= new hook_FireGrenade(GlazeShot);
				YesChef.OnEnter -= new hook_OnEnter(YesChef);
				CrabNativeEvents.Observed = null;
				fields.Clear();
			}
		}

		private static void Throw(orig_PlayThrowAnims orig, Dice self, float duration)
		{
			orig.Invoke(self, duration);
			Emit((EntityState)(object)self, "throw", duration, Flag((EntityState)(object)self, "hasBoost"));
		}

		private static void FireEnter(orig_OnEnter orig, Sear self)
		{
			orig.Invoke(self);
			Emit((EntityState)(object)self, "fire-start");
		}

		private static void FireExit(orig_OnExit orig, Sear self)
		{
			bool flag = Flag((EntityState)(object)self, "flamethrowerEnded");
			orig.Invoke(self);
			Emit((EntityState)(object)self, "fire-end", flag ? 0f : Number((EntityState)(object)self, "exitDuration", 0.3f));
		}

		private static void FireBurst(orig_FireBoostedFireball orig, Sear self, string muzzle)
		{
			orig.Invoke(self, muzzle);
			Emit((EntityState)(object)self, "fire-burst", 0.32f);
		}

		private static void IceEnter(orig_OnEnter orig, IceBox self)
		{
			orig.Invoke(self);
			Emit((EntityState)(object)self, "ice-start");
		}

		private static void IceExit(orig_OnExit orig, IceBox self)
		{
			bool boost = Flag((EntityState)(object)self, "hasBoost");
			orig.Invoke(self);
			Emit((EntityState)(object)self, "ice-end", Number((EntityState)(object)self, "exitDuration", 0.3f), boost);
		}

		private static void IceBurst(orig_FireBoostedIceCube orig, IceBox self)
		{
			orig.Invoke(self);
			Emit((EntityState)(object)self, "ice-burst", 0.65f, boost: true);
		}

		private static void Glaze(orig_OnEnter orig, Glaze self)
		{
			orig.Invoke(self);
			Emit((EntityState)(object)self, "glaze", Number((EntityState)(object)self, "duration", 1f));
		}

		private static void GlazeShot(orig_FireGrenade orig, Glaze self, string muzzle)
		{
			orig.Invoke(self, muzzle);
			Emit((EntityState)(object)self, "glaze-shot", 0.3f);
		}

		private static void YesChef(orig_OnEnter orig, YesChef self)
		{
			orig.Invoke(self);
			Emit((EntityState)(object)self, "yes-chef", Number((EntityState)(object)self, "duration", 1f));
		}
	}
	internal static class CrabActor
	{
		internal static CharacterBody Resolve(Component member)
		{
			if (!Object.op_Implicit((Object)(object)member))
			{
				return null;
			}
			CharacterModel componentInParent = member.GetComponentInParent<CharacterModel>();
			if (Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)componentInParent.body) && Object.op_Implicit((Object)(object)componentInParent.body.modelLocator) && (Object)(object)componentInParent.body.modelLocator.modelTransform == (Object)(object)((Component)componentInParent).transform)
			{
				return componentInParent.body;
			}
			AdvancedSkinModel componentInParent2 = member.GetComponentInParent<AdvancedSkinModel>();
			if (!Object.op_Implicit((Object)(object)componentInParent2))
			{
				return null;
			}
			return componentInParent2.AssociatedBody;
		}

		internal static bool Boosted(CharacterBody body)
		{
			if (Object.op_Implicit((Object)(object)body))
			{
				if ((!Object.op_Implicit((Object)(object)Buffs.Boosted) || !body.HasBuff(Buffs.Boosted)) && (!Object.op_Implicit((Object)(object)Buffs.boostedFireEffect) || !body.HasBuff(Buffs.boostedFireEffect)))
				{
					if (Object.op_Implicit((Object)(object)Buffs.boostedFrostEffect))
					{
						return body.HasBuff(Buffs.boostedFrostEffect);
					}
					return false;
				}
				return true;
			}
			return false;
		}
	}
	public sealed class CrabMotion : ISkinMotionSource, IDisposable
	{
		private sealed class Route
		{
			public string Clip;

			public string Group;

			public int Priority;

			public int[] Mask;

			public Route(string c, string g, int p, int[] m = null)
			{
				Clip = c;
				Group = g;
				Priority = p;
				Mask = m;
			}
		}

		private readonly Animator animator;

		private readonly MotionBank bank;

		private readonly Dictionary<string, MotionClip> clips;

		private readonly Dictionary<int, LayerMotionClock> clocks = new Dictionary<int, LayerMotionClock>();

		private readonly List<AnimatorClipInfo> infos = new List<AnimatorClipInfo>();

		private readonly int[] upper;

		private readonly int[] right;

		private readonly int[] left;

		private readonly int[] eyes;

		private readonly ObservedMotionChannel gaitChannel = new ObservedMotionChannel();

		private readonly HashSet<string> floatParameters;

		private double idlePhase;

		private double walkPhase;

		private double deathAt = -1.0;

		private float movement;

		private bool disposed;

		private readonly CrabActionTimeline actionTimeline = new CrabActionTimeline();

		private EntityState sustained;

		private EntityState suppressedState;

		private string sustainedKind;

		private float sustainedStart;

		private CharacterBody trackedBody;

		private EntityStateMachine[] machines = Array.Empty<EntityStateMachine>();

		private readonly HashSet<string> canceledGroups = new HashSet<string>();

		private readonly Dictionary<string, Route> routes = new Dictionary<string, Route>();

		private CharacterBody BindBody()
		{
			CharacterBody val = CrabActor.Resolve((Component)(object)animator);
			if ((Object)(object)val != (Object)(object)trackedBody)
			{
				trackedBody = val;
				machines = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponents<EntityStateMachine>() : Array.Empty<EntityStateMachine>());
				actionTimeline.Clear();
				sustained = null;
				suppressedState = null;
				canceledGroups.Clear();
			}
			return val;
		}

		private EntityState ActiveSecondary()
		{
			return (from m in machines
				where Object.op_Implicit((Object)(object)m) && m.state != null
				select m.state).FirstOrDefault((Func<EntityState, bool>)((EntityState s) => s is Sear || s is IceBox));
		}

		private void OnNativeAction(CrabNativeEvents.Signal signal)
		{
			if (disposed || !Object.op_Implicit((Object)(object)animator) || signal.State == null)
			{
				return;
			}
			CharacterBody val = BindBody();
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)signal.State.outer) || (Object)(object)((Component)signal.State.outer).GetComponent<CharacterBody>() != (Object)(object)val)
			{
				return;
			}
			string kind = signal.Kind;
			double now = Time.time;
			string item = ((kind.StartsWith("fire") || kind.StartsWith("ice")) ? "secondary" : (kind.StartsWith("glaze") ? "glaze" : ((kind == "throw") ? "primary" : "transformation")));
			canceledGroups.Remove(item);
			switch (kind)
			{
			case "fire-start":
			case "ice-start":
				actionTimeline.Remove("secondary");
				suppressedState = null;
				sustained = signal.State;
				sustainedKind = ((kind == "fire-start") ? "sear" : "icebox");
				sustainedStart = Time.time;
				break;
			case "fire-end":
			case "ice-end":
				if (sustained == signal.State)
				{
					sustained = null;
					sustainedKind = null;
				}
				if (CrabActionTimeline.PlayExit(kind, signal.Boosted, signal.Duration))
				{
					actionTimeline.Trigger("secondary", (kind == "fire-end") ? "sear_end" : "icebox_end", now, signal.Duration);
				}
				break;
			case "throw":
				actionTimeline.Trigger("primary", signal.Boosted ? "throw_boost" : "throw", now, signal.Duration);
				break;
			case "fire-burst":
				actionTimeline.Trigger("secondary", "sear_burst", now, signal.Duration);
				break;
			case "ice-burst":
				actionTimeline.Trigger("secondary", "icebox_burst", now, signal.Duration);
				break;
			case "glaze":
				actionTimeline.Trigger("glaze", "glaze_prep", now, signal.Duration);
				break;
			case "glaze-shot":
				actionTimeline.Trigger("glaze", "glaze", now, signal.Duration, 0.18);
				break;
			case "yes-chef":
				actionTimeline.Trigger("transformation", "yes_chef", now, signal.Duration);
				break;
			}
		}

		private void CollectNativeActions(List<NativeMotionCandidate> observed)
		{
			EntityState val = ActiveSecondary();
			if (observed.Any((NativeMotionCandidate c) => c.Motion.Group == "roll" && c.Motion.Samples.Any((WeightedMotion x) => x.Weight > 0f)))
			{
				actionTimeline.Clear();
				suppressedState = val;
				sustained = null;
				string[] array = new string[4] { "primary", "secondary", "glaze", "transformation" };
				foreach (string item in array)
				{
					canceledGroups.Add(item);
				}
				return;
			}
			if (val != null && val != suppressedState && val != sustained)
			{
				actionTimeline.Remove("secondary");
				sustained = val;
				sustainedKind = ((val is IceBox) ? "icebox" : "sear");
				sustainedStart = Time.time - CrabNativeEvents.Number(val, (val is IceBox) ? "fixedAge" : "stopwatch", 0f);
				canceledGroups.Remove("secondary");
			}
			else if (val == null)
			{
				sustained = null;
			}
			if (sustained != null)
			{
				float num2 = Mathf.Max(0.01f, CrabNativeEvents.Number(sustained, "entryDuration", 0.3f));
				float num3 = ((sustainedKind == "sear") ? CrabNativeEvents.Number(sustained, "stopwatch", Time.time - sustainedStart) : (Time.time - sustainedStart));
				double num4;
				string id;
				if (sustainedKind == "sear")
				{
					num4 = CrabActionTimeline.FirePhase(num3, num2, CrabNativeEvents.Number(sustained, "flamethrowerDuration", 1f), CrabNativeEvents.Number(sustained, "exitDuration", 0.3f), CrabNativeEvents.Flag(sustained, "flamethrowerStarted"), CrabNativeEvents.Flag(sustained, "flamethrowerEnded"), CrabNativeEvents.Flag(sustained, "hasBoost") && !CrabNativeEvents.Flag(sustained, "allBoostProjectilesFired"), out id);
					if (id == "sear_loop")
					{
						num4 /= (double)clips[id].Duration;
					}
				}
				else
				{
					bool flag = num3 < num2;
					id = "icebox" + (flag ? "_start" : "_loop");
					num4 = (flag ? (num3 / num2) : ((num3 - num2) / clips[id].Duration));
				}
				observed.Add(Candidate(id, "secondary", 30, -60000, Math.Max(0.0, num4), 1f, upper, "sustained:" + sustainedStart, 1500));
			}
			foreach (CrabActionTimeline.Sample item2 in actionTimeline.Samples(Time.time))
			{
				int num5 = ((item2.Group == "primary") ? 20 : ((item2.Group == "glaze") ? 25 : ((item2.Group == "transformation") ? 60 : 30)));
				int[] mask = ((item2.Group == "primary") ? ((item2.Clip == "throw_boost") ? upper : right) : ((item2.Group == "glaze") ? left : upper));
				observed.Add(Candidate(item2.Clip, item2.Group, num5, -61000 - num5, item2.Phase, item2.Weight, mask, item2.Token, 2000));
			}
		}

		private int[] Mask(Func<string, bool> predicate)
		{
			return (from x in bank.Bones.Select((Bone b, int i) => new { b.Name, i })
				where predicate(x.Name)
				select x.i).ToArray();
		}

		private void Map(string native, string clip, string group, int priority, int[] mask = null)
		{
			routes.Add(native, new Route(clip, group, priority, mask));
		}

		public CrabMotion(Animator animator, MotionBank bank)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			this.animator = animator;
			this.bank = bank;
			clips = bank.Clips.ToDictionary((MotionClip c) => c.Id);
			floatParameters = new HashSet<string>(from p in animator.parameters
				where (int)p.type == 1
				select p.name);
			upper = Mask((string n) => n == "Mouth" || n.StartsWith("Claw_") || n.StartsWith("Tool_") || n.StartsWith("Eye_"));
			right = Mask((string n) => n == "Eye_R" || n.StartsWith("Claw_R") || n == "Tool_R");
			left = Mask((string n) => n == "Eye_L" || n.StartsWith("Claw_L") || n == "Tool_L");
			eyes = Mask((string n) => n.StartsWith("Eye_"));
			Map("Chef_SliceAndDice", "throw", "primary", 20, right);
			Map("PrimaryDice1_Return_Start", "recall", "primary", 20, right);
			Map("PrimaryDice1_Return_Hold", "cleaver_hold", "primary", 20, right);
			Map("PrimaryDice1_Return_Catch", "catch", "primary", 20, right);
			Map("PrimaryDice1_Return_All", "catch", "primary", 20, right);
			Map("root|PrimaryDice1_Oops", "flinch", "primary", 20, right);
			Map("ChefGlazeStart", "glaze_prep", "glaze", 25, left);
			Map("Chef_Glaze3Shots", "glaze_boost", "glaze", 25, left);
			Map("Glaze_Glaze3Shot_Exit", "glaze_end", "glaze", 25, left);
			Map("SearBlaze_Prep", "sear_start", "secondary", 30, upper);
			Map("SearBlaze_Loop", "sear_loop", "secondary", 30, upper);
			Map("SearBlaze_Exit", "sear_end", "secondary", 30, upper);
			Map("YesChef", "yes_chef", "transformation", 60, upper);
			string[][] array = new string[3][]
			{
				new string[2] { "Chef_JumpStartTweaked", "jump_start" },
				new string[2] { "Chef_JumpUp", "jump_up" },
				new string[2] { "Chef_JumpDown", "fall" }
			};
			foreach (string[] array2 in array)
			{
				Map(array2[0], array2[1], "airborne", 10);
			}
			array = new string[10][]
			{
				new string[2] { "Rolypoly_Enter", "roll_enter" },
				new string[2] { "Rolypoly_ChargeLoop", "roll_charge" },
				new string[2] { "Chef_RolyPolyStart", "roll_enter" },
				new string[2] { "Chef_RolyPoly", "roll_loop" },
				new string[2] { "ExitRolyPoly", "roll_exit" },
				new string[2] { "Boosted_Rolypoly_Start", "roll_enter" },
				new string[2] { "Boosted_Rolypoly_Loop", "roll_boost" },
				new string[2] { "Chef_RolyPoly_JumpStart", "roll_enter" },
				new string[2] { "Chef_RolyPoly_JumpUp", "roll_charge" },
				new string[2] { "Chef_RolyPoly_JumpDown", "roll_charge" }
			};
			foreach (string[] array3 in array)
			{
				Map(array3[0], array3[1], "roll", 40);
			}
			Map("Chef_JumpLand", "land", "landing", 11);
			Map("Chef_RolyPoly_JumpLand", "roll_exit", "roll-landing", 41);
			string[] array4 = new string[2] { ",Additive", ",Override" };
			foreach (string text in array4)
			{
				Map("OilSpillJump" + text, "oil_jump", "oil", 45);
				Map("OilSpillLoop" + text, "oil_loop", "oil", 45);
				Map("OilSpillLand" + text, "oil_land", "oil", 45);
			}
			Map("Chef_Flinch1", "flinch", "flinch", 70, upper);
			Map("Chef_Flinch2", "flinch", "flinch", 70, upper);
			Map("LobbyIntro", "lobby_intro", "display", 10);
			array4 = new string[3] { "Chef_LobbyIdle", "Chef_LobbyIdleAlternate", "Chef_LobbyIdleAlternate2" };
			foreach (string native in array4)
			{
				Map(native, "lobby_idle", "display", 10);
			}
			foreach (Route value in routes.Values)
			{
				if (!clips.ContainsKey(value.Clip))
				{
					throw new InvalidOperationException("Missing crab action " + value.Clip);
				}
				if (value.Mask != null && value.Mask.Length == 0)
				{
					throw new InvalidOperationException("Empty crab action mask");
				}
			}
			array4 = new string[16]
			{
				"idle", "scuttle", "sprint", "backpedal", "strafe_left", "strafe_right", "death", "throw_boost", "empowered", "aim_yaw",
				"aim_pitch", "icebox_start", "icebox_loop", "icebox_end", "sear_burst", "icebox_burst"
			};
			foreach (string text2 in array4)
			{
				if (!clips.ContainsKey(text2))
				{
					throw new InvalidOperationException("Missing crab motion " + text2);
				}
			}
			CrabNativeEvents.Observed += OnNativeAction;
		}

		private NativeMotionCandidate Candidate(string id, string group, int priority, int layer, double time, float weight, int[] mask = null, string token = null, int rank = 1000)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_002d: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_008b: Expected O, but got Unknown
			NativeMotionCandidate val = new NativeMotionCandidate();
			val.SourceLayer = layer;
			val.SourceRank = rank;
			MotionLayer val2 = new MotionLayer();
			val2.Group = group;
			val2.Priority = priority;
			val2.Blend = (MotionBlend)0;
			val2.BoneMask = mask;
			val2.Samples = (WeightedMotion[])(object)new WeightedMotion[1]
			{
				new WeightedMotion
				{
					Clip = clips[id],
					Time = Math.Max(0.0, time),
					Weight = Mathf.Clamp01(weight),
					Token = (token ?? group)
				}
			};
			val.Motion = val2;
			return val;
		}

		private void Collect(int layer, AnimatorStateInfo state, MotionOccurrence occurrence, float transition, List<NativeMotionCandidate> result, bool boosted)
		{
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			string layerName = animator.GetLayerName(layer);
			float num = ((layer == 0) ? 1f : Mathf.Clamp01(animator.GetLayerWeight(layer)));
			float num2 = infos.Sum((AnimatorClipInfo x) => Mathf.Max(0f, ((AnimatorClipInfo)(ref x)).weight));
			if (num <= 0f)
			{
				return;
			}
			string text = ((((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireDice")) ? "throw" : ((((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireSliceAndDice")) ? "throw_boost" : null));
			if (text != null)
			{
				if (!canceledGroups.Contains("primary"))
				{
					result.Add(Candidate(text, "primary", 20, -1000 - layer, ((AnimatorStateInfo)(ref state)).normalizedTime, transition * num, (text == "throw_boost") ? upper : right, layer + ":" + occurrence.Serial + ":" + text, layerName.Contains("Override") ? 30 : 20));
				}
			}
			else
			{
				if (num2 <= 1E-06f)
				{
					return;
				}
				foreach (AnimatorClipInfo info in infos)
				{
					AnimatorClipInfo current = info;
					if (Object.op_Implicit((Object)(object)((AnimatorClipInfo)(ref current)).clip) && routes.TryGetValue(((Object)((AnimatorClipInfo)(ref current)).clip).name, out var value) && !canceledGroups.Contains(value.Group))
					{
						string text2 = value.Clip;
						if (((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireDice"))
						{
							text2 = "throw";
							value = new Route(text2, "primary", 20, right);
						}
						else if (((AnimatorStateInfo)(ref state)).fullPathHash == Animator.StringToHash(layerName + ".FireSliceAndDice"))
						{
							text2 = "throw_boost";
							value = new Route(text2, "primary", 20, right);
						}
						int rank = (layerName.Contains("Override") ? 30 : (layerName.Contains("Additive") ? 20 : 10));
						int layer2 = -1000 - layer;
						result.Add(Candidate(text2, value.Group, value.Priority, layer2, ((AnimatorStateInfo)(ref state)).normalizedTime, ((AnimatorClipInfo)(ref current)).weight / num2 * transition * num, value.Mask, layer + ":" + occurrence.Serial + ":" + text2, rank));
					}
				}
			}
		}

		public void Observe(List<NativeMotionCandidate> candidates, HashSet<string> replaced)
		{
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: 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_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Expected O, but got Unknown
			//IL_0324: Expected O, but got Unknown
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Expected O, but got Unknown
			//IL_03be: Expected O, but got Unknown
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0544: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0588: Unknown result type (might be due to invalid IL or missing references)
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0638: Unknown result type (might be due to invalid IL or missing references)
			if (disposed || !Object.op_Implicit((Object)(object)animator))
			{
				return;
			}
			MotionBinding[] bindings = bank.Bindings;
			foreach (MotionBinding val in bindings)
			{
				replaced.Add(val.Clip);
			}
			CharacterBody val2 = BindBody();
			bool num = Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.healthComponent) && !val2.healthComponent.alive;
			bool flag = CrabActor.Boosted(val2);
			float num2 = Mathf.Min(Time.deltaTime, 0.1f);
			idlePhase += num2 / clips["idle"].Duration;
			if (num)
			{
				actionTimeline.Clear();
				sustained = null;
				if (deathAt < 0.0)
				{
					deathAt = Time.time;
				}
				candidates.Add(Candidate("death", "death", 1000, -90000, ((double)Time.time - deathAt) / (double)clips["death"].Duration, 1f));
				return;
			}
			deathAt = -1.0;
			Vector3 val3 = Vector3.zero;
			if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.characterMotor) && val2.characterMotor.isGrounded)
			{
				val3 = val2.characterMotor.velocity;
				val3.y = 0f;
				val3 = ((Component)animator).transform.InverseTransformDirection(val3);
			}
			float magnitude = ((Vector3)(ref val3)).magnitude;
			movement = Mathf.MoveTowards(movement, (float)((magnitude > 0.15f) ? 1 : 0), num2 * 6f);
			walkPhase += num2 * Mathf.Min(magnitude / 0.65f, 3.5f);
			string text = ((!(Mathf.Abs(val3.x) > Mathf.Abs(val3.z))) ? ((val3.z < -0.1f) ? "backpedal" : ((Object.op_Implicit((Object)(object)val2) && val2.isSprinting) ? "sprint" : "scuttle")) : ((val3.x < 0f) ? "strafe_left" : "strafe_right"));
			candidates.Add(Candidate("idle", "base-idle", 1, -1, idlePhase, 1f - movement));
			WeightedMotion[] array = gaitChannel.Sample(clips[text], text, walkPhase, (double)Time.time, 0.12f, (string)null, 0, false);
			WeightedMotion[] array2 = array;
			foreach (WeightedMotion obj in array2)
			{
				obj.Weight *= movement;
			}
			candidates.Add(new NativeMotionCandidate
			{
				SourceLayer = -1,
				SourceRank = 1000,
				Motion = new MotionLayer
				{
					Group = "base-gait",
					Priority = 1,
					Blend = (MotionBlend)0,
					Samples = array
				}
			});
			List<NativeMotionCandidate> list = new List<NativeMotionCandidate>();
			AnimatorTransitionInfo animatorTransitionInfo;
			AnimatorStateInfo val4;
			for (int j = 0; j < animator.layerCount; j++)
			{
				bool flag2 = animator.IsInTransition(j);
				float num3;
				if (!flag2)
				{
					num3 = 0f;
				}
				else
				{
					animatorTransitionInfo = animator.GetAnimatorTransitionInfo(j);
					num3 = Mathf.Clamp01(((AnimatorTransitionInfo)(ref animatorTransitionInfo)).normalizedTime);
				}
				float num4 = num3;
				AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(j);
				AnimatorStateInfo val5;
				if (!flag2)
				{
					val4 = default(AnimatorStateInfo);
					val5 = val4;
				}
				else
				{
					val5 = animator.GetNextAnimatorStateInfo(j);
				}
				AnimatorStateInfo state = val5;
				if (!clocks.TryGetValue(j, out var value))
				{
					Dictionary<int, LayerMotionClock> dictionary = clocks;
					int key = j;
					LayerMotionClock val6 = new LayerMotionClock();
					value = val6;
					dictionary[key] = val6;
				}
				value.Observe(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, (double)((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime, flag2, ((AnimatorStateInfo)(ref state)).fullPathHash, (double)((AnimatorStateInfo)(ref state)).normalizedTime, (double)Time.time);
				infos.Clear();
				animator.GetCurrentAnimatorClipInfo(j, infos);
				Collect(j, currentAnimatorStateInfo, value.Current, 1f - num4, list, flag);
				if (flag2)
				{
					infos.Clear();
					animator.GetNextAnimatorClipInfo(j, infos);
					Collect(j, state, value.Next, num4, list, flag);
				}
			}
			CollectNativeActions(list);
			CrabActionTimeline.FilterCanceled(list, canceledGroups);
			candidates.AddRange(NativeMotionComposition.ResolveSources((IEnumerable<NativeMotionCandidate>)list));
			string[][] array3 = new string[2][]
			{
				new string[3] { "AimYaw", "aimYawCycle", "aim_yaw" },
				new string[3] { "AimPitch", "aimPitchCycle", "aim_pitch" }
			};
			foreach (string[] array4 in array3)
			{
				int layerIndex = animator.GetLayerIndex(array4[0]);
				if (layerIndex < 0 || !floatParameters.Contains(array4[1]))
				{
					continue;
				}
				bool flag3 = animator.IsInTransition(layerIndex);
				float num5;
				if (!flag3)
				{
					num5 = 0f;
				}
				else
				{
					animatorTransitionInfo = animator.GetAnimatorTransitionInfo(layerIndex);
					num5 = Mathf.Clamp01(((AnimatorTransitionInfo)(ref animatorTransitionInfo)).normalizedTime);
				}
				float num6 = num5;
				int num7 = Animator.StringToHash(array4[0] + ((array4[0] == "AimYaw") ? ".YawControl" : ".PitchControl"));
				val4 = animator.GetCurrentAnimatorStateInfo(layerIndex);
				float num8 = ((((AnimatorStateInfo)(ref val4)).fullPathHash == num7) ? (1f - num6) : 0f);
				float num9;
				if (flag3)
				{
					val4 = animator.GetNextAnimatorStateInfo(layerIndex);
					if (((AnimatorStateInfo)(ref val4)).fullPathHash == num7)
					{
						num9 = num6;
						goto IL_05d0;
					}
				}
				num9 = 0f;
				goto IL_05d0;
				IL_05d0:
				float num10 = num8 + num9;
				float num11 = Mathf.Clamp01(animator.GetLayerWeight(layerIndex)) * num10;
				if (!(num11 <= 0f))
				{
					NativeMotionCandidate val7 = Candidate(array4[2], array4[0], 80, -70000 - layerIndex, Mathf.Clamp01(animator.GetFloat(array4[1])), num11, upper);
					val7.Motion.Blend = (MotionBlend)1;
					candidates.Add(val7);
				}
			}
			if (flag)
			{
				candidates.Add(Candidate("empowered", "boost-eyes", 5, -80000, Time.time / clips["empowered"].Duration, 1f, eyes));
			}
		}

		public void Dispose()
		{
			disposed = true;
			CrabNativeEvents.Observed -= OnNativeAction;
			actionTimeline.Clear();
			sustained = null;
			trackedBody = null;
			machines = Array.Empty<EntityStateMachine>();
			canceledGroups.Clear();
			clocks.Clear();
			infos.Clear();
		}
	}
	public sealed class CrabEffects : ISkinEffectDriver, IDisposable
	{
		private readonly SkinnedMeshRenderer renderer;

		private Transform tool;

		private Vector3 visibleScale;

		private bool masked;

		private bool disposed;

		private readonly Material original;

		private readonly Material accent;

		private readonly Color originalColor;

		private float boostBlend;

		public CrabEffects(SkinnedMeshRenderer renderer)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0072: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			this.renderer = renderer;
			original = ((Renderer)renderer).sharedMaterial;
			if (!Object.op_Implicit((Object)(object)original))
			{
				throw new InvalidOperationException("Crab material unavailable");
			}
			accent = new Material(original)
			{
				name = "CrabActorAccent"
			};
			originalColor = (original.HasProperty("_Color") ? original.GetColor("_Color") : Color.white);
			((Renderer)renderer).sharedMaterial = accent;
		}

		public void Update()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			if (disposed || !Object.op_Implicit((Object)(object)renderer))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)tool))
			{
				tool = ((IEnumerable<Transform>)renderer.bones).FirstOrDefault((Func<Transform, bool>)((Transform b) => Object.op_Implicit((Object)(object)b) && ((Object)b).name == "Tool_R"));
			}
			CharacterBody val = CrabActor.Resolve((Component)(object)renderer);
			ChefController val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<ChefController>() : null);
			if (Object.op_Implicit((Object)(object)tool))
			{
				visibleScale = tool.localScale;
				masked = false;
				if (Object.op_Implicit((Object)(object)val2) && val2.cleaversAway)
				{
					tool.localScale = Vector3.zero;
					masked = true;
				}
			}
			bool flag = CrabActor.Boosted(val) && (!Object.op_Implicit((Object)(object)val.healthComponent) || val.healthComponent.alive);
			boostBlend = Mathf.MoveTowards(boostBlend, (float)(flag ? 1 : 0), Time.deltaTime * 5f);
			if (Object.op_Implicit((Object)(object)accent) && (Object)(object)((Renderer)renderer).sharedMaterial == (Object)(object)accent)
			{
				bool flag2 = Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)Buffs.boostedFrostEffect) && val.HasBuff(Buffs.boostedFrostEffect);
				accent.SetColor("_Color", Color.Lerp(originalColor, flag2 ? new Color(0.7f, 0.92f, 1f) : new Color(1f, 0.83f, 0.6f), boostBlend * 0.65f));
			}
		}

		public void Dispose()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!disposed)
			{
				disposed = true;
				if (masked && Object.op_Implicit((Object)(object)tool))
				{
					tool.localScale = visibleScale;
				}
				if (Object.op_Implicit((Object)(object)renderer) && (Object)(object)((Renderer)renderer).sharedMaterial == (Object)(object)accent)
				{
					((Renderer)renderer).sharedMaterial = original;
				}
				if (Object.op_Implicit((Object)(object)accent))
				{
					Object.Destroy((Object)(object)accent);
				}
				masked = false;
			}
		}
	}
	[DefaultExecutionOrder(32001)]
	public sealed class CrabNativeVisuals : MonoBehaviour
	{
		[SerializeField]
		private SkinnedMeshRenderer target;

		[SerializeField]
		private Mesh custom;

		[SerializeField]
		private Mesh empty;

		[SerializeField]
		private SkinnedMeshRenderer[] companions;

		[SerializeField]
		private Mesh[] originals;

		public void Configure(SkinnedMeshRenderer target, Mesh custom, Mesh empty, SkinnedMeshRenderer[] companions, Mesh[] originals)
		{
			this.target = target;
			this.custom = custom;
			this.empty = empty;
			this.companions = companions;
			this.originals = originals;
		}

		private void LateUpdate()
		{
			if (Object.op_Implicit((Object)(object)target) && companions != null && !((Object)(object)target.sharedMesh == (Object)(object)custom))
			{
				Restore();
			}
		}

		private void Restore()
		{
			if (companions == null)
			{
				return;
			}
			for (int i = 0; i < companions.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)companions[i]) && (Object)(object)companions[i].sharedMesh == (Object)(object)empty)
				{
					companions[i].sharedMesh = originals[i];
				}
			}
		}

		private void OnDestroy()
		{
			Restore();
		}
	}
	[BepInPlugin("eclipseplaytest.chef.e2", "CHEF - Crab Rangoon (Playtest)", "0.1.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class CrabRangoon : BaseUnityPlugin
	{
		[Serializable]
		public sealed class AssetFile
		{
			public string file;

			public string sha256;
		}

		[Serializable]
		public sealed class AssetManifest
		{
			public int schema;

			public string skinId;

			public string revision;

			public AssetFile mesh;

			public AssetFile motion;

			public AssetFile albedo;

			public string[] nativeBoneNames;
		}

		public const string Guid = "eclipseplaytest.chef.e2";

		public const string Version = "0.1.4";

		public const string SkinId = "EclipsePlaytestChefE2CrabRangoon";

		private static CrabRangoon instance;

		private string folder;

		private float deadline;

		private bool registered;

		private readonly Dictionary<string, Mesh> fallbackMeshes = new Dictionary<string, Mesh>();

		private GameObject modelPrefab;

		private GameObject displayModelPrefab;

		private Mesh nativeMesh;

		private Material nativeMaterial;

		private AssetManifest manifest;

		private IDisposable registration;

		private readonly List<AsyncOperationHandle> retainedAssets = new List<AsyncOperationHandle>();

		private static readonly string[] RendererNames = new string[5] { "meshChef", "meshChefPizzaCutter", "meshlChefCleaver", "meshChefOven", "meshChefIceBox" };

		private void Awake()
		{
			instance = this;
			CrabNativeEvents.Install();
			folder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			SystemInitializerInjector.InjectDependency(typeof(SkinCatalog), typeof(CrabRangoon));
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(SyncDisplaySkins));
			MainMenuController.OnMainMenuInitialised += SyncDisplaySkins;
		}

		[SystemInitializer(new Type[]
		{
			typeof(BodyCatalog),
			typeof(SurvivorCatalog)
		})]
		private static IEnumerator InitializeSkin()
		{
			if (!Object.op_Implicit((Object)(object)instance))
			{
				yield break;
			}
			instance.deadline = Time.realtimeSinceStartup + 45f;
			IEnumerator routine = instance.Register();
			try
			{
				while (true)
				{
					bool flag;
					try
					{
						flag = routine.MoveNext();
					}
					catch (Exception ex)
					{
						((BaseUnityPlugin)instance).Logger.LogError((object)("CHEF_E2_REGISTRATION_FAILED " + ex));
						break;
					}
					if (flag)
					{
						yield return routine.Current;
						continue;
					}
					break;
				}
			}
			finally
			{
				IDisposable disposable = routine as IDisposable;
				if (disposable != null)
				{
					disposable.Dispose();
				}
			}
		}

		private void CheckDeadline()
		{
			if (Time.realtimeSinceStartup > deadline)
			{
				throw new TimeoutException("Crab asset loading timed out; other startup work continues.");
			}
		}

		private byte[] ReadAsset(AssetFile entry)
		{
			if (entry == null || string.IsNullOrWhiteSpace(entry.file) || Path.GetFileName(entry.file) != entry.file || entry.file.Contains("..") || entry.sha256 == null || entry.sha256.Length != 64)
			{
				throw new InvalidDataException("Invalid crab asset manifest entry");
			}
			string text = Path.Combine(folder, entry.file);
			if (new FileInfo(text).Length > 67108864)
			{
				throw new InvalidDataException("Crab asset too large");
			}
			byte[] array = File.ReadAllBytes(text);
			using SHA256 sHA = SHA256.Create();
			if (BitConverter.ToString(sHA.ComputeHash(array)).Replace("-", "").ToLowerInvariant() != entry.sha256)
			{
				throw new InvalidDataException("Crab asset hash mismatch: " + entry.file);
			}
			return array;
		}

		private static SkinnedMeshRenderer Exact(GameObject model, string name)
		{
			Transform val = model.transform.Find(name);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent<SkinnedMeshRenderer>()))
			{
				throw new InvalidOperationException("Missing scoped CHEF renderer " + name);
			}
			return ((Component)val).GetComponent<SkinnedMeshRenderer>();
		}

		private void PrepareTemplate(GameObject model)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			AdvancedSkinModel component = model.GetComponent<AdvancedSkinModel>();
			if (Object.op_Implicit((Object)(object)component) && component.HasNativeSnapshot)
			{
				component.Prepare();
				return;
			}
			SkinnedMeshRenderer val = Exact(model, "meshChef");
			Animator component2 = model.GetComponent<Animator>();
			Vector3 val2 = ((Component)val).transform.localScale - Vector3.one * 100f;
			if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f) && !(Quaternion.Angle(((Component)val).transform.localRotation, Quaternion.Euler(-90f, 0f, 0f)) > 0.1f))
			{
				val2 = ((Component)val).transform.localPosition;
				if (!(((Vector3)(ref val2)).sqrMagnitude > 0.0001f))
				{
					if (!Object.op_Implicit((Object)(object)component2) || val.bones.Length != manifest.nativeBoneNames.Length)
					{
						throw new InvalidOperationException("Crab requires the original CHEF skeleton");
					}
					for (int i = 0; i < val.bones.Length; i++)
					{
						if (!Object.op_Implicit((Object)(object)val.bones[i]) || ((Object)val.bones[i]).name != manifest.nativeBoneNames[i])
						{
							throw new InvalidOperationException("Native bone slot mismatch " + i);
						}
					}
					AdvancedSkinModel val3 = model.GetComponent<AdvancedSkinModel>();
					if (!Object.op_Implicit((Object)(object)val3))
					{
						val3 = model.AddComponent<AdvancedSkinModel>();
					}
					val3.CaptureNativeTemplate(val, component2, nativeMesh, (Material[])(object)new Material[1] { nativeMaterial });
					val3.Prepare();
					return;
				}
			}
			throw new InvalidOperationException("CHEF renderer conversion contract changed");
		}

		private IEnumerator Register()
		{
			manifest = JsonUtility.FromJson<AssetManifest>(File.ReadAllText(Path.Combine(folder, "crab-assets.json")));
			if (manifest == null || manifest.schema != 1 || manifest.skinId != "EclipsePlaytestChefE2CrabRangoon" || string.IsNullOrWhiteSpace(manifest.revision) || manifest.nativeBoneNames == null || manifest.nativeBoneNames.Length != 61)
			{
				throw new InvalidDataException("Invalid crab asset identity");
			}
			MotionBank bank;
			using (MemoryStream memoryStream = new MemoryStream(ReadAsset(manifest.motion), writable: false))
			{
				bank = MotionBank.Read((Stream)memoryStream);
			}
			if (bank.SkinId != "EclipsePlaytestChefE2CrabRangoon")
			{
				throw new InvalidDataException("Motion identity mismatch");
			}
			bank.Find("idle");
			bank.Find("scuttle");
			bank.Find("claw_grip_proof");
			Mesh mesh;
			using (MemoryStream memoryStream2 = new MemoryStream(ReadAsset(manifest.mesh), writable: false))
			{
				mesh = SkinMesh.Read((Stream)memoryStream2, bank);
			}
			Texture2D albedo = new Texture2D(2, 2, (TextureFormat)4, false, false)
			{
				name = "CrabRangoonAlbedo",
				filterMode = (FilterMode)1,
				anisoLevel = 1
			};
			if (!ImageConversion.LoadImage(albedo, ReadAsset(manifest.albedo), false))
			{
				throw new InvalidDataException("Invalid crab albedo");
			}
			GameObject body = BodyCatalog.FindBodyPrefab("ChefBody");
			if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.GetComponent<ModelLocator>()))
			{
				throw new InvalidOperationException("CHEF body unavailable");
			}
			modelPrefab = ((Component)body.GetComponent<ModelLocator>().modelTransform).gameObject;
			ModelSkinController controller = modelPrefab.GetComponent<ModelSkinController>();
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null || controller.skins.Length == 0)
			{
				throw new InvalidOperationException("Native CHEF skins unavailable");
			}
			if (controller.skins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == "EclipsePlaytestChefE2CrabRangoon"))
			{
				yield break;
			}
			SkinDef baseSkin = controller.skins[0];
			SkinDefParams parameters = baseSkin.skinDefParams;
			if (!Object.op_Implicit((Object)(object)parameters) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<SkinDefParams> op = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(op));
				while (!op.IsDone)
				{
					CheckDeadline();
					yield return null;
				}
				parameters = op.Result;
			}
			if (!Object.op_Implicit((Object)(object)parameters))
			{
				throw new InvalidOperationException("Native skin parameters unavailable");
			}
			SkinnedMeshRenderer[] skinRenderers = modelPrefab.GetSkinRenderers<SkinnedMeshRenderer>(inactive: true, parameters);
			SkinnedMeshRenderer target = skinRenderers.Single((SkinnedMeshRenderer r) => ((Object)r).name == "meshChef");
			MeshReplacement val = ((IEnumerable<MeshReplacement>)parameters.meshReplacements).FirstOrDefault((Func<MeshReplacement, bool>)((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target));
			nativeMesh = val.mesh;
			if (!Object.op_Implicit((Object)(object)nativeMesh) && val.meshAddress != null && ((AssetReference)val.meshAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<Mesh> op2 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(op2));
				while (!op2.IsDone)
				{
					CheckDeadline();
					yield return null;
				}
				nativeMesh = op2.Result;
			}
			if (!Object.op_Implicit((Object)(object)nativeMesh))
			{
				nativeMesh = target.sharedMesh;
			}
			if (!Object.op_Implicit((Object)(object)nativeMesh) || nativeMesh.bindposes.Length != 61)
			{
				throw new InvalidOperationException("Native fallback mesh invalid");
			}
			RendererInfo info = parameters.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
			nativeMaterial = info.defaultMaterial;
			if (!Object.op_Implicit((Object)(object)nativeMaterial) && info.defaultMaterialAddress != null && ((AssetReference)info.defaultMaterialAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<Material> op3 = Addressables.LoadAssetAsync<Material>(((AssetReference)info.defaultMaterialAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(op3));
				while (!op3.IsDone)
				{
					CheckDeadline();
					yield return null;
				}
				nativeMaterial = op3.Result;
			}
			if (!Object.op_Implicit((Object)(object)nativeMaterial) || !Object.op_Implicit((Object)(object)nativeMaterial.shader))
			{
				throw new InvalidOperationException("Native fallback material invalid");
			}
			string[] rendererNames = RendererNames;
			foreach (string name in rendererNames)
			{
				SkinnedMeshRenderer nativeRenderer = Exact(modelPrefab, name);
				MeshReplacement val2 = parameters.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)nativeRenderer);
				Mesh val3 = val2.mesh;
				if (!Object.op_Implicit((Object)(object)val3) && val2.meshAddress != null && ((AssetReference)val2.meshAddress).RuntimeKeyIsValid())
				{
					AsyncOperationHandle<Mesh> op2 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
					retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(op2));
					while (!op2.IsDone)
					{
						CheckDeadline();
						yield return null;
					}
					val3 = op2.Result;
				}
				if (!Object.op_Implicit((Object)(object)val3))
				{
					val3 = nativeRenderer.sharedMesh;
				}
				if (!Object.op_Implicit((Object)(object)val3) || val3.bindposes.Length != 61)
				{
					throw new InvalidOperationException("Missing fallback mesh " + name);
				}
				fallbackMeshes.Add(name, val3);
			}
			SurvivorDef val4 = SurvivorCatalog.FindSurvivorDefFromBody(body);
			if (!Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val4.displayPrefab))
			{
				throw new InvalidOperationException("CHEF display unavailable");
			}
			CharacterModel componentInChildren = val4.displayPrefab.GetComponentInChildren<CharacterModel>(true);
			if (!Object.op_Implicit((Object)(object)componentInChildren))
			{
				throw new InvalidOperationException("CHEF display model unavailable");
			}
			displayModelPrefab = ((Component)componentInChildren).gameObject;
			PrepareTemplate(modelPrefab);
			PrepareTemplate(displayModelPrefab);
			ModelSkinController val5 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			Material val6 = new Material(nativeMaterial)
			{
				name = "matEclipseChefE2Crab"
			};
			val6.SetTexture("_MainTex", (Texture)(object)albedo);
			val6.SetColor("_Color", Color.white);
			val6.SetFloat("_NormalStrength", 0f);
			val6.SetFloat("_Smoothness", 0.16f);
			val6.SetFloat("_SpecularStrength", 0.15f);
			val6.SetFloat("_SpecularExponent", 8f);
			val6.SetFloat("_EmPower", 0f);
			val6.SetTexture("_EmTex", (Texture)(object)Texture2D.blackTexture);
			val6.DisableKeyword("FLOWMAP");
			val6.SetFloat("_FlowmapOn", 0f);
			val6.SetFloat("_FlowEmissionStrength", 0f);
			val6.DisableKeyword("FORCE_SPEC");
			val6.SetFloat("_ForceSpecOn", 0f);
			val6.DisableKeyword("LIMBREMOVAL");
			val6.SetFloat("_LimbRemovalOn", 0f);
			AdvancedSkinRegistry.Register(new AdvancedSkinDefinition
			{
				Mesh = mesh,
				Motion = bank,
				FallbackClip = "idle",
				AirTransitionSeconds = 0f,
				CreateEffects = (SkinnedMeshRenderer renderer) => (ISkinEffectDriver)(object)new CrabEffects(renderer),
				CreateMotionSource = (Animator animator, MotionBank motion) => (ISkinMotionSource)(object)new CrabMotion(animator, motion)
			});
			Mesh empty = new Mesh
			{
				name = "EclipseChefE2EmptyNativeVisuals"
			};
			empty.vertices = Array.Empty<Vector3>();
			empty.triangles = Array.Empty<int>();
			GameObject[] array = (GameObject[])(object)new GameObject[2] { modelPrefab, displayModelPrefab };
			foreach (GameObject model in array)
			{
				model.AddComponent<CrabNativeVisuals>().Configure(Exact(model, "meshChef"), mesh, empty, (from n in RendererNames.Skip(1)
					select Exact(model, n)).ToArray(), (from n in RendererNames.Skip(1)
					select fallbackMeshes[n]).ToArray());
			}
			info.defaultMaterial = val6;
			info.defaultMaterialAddress = new AssetReferenceT<Material>("");
			SkinDefParams val7 = ScriptableObject.CreateInstance<SkinDefParams>();
			val7.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { info };
			val7.meshReplacements = ((IEnumerable<string>)RendererNames).Select((Func<string, MeshReplacement>)((string n) => new MeshReplacement
			{
				renderer = (Renderer)(object)Exact(modelPrefab, n),
				mesh = ((n == "meshChef") ? mesh : empty),
				meshAddress = new AssetReferenceT<Mesh>("")
			})).ToArray();
			SkinDef val8 = ScriptableObject.CreateInstance<SkinDef>();
			((Object)val8).name = "EclipsePlaytestChefE2CrabRangoon";
			val8.nameToken = "ECLIPSE_PLAYTEST_CHEF_E2_CRAB_RANGOON";
			LanguageAPI.Add(val8.nameToken, "Crab Rangoon (Playtest)");
			val8.unlockableDef = null;
			val8.rootObject = modelPrefab;
			val8.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
			val8.skinDefParams = val7;
			val8.icon = baseSkin.icon;
			registration = AdvancedSkinApplications.Register(val8, mesh);
			val5.skins = (SkinDef[])(controller.skins = controller.skins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { val8 }).ToArray()).Clone();
			registered = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("CHEF_E2_REGISTERED revision=" + manifest.revision + " customBones=" + bank.Bones.Length + " unlocked=true audio=not_integrated items=uncalibrated gameplay=untested skills=authored_motion_native_effects_playtest"));
		}

		private void SyncDisplaySkins()
		{
			if (!registered)
			{
				return;
			}
			try
			{
				if (!Object.op_Implicit((Object)(object)displayModelPrefab))
				{
					throw new InvalidOperationException("Prepared crab display was destroyed");
				}
				PrepareTemplate(displayModelPrefab);
				ModelSkinController component = displayModelPrefab.GetComponent<ModelSkinController>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					throw new InvalidOperationException("Prepared crab display controller was removed");
				}
				component.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("CHEF_E2_DISPLAY_FAILED " + ex));
			}
		}

		private void OnDestroy()
		{
			CrabNativeEvents.Uninstall();
			RoR2Application.onLoad = (Action)Delegate.Remove(RoR2Application.onLoad, new Action(SyncDisplaySkins));
			MainMenuController.OnMainMenuInitialised -= SyncDisplaySkins;
			registration?.Dispose();
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}