Decompiled source of LobbySkinPreviewFix v1.0.0

plugins/LobbySkinPreviewFix.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace EVReborns.LobbySkinPreviewFix;

[BepInPlugin("evreborns.lobbyskinpreviewfix", "LobbySkinPreviewFix", "1.0.0")]
public class LobbySkinPreviewFix : BaseUnityPlugin
{
	internal static LobbySkinPreviewFix Inst;

	internal static ConfigEntry<bool> RemoveZeroFirst;

	internal static ConfigEntry<bool> Diagnostics;

	private static Type slotType;

	private static Type mscType;

	private static MethodInfo applyAsync;

	private static PropertyInfo curIdx;

	private bool hooked;

	private bool removedDsf;

	private static MethodInfo rebuild;

	private static MethodInfo applyLoadout;

	private static FieldInfo instField;

	private static bool rebuilding;

	private static bool enteredDuringRebuild;

	private static readonly Dictionary<int, int[]> last = new Dictionary<int, int[]>();

	private static Type locatorType;

	private static readonly HashSet<string> warned = new HashSet<string>();

	private static readonly HashSet<int> fixedLog = new HashSet<int>();

	private static readonly HashSet<int> ryoshuDone = new HashSet<int>();

	private void Awake()
	{
		Inst = this;
		RemoveZeroFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemoveDynamicSkinsFixZeroFirst", true, "Lepas hook 'ApplyZeroFirst' DynamicSkinsFix (penyebab tabrakan skin di lobby). Tidak diperlukan lagi karena mannequin dibuat ulang tiap ganti skin.");
		Diagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogDiagnostics", false, "Tulis info skin mannequin ke log setiap ganti skin (untuk debugging).");
		TryHook();
	}

	private void Start()
	{
		TryHook();
		TryRemoveDsf();
	}

	private void Update()
	{
		if (!removedDsf && Time.frameCount % 120 == 0 && Time.frameCount < 20000)
		{
			TryRemoveDsf();
		}
	}

	private static Type FindType(string full)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			Type type = null;
			try
			{
				type = assembly.GetType(full, throwOnError: false);
			}
			catch
			{
			}
			if (type != null)
			{
				return type;
			}
		}
		return null;
	}

	private void TryHook()
	{
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0313: Unknown result type (might be due to invalid IL or missing references)
		//IL_0321: Expected O, but got Unknown
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Expected O, but got Unknown
		//IL_0351: Unknown result type (might be due to invalid IL or missing references)
		//IL_035f: Expected O, but got Unknown
		if (hooked)
		{
			return;
		}
		try
		{
			Type type = FindType("RoR2.SurvivorMannequins.SurvivorMannequinSlotController");
			mscType = FindType("RoR2.ModelSkinController");
			if (type == null || mscType == null)
			{
				return;
			}
			MethodInfo method = type.GetMethod("ApplyLoadoutToMannequinInstance", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo[] methods = mscType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo.Name != "ApplySkinAsync") && typeof(IEnumerator).IsAssignableFrom(methodInfo.ReturnType) && (applyAsync == null || methodInfo.GetParameters().Length > applyAsync.GetParameters().Length))
				{
					applyAsync = methodInfo;
				}
			}
			curIdx = mscType.GetProperty("currentSkinIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null || applyAsync == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Method lobby/skin tidak ditemukan, mod tidak aktif.");
				hooked = true;
				return;
			}
			applyLoadout = method;
			rebuild = type.GetMethod("RebuildMannequinInstance", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			instField = type.GetField("mannequinInstanceTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (instField == null)
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.FieldType == typeof(Transform) && fieldInfo.Name.ToLower().Contains("instance"))
					{
						instField = fieldInfo;
						break;
					}
				}
			}
			if (rebuild == null || instField == null)
			{
				string text = "";
				FieldInfo[] fields2 = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo2 in fields2)
				{
					string text2 = text;
					text = text2 + fieldInfo2.FieldType.Name + " " + fieldInfo2.Name + "; ";
				}
				MethodInfo[] methods2 = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods2)
				{
					text = text + methodInfo2.Name + "(); ";
				}
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Info slot: " + text));
			}
			if (rebuild == null || instField == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("RebuildMannequinInstance/mannequinInstanceTransform tidak ketemu: rebuild=" + (rebuild != null) + " field=" + (instField != null)));
			}
			new Harmony("evreborns.lobbyskinpreviewfix").Patch((MethodBase)method, new HarmonyMethod(typeof(LobbySkinPreviewFix).GetMethod("Pre", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			slotType = type;
			Harmony val = new Harmony("evreborns.lobbyskinpreviewfix.apply");
			val.Patch((MethodBase)applyAsync, new HarmonyMethod(typeof(LobbySkinPreviewFix).GetMethod("PreApply", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			hooked = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook preview skin lobby terpasang.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Gagal hook: " + ex));
			hooked = true;
		}
	}

	private void TryRemoveDsf()
	{
		if (removedDsf || !RemoveZeroFirst.Value)
		{
			removedDsf = true;
			return;
		}
		try
		{
			Type type = FindType("DynamicSkinsFix.DynamicSkinsFix");
			Type type2 = FindType("On.RoR2.SurvivorMannequins.SurvivorMannequinSlotController");
			if (type == null)
			{
				removedDsf = true;
			}
			else if (!(type2 == null))
			{
				MethodInfo method = type.GetMethod("ApplyZeroFirst", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				EventInfo eventInfo = type2.GetEvent("ApplyLoadoutToMannequinInstance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null || eventInfo == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"ApplyZeroFirst tidak ditemukan; hanya pakai pemasangan ulang.");
					removedDsf = true;
					return;
				}
				Delegate obj = Delegate.CreateDelegate(eventInfo.EventHandlerType, method);
				eventInfo.GetRemoveMethod(nonPublic: true).Invoke(null, new object[1] { obj });
				removedDsf = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Hook ApplyZeroFirst DynamicSkinsFix dilepas (model dibuat ulang tiap ganti skin).");
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Gagal lepas ApplyZeroFirst: " + ex.Message));
			removedDsf = true;
		}
	}

	private static int MannequinId(object slot)
	{
		if (instField == null)
		{
			return 0;
		}
		object? value = instField.GetValue(slot);
		Object val = (Object)((value is Object) ? value : null);
		if (!(val == (Object)null))
		{
			return val.GetInstanceID();
		}
		return 0;
	}

	private static bool Pre(object __instance)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			int instanceID = ((Object)(Component)__instance).GetInstanceID();
			int num = MannequinId(__instance);
			int num2 = LoadoutSkin(__instance);
			if (rebuilding)
			{
				enteredDuringRebuild = true;
				last[instanceID] = new int[2] { num, num2 };
				return true;
			}
			if (rebuild != null && num != 0 && num2 >= 0 && last.TryGetValue(instanceID, out var value) && value[0] == num && value[1] != num2)
			{
				rebuilding = true;
				enteredDuringRebuild = false;
				try
				{
					rebuild.Invoke(__instance, null);
					if (!enteredDuringRebuild)
					{
						applyLoadout.Invoke(__instance, null);
					}
				}
				finally
				{
					rebuilding = false;
				}
				if ((Object)(object)Inst != (Object)null)
				{
					((BaseUnityPlugin)Inst).Logger.LogInfo((object)("Skin lobby ganti " + value[1] + " -> " + num2 + ": mannequin dibuat ulang."));
				}
				if (Diagnostics.Value)
				{
					((MonoBehaviour)__instance).StartCoroutine(Diag(__instance, num2));
				}
				return false;
			}
			bool flag = !last.TryGetValue(instanceID, out value) || value[0] != num;
			last[instanceID] = new int[2] { num, num2 };
			if (flag && num != 0 && Diagnostics.Value)
			{
				((MonoBehaviour)__instance).StartCoroutine(Diag(__instance, num2));
			}
		}
		catch (Exception ex)
		{
			rebuilding = false;
			if ((Object)(object)Inst != (Object)null)
			{
				((BaseUnityPlugin)Inst).Logger.LogWarning((object)("Pre: " + ex));
			}
		}
		return true;
	}

	private static object Member(object o, string typeName)
	{
		Type type = o.GetType();
		FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (fieldInfo.FieldType.FullName == typeName)
			{
				object value = fieldInfo.GetValue(o);
				if (value != null)
				{
					return value;
				}
			}
		}
		PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (PropertyInfo propertyInfo in properties)
		{
			if (!(propertyInfo.PropertyType.FullName == typeName) || propertyInfo.GetIndexParameters().Length != 0)
			{
				continue;
			}
			try
			{
				object value2 = propertyInfo.GetValue(o, null);
				if (value2 != null)
				{
					return value2;
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private static int LoadoutSkin(object slot)
	{
		try
		{
			object obj = Member(slot, "RoR2.Loadout");
			object obj2 = Member(slot, "RoR2.SurvivorDef");
			if (obj == null || obj2 == null)
			{
				return -1;
			}
			object? value = obj2.GetType().GetField("bodyPrefab").GetValue(obj2);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return -1;
			}
			Type type = FindType("RoR2.BodyCatalog");
			object obj3 = type.GetMethod("FindBodyIndex", new Type[1] { typeof(GameObject) }).Invoke(null, new object[1] { val });
			object value2 = obj.GetType().GetField("bodyLoadoutManager").GetValue(obj);
			MethodInfo method = value2.GetType().GetMethod("GetSkinIndex");
			return Convert.ToInt32(method.Invoke(value2, new object[1] { obj3 }));
		}
		catch
		{
			return -1;
		}
	}

	private static void Collect(object skinDef, List<Object> outList, int depth)
	{
		if (skinDef == null || depth > 4)
		{
			return;
		}
		FieldInfo[] fields = skinDef.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (typeof(ScriptableObject).IsAssignableFrom(fieldInfo.FieldType) && fieldInfo.Name.ToLower().Contains("param"))
			{
				Collect(fieldInfo.GetValue(skinDef), outList, depth + 1);
			}
			else
			{
				if (!fieldInfo.FieldType.IsArray || !(fieldInfo.GetValue(skinDef) is Array array))
				{
					continue;
				}
				Type elementType = fieldInfo.FieldType.GetElementType();
				if (fieldInfo.Name == "baseSkins")
				{
					foreach (object item in array)
					{
						Collect(item, outList, depth + 1);
					}
				}
				else
				{
					if (typeof(Object).IsAssignableFrom(elementType))
					{
						continue;
					}
					FieldInfo[] fields2 = elementType.GetFields(BindingFlags.Instance | BindingFlags.Public);
					foreach (object item2 in array)
					{
						if (item2 == null)
						{
							continue;
						}
						FieldInfo[] array2 = fields2;
						foreach (FieldInfo fieldInfo2 in array2)
						{
							if (typeof(Renderer).IsAssignableFrom(fieldInfo2.FieldType) || fieldInfo2.FieldType == typeof(GameObject))
							{
								object? value = fieldInfo2.GetValue(item2);
								Object val = (Object)((value is Object) ? value : null);
								if (val != (Object)null)
								{
									outList.Add(val);
								}
							}
						}
					}
				}
			}
		}
	}

	private static string RelPath(Transform t, Transform root)
	{
		string text = null;
		while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root)
		{
			text = ((text == null) ? ((Object)t).name : (((Object)t).name + "/" + text));
			t = t.parent;
		}
		if (!((Object)(object)t == (Object)(object)root))
		{
			return null;
		}
		return text;
	}

	private static Array FixClones(Component ctrl, Array skins)
	{
		bool flag = false;
		foreach (object skin in skins)
		{
			Object val = (Object)((skin is Object) ? skin : null);
			if (val != (Object)null && val.name.EndsWith("(Clone)"))
			{
				flag = true;
				break;
			}
		}
		if (!flag)
		{
			return skins;
		}
		Component componentInParent = ctrl.GetComponentInParent(slotType);
		if ((Object)(object)componentInParent == (Object)null)
		{
			return skins;
		}
		object obj = Member(componentInParent, "RoR2.SurvivorDef");
		if (obj == null)
		{
			return skins;
		}
		object? value = obj.GetType().GetField("bodyPrefab").GetValue(obj);
		GameObject val2 = (GameObject)((value is GameObject) ? value : null);
		if ((Object)(object)val2 == (Object)null)
		{
			return skins;
		}
		if (locatorType == null)
		{
			locatorType = FindType("RoR2.ModelLocator");
		}
		Component component = val2.GetComponent(locatorType);
		if ((Object)(object)component == (Object)null)
		{
			return skins;
		}
		Transform val3 = null;
		PropertyInfo property = locatorType.GetProperty("modelTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (property != null)
		{
			object? value2 = property.GetValue(component, null);
			val3 = (Transform)((value2 is Transform) ? value2 : null);
		}
		if ((Object)(object)val3 == (Object)null)
		{
			FieldInfo fieldInfo = locatorType.GetField("modelTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? locatorType.GetField("_modelTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (fieldInfo != null)
			{
				object? value3 = fieldInfo.GetValue(component);
				val3 = (Transform)((value3 is Transform) ? value3 : null);
			}
		}
		if ((Object)(object)val3 == (Object)null)
		{
			return skins;
		}
		Component component2 = ((Component)val3).GetComponent(mscType);
		if ((Object)(object)component2 == (Object)null)
		{
			return skins;
		}
		if (!(mscType.GetField("skins").GetValue(component2) is Array array))
		{
			return skins;
		}
		Dictionary<string, object> dictionary = new Dictionary<string, object>();
		foreach (object item in array)
		{
			Object val4 = (Object)((item is Object) ? item : null);
			if (val4 != (Object)null && !dictionary.ContainsKey(val4.name))
			{
				dictionary[val4.name] = item;
			}
		}
		Array array2 = (Array)skins.Clone();
		int num = 0;
		for (int i = 0; i < array2.Length; i++)
		{
			object? value4 = array2.GetValue(i);
			Object val5 = (Object)((value4 is Object) ? value4 : null);
			if (!(val5 == (Object)null) && val5.name.EndsWith("(Clone)"))
			{
				string text = val5.name.Substring(0, val5.name.Length - 7);
				Object val6 = (Object)((array.Length == array2.Length) ? /*isinst with value type is only supported in some contexts*/: null);
				object value5;
				if (val6 != (Object)null && val6.name == text)
				{
					array2.SetValue(val6, i);
					num++;
				}
				else if (dictionary.TryGetValue(text, out value5))
				{
					array2.SetValue(value5, i);
					num++;
				}
			}
		}
		if (num == 0)
		{
			if ((Object)(object)Inst != (Object)null && warned.Add(((Object)val2).name))
			{
				((BaseUnityPlugin)Inst).Logger.LogWarning((object)("Lobby: SkinDef asli untuk " + ((Object)val2).name + " tidak ketemu (skin tubuh: " + array.Length + ")."));
			}
			return skins;
		}
		if ((Object)(object)Inst != (Object)null && fixedLog.Add(((Object)ctrl).GetInstanceID()))
		{
			((BaseUnityPlugin)Inst).Logger.LogInfo((object)("Lobby: " + num + " skin salinan di " + ((Object)ctrl).name + " diganti ke SkinDef asli."));
		}
		mscType.GetField("skins").SetValue(ctrl, array2);
		return array2;
	}

	private static void FixRyoshu(object sd)
	{
		Object val = (Object)((sd is Object) ? sd : null);
		if (val == (Object)null || ryoshuDone.Contains(val.GetInstanceID()))
		{
			return;
		}
		FieldInfo field = sd.GetType().GetField("nameToken");
		if (field == null || field.GetValue(sd) as string != "XION_SKIN_SKINDEF_NAME")
		{
			return;
		}
		ryoshuDone.Add(val.GetInstanceID());
		object? value = sd.GetType().GetField("rootObject").GetValue(sd);
		GameObject val2 = (GameObject)((value is GameObject) ? value : null);
		if ((Object)(object)val2 == (Object)null)
		{
			return;
		}
		Transform val3 = val2.transform.Find("MercMesh");
		Renderer val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Renderer>() : null);
		if ((Object)(object)val4 == (Object)null)
		{
			((BaseUnityPlugin)Inst).Logger.LogWarning((object)"Ryoshu: MercMesh tidak ketemu.");
			return;
		}
		int num = Retarget(sd, val4, 0);
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		FieldInfo[] fields = sd.GetType().GetFields(bindingAttr);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (fieldInfo.FieldType.Name.Contains("RuntimeSkin"))
			{
				try
				{
					fieldInfo.SetValue(sd, fieldInfo.FieldType.IsValueType ? Activator.CreateInstance(fieldInfo.FieldType) : null);
				}
				catch
				{
				}
			}
			else if (fieldInfo.FieldType == typeof(bool) && fieldInfo.Name.ToLower().Contains("bak"))
			{
				try
				{
					fieldInfo.SetValue(sd, false);
				}
				catch
				{
				}
			}
		}
		((BaseUnityPlugin)Inst).Logger.LogInfo((object)("Ryoshu: " + num + " target dipindah dari partikel ke MercMesh."));
	}

	private static int Retarget(object obj, Renderer good, int depth)
	{
		if (obj == null || depth > 2)
		{
			return 0;
		}
		int num = 0;
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		FieldInfo[] fields = obj.GetType().GetFields(bindingAttr);
		foreach (FieldInfo fieldInfo in fields)
		{
			Type fieldType = fieldInfo.FieldType;
			if (typeof(ScriptableObject).IsAssignableFrom(fieldType) && fieldInfo.Name.ToLower().Contains("param"))
			{
				num += Retarget(fieldInfo.GetValue(obj), good, depth + 1);
			}
			else
			{
				if (!fieldType.IsArray)
				{
					continue;
				}
				Type elementType = fieldType.GetElementType();
				if (typeof(Object).IsAssignableFrom(elementType) || elementType.IsPrimitive || elementType == typeof(string) || !(fieldInfo.GetValue(obj) is Array array))
				{
					continue;
				}
				FieldInfo[] fields2 = elementType.GetFields(bindingAttr);
				for (int j = 0; j < array.Length; j++)
				{
					object value = array.GetValue(j);
					if (value == null)
					{
						continue;
					}
					bool flag = false;
					FieldInfo[] array2 = fields2;
					foreach (FieldInfo fieldInfo2 in array2)
					{
						if (typeof(Renderer).IsAssignableFrom(fieldInfo2.FieldType))
						{
							object? value2 = fieldInfo2.GetValue(value);
							Renderer val = (Renderer)((value2 is Renderer) ? value2 : null);
							if ((Object)(object)val != (Object)null && !(val is SkinnedMeshRenderer) && !(val is MeshRenderer))
							{
								fieldInfo2.SetValue(value, good);
								flag = true;
							}
						}
					}
					if (flag)
					{
						array.SetValue(value, j);
						num++;
					}
				}
			}
		}
		return num;
	}

	private static void PreApply(Component __instance, int __0)
	{
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Unknown result type (might be due to invalid IL or missing references)
		//IL_0317: Expected O, but got Unknown
		//IL_028a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Expected O, but got Unknown
		try
		{
			if ((Object)(object)__instance == (Object)null || slotType == null)
			{
				return;
			}
			try
			{
				if (mscType.GetField("skins").GetValue(__instance) is Array array && __0 >= 0 && __0 < array.Length)
				{
					FixRyoshu(array.GetValue(__0));
				}
			}
			catch (Exception ex)
			{
				if ((Object)(object)Inst != (Object)null && warned.Add("ry:" + ex.Message))
				{
					((BaseUnityPlugin)Inst).Logger.LogWarning((object)("FixRyoshu: " + ex));
				}
			}
			if ((Object)(object)__instance.GetComponentInParent(slotType) == (Object)null)
			{
				return;
			}
			Array array2 = mscType.GetField("skins").GetValue(__instance) as Array;
			if (array2 == null || __0 < 0 || __0 >= array2.Length)
			{
				return;
			}
			try
			{
				array2 = FixClones(__instance, array2);
			}
			catch (Exception ex2)
			{
				if ((Object)(object)Inst != (Object)null && warned.Add("fc:" + ex2.Message))
				{
					((BaseUnityPlugin)Inst).Logger.LogWarning((object)("FixClones: " + ex2));
				}
			}
			object value = array2.GetValue(__0);
			if (value == null)
			{
				return;
			}
			object? value2 = value.GetType().GetField("rootObject").GetValue(value);
			GameObject val = (GameObject)((value2 is GameObject) ? value2 : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			List<Object> list = new List<Object>();
			Collect(value, list, 0);
			Transform transform = __instance.transform;
			int num = 0;
			foreach (Object item in list)
			{
				Transform t = ((item is Component) ? ((Component)item).transform : ((GameObject)item).transform);
				string text = RelPath(t, val.transform);
				if (string.IsNullOrEmpty(text) || (Object)(object)transform.Find(text) != (Object)null)
				{
					continue;
				}
				string[] array3 = text.Split('/');
				bool flag = false;
				for (int i = 1; i < array3.Length; i++)
				{
					if (flag)
					{
						break;
					}
					string text2 = string.Join("/", array3, i, array3.Length - i);
					if ((Object)(object)transform.Find(text2) == (Object)null)
					{
						continue;
					}
					Transform val2 = transform.Find(array3[i]);
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2.parent != (Object)(object)transform)
					{
						continue;
					}
					Transform val3 = transform;
					for (int j = 0; j < i; j++)
					{
						Transform val4 = val3.Find(array3[j]);
						if ((Object)(object)val4 == (Object)null)
						{
							GameObject val5 = new GameObject(array3[j]);
							val5.transform.SetParent(val3, false);
							val4 = val5.transform;
						}
						val3 = val4;
					}
					val2.SetParent(val3, true);
					flag = true;
				}
				if (flag)
				{
					num++;
					continue;
				}
				Transform val6 = transform;
				for (int k = 0; k < array3.Length; k++)
				{
					Transform val7 = val6.Find(array3[k]);
					if ((Object)(object)val7 == (Object)null)
					{
						GameObject val8 = new GameObject(array3[k]);
						val8.transform.SetParent(val6, false);
						val7 = val8.transform;
					}
					val6 = val7;
				}
				if (item is Renderer && (Object)(object)((Component)val6).GetComponent<Renderer>() == (Object)null)
				{
					Renderer val9;
					if (item is SkinnedMeshRenderer)
					{
						val9 = (Renderer)(object)((Component)val6).gameObject.AddComponent<SkinnedMeshRenderer>();
					}
					else
					{
						((Component)val6).gameObject.AddComponent<MeshFilter>();
						val9 = (Renderer)(object)((Component)val6).gameObject.AddComponent<MeshRenderer>();
					}
					val9.enabled = false;
				}
				num++;
			}
			if (num > 0 && (Object)(object)Inst != (Object)null)
			{
				((BaseUnityPlugin)Inst).Logger.LogInfo((object)("Lobby: " + num + " bagian model yang hilang dibuatkan pengganti untuk skin '" + ((Object)value).name + "'."));
			}
		}
		catch (Exception ex3)
		{
			if ((Object)(object)Inst != (Object)null)
			{
				((BaseUnityPlugin)Inst).Logger.LogWarning((object)("PreApply: " + ex3));
			}
		}
	}

	private static IEnumerator Diag(object slot, int want)
	{
		yield return (object)new WaitForSecondsRealtime(1.5f);
		if (slot == null || (Object)slot == (Object)null)
		{
			yield break;
		}
		try
		{
			Component componentInChildren = ((Component)slot).GetComponentInChildren(mscType);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				((BaseUnityPlugin)Inst).Logger.LogInfo((object)"[Diag] tidak ada ModelSkinController di mannequin");
				yield break;
			}
			Array array = mscType.GetField("skins").GetValue(componentInChildren) as Array;
			string text = "";
			if (array != null)
			{
				for (int i = 0; i < array.Length; i++)
				{
					object? value = array.GetValue(i);
					Object val = (Object)((value is Object) ? value : null);
					object obj = text;
					text = string.Concat(obj, i, ":", (val != (Object)null) ? val.name : "null", " ");
				}
			}
			string text2 = "";
			MonoBehaviour[] components = componentInChildren.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val2 in components)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					text2 = text2 + ((object)val2).GetType().Name + " ";
				}
			}
			int num = ((curIdx != null) ? ((int)curIdx.GetValue(componentInChildren, null)) : (-1));
			string text3 = "";
			Renderer[] componentsInChildren = componentInChildren.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				string text4 = "-";
				SkinnedMeshRenderer val4 = (SkinnedMeshRenderer)(object)((val3 is SkinnedMeshRenderer) ? val3 : null);
				if ((Object)(object)val4 != (Object)null)
				{
					text4 = (((Object)(object)val4.sharedMesh != (Object)null) ? ((Object)val4.sharedMesh).name : "null");
				}
				else
				{
					MeshFilter component = ((Component)val3).GetComponent<MeshFilter>();
					if ((Object)(object)component != (Object)null)
					{
						text4 = (((Object)(object)component.sharedMesh != (Object)null) ? ((Object)component.sharedMesh).name : "null");
					}
				}
				string text5 = text3;
				text3 = text5 + RelPath(((Component)val3).transform, componentInChildren.transform) + "{" + ((val3.enabled && ((Component)val3).gameObject.activeInHierarchy) ? "on" : "off") + ",mesh=" + text4 + ",mat=" + (((Object)(object)val3.sharedMaterial != (Object)null) ? ((Object)val3.sharedMaterial).name : "null") + "} ";
			}
			string text6 = "";
			if (array != null && num >= 0 && num < array.Length)
			{
				List<Object> list = new List<Object>();
				object value2 = array.GetValue(num);
				Collect(value2, list, 0);
				object? value3 = value2.GetType().GetField("rootObject").GetValue(value2);
				GameObject val5 = (GameObject)((value3 is GameObject) ? value3 : null);
				foreach (Object item in list)
				{
					Transform val6 = ((item is Component) ? ((Component)item).transform : ((GameObject)item).transform);
					text6 = text6 + (((Object)(object)val5 != (Object)null) ? RelPath(val6, val5.transform) : ((Object)val6).name) + " ";
				}
				text6 = ((Object)value2).name + " root=" + (((Object)(object)val5 != (Object)null) ? ((Object)val5).name : "null") + " target=[" + text6 + "]";
			}
			((BaseUnityPlugin)Inst).Logger.LogInfo((object)("[Diag] renderer " + ((Object)componentInChildren).name + ": " + text3));
			((BaseUnityPlugin)Inst).Logger.LogInfo((object)("[Diag] skin aktif: " + text6));
			((BaseUnityPlugin)Inst).Logger.LogInfo((object)("[Diag] model=" + ((Object)componentInChildren).name + " mau=" + want + " current=" + num + " skins(" + (array?.Length ?? 0) + ")=[" + text + "] komponen=[" + text2 + "]"));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)Inst).Logger.LogWarning((object)("[Diag] " + ex.Message));
		}
	}
}