Decompiled source of Engineer Skin Pack v0.1.1

BepInEx/plugins/Local-Eclipse_Engineer_Skins_Playtest/Local-Engineer_Mine_Surveyor_Playtest/EngineerMineSurveyor.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.Text;
using BepInEx;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerMineSurveyorPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e2", "Engineer - Mine Surveyor (Playtest)", "0.1.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerMineSurveyor : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	public sealed class MineSurveyorVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE2_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0062: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.prepared.Single((Prepared p) => p.BodyName == ((asset == "walker") ? "EngiWalkerTurretBody" : "EngiTurretBody")).Material;
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				if (!lobbyDirty)
				{
					return;
				}
				lobbyDirty = false;
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					if (val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
					else if (((Object)val).name.IndexOf("Mine", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						Saved saved = Save((Renderer)(object)val);
						saved.ChangeMaterial = true;
						((Renderer)val).sharedMaterials = instance.PaintMine(saved.Materials);
						saved.AssignedMaterials = ((Renderer)val).sharedMaterials;
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					if (((Object)val2).name == "EngiMineMesh")
					{
						Saved saved2 = Save((Renderer)(object)val2);
						saved2.ChangeMaterial = true;
						((Renderer)val2).sharedMaterials = instance.PaintMine(saved2.Materials);
						saved2.AssignedMaterials = ((Renderer)val2).sharedMaterials;
					}
				}
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component = ((Component)val7).GetComponent<Renderer>();
						Saved saved3 = Save(component);
						saved3.ChangeMesh = true;
						val7.sharedMesh = instance.WristMesh(asset);
						saved3.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

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

	public const string Version = "0.1.2";

	private static EngineerMineSurveyor instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("mine-surveyor", "Mine Surveyor (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)214, (byte)160, (byte)48, byte.MaxValue),
			new Color32((byte)223, (byte)211, (byte)175, byte.MaxValue),
			new Color32((byte)91, (byte)93, (byte)82, byte.MaxValue),
			new Color32((byte)47, (byte)53, (byte)49, byte.MaxValue)
		})
	};

	private GameObject cosmeticStorage;

	private Texture2D minePaint;

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

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

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

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

	[SystemInitializer(new Type[] { typeof(BodyCatalog) })]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			yield break;
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 45f;
		IEnumerator routine = instance.RegisterAsync();
		while (true)
		{
			bool flag;
			try
			{
				flag = routine.MoveNext();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E2_REGISTRATION_FAILED: " + ex));
				break;
			}
			if (!flag)
			{
				break;
			}
			yield return null;
		}
		(routine as IDisposable)?.Dispose();
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E2_REGISTRATION_BEGIN 0.1.2");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "mine-surveyor", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			IEnumerator routine = Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
			while (routine.MoveNext())
			{
				yield return null;
			}
		}
		Prepared bodySkin = prepared.Single((Prepared p) => p.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared p) => p.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared p) => p.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		IEnumerator ghostRoutine = PrepareMineGhosts(bodySkin.Skin);
		while (ghostRoutine.MoveNext())
		{
			yield return null;
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.Controller.skins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { item.Skin }).ToArray();
		}
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		registered = true;
		foreach (Prepared item2 in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item2.Model.GetComponent<MineSurveyorVisuals>()))
			{
				item2.Model.AddComponent<MineSurveyorVisuals>();
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E2_REGISTERED Mine Surveyor, both turret variants, unlocked=true version=0.1.2");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE2_" + assetName;
		Material val5 = new Material(val3)
		{
			name = "matEclipsePlaytest_EngineerE2_" + assetName
		};
		val5.SetTexture("_MainTex", (Texture)(object)ReadTexture("albedo-spec.png", linear: false));
		val5.SetTexture("_NormalTex", (Texture)(object)ReadTexture("normal.png", linear: true));
		val5.SetColor("_Color", Color.white);
		val5.SetFloat("_NormalStrength", 0.3f);
		val5.SetFloat("_Smoothness", 0.28f);
		val5.SetFloat("_SpecularStrength", 0.35f);
		val5.SetFloat("_SpecularExponent", 8f);
		val5.SetFloat("_EmPower", 0f);
		val5.SetTexture("_EmTex", (Texture)(object)Texture2D.blackTexture);
		val5.DisableKeyword("LIMBREMOVAL");
		val5.SetFloat("_LimbRemovalOn", 0f);
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE2_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E2_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Mine Surveyor (Playtest)" : ("Mine Surveyor " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller))
		{
			controller = model.AddComponent<ModelSkinController>();
			controller.skins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<MineSurveyorVisuals>()))
			{
				val.displayPrefab.AddComponent<MineSurveyorVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_DISPLAY_READY skins=" + val2.skins.Length));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_004b: Expected O, but got Unknown
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = name,
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		if (!ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(folder, name)), false))
		{
			throw new InvalidDataException("Cannot decode " + name);
		}
		return val;
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0400: Unknown result type (might be due to invalid IL or missing references)
		//IL_0405: Unknown result type (might be due to invalid IL or missing references)
		//IL_0410: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Unknown result type (might be due to invalid IL or missing references)
		//IL_042a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0432: Unknown result type (might be due to invalid IL or missing references)
		//IL_043a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0442: 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_0452: Unknown result type (might be due to invalid IL or missing references)
		//IL_0458: Unknown result type (might be due to invalid IL or missing references)
		//IL_0460: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		Mesh val3 = new Mesh
		{
			name = "EclipsePlaytestEngineerMineSurveyor",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val3.RecalculateBounds();
		val3.RecalculateTangents();
		return val3;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("MineSurveyorCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		minePaint = new Texture2D(2, 2, (TextureFormat)4, false);
		minePaint.SetPixels(Enumerable.Repeat<Color>(new Color(0.65f, 0.39f, 0.07f, 0.2f), 4).ToArray());
		minePaint.Apply();
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing mine projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseMineSurveyor_" + name + "Ghost";
			val2.SetActive(true);
			SkinnedMeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			foreach (SkinnedMeshRenderer val3 in componentsInChildren)
			{
				((Renderer)val3).sharedMaterials = PaintMine(((Renderer)val3).sharedMaterials);
			}
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Material[] PaintMine(Material[] sources)
	{
		return ((IEnumerable<Material>)sources).Select((Func<Material, Material>)delegate(Material src)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)src))
			{
				return src;
			}
			if (mineMaterials.TryGetValue(src, out var value))
			{
				return value;
			}
			value = new Material(src)
			{
				name = "MineSurveyorMine_" + ((Object)src).name
			};
			value.SetTexture("_MainTex", (Texture)(object)minePaint);
			value.SetColor("_Color", Color.white);
			value.SetFloat("_Smoothness", 0.25f);
			value.SetFloat("_SpecularStrength", 0.3f);
			mineMaterials.Add(src, value);
			return value;
		}).ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target)
	{
		string key = asset + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, target.sharedMesh);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private Mesh WristMesh(string asset)
	{
		//IL_007e: 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_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		if (wristMeshes.TryGetValue(asset, out var value))
		{
			return value;
		}
		Prepared prepared = this.prepared.Single((Prepared p) => p.BodyName == ((asset == "walker") ? "EngiWalkerTurretBody" : "EngiTurretBody"));
		prepared.Model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer x) => x.bones.Length == 15);
		Matrix4x4 val = ((Matrix4x4)(ref prepared.Reference.bindposes[0])).inverse * prepared.Mesh.bindposes[0];
		value = Object.Instantiate<Mesh>(prepared.Mesh);
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref val)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int num = 0; num < vertices.Length; num++)
		{
			vertices[num] = ((Matrix4x4)(ref val)).MultiplyPoint3x4(vertices[num]);
			int num2 = num;
			Vector3 val2 = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[num]);
			normals[num2] = ((Vector3)(ref val2)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.RecalculateBounds();
		value.RecalculateTangents();
		wristMeshes.Add(asset, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}

BepInEx/plugins/Local-Eclipse_Engineer_Skins_Playtest/Local-Engineer_Union_Builder_Playtest/EngineerUnionBuilder.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.Text;
using BepInEx;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerUnionBuilderPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e1", "Engineer - Union Builder (Playtest)", "0.2.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerUnionBuilder : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class UnionVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE1_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e1";

	public const string Version = "0.2.1";

	private static EngineerUnionBuilder instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<UnionVisuals> startupVisuals = new List<UnionVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("union-builder", "Union Builder (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)248, (byte)199, (byte)38, byte.MaxValue),
			new Color32((byte)177, (byte)67, (byte)49, byte.MaxValue),
			new Color32((byte)95, (byte)73, (byte)48, byte.MaxValue),
			new Color32((byte)52, (byte)62, (byte)62, byte.MaxValue)
		})
	};

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E1_STARTUP_DISABLED version=0.2.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E1_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E1_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_STARTUP_STAGE version=0.2.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (UnionVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Union Builder skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E1_REGISTRATION_BEGIN 0.2.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "union-builder", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<UnionVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<UnionVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E1_REGISTERED Union Builder body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.2.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE1_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE1_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E1_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Union Builder (Playtest)" : ("Union Builder " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E1_DISPLAY_SYNC_FAILED version=0.2.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<UnionVisuals>()))
			{
				val.displayPrefab.AddComponent<UnionVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_DISPLAY_READY version=0.2.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_004b: Expected O, but got Unknown
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = name,
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		if (!ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(folder, name)), false))
		{
			throw new InvalidDataException("Cannot decode " + name);
		}
		return val;
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerUnionBuilder",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE1_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("UnionBuilderCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseUnionBuilder_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E1_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE1Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Union Builder startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Union Builder startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-bubble-works/EngineerBubbleWorks.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 System.Text;
using BepInEx;
using EngineerTrafficControlPlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerBubbleWorksPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e6", "Engineer - Bubble Works (Playtest)", "0.3.1")]
[BepInDependency("eclipseplaytest.engineer.e5", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerBubbleWorks : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class BandVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE6_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e6";

	public const string Version = "0.3.1";

	private static EngineerBubbleWorks instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<BandVisuals> startupVisuals = new List<BandVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("bubble-works", "Bubble Works (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)245, (byte)198, (byte)33, byte.MaxValue),
			new Color32((byte)237, (byte)91, (byte)24, byte.MaxValue),
			new Color32((byte)45, (byte)135, (byte)181, byte.MaxValue),
			new Color32((byte)136, (byte)98, (byte)48, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerTrafficControl)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E6_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E6_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E6_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (BandVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Bubble Works skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E6_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "bubble-works", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<BandVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<BandVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E6_REGISTERED Bubble Works body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE6_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE6_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E6_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Bubble Works (Playtest)" : ("Bubble Works " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E6_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<BandVisuals>()))
			{
				val.displayPrefab.AddComponent<BandVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerBubbleWorks",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE6_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("BubbleWorksCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseBubbleWorks_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E6_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE6Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Bubble Works startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Bubble Works startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-castle-doctrine/EngineerCastleDoctrine.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 System.Text;
using BepInEx;
using EngineerOneManBandPlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerCastleDoctrinePlaytest;

[BepInPlugin("eclipseplaytest.engineer.e4", "Engineer - Castle Doctrine (Playtest)", "0.3.1")]
[BepInDependency("eclipseplaytest.engineer.e3", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerCastleDoctrine : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class BandVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE4_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e4";

	public const string Version = "0.3.1";

	private static EngineerCastleDoctrine instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<BandVisuals> startupVisuals = new List<BandVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("castle-doctrine", "Castle Doctrine (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)216, (byte)209, (byte)181, byte.MaxValue),
			new Color32((byte)141, (byte)43, (byte)38, byte.MaxValue),
			new Color32((byte)61, (byte)65, (byte)65, byte.MaxValue),
			new Color32((byte)161, (byte)143, (byte)95, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerOneManBand)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E4_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E4_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E4_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (BandVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Castle Doctrine skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E4_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "castle-doctrine", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<BandVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<BandVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E4_REGISTERED Castle Doctrine body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE4_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE4_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E4_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Castle Doctrine (Playtest)" : ("Castle Doctrine " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E4_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<BandVisuals>()))
			{
				val.displayPrefab.AddComponent<BandVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerCastleDoctrine",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE4_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("CastleDoctrineCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseCastleDoctrine_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E4_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE4Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Castle Doctrine startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Castle Doctrine startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-one-man-band/EngineerOneManBand.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 System.Text;
using BepInEx;
using EngineerUnqualifiedPersonnelPlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerOneManBandPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e3", "Engineer - One-Man Band (Playtest)", "0.3.1")]
[BepInDependency("rodanius.engineer.unqualifiedpersonnel", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerOneManBand : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class BandVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE3_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e3";

	public const string Version = "0.3.1";

	private static EngineerOneManBand instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<BandVisuals> startupVisuals = new List<BandVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("one-man-band", "One-Man Band (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)167, (byte)36, (byte)41, byte.MaxValue),
			new Color32((byte)220, (byte)178, (byte)75, byte.MaxValue),
			new Color32((byte)28, (byte)39, (byte)59, byte.MaxValue),
			new Color32((byte)235, (byte)225, (byte)200, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerUnqualifiedPersonnel)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E3_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E3_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E3_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (BandVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate One-Man Band skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E3_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "one-man-band", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<BandVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<BandVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E3_REGISTERED One-Man Band body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE3_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE3_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E3_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "One-Man Band (Playtest)" : ("One-Man Band " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E3_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<BandVisuals>()))
			{
				val.displayPrefab.AddComponent<BandVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerOneManBand",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE3_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("OneManBandCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseOneManBand_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E3_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE3Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("One-Man Band startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("One-Man Band startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-orbital-architect/EngineerOrbitalArchitect.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 System.Text;
using BepInEx;
using EngineerPrimitiveSolutionsPlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerOrbitalArchitectPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e8", "Engineer - Orbital Architect (Playtest)", "0.3.1")]
[BepInDependency("eclipseplaytest.engineer.e7", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerOrbitalArchitect : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class BandVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE8_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e8";

	public const string Version = "0.3.1";

	private static EngineerOrbitalArchitect instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<BandVisuals> startupVisuals = new List<BandVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("orbital-architect", "Orbital Architect (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)224, (byte)220, (byte)196, byte.MaxValue),
			new Color32((byte)28, (byte)114, (byte)126, byte.MaxValue),
			new Color32((byte)238, (byte)121, (byte)36, byte.MaxValue),
			new Color32((byte)61, (byte)204, (byte)219, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerPrimitiveSolutions)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E8_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E8_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E8_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (BandVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Orbital Architect skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E8_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "orbital-architect", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<BandVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<BandVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E8_REGISTERED Orbital Architect body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE8_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE8_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E8_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Orbital Architect (Playtest)" : ("Orbital Architect " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E8_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<BandVisuals>()))
			{
				val.displayPrefab.AddComponent<BandVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerOrbitalArchitect",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE8_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("OrbitalArchitectCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseOrbitalArchitect_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E8_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE8Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Orbital Architect startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Orbital Architect startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-primitive-solutions/EngineerPrimitiveSolutions.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 System.Text;
using BepInEx;
using EngineerBubbleWorksPlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerPrimitiveSolutionsPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e7", "Engineer - Primitive Solutions (Playtest)", "0.3.1")]
[BepInDependency("eclipseplaytest.engineer.e6", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerPrimitiveSolutions : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class BandVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE7_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e7";

	public const string Version = "0.3.1";

	private static EngineerPrimitiveSolutions instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<BandVisuals> startupVisuals = new List<BandVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("primitive-solutions", "Primitive Solutions (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)145, (byte)99, (byte)57, byte.MaxValue),
			new Color32((byte)84, (byte)64, (byte)42, byte.MaxValue),
			new Color32((byte)169, (byte)163, (byte)147, byte.MaxValue),
			new Color32((byte)218, (byte)204, (byte)169, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerBubbleWorks)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E7_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E7_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E7_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (BandVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Primitive Solutions skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E7_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "primitive-solutions", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<BandVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<BandVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E7_REGISTERED Primitive Solutions body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE7_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE7_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E7_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Primitive Solutions (Playtest)" : ("Primitive Solutions " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E7_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<BandVisuals>()))
			{
				val.displayPrefab.AddComponent<BandVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerPrimitiveSolutions",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE7_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("PrimitiveSolutionsCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipsePrimitiveSolutions_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E7_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE7Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Primitive Solutions startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Primitive Solutions startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-traffic-control/EngineerTrafficControl.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 System.Text;
using BepInEx;
using EngineerCastleDoctrinePlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerTrafficControlPlaytest;

[BepInPlugin("eclipseplaytest.engineer.e5", "Engineer - Traffic Control (Playtest)", "0.3.1")]
[BepInDependency("eclipseplaytest.engineer.e4", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerTrafficControl : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class BandVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return ((Object)controller.skins[currentSkinIndex]).name.StartsWith("skinEclipsePlaytestEngineerE5_", StringComparison.Ordinal);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "eclipseplaytest.engineer.e5";

	public const string Version = "0.3.1";

	private static EngineerTrafficControl instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<BandVisuals> startupVisuals = new List<BandVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("traffic-control", "Traffic Control (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)240, (byte)101, (byte)24, byte.MaxValue),
			new Color32((byte)238, (byte)234, (byte)209, byte.MaxValue),
			new Color32((byte)40, (byte)44, (byte)46, byte.MaxValue),
			new Color32((byte)239, (byte)184, (byte)38, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerCastleDoctrine)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E5_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E5_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E5_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (BandVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Traffic Control skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E5_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "traffic-control", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<BandVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<BandVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E5_REGISTERED Traffic Control body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE5_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinEclipsePlaytestEngineerE5_" + assetName;
		val7.nameToken = "ECLIPSEPLAYTEST_ENGINEER_E5_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Traffic Control (Playtest)" : ("Traffic Control " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E5_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<BandVisuals>()))
			{
				val.displayPrefab.AddComponent<BandVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerTrafficControl",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE5_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("TrafficControlCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseTrafficControl_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E5_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE5Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Traffic Control startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Traffic Control startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}

BepInEx/plugins/RodaniusSkins/engineer-unqualified-personnel/EngineerUnqualifiedPersonnel.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 System.Text;
using BepInEx;
using EngineerUnionBuilderPlaytest;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using HG.Reflection;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Projectile;
using RoR2.UI.MainMenu;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
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 EngineerUnqualifiedPersonnelPlaytest;

[BepInPlugin("rodanius.engineer.unqualifiedpersonnel", "Engineer - Unqualified Personnel (Playtest)", "0.3.1")]
[BepInDependency("eclipseplaytest.engineer.e1", "0.2.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class EngineerUnqualifiedPersonnel : BaseUnityPlugin
{
	private sealed class Prepared
	{
		public SkinDef[] OriginalSkins;

		public SkinDef[] CommittedSkins;

		public string BodyName;

		public GameObject Model;

		public ModelSkinController Controller;

		public SkinDef Skin;

		public Mesh Mesh;

		public Mesh Reference;

		public Material Material;
	}

	private sealed class Design
	{
		public string Slug;

		public string Name;

		public Color32[] Colors;

		public Design(string slug, string name, Color32[] colors)
		{
			Slug = slug;
			Name = name;
			Colors = colors;
		}
	}

	private sealed class MeshBasis
	{
		public Mesh Reference;

		public Mesh Authored;
	}

	public sealed class PersonnelVisuals : MonoBehaviour
	{
		private sealed class Saved
		{
			public Renderer Renderer;

			public Mesh Mesh;

			public Material[] Materials;

			public Bounds Bounds;

			public bool Offscreen;

			public bool ChangeMesh;

			public bool ChangeMaterial;

			public Mesh AssignedMesh;

			public Material[] AssignedMaterials;

			public bool ChangeBounds;

			public Bounds AssignedBounds;

			public bool ChangeOffscreen;

			public bool AssignedOffscreen;
		}

		private readonly Dictionary<Renderer, Saved> changed = new Dictionary<Renderer, Saved>();

		private ModelSkinController controller;

		private CharacterBody body;

		private EntityStateMachine[] machines;

		private bool lobbyDirty = true;

		private static readonly FieldInfo Blueprint = typeof(PlaceTurret).GetField("blueprints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Wrist = typeof(PlaceTurret).GetField("wristDisplayObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Applied(int index)
		{
			if (!OwnSkin() && changed.Count > 0)
			{
				Restore();
			}
			lobbyDirty = true;
		}

		private void Start()
		{
			controller = ((Component)this).GetComponentInChildren<ModelSkinController>(true);
			body = ((Component)this).GetComponentInParent<CharacterBody>();
			machines = (EntityStateMachine[])(Object.op_Implicit((Object)(object)body) ? ((Array)((Component)body).GetComponents<EntityStateMachine>()) : ((Array)new EntityStateMachine[0]));
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied += Applied;
			}
		}

		private bool OwnSkin()
		{
			if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
			{
				return false;
			}
			int currentSkinIndex = controller.currentSkinIndex;
			if (currentSkinIndex >= 0 && currentSkinIndex < controller.skins.Length && Object.op_Implicit((Object)(object)controller.skins[currentSkinIndex]))
			{
				return SkinIdentity.Owns(((Object)controller.skins[currentSkinIndex]).name);
			}
			return false;
		}

		private Saved Save(Renderer r)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (changed.TryGetValue(r, out var value))
			{
				return value;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			value = new Saved
			{
				Renderer = r,
				Materials = r.sharedMaterials,
				Mesh = (Object.op_Implicit((Object)(object)val) ? val.sharedMesh : (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null)),
				Bounds = (Bounds)(Object.op_Implicit((Object)(object)val) ? ((Renderer)val).localBounds : default(Bounds)),
				Offscreen = (Object.op_Implicit((Object)(object)val) && val.updateWhenOffscreen)
			};
			changed.Add(r, value);
			return value;
		}

		private void ApplySkinned(SkinnedMeshRenderer r, string asset, bool keepMaterial)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Saved saved = Save((Renderer)(object)r);
			saved.ChangeMesh = true;
			saved.ChangeMaterial = !keepMaterial;
			Mesh val = (saved.AssignedMesh = instance.MeshFor(asset, r, saved.Mesh));
			if ((Object)(object)r.sharedMesh != (Object)(object)val)
			{
				r.sharedMesh = val;
				Mesh val2 = new Mesh();
				r.BakeMesh(val2);
				Bounds bounds = saved.Bounds;
				Bounds bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).min);
				bounds2 = val2.bounds;
				((Bounds)(ref bounds)).Encapsulate(((Bounds)(ref bounds2)).max);
				((Bounds)(ref bounds)).Expand(((Bounds)(ref bounds)).size * 0.5f);
				((Renderer)r).localBounds = bounds;
				saved.ChangeBounds = true;
				saved.AssignedBounds = bounds;
				Object.Destroy((Object)(object)val2);
			}
			r.updateWhenOffscreen = true;
			saved.ChangeOffscreen = true;
			saved.AssignedOffscreen = true;
			if (!keepMaterial)
			{
				((Renderer)r).sharedMaterial = instance.assetMaterials[asset];
				saved.AssignedMaterials = ((Renderer)r).sharedMaterials;
			}
		}

		private void Restore()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Saved value in changed.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.Renderer))
				{
					continue;
				}
				Renderer renderer = value.Renderer;
				SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
				MeshFilter component = ((Component)value.Renderer).GetComponent<MeshFilter>();
				if (Object.op_Implicit((Object)(object)val))
				{
					if (value.ChangeMesh && (Object)(object)val.sharedMesh == (Object)(object)value.AssignedMesh)
					{
						if (value.ChangeBounds && ((Renderer)val).localBounds == value.AssignedBounds)
						{
							((Renderer)val).localBounds = value.Bounds;
						}
						if (value.ChangeOffscreen && val.updateWhenOffscreen == value.AssignedOffscreen)
						{
							val.updateWhenOffscreen = value.Offscreen;
						}
						val.sharedMesh = value.Mesh;
					}
				}
				else if (Object.op_Implicit((Object)(object)component) && value.ChangeMesh && (Object)(object)component.sharedMesh == (Object)(object)value.AssignedMesh)
				{
					component.sharedMesh = value.Mesh;
				}
				if (value.ChangeMaterial && value.AssignedMaterials != null && value.Renderer.sharedMaterials.SequenceEqual(value.AssignedMaterials))
				{
					value.Renderer.sharedMaterials = value.Materials;
				}
			}
			changed.Clear();
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)instance) || !instance.registered)
			{
				return;
			}
			Renderer[] array = changed.Keys.Where((Renderer r) => !Object.op_Implicit((Object)(object)r)).ToArray();
			foreach (Renderer key in array)
			{
				changed.Remove(key);
			}
			if (!OwnSkin())
			{
				if (changed.Count > 0)
				{
					Restore();
				}
				lobbyDirty = true;
				return;
			}
			if (lobbyDirty)
			{
				SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val in componentsInChildren)
				{
					string text = MineAsset((Renderer)(object)val);
					if (text != null)
					{
						ApplySkinned(val, text, keepMaterial: false);
					}
					else if (!Object.op_Implicit((Object)(object)body) && val.bones.Length == 15 && Object.op_Implicit((Object)(object)((Component)this).transform.Find("TurretHolder")) && ((Component)val).transform.IsChildOf(((Component)this).transform.Find("TurretHolder")))
					{
						ApplySkinned(val, "turret", keepMaterial: false);
					}
				}
				MeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					string text2 = MineAsset((Renderer)(object)val2);
					if (text2 != null)
					{
						MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Saved saved = Save((Renderer)(object)val2);
							saved.ChangeMesh = true;
							component.sharedMesh = instance.StaticMeshFor(text2, saved.Mesh);
							saved.AssignedMesh = component.sharedMesh;
							saved.ChangeMaterial = true;
							((Renderer)val2).sharedMaterial = instance.assetMaterials[text2];
							saved.AssignedMaterials = ((Renderer)val2).sharedMaterials;
						}
					}
				}
				lobbyDirty = false;
			}
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			EntityStateMachine[] array2 = machines;
			for (int num = 0; num < array2.Length; num++)
			{
				EntityState state = array2[num].state;
				PlaceTurret val3 = (PlaceTurret)(object)((state is PlaceTurret) ? state : null);
				if (val3 == null)
				{
					continue;
				}
				string asset = ((val3 is PlaceWalkerTurret) ? "walker" : "turret");
				object? obj = Blueprint?.GetValue(val3);
				BlueprintController val4 = (BlueprintController)((obj is BlueprintController) ? obj : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					SkinnedMeshRenderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<SkinnedMeshRenderer>(true);
					foreach (SkinnedMeshRenderer val5 in componentsInChildren)
					{
						if (val5.bones.Length == 15)
						{
							ApplySkinned(val5, asset, keepMaterial: true);
						}
					}
				}
				object? obj2 = Wrist?.GetValue(val3);
				GameObject val6 = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					continue;
				}
				MeshFilter[] componentsInChildren3 = val6.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren3)
				{
					if (((Object)val7).name == "EngiTurretMesh")
					{
						Renderer component2 = ((Component)val7).GetComponent<Renderer>();
						Saved saved2 = Save(component2);
						saved2.ChangeMesh = true;
						val7.sharedMesh = instance.StaticMeshFor(asset, saved2.Mesh);
						saved2.AssignedMesh = val7.sharedMesh;
					}
				}
			}
		}

		private void OnDisable()
		{
			Restore();
			lobbyDirty = true;
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.onSkinApplied -= Applied;
			}
		}
	}

	public const string Guid = "rodanius.engineer.unqualifiedpersonnel";

	public const string Version = "0.3.1";

	private static EngineerUnqualifiedPersonnel instance;

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

	private float registrationDeadline;

	private string folder;

	private SkinDef skin;

	private GameObject modelPrefab;

	private string startupStage = "awake";

	private readonly List<PersonnelVisuals> startupVisuals = new List<PersonnelVisuals>();

	private readonly List<Prepared> prepared = new List<Prepared>();

	private bool registered;

	private static readonly Design[] Designs = new Design[1]
	{
		new Design("unqualified-personnel", "Unqualified Personnel (Playtest)", (Color32[])(object)new Color32[4]
		{
			new Color32((byte)45, (byte)125, (byte)132, byte.MaxValue),
			new Color32((byte)231, (byte)226, (byte)207, byte.MaxValue),
			new Color32((byte)68, (byte)116, (byte)154, byte.MaxValue),
			new Color32((byte)172, (byte)61, (byte)52, byte.MaxValue)
		})
	};

	private readonly TextureAssetCache textureCache = new TextureAssetCache();

	private GameObject cosmeticStorage;

	private readonly Dictionary<string, MeshBasis> canonicalBases = new Dictionary<string, MeshBasis>();

	private readonly Dictionary<string, Material> assetMaterials = new Dictionary<string, Material>();

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

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

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

	[SystemInitializer(new Type[]
	{
		typeof(BodyCatalog),
		typeof(ProjectileCatalog),
		typeof(SurvivorCatalog),
		typeof(EngineerUnionBuilder)
	})]
	private static IEnumerator InitializeSkin()
	{
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return EmptyStartup();
		}
		instance.registrationDeadline = Time.realtimeSinceStartup + 60f;
		return StartupGuard.Run(instance.RegisterAsync, () => Time.realtimeSinceStartup > instance.registrationDeadline, delegate(Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E2_STARTUP_DISABLED version=0.3.1 stage=" + instance.startupStage + " " + ex));
			try
			{
				instance.RollbackRegistration();
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"ENGINEER_E2_ROLLBACK_OK existing skin arrays retained.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)instance).Logger.LogError((object)("ENGINEER_E2_ROLLBACK_FAILED " + ex2));
			}
		});
	}

	private static IEnumerator EmptyStartup()
	{
		yield break;
	}

	private void Stage(string value)
	{
		startupStage = value;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_STARTUP_STAGE version=0.3.1 stage=" + value));
	}

	private void RollbackRegistration()
	{
		registered = false;
		foreach (Prepared item in prepared)
		{
			if (Object.op_Implicit((Object)(object)item.Controller) && item.CommittedSkins != null && item.Controller.skins == item.CommittedSkins)
			{
				item.Controller.skins = item.OriginalSkins;
			}
		}
		foreach (PersonnelVisuals startupVisual in startupVisuals)
		{
			if (Object.op_Implicit((Object)(object)startupVisual))
			{
				Object.Destroy((Object)(object)startupVisual);
			}
		}
		startupVisuals.Clear();
		if (Object.op_Implicit((Object)(object)cosmeticStorage))
		{
			Object.Destroy((Object)(object)cosmeticStorage);
			cosmeticStorage = null;
		}
	}

	private void ValidateAndCommit()
	{
		foreach (Prepared p in prepared)
		{
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Private bake produced no runtime skin: " + p.BodyName);
			}
			if (p.Controller.skins != p.OriginalSkins)
			{
				throw new InvalidOperationException("Skin list changed during startup: " + p.BodyName);
			}
			if (p.OriginalSkins.Any((SkinDef s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == ((Object)p.Skin).name))
			{
				throw new InvalidOperationException("Duplicate Unqualified Personnel skin: " + ((Object)p.Skin).name);
			}
			p.CommittedSkins = p.OriginalSkins.Concat((IEnumerable<SkinDef>)(object)new SkinDef[1] { p.Skin }).ToArray();
		}
		foreach (Prepared item in prepared)
		{
			item.Controller.skins = item.CommittedSkins;
		}
	}

	private IEnumerator RegisterAsync()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E2_REGISTRATION_BEGIN 0.3.1");
		string[][] array = new string[3][]
		{
			new string[4] { "EngiTurretBody", "turret", "15", "skinEngiTurretDefault" },
			new string[4] { "EngiWalkerTurretBody", "walker", "15", "skinEngiWalkerTurretDefault" },
			new string[4] { "EngiBody", "unqualified-personnel", "83", "skinEngiDefault" }
		};
		foreach (string[] array2 in array)
		{
			Stage("prepare:" + array2[0]);
			yield return Prepare(array2[0], array2[1], int.Parse(array2[2]), array2[3]);
		}
		Prepared bodySkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiBody");
		bodySkin.Skin.skinDefParams.minionSkinReplacements = (MinionSkinReplacement[])(object)new MinionSkinReplacement[2]
		{
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiTurretBody").Skin
			},
			new MinionSkinReplacement
			{
				minionBodyPrefab = BodyCatalog.FindBodyPrefab("EngiWalkerTurretBody"),
				minionSkin = prepared.Single((Prepared prepared) => prepared.BodyName == "EngiWalkerTurretBody").Skin
			}
		};
		Stage("prepare:mine-ghosts");
		yield return PrepareMineGhosts(bodySkin.Skin);
		foreach (Prepared p in prepared)
		{
			Stage("private-bake:" + p.BodyName);
			ValidateSkin(p);
			yield return p.Skin.BakeAsync();
			if (p.Skin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Bake returned without runtime skin: " + p.BodyName);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_PRIVATE_BAKE_OK body=" + p.BodyName));
		}
		Stage("commit");
		ValidateAndCommit();
		modelPrefab = bodySkin.Model;
		skin = bodySkin.Skin;
		foreach (Prepared item in prepared)
		{
			if (!Object.op_Implicit((Object)(object)item.Model.GetComponent<PersonnelVisuals>()))
			{
				startupVisuals.Add(item.Model.AddComponent<PersonnelVisuals>());
			}
		}
		registered = true;
		Stage("registered");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ENGINEER_E2_REGISTERED Unqualified Personnel body, both turrets, pressure and spider mines; native Animator retained; unlocked=true version=0.3.1");
	}

	private IEnumerator Prepare(string bodyName, string assetName, int boneCount, string defaultName)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Missing body " + bodyName);
		}
		GameObject model = ((Component)val.GetComponent<ModelLocator>().modelTransform).gameObject;
		ModelSkinController controller = model.GetComponent<ModelSkinController>();
		SkinDef baseSkin = null;
		if (Object.op_Implicit((Object)(object)controller) && controller.skins != null && controller.skins.Length != 0)
		{
			baseSkin = controller.skins[0];
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			AsyncOperationHandle<SkinDef> h = Addressables.LoadAssetAsync<SkinDef>((object)("RoR2/Base/Engi/" + defaultName + ".asset"));
			retainedAssets.Add(AsyncOperationHandle<SkinDef>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline("default skin " + bodyName);
				yield return null;
			}
			baseSkin = h.Result;
		}
		if (!Object.op_Implicit((Object)(object)baseSkin))
		{
			throw new InvalidOperationException("Missing default skin " + bodyName);
		}
		SkinDefParams bp = baseSkin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)bp) && baseSkin.skinDefParamsAddress != null && ((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<SkinDefParams> h2 = Addressables.LoadAssetAsync<SkinDefParams>(((AssetReference)baseSkin.skinDefParamsAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<SkinDefParams>.op_Implicit(h2));
			while (!h2.IsDone)
			{
				CheckLoadDeadline("parameters " + bodyName);
				yield return null;
			}
			bp = h2.Result;
		}
		if (!Object.op_Implicit((Object)(object)bp))
		{
			throw new InvalidOperationException("Missing parameters " + bodyName);
		}
		SkinnedMeshRenderer target = model.GetComponentsInChildren<SkinnedMeshRenderer>(true).Single((SkinnedMeshRenderer r) => r.bones.Length == boneCount);
		Mesh reference = target.sharedMesh;
		if (!Object.op_Implicit((Object)(object)reference))
		{
			MeshReplacement val2 = bp.meshReplacements.First((MeshReplacement r) => (Object)(object)r.renderer == (Object)(object)target);
			reference = val2.mesh;
			if (!Object.op_Implicit((Object)(object)reference))
			{
				AsyncOperationHandle<Mesh> h3 = Addressables.LoadAssetAsync<Mesh>(((AssetReference)val2.meshAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<Mesh>.op_Implicit(h3));
				while (!h3.IsDone)
				{
					CheckLoadDeadline("mesh " + bodyName);
					yield return null;
				}
				reference = h3.Result;
			}
		}
		if (!Object.op_Implicit((Object)(object)reference) || reference.bindposes.Length != target.bones.Length)
		{
			throw new InvalidOperationException("Bind pose mismatch " + bodyName);
		}
		RendererInfo ri = bp.rendererInfos.First((RendererInfo r) => (Object)(object)r.renderer == (Object)(object)target);
		Material val3 = ri.defaultMaterial;
		if (!Object.op_Implicit((Object)(object)val3) && ri.defaultMaterialAddress != null && ((AssetReference)ri.defaultMaterialAddress).RuntimeKeyIsValid())
		{
			AsyncOperationHandle<Material> h4 = Addressables.LoadAssetAsync<Material>(((AssetReference)ri.defaultMaterialAddress).RuntimeKey);
			retainedAssets.Add(AsyncOperationHandle<Material>.op_Implicit(h4));
			while (!h4.IsDone)
			{
				CheckLoadDeadline("material " + bodyName);
				yield return null;
			}
			val3 = h4.Result;
		}
		if (!Object.op_Implicit((Object)(object)val3))
		{
			val3 = ((Renderer)target).sharedMaterial;
		}
		if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader))
		{
			throw new InvalidOperationException("Missing native material " + bodyName);
		}
		Mesh val4 = ReadMesh(Path.Combine(folder, assetName + ".meshbin"), target, reference);
		((Object)val4).name = "EclipsePlaytest_EngineerE2_" + assetName;
		Material val5 = MakeMaterial(assetName, val3);
		canonicalBases[assetName] = new MeshBasis
		{
			Reference = reference,
			Authored = val4
		};
		ri.defaultMaterial = val5;
		ri.defaultMaterialAddress = new AssetReferenceT<Material>("");
		SkinDefParams val6 = ScriptableObject.CreateInstance<SkinDefParams>();
		val6.rendererInfos = (RendererInfo[])(object)new RendererInfo[1] { ri };
		val6.meshReplacements = (MeshReplacement[])(object)new MeshReplacement[1]
		{
			new MeshReplacement
			{
				renderer = (Renderer)(object)target,
				mesh = val4,
				meshAddress = new AssetReferenceT<Mesh>("")
			}
		};
		SkinDef val7 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val7).name = "skinRodaniusEngineerUnqualifiedPersonnel_" + assetName;
		val7.nameToken = "RODANIUS_ENGINEER_UNQUALIFIED_PERSONNEL_" + assetName.ToUpperInvariant().Replace('-', '_');
		LanguageAPI.Add(val7.nameToken, (bodyName == "EngiBody") ? "Unqualified Personnel (Playtest)" : ("Unqualified Personnel " + assetName));
		val7.icon = CreateIcon(Designs[0].Colors);
		val7.unlockableDef = null;
		val7.rootObject = model;
		val7.baseSkins = (SkinDef[])(object)new SkinDef[1] { baseSkin };
		val7.skinDefParams = val6;
		if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null)
		{
			throw new InvalidOperationException("Missing native skin controller/list: " + bodyName);
		}
		prepared.Add(new Prepared
		{
			BodyName = bodyName,
			Model = model,
			Controller = controller,
			Skin = val7,
			Mesh = val4,
			Reference = reference,
			Material = val5,
			OriginalSkins = controller.skins
		});
		((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_PREPARED body=" + bodyName + " vertices=" + val4.vertexCount + " unlocked=true"));
	}

	private static void ValidateSkin(Prepared p)
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		SkinDef skin = p.Skin;
		SkinDefParams skinDefParams = skin.skinDefParams;
		if (!Object.op_Implicit((Object)(object)skin.rootObject) || !Object.op_Implicit((Object)(object)skinDefParams) || skin.baseSkins == null || skin.baseSkins.Any((SkinDef s) => !Object.op_Implicit((Object)(object)s) || s == skin))
		{
			throw new InvalidOperationException("Invalid skin graph: " + p.BodyName);
		}
		if (skin.skinDefParamsAddress == null)
		{
			skin.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		}
		if (skinDefParams.rendererInfos == null || skinDefParams.meshReplacements == null || skinDefParams.gameObjectActivations == null || skinDefParams.lightReplacements == null || skinDefParams.projectileGhostReplacements == null || skinDefParams.minionSkinReplacements == null)
		{
			throw new InvalidOperationException("Null parameter collection: " + p.BodyName);
		}
		RendererInfo[] rendererInfos = skinDefParams.rendererInfos;
		foreach (RendererInfo val in rendererInfos)
		{
			if (!Object.op_Implicit((Object)(object)val.renderer) || !Object.op_Implicit((Object)(object)val.defaultMaterial) || !((Component)val.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid material/renderer root: " + p.BodyName);
			}
		}
		MeshReplacement[] meshReplacements = skinDefParams.meshReplacements;
		foreach (MeshReplacement val2 in meshReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val2.renderer) || !Object.op_Implicit((Object)(object)val2.mesh) || !((Component)val2.renderer).transform.IsChildOf(skin.rootObject.transform))
			{
				throw new InvalidOperationException("Invalid mesh/renderer root: " + p.BodyName);
			}
		}
		ProjectileGhostReplacement[] projectileGhostReplacements = skinDefParams.projectileGhostReplacements;
		foreach (ProjectileGhostReplacement val3 in projectileGhostReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val3.projectilePrefab) || !Object.op_Implicit((Object)(object)val3.projectileGhostReplacementPrefab) || ProjectileCatalog.GetProjectileIndex(val3.projectilePrefab) < 0)
			{
				throw new InvalidOperationException("Unregistered mine projectile: " + p.BodyName);
			}
		}
		MinionSkinReplacement[] minionSkinReplacements = skinDefParams.minionSkinReplacements;
		foreach (MinionSkinReplacement val4 in minionSkinReplacements)
		{
			if (!Object.op_Implicit((Object)(object)val4.minionBodyPrefab) || !Object.op_Implicit((Object)(object)val4.minionSkin) || val4.minionSkin.runtimeSkin == null)
			{
				throw new InvalidOperationException("Unbaked turret skin: " + p.BodyName);
			}
		}
	}

	private static Sprite CreateIcon(Color32[] colors)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				int num = ((i > j) ? ((i <= 63 - j) ? 1 : 0) : ((i > 63 - j) ? 2 : 3));
				array[i * 64 + j] = (Color32)((j < 2 || j > 61 || i < 2 || i > 61 || Math.Abs(i - j) < 2 || Math.Abs(i - (63 - j)) < 2) ? new Color32((byte)48, (byte)48, (byte)48, byte.MaxValue) : colors[num]);
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
	}

	private void CheckLoadDeadline(string asset)
	{
		if (Time.realtimeSinceStartup > registrationDeadline)
		{
			throw new TimeoutException("Stopped loading " + asset + "; continuing startup without the skin.");
		}
	}

	private void SyncDisplaySkins()
	{
		if (!registered)
		{
			return;
		}
		try
		{
			SyncDisplaySkinsChecked();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("ENGINEER_E2_DISPLAY_SYNC_FAILED version=0.3.1 " + ex));
		}
	}

	private void SyncDisplaySkinsChecked()
	{
		SurvivorDef val = SurvivorCatalog.allSurvivorDefs.FirstOrDefault((Func<SurvivorDef, bool>)((SurvivorDef s) => Object.op_Implicit((Object)(object)s) && Object.op_Implicit((Object)(object)s.bodyPrefab) && ((Object)s.bodyPrefab).name == "EngiBody"));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.displayPrefab))
		{
			return;
		}
		CharacterModel componentInChildren = val.displayPrefab.GetComponentInChildren<CharacterModel>(true);
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			ModelSkinController val2 = ((Component)componentInChildren).GetComponent<ModelSkinController>() ?? ((Component)componentInChildren).gameObject.AddComponent<ModelSkinController>();
			val2.skins = (SkinDef[])modelPrefab.GetComponent<ModelSkinController>().skins.Clone();
			if (!Object.op_Implicit((Object)(object)val.displayPrefab.GetComponent<PersonnelVisuals>()))
			{
				val.displayPrefab.AddComponent<PersonnelVisuals>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_DISPLAY_READY version=0.3.1 skins=" + val2.skins.Length + " catalogSkins=" + SkinCatalog.skinCount));
		}
	}

	private Texture2D ReadTexture(string name, bool linear)
	{
		return textureCache.Load(Path.Combine(folder, name), linear);
	}

	private Mesh ReadMesh(string path, SkinnedMeshRenderer renderer, Mesh reference)
	{
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f2: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0512: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_051b: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_054a: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0558: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
		if (new string(binaryReader.ReadChars(4)) != "PWE2")
		{
			throw new InvalidDataException("Invalid mesh signature.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num < 3 || num > 200000 || num2 < 3 || num2 > 1200000 || num2 % 3 != 0 || num3 != renderer.bones.Length)
		{
			throw new InvalidDataException("Invalid mesh dimensions.");
		}
		int[] array = new int[num3];
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < num3; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 128)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			string name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num4));
			array[i] = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == name);
			if (array[i] < 0 || !hashSet.Add(array[i]))
			{
				throw new InvalidDataException("Missing/duplicate reference bone: " + name);
			}
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num3];
		for (int num5 = 0; num5 < num3; num5++)
		{
			Matrix4x4 val = default(Matrix4x4);
			for (int num6 = 0; num6 < 4; num6++)
			{
				for (int num7 = 0; num7 < 4; num7++)
				{
					float num8 = binaryReader.ReadSingle();
					if (float.IsNaN(num8) || float.IsInfinity(num8))
					{
						throw new InvalidDataException("Invalid bind matrix.");
					}
					((Matrix4x4)(ref val))[num6, num7] = num8;
				}
			}
			if (Math.Abs(((Matrix4x4)(ref val)).determinant) < 1E-05f)
			{
				throw new InvalidDataException("Singular bind matrix.");
			}
			array2[array[num5]] = val;
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num];
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num];
		for (int num9 = 0; num9 < num; num9++)
		{
			array3[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array4[num9] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			array5[num9] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			int[] array7 = new int[4];
			for (int num10 = 0; num10 < 4; num10++)
			{
				int num11 = binaryReader.ReadInt32();
				if (num11 < 0 || num11 >= num3)
				{
					throw new InvalidDataException("Bone out of range.");
				}
				array7[num10] = array[num11];
			}
			float[] array8 = new float[4];
			for (int num12 = 0; num12 < 4; num12++)
			{
				array8[num12] = binaryReader.ReadSingle();
			}
			if (array8.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f) || Math.Abs(array8.Sum() - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weight.");
			}
			if (!Finite(array3[num9]) || !Finite(array4[num9]))
			{
				throw new InvalidDataException("Non-finite vertex.");
			}
			int num13 = num9;
			BoneWeight val2 = default(BoneWeight);
			((BoneWeight)(ref val2)).boneIndex0 = array7[0];
			((BoneWeight)(ref val2)).boneIndex1 = array7[1];
			((BoneWeight)(ref val2)).boneIndex2 = array7[2];
			((BoneWeight)(ref val2)).boneIndex3 = array7[3];
			((BoneWeight)(ref val2)).weight0 = array8[0];
			((BoneWeight)(ref val2)).weight1 = array8[1];
			((BoneWeight)(ref val2)).weight2 = array8[2];
			((BoneWeight)(ref val2)).weight3 = array8[3];
			array6[num13] = val2;
		}
		int[] array9 = new int[num2];
		for (int num14 = 0; num14 < num2; num14++)
		{
			array9[num14] = binaryReader.ReadInt32();
			if (array9[num14] < 0 || array9[num14] >= num)
			{
				throw new InvalidDataException("Triangle out of range.");
			}
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Unexpected trailing mesh data.");
		}
		if (Object.op_Implicit((Object)(object)reference) && reference.bindposes.Length == num3)
		{
			Matrix4x4[] bindposes = reference.bindposes;
			int num15 = Array.FindIndex(renderer.bones, (Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Base");
			if (num15 < 0)
			{
				num15 = 0;
			}
			Matrix4x4 b = ((Matrix4x4)(ref bindposes[num15])).inverse * array2[num15];
			bool flag = true;
			for (int num16 = 0; num16 < num3; num16++)
			{
				if (!SameMatrix(((Matrix4x4)(ref bindposes[num16])).inverse * array2[num16], b, 0.0002f))
				{
					flag = false;
				}
			}
			if (!flag)
			{
				if (num3 != 2 && (num3 != 14 || !renderer.bones.Any((Transform t) => Object.op_Implicit((Object)(object)t) && ((Object)t).name == "Screw")))
				{
					throw new InvalidDataException("Unsupported nonuniform bind variant: " + ((Object)renderer).name);
				}
				Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
				Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
				for (int num17 = 0; num17 < num; num17++)
				{
					array3[num17] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(array3[num17]);
					int num18 = num17;
					Vector3 val3 = ((Matrix4x4)(ref transpose)).MultiplyVector(array4[num17]);
					array4[num18] = ((Vector3)(ref val3)).normalized;
				}
				array2 = bindposes;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_MINE_BIND_VARIANT renderer=" + ((Object)renderer).name + " reference=" + ((Object)reference).name));
			}
		}
		Mesh val4 = new Mesh
		{
			name = "EclipsePlaytestEngineerUnqualifiedPersonnel",
			indexFormat = (IndexFormat)(num > 65535),
			vertices = array3,
			normals = array4,
			uv = array5,
			boneWeights = array6,
			bindposes = array2,
			triangles = array9
		};
		val4.RecalculateBounds();
		val4.RecalculateTangents();
		return val4;
	}

	private Material MakeMaterial(string asset, Material source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (assetMaterials.TryGetValue(asset, out var value))
		{
			return value;
		}
		if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader))
		{
			throw new InvalidOperationException("Missing shader for " + asset);
		}
		value = new Material(source)
		{
			name = "matEclipsePlaytest_EngineerE2_" + asset
		};
		value.SetTexture("_MainTex", (Texture)(object)ReadTexture(asset + "-albedo-spec.png", linear: false));
		value.SetTexture("_NormalTex", (Texture)(object)ReadTexture(asset + "-normal.png", linear: true));
		value.SetTexture("_EmTex", (Texture)(object)ReadTexture(asset + "-emission.png", linear: false));
		value.SetColor("_Color", Color.white);
		value.SetFloat("_NormalStrength", 0.3f);
		value.SetFloat("_Smoothness", 0.28f);
		value.SetFloat("_SpecularStrength", 0.35f);
		value.SetFloat("_SpecularExponent", 8f);
		value.SetFloat("_EmPower", asset.EndsWith("mine", StringComparison.Ordinal) ? 0.4f : 0f);
		value.DisableKeyword("LIMBREMOVAL");
		value.SetFloat("_LimbRemovalOn", 0f);
		assetMaterials.Add(asset, value);
		return value;
	}

	private static string MineAsset(Renderer r)
	{
		if (((Object)r).name == "EngiMineMesh")
		{
			return "pressure-mine";
		}
		if (((Object)r).name == "EngiSpiderMineMesh")
		{
			return "spider-mine";
		}
		return null;
	}

	private IEnumerator PrepareMineGhosts(SkinDef bodySkin)
	{
		cosmeticStorage = new GameObject("UnqualifiedPersonnelCosmeticPrefabs");
		cosmeticStorage.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)cosmeticStorage);
		List<ProjectileGhostReplacement> replacements = new List<ProjectileGhostReplacement>();
		string[] array = new string[2] { "EngiMine", "SpiderMine" };
		foreach (string name in array)
		{
			AsyncOperationHandle<GameObject> h = Addressables.LoadAssetAsync<GameObject>((object)("RoR2/Base/Engi/" + name + ".prefab"));
			retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(h));
			while (!h.IsDone)
			{
				CheckLoadDeadline(name);
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)h.Result))
			{
				throw new InvalidOperationException("Missing projectile " + name);
			}
			ProjectileController component = h.Result.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Missing ProjectileController " + name);
			}
			GameObject val = component.ghostPrefab;
			if (!Object.op_Implicit((Object)(object)val) && component.ghostPrefabAddress != null && ((AssetReference)component.ghostPrefabAddress).RuntimeKeyIsValid())
			{
				AsyncOperationHandle<GameObject> gh = Addressables.LoadAssetAsync<GameObject>(((AssetReference)component.ghostPrefabAddress).RuntimeKey);
				retainedAssets.Add(AsyncOperationHandle<GameObject>.op_Implicit(gh));
				while (!gh.IsDone)
				{
					CheckLoadDeadline(name + " ghost");
					yield return null;
				}
				val = gh.Result;
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Missing mine ghost " + name);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, cosmeticStorage.transform);
			((Object)val2).name = "EclipseUnqualifiedPersonnel_" + name + "Ghost";
			string asset = ((name == "EngiMine") ? "pressure-mine" : "spider-mine");
			SkinnedMeshRenderer[] array2 = (from r in val2.GetComponentsInChildren<SkinnedMeshRenderer>(true)
				where MineAsset((Renderer)(object)r) == asset
				select r).ToArray();
			if (array2.Length != 1)
			{
				throw new InvalidOperationException("Ambiguous mine renderer " + name + ": " + array2.Length);
			}
			SkinnedMeshRenderer val3 = array2[0];
			int num = ((asset == "pressure-mine") ? 2 : 14);
			if (val3.bones.Length != num || !Object.op_Implicit((Object)(object)val3.sharedMesh))
			{
				throw new InvalidOperationException("Missing native mine rig " + name);
			}
			Mesh sharedMesh = val3.sharedMesh;
			Mesh val4 = MeshFor(asset, val3);
			Material sharedMaterial = MakeMaterial(asset, ((Renderer)val3).sharedMaterial);
			canonicalBases[asset] = new MeshBasis
			{
				Reference = sharedMesh,
				Authored = val4
			};
			val3.sharedMesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			Mesh val5 = new Mesh();
			val3.BakeMesh(val5);
			Bounds localBounds = ((Renderer)val3).localBounds;
			Bounds bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).min);
			bounds = val5.bounds;
			((Bounds)(ref localBounds)).Encapsulate(((Bounds)(ref bounds)).max);
			((Bounds)(ref localBounds)).Expand(((Bounds)(ref localBounds)).size * 0.5f);
			((Renderer)val3).localBounds = localBounds;
			Object.Destroy((Object)(object)val5);
			val3.updateWhenOffscreen = true;
			val2.SetActive(true);
			replacements.Add(new ProjectileGhostReplacement
			{
				projectilePrefab = h.Result,
				projectileGhostReplacementPrefab = val2,
				ghostReplacementAddress = new AssetReferenceT<GameObject>("")
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_MINE_READY asset=" + asset + " vertices=" + val4.vertexCount + " native effects/controller preserved"));
		}
		bodySkin.skinDefParams.projectileGhostReplacements = replacements.ToArray();
	}

	private Mesh MeshFor(string asset, SkinnedMeshRenderer target, Mesh nativeReference = null)
	{
		if (!Object.op_Implicit((Object)(object)nativeReference))
		{
			nativeReference = target.sharedMesh;
		}
		string key = asset + "|" + (Object.op_Implicit((Object)(object)nativeReference) ? ((Object)nativeReference).GetInstanceID() : 0) + "|" + string.Join("|", target.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "<null>" : ((Object)b).name));
		if (!remappedMeshes.TryGetValue(key, out var value))
		{
			value = ReadMesh(Path.Combine(folder, asset + ".meshbin"), target, nativeReference);
			remappedMeshes.Add(key, value);
		}
		return value;
	}

	private static bool SameMatrix(Matrix4x4 a, Matrix4x4 b, float tolerance)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (Math.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > tolerance)
				{
					return false;
				}
			}
		}
		return true;
	}

	private Mesh StaticMeshFor(string asset, Mesh reference)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_00d7: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)reference))
		{
			throw new InvalidOperationException("Missing static reference " + asset);
		}
		string key = asset + "|" + ((Object)reference).GetInstanceID();
		if (staticMeshes.TryGetValue(key, out var value))
		{
			return value;
		}
		if (!canonicalBases.TryGetValue(asset, out var value2))
		{
			throw new InvalidOperationException("Missing canonical rig " + asset);
		}
		Matrix4x4[] bindposes = reference.bindposes;
		Matrix4x4[] bindposes2 = value2.Authored.bindposes;
		if (bindposes.Length != bindposes2.Length || bindposes.Length == 0)
		{
			throw new InvalidOperationException("Static bind count " + asset);
		}
		Matrix4x4 b = ((Matrix4x4)(ref bindposes[0])).inverse * bindposes2[0];
		for (int i = 1; i < bindposes.Length; i++)
		{
			if (!SameMatrix(((Matrix4x4)(ref bindposes[i])).inverse * bindposes2[i], b, 0.0002f))
			{
				if (asset != "pressure-mine" && asset != "spider-mine")
				{
					throw new InvalidOperationException("Nonuniform static bind conversion " + asset + " bone " + i);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ENGINEER_E2_STATIC_MINE_BIND_VARIANT " + asset + " uses canonical assembled rest shape"));
				break;
			}
		}
		value = Object.Instantiate<Mesh>(value2.Authored);
		((Object)value).name = "EclipseEngineerE2Static_" + asset;
		Vector3[] vertices = value.vertices;
		Vector3[] normals = value.normals;
		Matrix4x4 inverse = ((Matrix4x4)(ref b)).inverse;
		Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose;
		for (int j = 0; j < vertices.Length; j++)
		{
			vertices[j] = ((Matrix4x4)(ref b)).MultiplyPoint3x4(vertices[j]);
			int num = j;
			Vector3 val = ((Matrix4x4)(ref transpose)).MultiplyVector(normals[j]);
			normals[num] = ((Vector3)(ref val)).normalized;
		}
		value.vertices = vertices;
		value.normals = normals;
		value.boneWeights = (BoneWeight[])(object)new BoneWeight[0];
		value.bindposes = (Matrix4x4[])(object)new Matrix4x4[0];
		value.RecalculateBounds();
		value.RecalculateTangents();
		staticMeshes.Add(key, value);
		return value;
	}

	private static bool Finite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!float.IsNaN(v.x + v.y + v.z))
		{
			return !float.IsInfinity(v.x + v.y + v.z);
		}
		return false;
	}
}
internal static class SkinIdentity
{
	internal static bool Owns(string name)
	{
		if (!(name == "skinRodaniusEngineerUnqualifiedPersonnel_unqualified-personnel") && !(name == "skinRodaniusEngineerUnqualifiedPersonnel_turret"))
		{
			return name == "skinRodaniusEngineerUnqualifiedPersonnel_walker";
		}
		return true;
	}
}
internal static class StartupGuard
{
	internal static IEnumerator Run(Func<IEnumerator> create, Func<bool> expired, Action<Exception> failed)
	{
		Stack<IEnumerator> stack = new Stack<IEnumerator>();
		Exception failure = null;
		try
		{
			stack.Push(create());
		}
		catch (Exception ex)
		{
			failure = ex;
		}
		try
		{
			while (failure == null && stack.Count > 0)
			{
				bool flag = false;
				object obj = null;
				try
				{
					if (expired())
					{
						throw new TimeoutException("Unqualified Personnel startup deadline exceeded.");
					}
					IEnumerator enumerator = stack.Peek();
					flag = enumerator.MoveNext();
					if (flag)
					{
						obj = enumerator.Current;
					}
					else
					{
						stack.Pop();
						(enumerator as IDisposable)?.Dispose();
					}
				}
				catch (Exception ex2)
				{
					failure = ex2;
				}
				if (failure != null)
				{
					break;
				}
				if (flag)
				{
					if (obj is IEnumerator item)
					{
						stack.Push(item);
					}
					else
					{
						yield return obj;
					}
				}
			}
		}
		finally
		{
			if (stack.Count > 0 && failure == null)
			{
				failure = new OperationCanceledException("Unqualified Personnel startup iterator was cancelled.");
			}
			while (stack.Count > 0)
			{
				try
				{
					(stack.Pop() as IDisposable)?.Dispose();
				}
				catch (Exception ex3)
				{
					if (failure == null)
					{
						failure = ex3;
					}
				}
			}
			if (failure != null)
			{
				try
				{
					failed(failure);
				}
				catch
				{
				}
			}
		}
	}
}
internal sealed class TextureAssetCache
{
	private readonly Dictionary<string, Texture2D> values = new Dictionary<string, Texture2D>();

	internal Texture2D Load(string path, bool linear)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		byte[] array = File.ReadAllBytes(path);
		string key;
		using (SHA256 sHA = SHA256.Create())
		{
			key = (linear ? "linear:" : "srgb:") + Convert.ToBase64String(sHA.ComputeHash(array));
		}
		if (values.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
		{
			name = Path.GetFileName(path),
			anisoLevel = 4,
			filterMode = (FilterMode)2
		};
		try
		{
			if (!ImageConversion.LoadImage(val, array, true))
			{
				throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
			}
			values[key] = val;
			return val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}
}