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(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(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(); private static readonly List _pendingVanilla = new List(); private static int _nextId; private static readonly List _registeredDirs = new List(); 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 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 list2 = new List(); 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 list3 = new List(_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 list = new List(); List list2 = new List(); 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 list3 = new List(_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(entry.type, ignoreCase: true, out CosmeticType result)) { return null; } CosmeticRarity result2 = (CosmeticRarity)0; if (!string.IsNullOrEmpty(entry.rarity)) { Enum.TryParse(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(); ((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().sharedMesh = val; val2.AddComponent(); 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 dictionary)) { return null; } foreach (KeyValuePair 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(); 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().sharedMesh = Object.Instantiate(component.sharedMesh); val.AddComponent(); 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 ParseFromJson(string json) { List list = new List(); 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 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 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 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 list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); 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 dict = new Dictionary(); List list6 = new List(); List list7 = new List(); List list8 = new List(); List list9 = new List(); 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 dict, List verts, List uvs, List norms, List posSrc, List uvSrc, List 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 vertices, List<(int, int, int)> faces) { List list = new List(); 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 hashSet = new HashSet { 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 Enabled { get; private set; } public static ConfigEntry AutoDiscover { get; private set; } public static ConfigEntry AutoUnlockModCosmetics { get; private set; } public static ConfigEntry CosmeticIdStart { get; private set; } public static void Bind(ConfigFile config) { Enabled = config.Bind("General", "Enabled", true, "Globally enables or disables the library and all loaded cosmetics."); AutoDiscover = config.Bind("General", "AutoDiscover", true, "When true, automatically scans all plugin folders for cosmetics.json files."); AutoUnlockModCosmetics = config.Bind("General", "AutoUnlockModCosmetics", true, "When true, all loaded cosmetics are automatically unlocked on game start."); CosmeticIdStart = config.Bind("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> ParseArray(string json) { List> list = new List>(); 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 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 dictionary2 = ParseObject(json.Substring(num2 + 1, json.Length - num2 - 2)); if (dictionary2 != null) { list.Add(dictionary2); } } return list; } public static Dictionary ParseObject(string segment) { Dictionary dictionary = new Dictionary(); 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(); } List list = new List(); 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 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(); 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); } } }