Decompiled source of GAIS Shirts v1.2.1

GaisShirts.dll

Decompiled 19 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using RoR2;
using RoR2.ContentManagement;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;

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

[BepInPlugin("lukas.gaisshirts", "GAIS Shirts", "1.2.1")]
public class GaisShirtsPlugin : BaseUnityPlugin
{
	private class BossShirt
	{
		public ShirtData data;

		public GameObject template;

		public string bodyName;

		public bool warned;
	}

	public const string GUID = "lukas.gaisshirts";

	public const string NAME = "GAIS Shirts";

	public const string VERSION = "1.2.1";

	internal static ManualLogSource Log;

	private List<ShirtData> shirts;

	private List<ShirtData> bossShirts;

	private ConfigEntry<bool> bossShirtsEnabled;

	private Material shirtMaterial;

	private Material ifkMaterial;

	private Sprite icon;

	private GameObject prefabHolder;

	private readonly Dictionary<BodyIndex, BossShirt> bossByBody = new Dictionary<BodyIndex, BossShirt>();

	private GameObject bossHolder;

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			shirts = ShirtData.LoadAll(ReadResource("gais_shirts.bin"));
			Log.LogInfo((object)("Loaded " + shirts.Count + " GAIS shirt meshes."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not load shirt data: " + ex));
			shirts = null;
		}
		bossShirtsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Bosses", "IFKShirts", true, "Dress every boss in an IFK Goteborg shirt (blue/white stripes). Set to false to turn boss shirts off (applies to bosses spawned after the change).");
		try
		{
			bossShirts = ShirtData.LoadAll(ReadResource("ifk_shirts.bin"));
			Log.LogInfo((object)("Loaded " + bossShirts.Count + " IFK boss shirt meshes" + (bossShirtsEnabled.Value ? "." : " (turned off in the config).")));
		}
		catch (Exception ex2)
		{
			Log.LogError((object)("Could not load IFK boss shirt data: " + ex2));
			bossShirts = null;
		}
		if (shirts != null || bossShirts != null)
		{
			((ResourceAvailability)(ref BodyCatalog.availability)).CallWhenAvailable((Action)OnBodyCatalogAvailable);
		}
	}

	private void OnBodyCatalogAvailable()
	{
		if (shirts != null)
		{
			AddSurvivorSkins();
		}
		if (bossShirts != null)
		{
			AddBossShirts();
		}
	}

	private void AddSurvivorSkins()
	{
		try
		{
			if (((ResourceAvailability)(ref SkinCatalog.availability)).available)
			{
				Log.LogWarning((object)"SkinCatalog was already initialised; GAIS skins may not show up.");
			}
			CreateSharedAssets();
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not create shirt material/icon: " + ex));
			return;
		}
		int num = 0;
		foreach (ShirtData shirt in shirts)
		{
			try
			{
				if (AddSkin(shirt))
				{
					num++;
				}
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Failed to add GAIS skin for " + shirt.bodyName + ": " + ex2));
			}
		}
		Log.LogInfo((object)("Added GAIS skin to " + num + " survivors."));
	}

	private static byte[] ReadResource(string name)
	{
		Assembly executingAssembly = Assembly.GetExecutingAssembly();
		string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
		foreach (string text in manifestResourceNames)
		{
			if (!text.EndsWith(name, StringComparison.OrdinalIgnoreCase))
			{
				continue;
			}
			using Stream stream = executingAssembly.GetManifestResourceStream(text);
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
		throw new FileNotFoundException("Embedded resource not found: " + name);
	}

	private Texture2D LoadPng(string fileName, bool mipmaps)
	{
		//IL_0070: 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_007d: Expected O, but got Unknown
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected O, but got Unknown
		byte[] array = null;
		try
		{
			string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), fileName);
			if (File.Exists(text))
			{
				array = File.ReadAllBytes(text);
				Log.LogInfo((object)("Using texture from " + text));
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not read " + fileName + " from plugin folder: " + ex.Message));
		}
		if (array == null)
		{
			array = ReadResource(fileName);
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, mipmaps);
		ImageConversion.LoadImage(val, array, false);
		((Object)val).name = Path.GetFileNameWithoutExtension(fileName);
		return val;
	}

