Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of InfernoSkinFix v0.1.0
plugins/InfernoSkinFix.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using HG; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using RoR2; using RoR2.ContentManagement; using RoR2.UI.MainMenu; using UnityEngine; using UnityEngine.AddressableAssets; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("InfernoSkinFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+e9674f1eacdd89232c4a4bde643cd94cce44951e")] [assembly: AssemblyProduct("InfernoSkinFix")] [assembly: AssemblyTitle("InfernoSkinFix")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 InfernoSkinFix { internal sealed class AccessoryRigSpec { public readonly InfernoSkin Skin; public readonly GameObject ChainPrefab; public readonly string ParentBone; public readonly int InsertAt; public readonly int BaseBoneCount; public readonly int ChainLength; public readonly object DynamicBoneData; public readonly HashSet<Mesh> Meshes; private AccessoryRigSpec(InfernoSkin skin, GameObject prefab, string parentBone, int insertAt, int baseBoneCount, int chainLength, object dynamicBoneData, HashSet<Mesh> meshes) { Skin = skin; ChainPrefab = prefab; ParentBone = parentBone; InsertAt = insertAt; BaseBoneCount = baseBoneCount; ChainLength = chainLength; DynamicBoneData = dynamicBoneData; Meshes = meshes; } public static AccessoryRigSpec TryCreate(InfernoSkin skin, SkinDef bodySkin, ModelSkinController body, out string error) { //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) object[] modifications = InfernoDynamicSkins.GetModifications(skin.Token); if (modifications.Length != 1) { error = $"expected 1 DynamicSkins modification for {skin.Token}, found {modifications.Length}"; return null; } object owner = modifications[0]; object field = InfernoDynamicSkins.GetField(owner, "prefab"); GameObject val = (GameObject)((field is GameObject) ? field : null); string text = InfernoDynamicSkins.GetField(owner, "parentname") as string; object field2 = InfernoDynamicSkins.GetField(owner, "boneIndex"); object field3 = InfernoDynamicSkins.GetField(owner, "affectsbasemodel"); if (!Object.op_Implicit((Object)(object)val) || string.IsNullOrEmpty(text) || !(field2 is int num) || !(field3 is bool) || !(bool)field3) { error = "unexpected DynamicSkins modification data"; return null; } SkinnedMeshRenderer[] array = BaseRenderers(((Component)body).transform); int boneCount = ((array.Length != 0) ? array[0].bones.Length : 0); if (array.Length == 0 || array.Any((SkinnedMeshRenderer r) => r.bones.Length != boneCount) || num < 0 || num > boneCount) { error = $"body skinned renderers do not share one bone list (count {boneCount}, insert at {num})"; return null; } if (!Object.op_Implicit((Object)(object)FindChild(((Component)body).transform, text))) { error = "parent bone '" + text + "' not found"; return null; } int count = Chain(val.transform).Count; HashSet<Mesh> hashSet = new HashSet<Mesh>(); MeshReplacement[] meshReplacements = bodySkin.meshReplacements; foreach (MeshReplacement val2 in meshReplacements) { if (Object.op_Implicit((Object)(object)val2.mesh) && val2.renderer is SkinnedMeshRenderer && !((Object)(object)((Component)val2.renderer).transform.parent != (Object)(object)((Component)body).transform)) { int num3 = val2.mesh.bindposes.Length; if (num3 != boneCount + count) { error = $"mesh '{((Object)val2.mesh).name}' has {num3} bindposes, expected {boneCount} + {count}"; return null; } hashSet.Add(val2.mesh); } } if (hashSet.Count == 0) { error = "no Inferno mesh needs the extra bones"; return null; } error = null; return new AccessoryRigSpec(skin, val, text, num, boneCount, count, InfernoDynamicSkins.GetField(owner, "dynamicBoneData"), hashSet); } internal static SkinnedMeshRenderer[] BaseRenderers(Transform model) { return (from r in ((Component)model).GetComponentsInChildren<SkinnedMeshRenderer>(true) where (Object)(object)((Component)r).transform.parent == (Object)(object)model select r).ToArray(); } internal static List<Transform> Chain(Transform root) { List<Transform> list = new List<Transform>(); Walk(root); return list; void Walk(Transform t) { if (!((Object)t).name.EndsWith("_end", StringComparison.Ordinal)) { list.Add(t); } for (int i = 0; i < t.childCount; i++) { Walk(t.GetChild(i)); } } } internal static Transform FindChild(Transform root, string name) { if (((Object)root).name == name) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChild(root.GetChild(i), name); if (Object.op_Implicit((Object)(object)val)) { return val; } } return null; } } internal sealed class AccessoryBoneRig : MonoBehaviour { internal static Action<string> LogError = delegate { }; private AccessoryRigSpec spec; private SkinnedMeshRenderer[] renderers; private Transform[][] originalBones; private Mesh[] seenMesh; private bool[] extended; private bool initialized; private GameObject chainRoot; private Transform[] chain; private readonly List<Component> addedComponents = new List<Component>(); public static void Ensure(ModelSkinController controller, AccessoryRigSpec spec) { AccessoryBoneRig accessoryBoneRig = default(AccessoryBoneRig); if (((Component)controller).TryGetComponent<AccessoryBoneRig>(ref accessoryBoneRig)) { accessoryBoneRig.Sync(); return; } SkinnedMeshRenderer[] array = AccessoryRigSpec.BaseRenderers(((Component)controller).transform); if (array.Length == 0 || array.Any((SkinnedMeshRenderer r) => r.bones.Length != spec.BaseBoneCount)) { LogError($"{spec.Skin.Survivor}: '{((Object)controller).name}' does not have the expected {spec.BaseBoneCount}-bone layout; accessory bones not added."); return; } AccessoryBoneRig accessoryBoneRig2 = ((Component)controller).gameObject.AddComponent<AccessoryBoneRig>(); accessoryBoneRig2.spec = spec; accessoryBoneRig2.renderers = array; accessoryBoneRig2.originalBones = array.Select((SkinnedMeshRenderer r) => r.bones).ToArray(); accessoryBoneRig2.seenMesh = (Mesh[])(object)new Mesh[array.Length]; accessoryBoneRig2.extended = new bool[array.Length]; accessoryBoneRig2.Sync(); } private void LateUpdate() { Sync(); } internal void Sync() { bool flag = false; for (int i = 0; i < renderers.Length; i++) { SkinnedMeshRenderer val = renderers[i]; if (!Object.op_Implicit((Object)(object)val)) { continue; } Mesh sharedMesh = val.sharedMesh; if (initialized && sharedMesh == seenMesh[i]) { flag |= extended[i]; continue; } seenMesh[i] = sharedMesh; bool flag2 = Object.op_Implicit((Object)(object)sharedMesh) && spec.Meshes.Contains(sharedMesh); if (flag2 != extended[i]) { if (flag2 && !AttachChain()) { flag2 = false; } val.bones = (flag2 ? Extend(originalBones[i]) : originalBones[i]); extended[i] = flag2; } flag |= extended[i]; } initialized = true; if (!flag && Object.op_Implicit((Object)(object)chainRoot)) { DetachChain(); } } private Transform[] Extend(Transform[] original) { List<Transform> list = new List<Transform>(original.Length + chain.Length); list.AddRange(original); list.InsertRange(spec.InsertAt, chain); return list.ToArray(); } private bool AttachChain() { if (Object.op_Implicit((Object)(object)chainRoot)) { return true; } try { Transform val = AccessoryRigSpec.FindChild(((Component)this).transform, spec.ParentBone); chainRoot = Object.Instantiate<GameObject>(spec.ChainPrefab, val, false); ((Object)chainRoot).name = ((Object)spec.ChainPrefab).name; chain = AccessoryRigSpec.Chain(chainRoot.transform).ToArray(); if (spec.DynamicBoneData != null) { AddDynamicBone(); } return true; } catch (Exception arg) { LogError($"{spec.Skin.Survivor}: could not add accessory bones to '{((Object)this).name}': {arg}"); DetachChain(); return false; } } private void AddDynamicBone() { object dynamicBoneData = spec.DynamicBoneData; DynamicBone val = chainRoot.AddComponent<DynamicBone>(); addedComponents.Add((Component)(object)val); CopyMatchingFields(dynamicBoneData, val, "m_Root", "m_Colliders", "m_Exclusions"); val.m_Root = AccessoryRigSpec.FindChild(chainRoot.transform, (InfernoDynamicSkins.GetField(dynamicBoneData, "m_Root") as string) ?? ((Object)chainRoot).name); val.m_Exclusions = new List<Transform>(); if (InfernoDynamicSkins.GetField(dynamicBoneData, "m_Exclusions") is IEnumerable<string> enumerable) { foreach (string item in enumerable) { Transform val2 = AccessoryRigSpec.FindChild(val.m_Root, item); if (Object.op_Implicit((Object)(object)val2)) { val.m_Exclusions.Add(val2); } } } val.m_Colliders = new List<DynamicBoneCollider>(); if (!(InfernoDynamicSkins.GetField(dynamicBoneData, "m_Colliders") is IEnumerable enumerable2)) { return; } foreach (object item2 in enumerable2) { Transform val3 = AccessoryRigSpec.FindChild(((Component)this).transform, (InfernoDynamicSkins.GetField(item2, "m_parent_name") as string) ?? ""); if (Object.op_Implicit((Object)(object)val3)) { DynamicBoneCollider val4 = ((Component)val3).gameObject.AddComponent<DynamicBoneCollider>(); CopyMatchingFields(item2, val4, "m_parent_name"); val.m_Colliders.Add(val4); addedComponents.Add((Component)(object)val4); } } } private static void CopyMatchingFields(object source, object target, params string[] skip) { FieldInfo[] fields = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (Array.IndexOf(skip, fieldInfo.Name) < 0) { FieldInfo field = target.GetType().GetField(fieldInfo.Name, BindingFlags.Instance | BindingFlags.Public); if (field != null && field.FieldType == fieldInfo.FieldType) { field.SetValue(target, fieldInfo.GetValue(source)); } } } } private void DetachChain() { foreach (Component addedComponent in addedComponents) { if (Object.op_Implicit((Object)(object)addedComponent)) { Object.Destroy((Object)(object)addedComponent); } } addedComponents.Clear(); if (Object.op_Implicit((Object)(object)chainRoot)) { Object.Destroy((Object)(object)chainRoot); } chainRoot = null; chain = null; } } [BepInPlugin("Nhiblam.InfernoSkinFix", "InfernoSkinFix", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class InfernoSkinFixPlugin : BaseUnityPlugin { private delegate IEnumerator ApplySkinAsyncFn(ModelSkinController self, int skinIndex, AsyncReferenceHandleUnloadType unloadType); public const string Guid = "Nhiblam.InfernoSkinFix"; public const string PluginName = "InfernoSkinFix"; public const string PluginVersion = "0.1.0"; private const string LobbySkinsFixGuid = "com.KingEnderBrine.LobbySkinsFix"; private const string R2ApiSkinsGuid = "com.bepis.r2api.skins"; private const string DynamicSkinsFixGuid = "Miyowi.DynamicSkinsFix"; private Hook skinCatalogInitHook; private Hook applySkinHook; private void Awake() { //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown SkinTrace.Log = ((BaseUnityPlugin)this).Logger.LogInfo; SkinTrace.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "TraceSkinApplication", false, "Troubleshooting: log the renderer, mesh, bone and material state of Inferno-skinned survivors whenever a skin is applied (lobby and run).").Value; SkinRepairs.LogInfo = ((BaseUnityPlugin)this).Logger.LogInfo; SkinRepairs.LogError = ((BaseUnityPlugin)this).Logger.LogError; AccessoryBoneRig.LogError = ((BaseUnityPlugin)this).Logger.LogError; ((BaseUnityPlugin)this).Logger.LogInfo((object)("InfernoSkinFix 0.1.0 build=" + BuildId() + " sha256=" + OwnHash() + " with Inferno " + InfernoSkins.GetPluginVersion("HIFU.Inferno") + " (InfernoSkinMod " + InfernoSkins.GetPluginVersion("com.Dotflare.InfernoSkinMod") + ")")); string pluginVersion = InfernoSkins.GetPluginVersion("Miyowi.DynamicSkinsFix"); if (pluginVersion != null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("DynamicSkinsFix " + pluginVersion + " detected: Inferno's own Bandit/Railgunner bone hook stays disabled; InfernoSkinFix adds those bones.")); } if (!InfernoDynamicSkins.Bind()) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not read InfernoSkinMod's DynamicSkins data (" + InfernoDynamicSkins.BindError + "); Bandit and Railgunner will not be repaired.")); } try { MethodInfo methodInfo = typeof(SkinCatalog).GetMethod("Init", BindingFlags.Static | BindingFlags.NonPublic, null, Type.EmptyTypes, null) ?? throw new MissingMethodException("RoR2.SkinCatalog", "Init"); skinCatalogInitHook = new Hook((MethodBase)methodInfo, (Delegate)new Func<Func<IEnumerator>, IEnumerator>(OnSkinCatalogInit)); MethodInfo method = typeof(ModelSkinController).GetMethod("ApplySkinAsync", new Type[2] { typeof(int), typeof(AsyncReferenceHandleUnloadType) }); applySkinHook = new Hook((MethodBase)method, (Delegate)new Func<ApplySkinAsyncFn, ModelSkinController, int, AsyncReferenceHandleUnloadType, IEnumerator>(OnApplySkinAsync)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Hook installation failed; Inferno skins are not repaired: " + ex)); Hook obj = skinCatalogInitHook; if (obj != null) { obj.Dispose(); } Hook obj2 = applySkinHook; if (obj2 != null) { obj2.Dispose(); } return; } ((ResourceAvailability)(ref SkinCatalog.availability)).CallWhenAvailable((Action)SkinRepairs.Report); if (SkinTrace.Enabled) { ((ResourceAvailability)(ref SkinCatalog.availability)).CallWhenAvailable((Action)ReportBodySkins); MainMenuController.OnMainMenuInitialised += ReportDisplaySkins; } } private void OnDestroy() { Hook obj = skinCatalogInitHook; if (obj != null) { obj.Dispose(); } Hook obj2 = applySkinHook; if (obj2 != null) { obj2.Dispose(); } MainMenuController.OnMainMenuInitialised -= ReportDisplaySkins; } private static IEnumerator OnSkinCatalogInit(Func<IEnumerator> orig) { SkinRepairs.PatchSkinDefs(); return orig(); } private static IEnumerator OnApplySkinAsync(ApplySkinAsyncFn orig, ModelSkinController self, int skinIndex, AsyncReferenceHandleUnloadType unloadType) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) IEnumerator inner = orig(self, skinIndex, unloadType); bool flag = false; try { SkinDef[] skins = self.skins; AccessoryRigSpec accessoryRigSpec = SkinRepairs.FindRig(InfernoSkins.Identify((skins != null && skins.Length != 0) ? skins[((uint)skinIndex < skins.Length) ? skinIndex : 0] : null)); if (accessoryRigSpec != null) { AccessoryBoneRig.Ensure(self, accessoryRigSpec); } AccessoryBoneRig accessoryBoneRig = default(AccessoryBoneRig); flag = ((Component)self).TryGetComponent<AccessoryBoneRig>(ref accessoryBoneRig); } catch (Exception arg) { AccessoryBoneRig.LogError(string.Format("Accessory bone setup failed on '{0}': {1}", Object.op_Implicit((Object)(object)self) ? ((Object)self).name : "null", arg)); } if (flag) { inner = SyncAfter(self, inner); } return SkinTrace.Wrap(self, skinIndex, inner); } private static IEnumerator SyncAfter(ModelSkinController controller, IEnumerator inner) { while (inner.MoveNext()) { yield return inner.Current; } AccessoryBoneRig accessoryBoneRig = default(AccessoryBoneRig); if (Object.op_Implicit((Object)(object)controller) && ((Component)controller).TryGetComponent<AccessoryBoneRig>(ref accessoryBoneRig)) { accessoryBoneRig.Sync(); } } private void ReportBodySkins() { InfernoSkin[] all = InfernoSkins.All; foreach (InfernoSkin infernoSkin in all) { try { ModelSkinController val = InfernoSkins.FindBodyModelSkinController(infernoSkin.BodyName); SkinDef val2 = infernoSkin.FindBodySkin(); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(SkinTrace.DescribeModel(infernoSkin.Survivor + " body", val) + "\n" + SkinTrace.DescribeLegacyTargets(val2, val) + "\n" + SkinTrace.DescribeSkin(val2, " ") + "\n" + SkinTrace.DescribeSkin(val.skins[0], " "))); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{infernoSkin.Survivor}: body report failed: {arg}"); } } } private void ReportDisplaySkins() { MainMenuController.OnMainMenuInitialised -= ReportDisplaySkins; InfernoSkin[] all = InfernoSkins.All; foreach (InfernoSkin infernoSkin in all) { try { SurvivorDef val = SurvivorCatalog.FindSurvivorDefFromBody(BodyCatalog.FindBodyPrefab(infernoSkin.BodyName)); ModelSkinController val2 = ((Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.displayPrefab)) ? val.displayPrefab.GetComponentInChildren<ModelSkinController>() : null); if (!Object.op_Implicit((Object)(object)val2)) { continue; } string text = SkinTrace.DescribeModel(infernoSkin.Survivor + " display", val2); SkinDef[] skins = val2.skins; foreach (SkinDef skin in skins) { if (InfernoSkins.Identify(skin) == infernoSkin) { text = text + "\n" + SkinTrace.DescribeSkin(skin, " "); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)text); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{infernoSkin.Survivor}: display report failed: {arg}"); } } } private static string BuildId() { return typeof(InfernoSkinFixPlugin).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "unknown"; } private string OwnHash() { try { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(((BaseUnityPlugin)this).Info.Location); return BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", ""); } catch (Exception ex) { return "unavailable (" + ex.GetType().Name + ")"; } } } internal sealed class InfernoSkin { public readonly string Survivor; public readonly string BodyName; public readonly string SkinName; public readonly string Token; public InfernoSkin(string survivor, string bodyName, string skinName, string token) { Survivor = survivor; BodyName = bodyName; SkinName = skinName; Token = token; } public SkinDef FindBodySkin() { ModelSkinController val = InfernoSkins.FindBodyModelSkinController(BodyName); if (!Object.op_Implicit((Object)(object)val) || val.skins == null) { return null; } SkinDef[] skins = val.skins; foreach (SkinDef val2 in skins) { if (Object.op_Implicit((Object)(object)val2) && ((Object)val2).name == SkinName && val2.nameToken == Token) { return val2; } } return null; } } internal static class InfernoSkins { public const string InfernoGuid = "HIFU.Inferno"; public const string SkinModGuid = "com.Dotflare.InfernoSkinMod"; public static readonly InfernoSkin Commando = new InfernoSkin("Commando", "CommandoBody", "MMando", "DOTFLARE_SKIN_MMANDO_NAME"); public static readonly InfernoSkin Bandit = new InfernoSkin("Bandit", "Bandit2Body", "DBandit", "DOTFLARE_SKIN_DBANDIT_NAME"); public static readonly InfernoSkin Captain = new InfernoSkin("Captain", "CaptainBody", "BCaptain", "DOTFLARE_SKIN_BCAPTAIN_NAME"); public static readonly InfernoSkin Mercenary = new InfernoSkin("Mercenary", "MercBody", "HMerc", "DOTFLARE_SKIN_HMERC_NAME"); public static readonly InfernoSkin Artificer = new InfernoSkin("Artificer", "MageBody", "CArti", "DOTFLARE_SKIN_CARTI_NAME"); public static readonly InfernoSkin Railgunner = new InfernoSkin("Railgunner", "RailgunnerBody", "PGunner", "DOTFLARE_SKIN_PGUNNER_NAME"); public static readonly InfernoSkin[] All = new InfernoSkin[6] { Commando, Bandit, Captain, Mercenary, Artificer, Railgunner }; public static InfernoSkin Identify(SkinDef skin) { if (!Object.op_Implicit((Object)(object)skin)) { return null; } string name = ((Object)skin).name; InfernoSkin[] all = All; foreach (InfernoSkin infernoSkin in all) { if (skin.nameToken == infernoSkin.Token && (name == infernoSkin.SkinName || name.StartsWith(infernoSkin.SkinName + "(", StringComparison.Ordinal))) { return infernoSkin; } } return null; } public static InfernoSkin FindOnController(ModelSkinController controller) { if (!Object.op_Implicit((Object)(object)controller) || controller.skins == null) { return null; } SkinDef[] skins = controller.skins; for (int i = 0; i < skins.Length; i++) { InfernoSkin infernoSkin = Identify(skins[i]); if (infernoSkin != null) { return infernoSkin; } } return null; } public static ModelSkinController FindBodyModelSkinController(string bodyName) { GameObject val = BodyCatalog.FindBodyPrefab(bodyName); ModelLocator val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ModelLocator>() : null); if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val2.modelTransform)) { return null; } return ((Component)val2.modelTransform).GetComponent<ModelSkinController>(); } public static string GetPluginVersion(string guid) { if (!Chainloader.PluginInfos.TryGetValue(guid, out var value)) { return null; } return value.Metadata.Version.ToString(); } } internal static class InfernoDynamicSkins { private const BindingFlags Fields = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public static object Manager { get; private set; } public static string BindError { get; private set; } public static int ModifiedObjectCount { get { if (!(GetField(Manager, "ModifiedObjects") is ICollection collection)) { return -1; } return collection.Count; } } public static bool Bind() { try { if (!Chainloader.PluginInfos.TryGetValue("com.Dotflare.InfernoSkinMod", out var value) || !Object.op_Implicit((Object)(object)value.Instance)) { return Fail("InfernoSkinMod is not loaded"); } Type type = ((object)value.Instance).GetType(); Manager = type.GetField("_DynamicSkinManager", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null); return Manager != null || Fail(type.FullName + "._DynamicSkinManager not found"); } catch (Exception ex) { return Fail(ex.GetType().Name + ": " + ex.Message); } } private static bool Fail(string error) { BindError = error; Manager = null; return false; } public static object GetField(object owner, string name) { return owner?.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(owner); } public static object[] GetModifications(string token) { if (!(GetField(Manager, "ModificationList") is IDictionary dictionary) || !(dictionary[token] is IDictionary dictionary2)) { return Array.Empty<object>(); } object[] array = new object[dictionary2.Count]; dictionary2.Values.CopyTo(array, 0); return array; } public static void DisableOriginal(string token) { if (GetField(Manager, "SkinDefs") is IDictionary dictionary) { dictionary.Remove(token); } } } internal sealed class SkinRepair { public readonly InfernoSkin Skin; public readonly string BaseSkinName; public readonly string[] ExtraActivations; public readonly bool AccessoryBones; public SkinRepair(InfernoSkin skin, string baseSkinName, string[] extraActivations = null, bool accessoryBones = false) { Skin = skin; BaseSkinName = baseSkinName; ExtraActivations = extraActivations ?? Array.Empty<string>(); AccessoryBones = accessoryBones; } } internal static class SkinRepairs { internal static Action<string> LogInfo = delegate { }; internal static Action<string> LogError = delegate { }; public static readonly SkinRepair[] All = new SkinRepair[3] { new SkinRepair(InfernoSkins.Captain, "skinCaptainDefault"), new SkinRepair(InfernoSkins.Bandit, "skinBandit2Default", new string[1] { "Bandit2AccessoriesMesh" }, accessoryBones: true), new SkinRepair(InfernoSkins.Railgunner, "skinRailGunnerDefault", null, accessoryBones: true) }; private static readonly Dictionary<InfernoSkin, AccessoryRigSpec> rigs = new Dictionary<InfernoSkin, AccessoryRigSpec>(); private static readonly HashSet<SkinDef> patched = new HashSet<SkinDef>(); private static readonly Dictionary<InfernoSkin, string> failures = new Dictionary<InfernoSkin, string>(); public static AccessoryRigSpec FindRig(InfernoSkin skin) { if (skin == null || !rigs.TryGetValue(skin, out var value)) { return null; } return value; } public static void PatchSkinDefs() { SkinRepair[] all = All; foreach (SkinRepair skinRepair in all) { try { string text = Patch(skinRepair); if (text != null) { failures[skinRepair.Skin] = text; } } catch (Exception ex) { failures[skinRepair.Skin] = ex.GetType().Name + ": " + ex.Message; } } } private static string Patch(SkinRepair repair) { //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) InfernoSkin skin = repair.Skin; ModelSkinController val = InfernoSkins.FindBodyModelSkinController(skin.BodyName); SkinDef val2 = skin.FindBodySkin(); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2)) { return "skin '" + skin.SkinName + "' not found on " + skin.BodyName; } if (patched.Contains(val2)) { return null; } if (val2.runtimeSkin != null || Object.op_Implicit((Object)(object)val2.skinDefParams)) { return "skin was already converted or baked before InfernoSkinFix could repair it"; } SkinDef val3 = ((IEnumerable<SkinDef>)val.skins).FirstOrDefault((Func<SkinDef, bool>)((SkinDef d) => Object.op_Implicit((Object)(object)d) && ((Object)d).name == repair.BaseSkinName)); if (!Object.op_Implicit((Object)(object)val3)) { return "vanilla skin '" + repair.BaseSkinName + "' not found"; } List<Transform> list = new List<Transform>(); string[] extraActivations = repair.ExtraActivations; foreach (string text in extraActivations) { Transform val4 = ((Component)val).transform.Find(text); if (!Object.op_Implicit((Object)(object)val4)) { return "'" + text + "' not found on the body model"; } list.Add(val4); } AccessoryRigSpec accessoryRigSpec = null; if (repair.AccessoryBones) { accessoryRigSpec = AccessoryRigSpec.TryCreate(skin, val2, val, out var error); if (accessoryRigSpec == null) { return "accessory bones: " + error; } } if (!val2.baseSkins.Contains(val3)) { val2.baseSkins = ((IEnumerable<SkinDef>)(object)new SkinDef[1] { val3 }).Concat(val2.baseSkins.Where((SkinDef b) => Object.op_Implicit((Object)(object)b))).ToArray(); } foreach (Transform t in list) { if (!val2.gameObjectActivations.Any((GameObjectActivation a) => (Object)(object)a.gameObject == (Object)(object)((Component)t).gameObject)) { val2.gameObjectActivations = val2.gameObjectActivations.Append(new GameObjectActivation { gameObject = ((Component)t).gameObject, shouldActivate = true }).ToArray(); } } if (accessoryRigSpec != null) { rigs[skin] = accessoryRigSpec; InfernoDynamicSkins.DisableOriginal(skin.Token); } patched.Add(val2); return null; } public static void Report() { List<string> list = new List<string>(); SkinRepair[] all = All; foreach (SkinRepair repair in all) { InfernoSkin skin = repair.Skin; if (failures.TryGetValue(skin, out var value)) { LogError(skin.Survivor + " (" + skin.SkinName + ") not repaired: " + value); continue; } SkinDef val = skin.FindBodySkin(); RuntimeSkin val2 = (Object.op_Implicit((Object)(object)val) ? val.runtimeSkin : null); if (val2 == null || !val.baseSkins.Any((SkinDef b) => Object.op_Implicit((Object)(object)b) && ((Object)b).name == repair.BaseSkinName)) { LogError(skin.Survivor + " (" + skin.SkinName + ") not repaired: the skin was not patched before it was baked."); continue; } AccessoryRigSpec accessoryRigSpec = FindRig(skin); list.Add($"{skin.Survivor} (base {repair.BaseSkinName}, {val2.gameObjectActivationTemplates.Length} activations" + ((accessoryRigSpec != null) ? string.Format(", +{0} bone{1} at {2} for {3} meshes", accessoryRigSpec.ChainLength, (accessoryRigSpec.ChainLength == 1) ? "" : "s", accessoryRigSpec.InsertAt, accessoryRigSpec.Meshes.Count) : "") + ")"); } if (list.Count > 0) { LogInfo("Repaired Inferno skins: " + string.Join("; ", list) + ". Commando, Mercenary and Artificer need no repair."); } } } internal static class SkinTrace { internal static Action<string> Log = delegate { }; internal static bool Enabled; private static int nextId; private static readonly Dictionary<int, int> pendingByController = new Dictionary<int, int>(); private static readonly HashSet<int> describedSkins = new HashSet<int>(); private static readonly Dictionary<int, int> bindposeCountByMesh = new Dictionary<int, int>(); private static bool IsDetailed(InfernoSkin s) { if (s != InfernoSkins.Captain && s != InfernoSkins.Bandit) { return s == InfernoSkins.Railgunner; } return true; } internal static IEnumerator Wrap(ModelSkinController controller, int requestedIndex, IEnumerator inner) { if (!Enabled) { return inner; } InfernoSkin infernoSkin = InfernoSkins.FindOnController(controller); if (infernoSkin != null) { return Traced(controller, infernoSkin, requestedIndex, inner); } return inner; } private static IEnumerator Traced(ModelSkinController controller, InfernoSkin survivor, int requestedIndex, IEnumerator inner) { int id = ++nextId; int key = ((Object)controller).GetInstanceID(); pendingByController.TryGetValue(key, out var overlapping); pendingByController[key] = overlapping + 1; bool completed = false; try { Safe(delegate { Snapshot(id, controller, survivor, requestedIndex, "start", overlapping); }); while (inner.MoveNext()) { yield return inner.Current; } completed = true; } finally { if (pendingByController.TryGetValue(key, out var value)) { pendingByController[key] = value - 1; } if (!completed) { Log($"#{id} {survivor.Survivor}: skin application ended without completing (exception or abandoned coroutine)."); } } Safe(delegate { Snapshot(id, controller, survivor, requestedIndex, "done", pendingByController[key]); }); if (Object.op_Implicit((Object)(object)controller)) { ((MonoBehaviour)controller).StartCoroutine(Settled(id, controller, survivor, requestedIndex)); } } private static IEnumerator Settled(int id, ModelSkinController controller, InfernoSkin survivor, int requestedIndex) { yield return (object)new WaitForSecondsRealtime(1f); if (Object.op_Implicit((Object)(object)controller)) { Safe(delegate { Snapshot(id, controller, survivor, requestedIndex, "+1s", pendingByController.TryGetValue(((Object)controller).GetInstanceID(), out var value) ? value : 0); }); } } private static void Safe(Action a) { try { a(); } catch (Exception ex) { Log("trace failed: " + ex); } } private static void Snapshot(int id, ModelSkinController controller, InfernoSkin survivor, int requestedIndex, string phase, int pending) { CharacterModel component = ((Component)controller).GetComponent<CharacterModel>(); SkinDef[] array = controller.skins ?? Array.Empty<SkinDef>(); int num = (((uint)requestedIndex < array.Length) ? requestedIndex : 0); SkinDef val = ((array.Length != 0) ? array[num] : null); SkinDef s = (((uint)controller.currentSkinIndex < array.Length) ? array[controller.currentSkinIndex] : null); string text = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.body)) ? "body" : "display"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(string.Format("#{0} {1} {2} {3}: target[{4}]={5}{6} current[{7}]={8} otherPending={9} dynSkinsModified={10}", id, survivor.Survivor, text, phase, requestedIndex, Name(val), (InfernoSkins.Identify(val) != null) ? " (Inferno)" : "", controller.currentSkinIndex, Name(s), pending, InfernoDynamicSkins.ModifiedObjectCount)); if (Object.op_Implicit((Object)(object)val) && describedSkins.Add(((Object)val).GetInstanceID()) && val.runtimeSkin != null) { stringBuilder.Append('\n').Append(DescribeSkin(val, " ")); } HashSet<string> hashSet = MeshTemplatePaths(val); Renderer[] componentsInChildren = ((Component)controller).GetComponentsInChildren<Renderer>(true); int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; StringBuilder stringBuilder2 = new StringBuilder(); for (int i = 0; i < componentsInChildren.Length; i++) { Renderer val2 = componentsInChildren[i]; string text2 = PathFrom(((Component)controller).transform, ((Component)val2).transform); bool hasMeshSlot; Mesh val3 = MeshOf(val2, out hasMeshSlot); bool flag = ((Component)val2).gameObject.activeInHierarchy && val2.enabled; List<string> list = new List<string>(); if (!((Component)val2).gameObject.activeInHierarchy) { num2++; } if (!((Component)val2).gameObject.activeInHierarchy && hashSet.Contains(text2)) { list.Add("OFF-BUT-SKINNED"); num6++; } if (hasMeshSlot && flag && !Object.op_Implicit((Object)(object)val3)) { list.Add("NO-MESH"); num3++; } if (flag && !(val2 is ParticleSystemRenderer) && val2.sharedMaterials.All((Material m) => !Object.op_Implicit((Object)(object)m))) { list.Add("NO-MATERIAL"); num4++; } string text3 = ""; SkinnedMeshRenderer val4 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if (val4 != null) { int num7 = val4.bones.Length; int num8 = (Object.op_Implicit((Object)(object)val3) ? BindposeCount(val3) : (-1)); text3 = $" bones={num7}" + (Object.op_Implicit((Object)(object)val3) ? (" bindposes=" + ((num8 >= 0) ? num8.ToString() : "?")) : ""); if (num8 >= 0 && num8 != num7) { list.Add("BONES-MISMATCH"); num5++; } } stringBuilder2.Append(string.Format("\n r[{0}] {1} '{2}' self={3} hier={4} en={5}", i, ((object)val2).GetType().Name.Replace("Renderer", ""), text2, On(((Component)val2).gameObject.activeSelf), On(((Component)val2).gameObject.activeInHierarchy), On(val2.enabled)) + " mesh=" + (hasMeshSlot ? MeshName(val3) : "-") + text3 + " mats=[" + string.Join(",", val2.sharedMaterials.Select((Material m) => (!Object.op_Implicit((Object)(object)m)) ? "null" : ((Object)m).name)) + "]" + ((list.Count > 0) ? (" !! " + string.Join(" ", list)) : "")); } stringBuilder.Append($"\n renderers={componentsInChildren.Length} inactive={num2} offButSkinned={num6} noMesh={num3} noMaterial={num4} boneMismatch={num5}"); if (IsDetailed(survivor)) { stringBuilder.Append(stringBuilder2); if (Object.op_Implicit((Object)(object)component)) { stringBuilder.Append($"\n baseRendererInfos({component.baseRendererInfos.Length}): " + string.Join(", ", component.baseRendererInfos.Select((RendererInfo ri) => (Object.op_Implicit((Object)(object)ri.renderer) ? PathFrom(((Component)controller).transform, ((Component)ri.renderer).transform) : "null") + "=" + (Object.op_Implicit((Object)(object)ri.defaultMaterial) ? ((Object)ri.defaultMaterial).name : "null")))); stringBuilder.Append($"\n activatedBySkin({component.gameObjectActivationTransforms.Count}): " + string.Join(", ", component.gameObjectActivationTransforms.Select((Transform t) => (!Object.op_Implicit((Object)(object)t)) ? "destroyed" : (PathFrom(((Component)controller).transform, t) + "=" + On(((Component)t).gameObject.activeSelf))))); } } Log(stringBuilder.ToString()); } private static HashSet<string> MeshTemplatePaths(SkinDef skin) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) HashSet<string> hashSet = new HashSet<string>(); if (Object.op_Implicit((Object)(object)skin) && skin.runtimeSkin != null) { Enumerator<MeshReplacementTemplate> enumerator = skin.runtimeSkin.meshReplacementTemplates.GetEnumerator(); try { while (enumerator.MoveNext()) { MeshReplacementTemplate current = enumerator.Current; if (Object.op_Implicit((Object)(object)current.meshReference.directRef) || (current.meshReference.address != null && ((AssetReference)current.meshReference.address).RuntimeKeyIsValid())) { hashSet.Add(current.transformPath); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } return hashSet; } internal static string DescribeSkin(SkinDef skin, string indent) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected I4, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); string text = (Object.op_Implicit((Object)(object)skin.rootObject) ? PathFrom(null, skin.rootObject.transform) : "null"); string text2 = string.Join(",", (skin.baseSkins ?? Array.Empty<SkinDef>()).Select(Name)); stringBuilder.Append($"{indent}skin {Name(skin)} token={skin.nameToken} catalogIndex={(int)skin.skinIndex} baseSkins=[{text2}] rootObject={text}" + " unlockable=" + (Object.op_Implicit((Object)(object)skin.unlockableDef) ? skin.unlockableDef.cachedName : "none") + " params=" + (Object.op_Implicit((Object)(object)skin.skinDefParams) ? ((Object)skin.skinDefParams).name : "none")); RuntimeSkin runtimeSkin = skin.runtimeSkin; if (runtimeSkin == null) { return stringBuilder.Append(" (not baked)").ToString(); } Enumerator<GameObjectActivationTemplate> enumerator = runtimeSkin.gameObjectActivationTemplates.GetEnumerator(); try { while (enumerator.MoveNext()) { GameObjectActivationTemplate current = enumerator.Current; stringBuilder.Append("\n" + indent + " activation '" + current.transformPath + "'=" + (current.isCustomActivation ? "custom prefab" : On(current.shouldActivate))); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } Enumerator<MeshReplacementTemplate> enumerator2 = runtimeSkin.meshReplacementTemplates.GetEnumerator(); try { while (enumerator2.MoveNext()) { MeshReplacementTemplate current2 = enumerator2.Current; stringBuilder.Append("\n" + indent + " mesh '" + current2.transformPath + "'=" + (Object.op_Implicit((Object)(object)current2.meshReference.directRef) ? MeshName(current2.meshReference.directRef) : ((current2.meshReference.address != null && ((AssetReference)current2.meshReference.address).RuntimeKeyIsValid()) ? ("address:" + ((AssetReference)current2.meshReference.address).RuntimeKey) : "null (hide)"))); } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } Enumerator<RendererInfoTemplate> enumerator3 = runtimeSkin.rendererInfoTemplates.GetEnumerator(); try { while (enumerator3.MoveNext()) { RendererInfoTemplate current3 = enumerator3.Current; AssetOrDirectReference<Material> materialReference = current3.materialReference; string text3 = (Object.op_Implicit((Object)(object)materialReference.directRef) ? ((Object)materialReference.directRef).name : ((materialReference.address != null && ((AssetReference)materialReference.address).RuntimeKeyIsValid()) ? ("address:" + ((AssetReference)materialReference.address).RuntimeKey) : "null")); stringBuilder.Append("\n" + indent + " material '" + current3.transformPath + "'=" + text3); } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } return stringBuilder.ToString(); } internal static string DescribeModel(string label, ModelSkinController controller) { StringBuilder stringBuilder = new StringBuilder(label + " model '" + PathFrom(null, ((Component)controller).transform) + "' skins=[" + string.Join(",", controller.skins.Select(Name)) + "]"); Renderer[] componentsInChildren = ((Component)controller).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Renderer val = componentsInChildren[i]; bool hasMeshSlot; Mesh mesh = MeshOf(val, out hasMeshSlot); SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); string text = ((val2 != null) ? $" bones={val2.bones.Length}" : ""); stringBuilder.Append(string.Format("\n r[{0}] {1} '{2}' self={3} en={4} mesh={5}{6}", i, ((object)val).GetType().Name.Replace("Renderer", ""), PathFrom(((Component)controller).transform, ((Component)val).transform), On(((Component)val).gameObject.activeSelf), On(val.enabled), hasMeshSlot ? MeshName(mesh) : "-", text)); } return stringBuilder.ToString(); } internal static string DescribeLegacyTargets(SkinDef skin, ModelSkinController bodyController) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) Renderer[] renderers = ((Component)bodyController).GetComponentsInChildren<Renderer>(true); StringBuilder stringBuilder = new StringBuilder($" legacy fields of {Name(skin)}: activations={skin.gameObjectActivations.Length}"); MeshReplacement[] meshReplacements = skin.meshReplacements; foreach (MeshReplacement val in meshReplacements) { stringBuilder.Append("\n meshReplacement " + Target(val.renderer) + " <- " + MeshName(val.mesh) + (Object.op_Implicit((Object)(object)val.mesh) ? $" bindposes={BindposeCount(val.mesh)}" : "")); } RendererInfo[] rendererInfos = skin.rendererInfos; foreach (RendererInfo val2 in rendererInfos) { stringBuilder.Append(string.Format("\n rendererInfo {0} <- {1} shadows={2}", Target(val2.renderer), Object.op_Implicit((Object)(object)val2.defaultMaterial) ? ((Object)val2.defaultMaterial).name : "null", val2.defaultShadowCastingMode)); } return stringBuilder.ToString(); string Target(Renderer r) { if (!Object.op_Implicit((Object)(object)r)) { return "null"; } return $"r[{Array.IndexOf(renderers, r)}]'{PathFrom(((Component)bodyController).transform, ((Component)r).transform)}'"; } } private static Mesh MeshOf(Renderer r, out bool hasMeshSlot) { hasMeshSlot = true; SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null); if (val != null) { return val.sharedMesh; } if (r is MeshRenderer) { MeshFilter component = ((Component)r).GetComponent<MeshFilter>(); if (!Object.op_Implicit((Object)(object)component)) { return null; } return component.sharedMesh; } hasMeshSlot = false; return null; } private static int BindposeCount(Mesh mesh) { int instanceID = ((Object)mesh).GetInstanceID(); if (!bindposeCountByMesh.TryGetValue(instanceID, out var value)) { try { value = mesh.bindposes.Length; } catch (Exception) { value = -1; } bindposeCountByMesh[instanceID] = value; } return value; } private static string MeshName(Mesh mesh) { if (!Object.op_Implicit((Object)(object)mesh)) { return "null"; } return $"{((Object)mesh).name}(v{mesh.vertexCount})"; } private static string Name(SkinDef s) { if (!Object.op_Implicit((Object)(object)s)) { return "null"; } return ((Object)s).name; } private static string On(bool b) { if (!b) { return "0"; } return "1"; } internal static string PathFrom(Transform root, Transform t) { List<string> list = new List<string>(); Transform val = t; while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } } }