Decompiled source of MoreCosmetics v0.2.2

BepInEx\plugins\More-Cosmetics\More-Cosmetics.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using GWYF_NewClothing.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GWYF_NewClothing
{
	internal static class AssetBundleLoader
	{
		public static GameObject LoadModel(string bundlePath, string assetName)
		{
			try
			{
				if (!File.Exists(bundlePath))
				{
					Debug.LogError((object)("[GWYF] Bundle file not found: " + bundlePath));
					return null;
				}
				AssetBundle val = AssetBundle.LoadFromFile(bundlePath);
				if ((Object)(object)val == (Object)null)
				{
					Debug.LogError((object)("[GWYF] Failed to load bundle: " + bundlePath));
					return null;
				}
				GameObject val2 = val.LoadAsset<GameObject>(assetName);
				val.Unload(false);
				if ((Object)(object)val2 == (Object)null)
				{
					Debug.LogError((object)("[GWYF] Asset '" + assetName + "' not found in bundle: " + bundlePath));
					return null;
				}
				GameObject obj = Object.Instantiate<GameObject>(val2);
				((Object)obj).hideFlags = (HideFlags)61;
				obj.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)obj);
				return obj;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GWYF] Bundle load failed: " + bundlePath + " — " + ex.Message));
				return null;
			}
		}
	}
	public static class CosmeticRegistry
	{
		private static CosmeticData[] _allCosmetics = Array.Empty<CosmeticData>();

		private static readonly List<CosmeticEntry> _pendingVanilla = new List<CosmeticEntry>();

		private static int _nextId;

		private static readonly List<string> _registeredDirs = new List<string>();

		private static string _lastModelsDir = "";

		private static string _lastTexDir = "";

		private static string _lastBundlesDir = "";

		public static CosmeticData[] AllCosmetics
		{
			get
			{
				ResolvePending();
				return _allCosmetics;
			}
		}

		public static void RegisterFrom(string pluginDir)
		{
			if (string.IsNullOrEmpty(pluginDir) || _registeredDirs.Contains(pluginDir))
			{
				return;
			}
			_registeredDirs.Add(pluginDir);
			string path = Path.Combine(pluginDir, "cosmetics.json");
			if (!File.Exists(path))
			{
				Debug.Log((object)("[MoreCosmetics] No cosmetics.json in " + pluginDir + ", skipping."));
				return;
			}
			try
			{
				List<CosmeticEntry> list = ParseFromJson(File.ReadAllText(path));
				string text = Path.Combine(pluginDir, "models");
				string text2 = Path.Combine(pluginDir, "textures");
				string text3 = Path.Combine(pluginDir, "bundles");
				try
				{
					Directory.CreateDirectory(text);
				}
				catch
				{
				}
				try
				{
					Directory.CreateDirectory(text2);
				}
				catch
				{
				}
				try
				{
					Directory.CreateDirectory(text3);
				}
				catch
				{
				}
				List<CosmeticData> list2 = new List<CosmeticData>();
				foreach (CosmeticEntry item in list)
				{
					CosmeticData val = CreateCosmetic(item, list2.Count, text, text2, text3);
					if ((Object)(object)val != (Object)null)
					{
						list2.Add(val);
					}
					else if (item != null && (item.model?.IsVanilla).GetValueOrDefault())
					{
						_pendingVanilla.Add(item);
					}
				}
				if (_allCosmetics.Length == 0)
				{
					_allCosmetics = list2.ToArray();
				}
				else
				{
					List<CosmeticData> list3 = new List<CosmeticData>(_allCosmetics);
					list3.AddRange(list2);
					_allCosmetics = list3.ToArray();
				}
				Debug.Log((object)$"[MoreCosmetics] Registered {list2.Count} cosmetics from {Path.GetFileName(pluginDir)}");
				if (_pendingVanilla.Count > 0)
				{
					Debug.Log((object)$"[MoreCosmetics]   {_pendingVanilla.Count} vanilla-model entries deferred (not in cache yet)");
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[MoreCosmetics] Failed to register cosmetics from " + pluginDir + ": " + ex.Message));
			}
		}

		internal static void ResolvePending()
		{
			if (_pendingVanilla.Count == 0 || !IsCacheReady())
			{
				return;
			}
			List<CosmeticData> list = new List<CosmeticData>();
			List<CosmeticEntry> list2 = new List<CosmeticEntry>();
			foreach (CosmeticEntry item in _pendingVanilla)
			{
				CosmeticData val = CreateCosmetic(item, list.Count, _lastModelsDir, _lastTexDir, _lastBundlesDir);
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val);
				}
				else
				{
					list2.Add(item);
				}
			}
			if (list.Count > 0)
			{
				List<CosmeticData> list3 = new List<CosmeticData>(_allCosmetics);
				list3.AddRange(list);
				_allCosmetics = list3.ToArray();
			}
			_pendingVanilla.Clear();
			_pendingVanilla.AddRange(list2);
		}

		private static bool IsCacheReady()
		{
			try
			{
				object obj = typeof(CosmeticDataManager).GetField("_isInitialized", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null);
				return obj is bool && (bool)obj;
			}
			catch
			{
				return false;
			}
		}

		private static CosmeticData? CreateCosmetic(CosmeticEntry entry, int index, string modelsDir, string texturesDir, string bundlesDir)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: 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_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			_lastModelsDir = modelsDir;
			_lastTexDir = texturesDir;
			_lastBundlesDir = bundlesDir;
			if (string.IsNullOrEmpty(entry.name) || string.IsNullOrEmpty(entry.type))
			{
				return null;
			}
			if (!Enum.TryParse<CosmeticType>(entry.type, ignoreCase: true, out CosmeticType result))
			{
				return null;
			}
			CosmeticRarity result2 = (CosmeticRarity)0;
			if (!string.IsNullOrEmpty(entry.rarity))
			{
				Enum.TryParse<CosmeticRarity>(entry.rarity, ignoreCase: true, out result2);
			}
			if (entry.model == null)
			{
				return null;
			}
			GameObject val = ResolveModel(entry, modelsDir, bundlesDir);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Material val2 = new Material(Shader.Find((!string.IsNullOrEmpty(entry.shader)) ? entry.shader : "01_GWYF/GlobalShader") ?? Shader.Find("Standard") ?? Shader.Find("Diffuse"));
			((Object)val2).name = entry.name + "_Mat";
			if (!string.IsNullOrEmpty(entry.texture))
			{
				Texture2D val3 = TextureLoader.Load(Path.Combine(texturesDir, entry.texture));
				if ((Object)(object)val3 != (Object)null)
				{
					val2.SetTexture("_MainTex", (Texture)(object)val3);
					val2.SetTexture("_BaseMap", (Texture)(object)val3);
					val2.color = Color.white;
				}
				else
				{
					val2.color = GetTintColor(entry.tint);
				}
			}
			else
			{
				val2.color = GetTintColor(entry.tint);
			}
			CosmeticData obj = ScriptableObject.CreateInstance<CosmeticData>();
			((Object)obj).name = entry.name;
			obj.cosmeticId = PluginConfig.CosmeticIdStart.Value + _nextId++;
			obj.cosmeticName = entry.name;
			obj.description = entry.description ?? "";
			obj.cosmeticType = result;
			obj.rarity = result2;
			obj.cosmeticModel = val;
			obj.cosmeticMaterial = val2;
			return obj;
		}

		private static GameObject? ResolveModel(CosmeticEntry entry, string modelsDir, string bundlesDir)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			if (entry.model.IsVanilla)
			{
				return CloneVanillaModel(entry.model.vanilla);
			}
			if (entry.model.IsObj)
			{
				Mesh val = ObjImporter.Import(Path.Combine(modelsDir, entry.model.obj));
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				GameObject val2 = new GameObject(entry.name + "_Model")
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)val2);
				val2.AddComponent<MeshFilter>().sharedMesh = val;
				val2.AddComponent<MeshRenderer>();
				return val2;
			}
			if (entry.model.IsBundle)
			{
				return AssetBundleLoader.LoadModel(Path.Combine(bundlesDir, entry.model.bundle), entry.model.asset);
			}
			return null;
		}

		private static GameObject? CloneVanillaModel(string cosmeticName)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			try
			{
				if (!(typeof(CosmeticDataManager).GetField("_cosmeticCache", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) is Dictionary<int, CosmeticData> dictionary))
				{
					return null;
				}
				foreach (KeyValuePair<int, CosmeticData> item in dictionary)
				{
					CosmeticData value = item.Value;
					if (!((Object)(object)value == (Object)null) && !((Object)(object)value.cosmeticModel == (Object)null) && string.Equals(value.cosmeticName, cosmeticName, StringComparison.OrdinalIgnoreCase))
					{
						MeshFilter component = value.cosmeticModel.GetComponent<MeshFilter>();
						if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
						{
							GameObject val = new GameObject(cosmeticName + "_Clone")
							{
								hideFlags = (HideFlags)61
							};
							Object.DontDestroyOnLoad((Object)val);
							val.AddComponent<MeshFilter>().sharedMesh = Object.Instantiate<Mesh>(component.sharedMesh);
							val.AddComponent<MeshRenderer>();
							return val;
						}
					}
				}
				return null;
			}
			catch
			{
				return null;
			}
		}

		private static Color GetTintColor(float[] tint)
		{
			//IL_0009: 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)
			if (tint == null || tint.Length < 3)
			{
				return Color.white;
			}
			return new Color(Mathf.Clamp01(tint[0]), Mathf.Clamp01(tint[1]), Mathf.Clamp01(tint[2]));
		}

		private static List<CosmeticEntry> ParseFromJson(string json)
		{
			List<CosmeticEntry> list = new List<CosmeticEntry>();
			try
			{
				json = json.Trim();
				if (json.StartsWith("{"))
				{
					if (!TinyJson.ParseObject(json).TryGetValue("cosmetics", out object value) || !(value is string text))
					{
						return list;
					}
					json = text.Trim();
				}
				if (!json.StartsWith("["))
				{
					return list;
				}
				foreach (Dictionary<string, object> item in TinyJson.ParseArray(json))
				{
					CosmeticEntry cosmeticEntry = new CosmeticEntry();
					if (item.TryGetValue("name", out var value2) && value2 is string name)
					{
						cosmeticEntry.name = name;
					}
					if (item.TryGetValue("type", out var value3) && value3 is string type)
					{
						cosmeticEntry.type = type;
					}
					if (item.TryGetValue("rarity", out var value4) && value4 is string rarity)
					{
						cosmeticEntry.rarity = rarity;
					}
					if (item.TryGetValue("description", out var value5) && value5 is string description)
					{
						cosmeticEntry.description = description;
					}
					if (item.TryGetValue("texture", out var value6) && value6 is string texture)
					{
						cosmeticEntry.texture = texture;
					}
					if (item.TryGetValue("shader", out var value7) && value7 is string shader)
					{
						cosmeticEntry.shader = shader;
					}
					if (item.TryGetValue("tint", out var value8))
					{
						if (value8 is float[] tint)
						{
							cosmeticEntry.tint = tint;
						}
						else if (value8 is List<float> list2)
						{
							cosmeticEntry.tint = list2.ToArray();
						}
					}
					if (item.TryGetValue("model", out var value9))
					{
						cosmeticEntry.model = new ModelRef();
						if (value9 is string vanilla)
						{
							cosmeticEntry.model.vanilla = vanilla;
						}
						else if (value9 is Dictionary<string, object> dictionary)
						{
							if (dictionary.TryGetValue("vanilla", out var value10) && value10 is string vanilla2)
							{
								cosmeticEntry.model.vanilla = vanilla2;
							}
							if (dictionary.TryGetValue("obj", out var value11) && value11 is string obj)
							{
								cosmeticEntry.model.obj = obj;
							}
							if (dictionary.TryGetValue("bundle", out var value12) && value12 is string bundle)
							{
								cosmeticEntry.model.bundle = bundle;
							}
							if (dictionary.TryGetValue("asset", out var value13) && value13 is string asset)
							{
								cosmeticEntry.model.asset = asset;
							}
						}
					}
					if (!string.IsNullOrEmpty(cosmeticEntry.name))
					{
						list.Add(cosmeticEntry);
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[MoreCosmetics] JSON parse error: " + ex.Message));
			}
			return list;
		}
	}
	[Serializable]
	public class CosmeticEntry
	{
		public string name;

		public string type;

		public string rarity;

		public string description;

		public ModelRef model;

		public string texture;

		public float[] tint;

		public string shader;
	}
	[Serializable]
	public class ModelRef
	{
		public string vanilla;

		public string obj;

		public string bundle;

		public string asset;

		public bool IsVanilla => !string.IsNullOrEmpty(vanilla);

		public bool IsObj => !string.IsNullOrEmpty(obj);

		public bool IsBundle => !string.IsNullOrEmpty(bundle);
	}
	internal static class ObjImporter
	{
		private readonly struct VertexTriplet
		{
			public readonly int posIndex;

			public readonly int uvIndex;

			public readonly int nrmIndex;

			public VertexTriplet(int pos, int uv, int nrm)
			{
				posIndex = pos;
				uvIndex = uv;
				nrmIndex = nrm;
			}

			public override bool Equals(object obj)
			{
				if (obj is VertexTriplet vertexTriplet && posIndex == vertexTriplet.posIndex && uvIndex == vertexTriplet.uvIndex)
				{
					return nrmIndex == vertexTriplet.nrmIndex;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return HashCode.Combine(posIndex, uvIndex, nrmIndex);
			}
		}

		public static Mesh Import(string path)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Expected O, but got Unknown
			//IL_00e5: 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)
			if (!File.Exists(path))
			{
				Debug.LogError((object)("[GWYF] OBJ file not found: " + path));
				return null;
			}
			string[] array = File.ReadAllLines(path);
			List<Vector3> list = new List<Vector3>();
			List<Vector2> list2 = new List<Vector2>();
			List<Vector3> list3 = new List<Vector3>();
			List<VertexTriplet> list4 = new List<VertexTriplet>();
			List<(int, int, int)> list5 = new List<(int, int, int)>();
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string text = array2[i].Trim();
				if (text.Length == 0 || text[0] == '#')
				{
					continue;
				}
				string[] array3 = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
				if (array3.Length >= 2)
				{
					switch (array3[0])
					{
					case "v":
						list.Add(ParseVector3(array3, 1));
						break;
					case "vt":
						list2.Add(ParseVector2(array3, 1));
						break;
					case "vn":
						list3.Add(ParseVector3(array3, 1));
						break;
					case "f":
						ParseFace(array3, list4, list5);
						break;
					}
				}
			}
			Dictionary<VertexTriplet, int> dict = new Dictionary<VertexTriplet, int>();
			List<Vector3> list6 = new List<Vector3>();
			List<Vector2> list7 = new List<Vector2>();
			List<Vector3> list8 = new List<Vector3>();
			List<int> list9 = new List<int>();
			foreach (var item4 in list5)
			{
				int item = item4.Item1;
				int item2 = item4.Item2;
				int item3 = item4.Item3;
				VertexTriplet vt = list4[item];
				VertexTriplet vt2 = list4[item2];
				VertexTriplet vt3 = list4[item3];
				list9.Add(GetOrAdd(vt, dict, list6, list7, list8, list, list2, list3));
				list9.Add(GetOrAdd(vt2, dict, list6, list7, list8, list, list2, list3));
				list9.Add(GetOrAdd(vt3, dict, list6, list7, list8, list, list2, list3));
			}
			Mesh val = new Mesh();
			((Object)val).name = Path.GetFileNameWithoutExtension(path);
			val.indexFormat = (IndexFormat)(list6.Count > 65535);
			val.SetVertices(list6);
			val.SetTriangles(list9, 0);
			if (list7.Count == list6.Count)
			{
				val.SetUVs(0, list7);
			}
			if (list8.Count == list6.Count)
			{
				val.SetNormals(list8);
			}
			else
			{
				val.RecalculateNormals();
			}
			val.RecalculateBounds();
			val.RecalculateTangents();
			Debug.Log((object)$"[GWYF] Imported OBJ '{Path.GetFileName(path)}': {list6.Count} verts, {list9.Count / 3} tris.");
			return val;
		}

		private static int GetOrAdd(VertexTriplet vt, Dictionary<VertexTriplet, int> dict, List<Vector3> verts, List<Vector2> uvs, List<Vector3> norms, List<Vector3> posSrc, List<Vector2> uvSrc, List<Vector3> nrmSrc)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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)
			if (dict.TryGetValue(vt, out var value))
			{
				return value;
			}
			int result = (dict[vt] = verts.Count);
			verts.Add((vt.posIndex > 0 && vt.posIndex <= posSrc.Count) ? posSrc[vt.posIndex - 1] : Vector3.zero);
			if (vt.uvIndex > 0 && vt.uvIndex <= uvSrc.Count)
			{
				uvs.Add(uvSrc[vt.uvIndex - 1]);
			}
			if (vt.nrmIndex > 0 && vt.nrmIndex <= nrmSrc.Count)
			{
				norms.Add(nrmSrc[vt.nrmIndex - 1]);
			}
			return result;
		}

		private static Vector3 ParseVector3(string[] parts, int start)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			float result = 0f;
			float result2 = 0f;
			float result3 = 0f;
			if (parts.Length > start)
			{
				float.TryParse(parts[start], NumberStyles.Float, CultureInfo.InvariantCulture, out result);
			}
			if (parts.Length > start + 1)
			{
				float.TryParse(parts[start + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out result2);
			}
			if (parts.Length > start + 2)
			{
				float.TryParse(parts[start + 2], NumberStyles.Float, CultureInfo.InvariantCulture, out result3);
			}
			return new Vector3(result, result2, result3);
		}

		private static Vector2 ParseVector2(string[] parts, int start)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			float result = 0f;
			float result2 = 0f;
			if (parts.Length > start)
			{
				float.TryParse(parts[start], NumberStyles.Float, CultureInfo.InvariantCulture, out result);
			}
			if (parts.Length > start + 1)
			{
				float.TryParse(parts[start + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out result2);
			}
			return new Vector2(result, result2);
		}

		private static void ParseFace(string[] parts, List<VertexTriplet> vertices, List<(int, int, int)> faces)
		{
			List<int> list = new List<int>();
			for (int i = 1; i < parts.Length; i++)
			{
				list.Add(vertices.Count);
				vertices.Add(ParseVertexTriplet(parts[i]));
			}
			for (int j = 1; j < list.Count - 1; j++)
			{
				faces.Add((list[0], list[j], list[j + 1]));
			}
		}

		private static VertexTriplet ParseVertexTriplet(string part)
		{
			string[] array = part.Split('/');
			int result = 0;
			int result2 = 0;
			int result3 = 0;
			if (array.Length != 0)
			{
				int.TryParse(array[0], out result);
			}
			if (array.Length > 1 && !string.IsNullOrEmpty(array[1]))
			{
				int.TryParse(array[1], out result2);
			}
			if (array.Length > 2)
			{
				int.TryParse(array[2], out result3);
			}
			return new VertexTriplet(result, result2, result3);
		}
	}
	[BepInPlugin("com.morecosmetics.injector", "More Cosmetics", "0.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.morecosmetics.injector";

		public const string PluginName = "More Cosmetics";

		public const string PluginVersion = "0.2.0";

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			try
			{
				PluginConfig.Bind(((BaseUnityPlugin)this).Config);
				if (!PluginConfig.Enabled.Value)
				{
					return;
				}
				string item = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Path.Combine(Paths.PluginPath, "More-Cosmetics");
				HashSet<string> hashSet = new HashSet<string> { item };
				if (PluginConfig.AutoDiscover.Value)
				{
					string pluginPath = Paths.PluginPath;
					if (Directory.Exists(pluginPath))
					{
						string[] directories = Directory.GetDirectories(pluginPath);
						foreach (string text in directories)
						{
							if (File.Exists(Path.Combine(text, "cosmetics.json")))
							{
								hashSet.Add(text);
							}
						}
					}
				}
				Debug.Log((object)$"[MoreCosmetics] Scanning {hashSet.Count} directories for cosmetics...");
				foreach (string item2 in hashSet)
				{
					if (File.Exists(Path.Combine(item2, "cosmetics.json")))
					{
						CosmeticRegistry.RegisterFrom(item2);
					}
				}
				Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, (string)null);
				CosmeticDataManagerPatches.InjectCustomCosmeticsOnce();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"More Cosmetics 0.2.0 loaded.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} failed: {1}", "More Cosmetics", arg));
			}
		}
	}
	internal static class PluginConfig
	{
		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<bool> AutoDiscover { get; private set; }

		public static ConfigEntry<bool> AutoUnlockModCosmetics { get; private set; }

		public static ConfigEntry<int> CosmeticIdStart { get; private set; }

		public static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Globally enables or disables the library and all loaded cosmetics.");
			AutoDiscover = config.Bind<bool>("General", "AutoDiscover", true, "When true, automatically scans all plugin folders for cosmetics.json files.");
			AutoUnlockModCosmetics = config.Bind<bool>("General", "AutoUnlockModCosmetics", true, "When true, all loaded cosmetics are automatically unlocked on game start.");
			CosmeticIdStart = config.Bind<int>("General", "CosmeticIdStart", 10000, "Starting ID for auto-assigned cosmetic IDs.");
		}
	}
	internal static class TextureLoader
	{
		public static Texture2D Load(string path)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if (!File.Exists(path))
			{
				Debug.LogError((object)("[GWYF] Texture file not found: " + path));
				return null;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				Debug.LogError((object)("[GWYF] Failed to load texture: " + path));
				Object.Destroy((Object)(object)val);
				return null;
			}
			((Texture)val).filterMode = (FilterMode)0;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			return val;
		}
	}
	internal static class TinyJson
	{
		public static List<Dictionary<string, object>> ParseArray(string json)
		{
			List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
			json = json.Trim();
			if (!json.StartsWith("[") || !json.EndsWith("]"))
			{
				return list;
			}
			int num = 0;
			int num2 = 0;
			bool flag = false;
			for (int i = 1; i < json.Length - 1; i++)
			{
				char c = json[i];
				if (c == '"' && (i == 0 || json[i - 1] != '\\'))
				{
					flag = !flag;
				}
				if (flag)
				{
					continue;
				}
				switch (c)
				{
				case '{':
					num++;
					break;
				case '}':
					num--;
					break;
				case ',':
					if (num == 0)
					{
						Dictionary<string, object> dictionary = ParseObject(json.Substring(num2 + 1, i - num2 - 1));
						if (dictionary != null)
						{
							list.Add(dictionary);
						}
						num2 = i;
					}
					break;
				}
			}
			if (num2 + 1 < json.Length - 1)
			{
				Dictionary<string, object> dictionary2 = ParseObject(json.Substring(num2 + 1, json.Length - num2 - 2));
				if (dictionary2 != null)
				{
					list.Add(dictionary2);
				}
			}
			return list;
		}

		public static Dictionary<string, object> ParseObject(string segment)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			segment = segment.Trim();
			if (!segment.StartsWith("{") || !segment.EndsWith("}"))
			{
				return dictionary;
			}
			int i = 1;
			while (i < segment.Length - 1)
			{
				SkipWhitespace(segment, ref i);
				if (i >= segment.Length - 1)
				{
					break;
				}
				string text = ReadString(segment, ref i);
				SkipWhitespace(segment, ref i);
				if (i >= segment.Length - 1 || segment[i] != ':')
				{
					break;
				}
				i++;
				SkipWhitespace(segment, ref i);
				object value = ReadValue(segment, ref i);
				if (text != null)
				{
					dictionary[text] = value;
				}
				SkipWhitespace(segment, ref i);
				if (i < segment.Length - 1 && segment[i] == ',')
				{
					i++;
				}
			}
			return dictionary;
		}

		private static object ReadValue(string s, ref int i)
		{
			SkipWhitespace(s, ref i);
			if (i >= s.Length)
			{
				return null;
			}
			if (s[i] == '"')
			{
				return ReadString(s, ref i);
			}
			if (s[i] == '{')
			{
				return ParseObject(ReadBraced(s, ref i));
			}
			if (s[i] == '[')
			{
				return ReadArray(s, ref i);
			}
			return ReadLiteral(s, ref i);
		}

		private static string ReadString(string s, ref int i)
		{
			if (i >= s.Length || s[i] != '"')
			{
				return "";
			}
			int num = ++i;
			while (i < s.Length)
			{
				if (s[i] == '\\')
				{
					i += 2;
					continue;
				}
				if (s[i] == '"')
				{
					break;
				}
				i++;
			}
			string result = s.Substring(num, i - num);
			i++;
			return result;
		}

		private static string ReadBraced(string s, ref int i)
		{
			if (i >= s.Length || s[i] != '{')
			{
				return "{}";
			}
			int num = i;
			int num2 = 0;
			bool flag = false;
			while (i < s.Length)
			{
				char c = s[i];
				if (c == '"' && (i == 0 || s[i - 1] != '\\'))
				{
					flag = !flag;
				}
				if (!flag)
				{
					if (c == '{')
					{
						num2++;
					}
					else if (c == '}')
					{
						num2--;
						i++;
						if (num2 == 0)
						{
							break;
						}
						continue;
					}
				}
				i++;
			}
			return s.Substring(num, i - num);
		}

		private static object ReadArray(string s, ref int i)
		{
			if (i >= s.Length || s[i] != '[')
			{
				return Array.Empty<float>();
			}
			List<float> list = new List<float>();
			i++;
			while (i < s.Length && s[i] != ']')
			{
				SkipWhitespace(s, ref i);
				if (i < s.Length && s[i] != ']' && ReadLiteral(s, ref i) is float item)
				{
					list.Add(item);
				}
				SkipWhitespace(s, ref i);
				if (i < s.Length && s[i] == ',')
				{
					i++;
				}
			}
			if (i < s.Length && s[i] == ']')
			{
				i++;
			}
			return list.ToArray();
		}

		private static object ReadLiteral(string s, ref int i)
		{
			int num = i;
			while (i < s.Length && !IsDelimiter(s[i]))
			{
				i++;
			}
			string text = s.Substring(num, i - num).Trim().ToLowerInvariant();
			switch (text)
			{
			case "null":
				return null;
			case "true":
				return true;
			case "false":
				return false;
			default:
			{
				if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					return result;
				}
				return text;
			}
			}
		}

		private static bool IsDelimiter(char c)
		{
			if (c != ',' && c != '}' && c != ']' && c != ':')
			{
				return char.IsWhiteSpace(c);
			}
			return true;
		}

		private static void SkipWhitespace(string s, ref int i)
		{
			while (i < s.Length && char.IsWhiteSpace(s[i]))
			{
				i++;
			}
		}
	}
}
namespace GWYF_NewClothing.Patches
{
	[HarmonyPatch]
	internal static class CosmeticDataManagerPatches
	{
		private static bool _injected;

		private static bool IsEnabled => PluginConfig.Enabled.Value;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CosmeticDataManager), "Initialize")]
		private static void Initialize_Postfix()
		{
			if (IsEnabled)
			{
				CosmeticRegistry.ResolvePending();
				InjectCustomCosmeticsOnce();
			}
		}

		internal static void InjectCustomCosmeticsOnce()
		{
			if (_injected)
			{
				return;
			}
			if (!(AccessTools.Field(typeof(CosmeticDataManager), "_cosmeticCache").GetValue(null) is Dictionary<int, CosmeticData> dictionary))
			{
				Debug.LogWarning((object)"[MoreCosmetics] _cosmeticCache is null. Aborting injection.");
				return;
			}
			CosmeticData[] allCosmetics = CosmeticRegistry.AllCosmetics;
			if (allCosmetics.Length == 0)
			{
				return;
			}
			int num = 0;
			CosmeticData[] array = allCosmetics;
			foreach (CosmeticData val in array)
			{
				if (!dictionary.ContainsKey(val.cosmeticId))
				{
					dictionary[val.cosmeticId] = val;
					num++;
				}
			}
			if (num > 0)
			{
				AccessTools.Method(typeof(CosmeticDataManager), "RebuildSortedCosmeticIds", (Type[])null, (Type[])null).Invoke(null, null);
				Debug.Log((object)$"[MoreCosmetics] Injected {num} cosmetics. Cache has {dictionary.Count} total.");
			}
			_injected = true;
		}
	}
	[HarmonyPatch]
	internal static class CosmeticsUnlockManagerPatches
	{
		private static bool IsEnabled => PluginConfig.Enabled.Value;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CosmeticsUnlockManager), "OnAwake")]
		private static void OnAwake_Postfix(CosmeticsUnlockManager __instance)
		{
			if (!IsEnabled || !PluginConfig.AutoUnlockModCosmetics.Value)
			{
				return;
			}
			CosmeticData[] allCosmetics = CosmeticRegistry.AllCosmetics;
			foreach (CosmeticData val in allCosmetics)
			{
				if (__instance.UnlockCosmetic(val.cosmeticId))
				{
					Debug.Log((object)$"[MoreCosmetics] Unlocked: {val.cosmeticName} (ID:{val.cosmeticId})");
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerCustomization), "ApplyCosmetic")]
	internal static class PlayerCustomizationApplyPatch
	{
		private static bool IsEnabled => PluginConfig.Enabled.Value;

		[HarmonyPostfix]
		private static void Postfix(PlayerCustomization __instance, int cosmeticId)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled)
			{
				return;
			}
			CosmeticData cosmeticById = CosmeticDataManager.GetCosmeticById(cosmeticId);
			if ((Object)(object)cosmeticById == (Object)null || (Object)(object)cosmeticById.cosmeticMaterial == (Object)null)
			{
				return;
			}
			MeshFilter meshFilterForType = GetMeshFilterForType(__instance, cosmeticById.cosmeticType);
			if (!((Object)(object)meshFilterForType == (Object)null))
			{
				MeshRenderer component = ((Component)meshFilterForType).GetComponent<MeshRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					((Renderer)component).sharedMaterial = cosmeticById.cosmeticMaterial;
				}
			}
		}

		private static MeshFilter GetMeshFilterForType(PlayerCustomization instance, CosmeticType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected I4, but got Unknown
			string text = (int)type switch
			{
				0 => "hat", 
				1 => "hair", 
				2 => "mustache", 
				3 => "beard", 
				4 => "neckwear", 
				5 => "clothing", 
				6 => "facewear", 
				_ => null, 
			};
			if (text == null)
			{
				return null;
			}
			object? obj = typeof(PlayerCustomization).GetField(text, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance);
			return (MeshFilter)((obj is MeshFilter) ? obj : null);
		}
	}
}