	private void CreateSharedAssets()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Expected O, but got Unknown
		Texture2D tex = LoadShirtTexture("gais_shirt.png");
		Texture2D val = LoadPng("gais_icon.png", mipmaps: false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		((Object)icon).name = "texGaisSkinIcon";
		shirtMaterial = MakeShirtMaterial(tex, "matGaisShirt");
		prefabHolder = new GameObject("GaisShirtPrefabs");
		prefabHolder.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)prefabHolder);
	}

	private Texture2D LoadShirtTexture(string fileName)
	{
		Texture2D obj = LoadPng(fileName, mipmaps: true);
		((Texture)obj).wrapMode = (TextureWrapMode)0;
		((Texture)obj).wrapModeV = (TextureWrapMode)1;
		((Texture)obj).filterMode = (FilterMode)2;
		((Texture)obj).anisoLevel = 4;
		return obj;
	}

	private static Material MakeShirtMaterial(Texture2D tex, string name)
	{
		//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_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected O, but got Unknown
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_005d: 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_006d: Expected O, but got Unknown
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Expected O, but got Unknown
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Expected O, but got Unknown
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Expected O, but got Unknown
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Expected O, but got Unknown
		//IL_00c9: Expected O, but got Unknown
		Material val = new Material(Addressables.LoadAssetAsync<Material>((object)"RoR2/Base/Commando/matCommandoDualies.mat").WaitForCompletion())
		{
			name = name,
			mainTexture = (Texture)(object)tex
		};
		SetColor(val, "_Color", Color.white);
		SetTex(val, "_EmTex", null);
		SetTex(val, "_NormalTex", null);
		SetFloat(val, "_EmPower", 0f);
		SetColor(val, "_EmColor", Color.black);
		SetFloat(val, "_Cull", 0f);
		SetFloat(val, "_LimbRemovalOn", 0f);
		val.DisableKeyword("LIMBREMOVAL");
		SetFloat(val, "_SpecularStrength", 0.12f);
		SetFloat(val, "_SpecularExponent", 3f);
		SetFloat(val, "_Smoothness", 0f);
		return val;
	}

	private static void SetFloat(Material m, string p, float v)
	{
		if (m.HasProperty(p))
		{
			m.SetFloat(p, v);
		}
	}

	private static void SetColor(Material m, string p, Color v)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		if (m.HasProperty(p))
		{
			m.SetColor(p, v);
		}
	}

	private static void SetTex(Material m, string p, Texture v)
	{
		if (m.HasProperty(p))
		{
			m.SetTexture(p, v);
		}
	}

	private bool AddSkin(ShirtData d)
	{
		GameObject val = BodyCatalog.FindBodyPrefab(d.bodyName);
		if (!Object.op_Implicit((Object)(object)val))
		{
			Log.LogInfo((object)(d.bodyName + " not found (DLC content not present?) - skipping."));
			return false;
		}
		ModelLocator component = val.GetComponent<ModelLocator>();
		Transform val2 = (Object.op_Implicit((Object)(object)component) ? component.modelTransform : null);
		ModelSkinController val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<ModelSkinController>() : null);
		if (!Object.op_Implicit((Object)(object)val3) || val3.skins == null || val3.skins.Length == 0)
		{
			Log.LogWarning((object)(d.bodyName + " has no ModelSkinController/skins - skipping."));
			return false;
		}
		SkinDef val4 = val3.skins[0];
		GameObject shirtPrefab = BuildShirtPrefab(d);
		SkinDef val5 = CreateSkinDef(d, val4, val2, shirtPrefab, "");
		if (!Object.op_Implicit((Object)(object)val5))
		{
			return false;
		}
		SkinDef[] array = val3.skins;
		Array.Resize(ref array, array.Length + 1);
		array[^1] = val5;
		val3.skins = array;
		int num = array.Length - 1;
		SurvivorDef[] survivorDefs = ContentManager.survivorDefs;
		if (survivorDefs != null)
		{
			SurvivorDef[] array2 = survivorDefs;
			foreach (SurvivorDef val6 in array2)
			{
				if (!Object.op_Implicit((Object)(object)val6) || (Object)(object)val6.bodyPrefab != (Object)(object)val || !Object.op_Implicit((Object)(object)val6.displayPrefab))
				{
					continue;
				}
				ModelSkinController componentInChildren = val6.displayPrefab.GetComponentInChildren<ModelSkinController>(true);
				if (!Object.op_Implicit((Object)(object)componentInChildren) || (Object)(object)componentInChildren == (Object)(object)val3)
				{
					continue;
				}
				List<SkinDef> list = new List<SkinDef>((IEnumerable<SkinDef>)(((object)componentInChildren.skins) ?? ((object)new SkinDef[0])));
				if (list.Contains(val5))
				{
					continue;
				}
				SkinDef val7 = ((list.Count > 0 && Object.op_Implicit((Object)(object)list[0])) ? list[0] : val4);
				SkinDef val8 = val5;
				if ((Object)(object)val7 != (Object)(object)val4)
				{
					val8 = CreateSkinDef(d, val7, ((Component)componentInChildren).transform, shirtPrefab, "Display");
					if (!Object.op_Implicit((Object)(object)val8))
					{
						val8 = val5;
					}
				}
				while (list.Count < num)
				{
					list.Add(val7);
				}
				if (list.Count == num)
				{
					list.Add(val8);
				}
				else
				{
					list.Insert(num, val8);
				}
				componentInChildren.skins = list.ToArray();
			}
		}
		Log.LogInfo((object)("Added GAIS skin to " + d.bodyName + " (skin #" + (num + 1) + ")."));
		return true;
	}

	private SkinDef CreateSkinDef(ShirtData d, SkinDef baseSkin, Transform model, GameObject shirtPrefab, string suffix)
	{
		//IL_00c2: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = ((Object.op_Implicit((Object)(object)baseSkin) && Object.op_Implicit((Object)(object)baseSkin.rootObject)) ? baseSkin.rootObject : ((Component)model).gameObject);
		Transform val2 = BoneResolver.Find(val.transform, d.spawnPath);
		if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)(object)val.transform)
		{
			val2 = BoneResolver.Find(val.transform, d.bonePaths[d.rootBone]);
		}
		if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)(object)val.transform)
		{
			Log.LogWarning((object)(d.bodyName + suffix + ": could not find attach bone " + d.spawnPath + " - skipping."));
			return null;
		}
		List<GameObjectActivation> list = new List<GameObjectActivation>();
		list.Add(new GameObjectActivation
		{
			spawnPrefabOnModelObject = true,
			gameObject = ((Component)val2).gameObject,
			prefab = shirtPrefab,
			shouldActivate = true,
			localPosition = Vector3.zero,
			localRotation = Vector3.zero,
			localScale = Vector3.one
		});
		string[] hidePaths = d.hidePaths;
		foreach (string path in hidePaths)
		{
			Transform val3 = BoneResolver.Find(val.transform, path);
			if (Object.op_Implicit((Object)(object)val3) && (Object)(object)val3 != (Object)(object)val.transform)
			{
				list.Add(new GameObjectActivation
				{
					gameObject = ((Component)val3).gameObject,
					shouldActivate = false,
					localScale = Vector3.one
				});
			}
		}
		SkinDefParams val4 = ScriptableObject.CreateInstance<SkinDefParams>();
		((Object)val4).name = "skin" + d.bodyName + "GAIS" + suffix + "_params";
		val4.gameObjectActivations = list.ToArray();
		SkinDef val5 = ScriptableObject.CreateInstance<SkinDef>();
		((Object)val5).name = "skin" + d.bodyName + "GAIS" + suffix;
		val5.nameToken = "GAIS";
		val5.icon = icon;
		val5.baseSkins = (SkinDef[])(object)((!Object.op_Implicit((Object)(object)baseSkin)) ? new SkinDef[0] : new SkinDef[1] { baseSkin });
		val5.rootObject = val;
		val5.unlockableDef = null;
		val5.skinDefParams = val4;
		val5.skinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		val5.optimizedSkinDefParamsAddress = new AssetReferenceT<SkinDefParams>("");
		return val5;
	}

	private void AddBossShirts()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Invalid comparison between Unknown and I4
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			ifkMaterial = MakeShirtMaterial(LoadShirtTexture("ifk_shirt.png"), "matIfkShirt");
			IfkShirtLink.material = ifkMaterial;
			bossHolder = new GameObject("IfkShirtTemplates");
			bossHolder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)bossHolder);
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not create IFK shirt material: " + ex));
			return;
		}
		int num = 0;
		int num2 = 0;
		foreach (ShirtData bossShirt in bossShirts)
		{
			GameObject val = null;
			string[] array = bossShirt.bodyName.Split('|');
			foreach (string text in array)
			{
				num2++;
				try
				{
					BodyIndex val2 = BodyCatalog.FindBodyIndex(text);
					if ((int)val2 == -1)
					{
						Log.LogInfo((object)(text + " not found (DLC content not present?) - skipping."));
						continue;
					}
					if ((Object)(object)val == (Object)null)
					{
						val = BuildBossTemplate(bossShirt);
					}
					bossByBody[val2] = new BossShirt
					{
						data = bossShirt,
						template = val,
						bodyName = text
					};
					num++;
				}
				catch (Exception ex2)
				{
					Log.LogError((object)("Failed to prepare IFK shirt for " + text + ": " + ex2));
				}
			}
		}
		CharacterBody.onBodyStartGlobal += OnBodyStart;
		Log.LogInfo((object)("IFK shirts ready for " + num + " of " + num2 + " boss bodies."));
	}

	private GameObject BuildBossTemplate(ShirtData d)
	{
		//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_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Expected O, but got Unknown
		GameObject val = new GameObject("IfkShirt");
		val.transform.SetParent(bossHolder.transform, false);
		SkinnedMeshRenderer obj = val.AddComponent<SkinnedMeshRenderer>();
		obj.sharedMesh = d.BuildMesh();
		((Object)obj.sharedMesh).name = "meshIfkShirt_" + d.bodyName.Split('|')[0];
		((Renderer)obj).sharedMaterial = ifkMaterial;
		obj.updateWhenOffscreen = true;
		((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
		((Renderer)obj).receiveShadows = true;
		val.AddComponent<IfkShirtLink>();
		return val;
	}

	private void OnBodyStart(CharacterBody body)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)body) || !bossShirtsEnabled.Value || !bossByBody.TryGetValue(body.bodyIndex, out var value))
		{
			return;
		}
		try
		{
			DressBoss(body, value);
		}
		catch (Exception ex)
		{
			if (!value.warned)
			{
				Log.LogError((object)("Failed to put IFK shirt on " + value.bodyName + ": " + ex));
			}
			value.warned = true;
		}
	}

	private void DressBoss(CharacterBody body, BossShirt bs)
	{
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		ShirtData data = bs.data;
		Transform val = (Object.op_Implicit((Object)(object)body.modelLocator) ? body.modelLocator.modelTransform : null);
		if (!Object.op_Implicit((Object)(object)val) || Object.op_Implicit((Object)(object)((Component)val).GetComponentInChildren<IfkShirtLink>(true)))
		{
			return;
		}
		Transform[] array = (Transform[])(object)new Transform[data.bonePaths.Length];
		int num = 0;
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = BoneResolver.Find(val, data.bonePaths[i]);
			if (!Object.op_Implicit((Object)(object)array[i]) || (Object)(object)array[i] == (Object)(object)val)
			{
				array[i] = null;
				num++;
			}
		}
		if (num * 2 > array.Length)
		{
			if (!bs.warned)
			{
				Log.LogWarning((object)(bs.bodyName + ": skeleton does not match (" + num + "/" + array.Length + " bones missing) - no shirt."));
			}
			bs.warned = true;
			return;
		}
		Transform val2 = BoneResolver.Find(val, data.spawnPath);
		if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)(object)val)
		{
			val2 = array[Mathf.Clamp(data.rootBone, 0, array.Length - 1)];
		}
		if (!Object.op_Implicit((Object)(object)val2))
		{
			val2 = val;
		}
		for (int j = 0; j < array.Length; j++)
		{
			if (!Object.op_Implicit((Object)(object)array[j]))
			{
				array[j] = val2;
			}
		}
		if (num > 0 && !bs.warned)
		{
			Log.LogWarning((object)(bs.bodyName + ": " + num + " shirt bone(s) not found, using " + ((Object)val2).name));
			bs.warned = true;
		}
		GameObject obj = Object.Instantiate<GameObject>(bs.template, val2, false);
		((Object)obj).name = "IfkShirt";
		obj.layer = ((Component)val2).gameObject.layer;
		obj.transform.localPosition = Vector3.zero;
		obj.transform.localRotation = Quaternion.identity;
		obj.transform.localScale = Vector3.one;
		SkinnedMeshRenderer component = obj.GetComponent<SkinnedMeshRenderer>();
		component.bones = array;
		component.rootBone = array[Mathf.Clamp(data.rootBone, 0, array.Length - 1)];
	}

	private GameObject BuildShirtPrefab(ShirtData d)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("GaisShirt_" + d.bodyName);
		val.transform.SetParent(prefabHolder.transform, false);
		SkinnedMeshRenderer val2 = val.AddComponent<SkinnedMeshRenderer>();
		val2.sharedMesh = d.BuildMesh();
		((Renderer)val2).sharedMaterial = shirtMaterial;
		val2.updateWhenOffscreen = true;
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1;
		((Renderer)val2).receiveShadows = true;
		GaisShirtBinder gaisShirtBinder = val.AddComponent<GaisShirtBinder>();
		gaisShirtBinder.bonePaths = d.bonePaths;
		gaisShirtBinder.rootBoneIndex = d.rootBone;
		GaisShirtBinder.Registry[((Object)val).name] = new KeyValuePair<string[], int>(d.bonePaths, d.rootBone);
		CustomGameObjectActivationInfoContainer val3 = val.AddComponent<CustomGameObjectActivationInfoContainer>();
		val3.rendererInfos = (RendererInfo[])(object)new RendererInfo[1]
		{
			new RendererInfo
			{
				renderer = (Renderer)(object)val2,
				defaultMaterial = shirtMaterial,
				defaultShadowCastingMode = (ShadowCastingMode)1,
				ignoreOverlays = false,
				hideOnDeath = false,
				ignoresMaterialOverrides = false
			}
		};
		val3.lightInfos = (LightInfo[])(object)new LightInfo[0];
		return val;
	}
}
public class GaisShirtBinder : MonoBehaviour
{
	internal static readonly Dictionary<string, KeyValuePair<string[], int>> Registry = new Dictionary<string, KeyValuePair<string[], int>>();

	public string[] bonePaths;

	public int rootBoneIndex;

	private bool bound;

	private void Awake()
	{
		Bind();
	}

	private void OnEnable()
	{
		if (!bound)
		{
			Bind();
		}
	}

	private void Bind()
	{
		SkinnedMeshRenderer component = ((Component)this).GetComponent<SkinnedMeshRenderer>();
		if ((bonePaths == null || bonePaths.Length == 0) && Registry.TryGetValue(((Object)this).name.Replace("(Clone)", "").Trim(), out var value))
		{
			bonePaths = value.Key;
			rootBoneIndex = value.Value;
		}
		if (!Object.op_Implicit((Object)(object)component) || bonePaths == null || bonePaths.Length == 0)
		{
			return;
		}
		if (Object.op_Implicit((Object)(object)((Component)this).transform.parent))
		{
			((Component)this).gameObject.layer = ((Component)((Component)this).transform.parent).gameObject.layer;
		}
		CharacterModel componentInParent = ((Component)this).GetComponentInParent<CharacterModel>();
		Transform val = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).transform : ((Component)this).transform.root);
		Transform[] array = (Transform[])(object)new Transform[bonePaths.Length];
		int num = 0;
		for (int i = 0; i < bonePaths.Length; i++)
		{
			array[i] = BoneResolver.Find(val, bonePaths[i]);
			if (!Object.op_Implicit((Object)(object)array[i]))
			{
				array[i] = (Object.op_Implicit((Object)(object)((Component)this).transform.parent) ? ((Component)this).transform.parent : val);
				num++;
			}
		}
		if (num > 0 && GaisShirtsPlugin.Log != null)
		{
			GaisShirtsPlugin.Log.LogWarning((object)(((Object)this).name + ": " + num + " bone(s) not found under " + ((Object)val).name));
		}
		component.bones = array;
		component.rootBone = array[Mathf.Clamp(rootBoneIndex, 0, array.Length - 1)];
		bound = true;
	}
}
public class IfkShirtLink : MonoBehaviour
{
	internal static Material material;

	private CharacterModel characterModel;

	private ModelSkinController skinController;

	private SkinnedMeshRenderer smr;

	private void Awake()
	{
		smr = ((Component)this).GetComponent<SkinnedMeshRenderer>();
		characterModel = ((Component)this).GetComponentInParent<CharacterModel>();
		if (Object.op_Implicit((Object)(object)characterModel))
		{
			skinController = ((Component)characterModel).GetComponent<ModelSkinController>();
			if (Object.op_Implicit((Object)(object)skinController))
			{
				skinController.onSkinApplied += OnSkinApplied;
			}
		}
	}

	private void Start()
	{
		if (Object.op_Implicit((Object)(object)characterModel) && ((characterModel.baseRendererInfos != null && characterModel.baseRendererInfos.Length != 0) || !Object.op_Implicit((Object)(object)skinController)))
		{
			Register();
		}
	}

	private void OnSkinApplied(int skinIndex)
	{
		Register();
	}

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

	private void Register()
	{
		//IL_0074: 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_00cc: 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)
		if (!Object.op_Implicit((Object)(object)characterModel) || !Object.op_Implicit((Object)(object)smr))
		{
			return;
		}
		RendererInfo[] array = (RendererInfo[])(((object)characterModel.baseRendererInfos) ?? ((object)new RendererInfo[0]));
		for (int i = 0; i < array.Length; i++)
		{
			if ((Object)(object)array[i].renderer == (Object)(object)smr)
			{
				return;
			}
		}
		RendererInfo[] array2 = (RendererInfo[])(object)new RendererInfo[array.Length + 1];
		Array.Copy(array, array2, array.Length);
		array2[array.Length] = new RendererInfo
		{
			renderer = (Renderer)(object)smr,
			defaultMaterial = (Object.op_Implicit((Object)(object)material) ? material : ((Renderer)smr).sharedMaterial),
			defaultShadowCastingMode = (ShadowCastingMode)1,
			ignoreOverlays = false,
			hideOnDeath = false,
			ignoresMaterialOverrides = false
		};
		characterModel.baseRendererInfos = array2;
		characterModel.forceUpdate = true;
	}
}
public static class BoneResolver
{
	public static Transform Find(Transform root, string path)
	{
		if (!Object.op_Implicit((Object)(object)root) || string.IsNullOrEmpty(path))
		{
			return null;
		}
		string[] array = path.Split('/');
		for (int i = 0; i < array.Length; i++)
		{
			Transform val = root.Find(string.Join("/", array, i, array.Length - i));
			if (Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
		}
		Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
		Transform[] array2;
		for (int j = 0; j < array.Length - 1; j++)
		{
			string text = string.Join("/", array, j + 1, array.Length - j - 1);
			array2 = componentsInChildren;
			foreach (Transform val2 in array2)
			{
				if (!(((Object)val2).name != array[j]))
				{
					Transform val3 = val2.Find(text);
					if (Object.op_Implicit((Object)(object)val3))
					{
						return val3;
					}
				}
			}
		}
		string text2 = array[^1];
		array2 = componentsInChildren;
		foreach (Transform val4 in array2)
		{
			if (((Object)val4).name == text2)
			{
				return val4;
			}
		}
		return null;
	}
}
public class ShirtData
{
	public string bodyName;

	public string spawnPath;

	public string[] hidePaths;

	public string[] bonePaths;

	public Matrix4x4[] bindposes;

	public int rootBone;

	public Vector3[] positions;

	public Vector3[] normals;

	public Vector2[] uvs;

	public BoneWeight[] weights;

	public int[] triangles;

	public static List<ShirtData> LoadAll(byte[] gz)
	{
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_020b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: 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_02d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0358: Unknown result type (might be due to invalid IL or missing references)
		//IL_035a: Unknown result type (might be due to invalid IL or missing references)
		byte[] buffer;
		using (GZipStream gZipStream = new GZipStream(new MemoryStream(gz), CompressionMode.Decompress))
		{
			using MemoryStream memoryStream = new MemoryStream();
			gZipStream.CopyTo(memoryStream);
			buffer = memoryStream.ToArray();
		}
		List<ShirtData> list = new List<ShirtData>();
		using BinaryReader binaryReader = new BinaryReader(new MemoryStream(buffer));
		string text = Encoding.ASCII.GetString(binaryReader.ReadBytes(5));
		if (text != "GAIS1")
		{
			throw new InvalidDataException("bad magic " + text);
		}
		int num = binaryReader.ReadInt32();
		for (int i = 0; i < num; i++)
		{
			ShirtData shirtData = new ShirtData();
			shirtData.bodyName = Str(binaryReader);
			shirtData.spawnPath = Str(binaryReader);
			int num2 = binaryReader.ReadInt32();
			shirtData.hidePaths = new string[num2];
			for (int j = 0; j < num2; j++)
			{
				shirtData.hidePaths[j] = Str(binaryReader);
			}
			int num3 = binaryReader.ReadInt32();
			shirtData.bonePaths = new string[num3];
			shirtData.bindposes = (Matrix4x4[])(object)new Matrix4x4[num3];
			for (int k = 0; k < num3; k++)
			{
				shirtData.bonePaths[k] = Str(binaryReader);
				Matrix4x4 val = default(Matrix4x4);
				for (int l = 0; l < 4; l++)
				{
					for (int m = 0; m < 4; m++)
					{
						((Matrix4x4)(ref val))[l, m] = binaryReader.ReadSingle();
					}
				}
				shirtData.bindposes[k] = val;
			}
			shirtData.rootBone = binaryReader.ReadInt32();
			int num4 = binaryReader.ReadInt32();
			shirtData.positions = (Vector3[])(object)new Vector3[num4];
			for (int n = 0; n < num4; n++)
			{
				shirtData.positions[n] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			shirtData.normals = (Vector3[])(object)new Vector3[num4];
			for (int num5 = 0; num5 < num4; num5++)
			{
				shirtData.normals[num5] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			shirtData.uvs = (Vector2[])(object)new Vector2[num4];
			for (int num6 = 0; num6 < num4; num6++)
			{
				shirtData.uvs[num6] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			int[] array = new int[num4 * 4];
			for (int num7 = 0; num7 < num4 * 4; num7++)
			{
				array[num7] = binaryReader.ReadInt32();
			}
			float[] array2 = new float[num4 * 4];
			for (int num8 = 0; num8 < num4 * 4; num8++)
			{
				array2[num8] = binaryReader.ReadSingle();
			}
			shirtData.weights = (BoneWeight[])(object)new BoneWeight[num4];
			for (int num9 = 0; num9 < num4; num9++)
			{
				BoneWeight[] array3 = shirtData.weights;
				int num10 = num9;
				BoneWeight val2 = default(BoneWeight);
				((BoneWeight)(ref val2)).boneIndex0 = array[num9 * 4];
				((BoneWeight)(ref val2)).weight0 = array2[num9 * 4];
				((BoneWeight)(ref val2)).boneIndex1 = array[num9 * 4 + 1];
				((BoneWeight)(ref val2)).weight1 = array2[num9 * 4 + 1];
				((BoneWeight)(ref val2)).boneIndex2 = array[num9 * 4 + 2];
				((BoneWeight)(ref val2)).weight2 = array2[num9 * 4 + 2];
				((BoneWeight)(ref val2)).boneIndex3 = array[num9 * 4 + 3];
				((BoneWeight)(ref val2)).weight3 = array2[num9 * 4 + 3];
				array3[num10] = val2;
			}
			int num11 = binaryReader.ReadInt32();
			shirtData.triangles = new int[num11 * 3];
			for (int num12 = 0; num12 < num11 * 3; num12++)
			{
				shirtData.triangles[num12] = binaryReader.ReadInt32();
			}
			list.Add(shirtData);
		}
		return list;
	}

	private static string Str(BinaryReader r)
	{
		int count = r.ReadInt32();
		return Encoding.UTF8.GetString(r.ReadBytes(count));
	}

	public Mesh BuildMesh()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: 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_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Expected O, but got Unknown
		Mesh val = new Mesh
		{
			name = "meshGaisShirt_" + bodyName,
			vertices = positions,
			normals = normals,
			uv = uvs,
			boneWeights = weights,
			bindposes = bindposes,
			triangles = triangles
		};
		val.RecalculateBounds();
		val.RecalculateTangents();
		return val;
	}
}