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 VRM Fixes v1.1.4
plugins/VRMFixes.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using LocalValheimFixes.Packages; using Microsoft.CodeAnalysis; using UniGLTF; using UniGLTF.Utils; using UniVRM10; using UnityEngine; [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("VRMFixes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.4.0")] [assembly: AssemblyInformationalVersion("1.1.4+ad276bd4679d2af06e242ff621684e865f1348ee")] [assembly: AssemblyProduct("VRMFixes")] [assembly: AssemblyTitle("VRMFixes")] [assembly: AssemblyVersion("1.1.4.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 LocalValheimFixes { [BepInPlugin("local.valheim.vrm1springclonefix", "VRM Fixes", "1.1.4")] [BepInDependency("com.rawrtastic.plugins.enhancedvalheimvrm", "1.0.0")] public sealed class SpringCloneFixPlugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static FieldInfo CloneField; private void Awake() { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; PluginInfo val = Chainloader.PluginInfos["com.rawrtastic.plugins.enhancedvalheimvrm"]; Version version = val.Metadata.Version; if (!EnhancedVrmCompatibility.AllowsVersion(version)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Inactive: EnhancedValheimVRM " + version?.ToString() + " is outside the supported 1.x version family.")); return; } Type type = ((object)val.Instance).GetType().Assembly.GetType("EnhancedValheimVRM.VrmInstance", throwOnError: false); MethodInfo methodInfo = ((type == null) ? null : AccessTools.DeclaredMethod(type, "CreateVrmGo", Type.EmptyTypes, (Type[])null)); CloneField = ((type == null) ? null : AccessTools.DeclaredField(type, "_vrmGo")); if (methodInfo == null || methodInfo.IsStatic || methodInfo.ContainsGenericParameters || methodInfo.ReturnType != typeof(void) || CloneField == null || CloneField.IsStatic || CloneField.FieldType != typeof(GameObject)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Inactive: the expected clone staging hook was not found."); return; } try { new Harmony("local.valheim.vrm1springclonefix").Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(SpringCloneFixPlugin), "BeforeCreate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Inactive: clone staging hook could not be installed: " + ex)); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("VRM1 spring clone repair enabled for EnhancedValheimVRM " + version?.ToString() + ".")); try { PackagedAvatarHooks.Install(type.Assembly, ((BaseUnityPlugin)this).Logger); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Packaged avatar support inactive: " + ex2)); } try { BearPawsFix.Install(type.Assembly, version, ((BaseUnityPlugin)this).Logger); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogError((object)("Nordic bear paws support inactive: " + ex3)); } } private static void BeforeCreate(object __instance) { try { object? value = CloneField.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); int num = SpringGraphRepair.RepairFromCachedTemplate(val); if (num > 0) { Log.LogInfo((object)("Restored VRM1 spring graph: " + num + " joint references on " + ((Object)val).name + ".")); } } catch (Exception ex) { Log.LogError((object)("VRM1 spring clone repair failed: " + ex)); } } } public static class SpringGraphRepair { private static readonly FieldInfo RuntimeField = AccessTools.DeclaredField(typeof(Vrm10Instance), "m_runtime"); public static int RepairFromCachedTemplate(GameObject cloneRoot) { if ((Object)(object)cloneRoot == (Object)null) { return 0; } Vrm10Instance clone = cloneRoot.GetComponent<Vrm10Instance>(); if (!NeedsRepair(clone)) { return 0; } Vrm10Instance[] array = (from v in Resources.FindObjectsOfTypeAll<Vrm10Instance>() where (Object)(object)v != (Object)(object)clone && (Object)(object)v.Vrm == (Object)(object)clone.Vrm && (Object)(object)((Component)v).transform.parent == (Object)null && !((Component)v).gameObject.activeInHierarchy && v.SpringBone != null && v.SpringBone.Springs.Count > 0 select v).ToArray(); if (array.Length != 1) { throw new InvalidOperationException("Expected one inactive imported template, found " + array.Length); } return Repair(((Component)array[0]).gameObject, cloneRoot); } private static bool NeedsRepair(Vrm10Instance clone) { if ((Object)(object)clone != (Object)null && (clone.SpringBone == null || clone.SpringBone.Springs.Count == 0)) { return ((Component)clone).GetComponentsInChildren<VRM10SpringBoneJoint>(true).Length > 1; } return false; } public static int Repair(GameObject sourceRoot, GameObject cloneRoot) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourceRoot == (Object)null || (Object)(object)cloneRoot == (Object)null || (Object)(object)sourceRoot == (Object)(object)cloneRoot) { return 0; } Vrm10Instance component = sourceRoot.GetComponent<Vrm10Instance>(); Vrm10Instance component2 = cloneRoot.GetComponent<Vrm10Instance>(); if (!NeedsRepair(component2) || (Object)(object)component == (Object)null || component.SpringBone == null || component.SpringBone.Springs.Count == 0) { return 0; } Dictionary<Transform, Transform> transforms = new Dictionary<Transform, Transform>(); MapHierarchy(sourceRoot.transform, cloneRoot.transform, transforms); Vrm10InstanceSpringBone val = new Vrm10InstanceSpringBone(); Dictionary<VRM10SpringBoneColliderGroup, List<VRM10SpringBoneCollider>> dictionary = new Dictionary<VRM10SpringBoneColliderGroup, List<VRM10SpringBoneCollider>>(); VRM10SpringBoneColliderGroup[] componentsInChildren = ((Component)component).GetComponentsInChildren<VRM10SpringBoneColliderGroup>(true); foreach (VRM10SpringBoneColliderGroup val2 in componentsInChildren) { VRM10SpringBoneColliderGroup key = MapComponent<VRM10SpringBoneColliderGroup>(val2, transforms); dictionary[key] = val2.Colliders.Select((VRM10SpringBoneCollider c) => MapComponent<VRM10SpringBoneCollider>(c, transforms)).ToList(); } val.ColliderGroups = component.SpringBone.ColliderGroups.Select((VRM10SpringBoneColliderGroup g) => MapComponent<VRM10SpringBoneColliderGroup>(g, transforms)).ToList(); int num = 0; foreach (Spring spring in component.SpringBone.Springs) { Spring val3 = new Spring(spring.Name); val3.Center = (((Object)(object)spring.Center == (Object)null) ? null : transforms[spring.Center]); val3.Joints = spring.Joints.Select((VRM10SpringBoneJoint j) => MapComponent<VRM10SpringBoneJoint>(j, transforms)).ToList(); val3.ColliderGroups = spring.ColliderGroups.Select((VRM10SpringBoneColliderGroup g) => MapComponent<VRM10SpringBoneColliderGroup>(g, transforms)).ToList(); if (val3.Joints.Count((VRM10SpringBoneJoint j) => (Object)(object)j != (Object)null) < 2) { throw new InvalidOperationException("Imported spring has fewer than two usable joints."); } num += val3.Joints.Count; val.Springs.Add(val3); } RuntimeGltfInstance component3 = sourceRoot.GetComponent<RuntimeGltfInstance>(); RuntimeGltfInstance component4 = cloneRoot.GetComponent<RuntimeGltfInstance>(); IDictionary<Transform, TransformState> dictionary2 = (((Object)(object)component4 == (Object)null) ? null : (component4.InitialTransformStates as IDictionary<Transform, TransformState>)); if ((Object)(object)component3 == (Object)null || dictionary2 == null) { throw new InvalidOperationException("Initial transform state storage unavailable."); } Dictionary<Transform, TransformState> dictionary3 = new Dictionary<Transform, TransformState>(); foreach (KeyValuePair<Transform, TransformState> initialTransformState in component3.InitialTransformStates) { dictionary3.Add(transforms[initialTransformState.Key], initialTransformState.Value); } foreach (KeyValuePair<VRM10SpringBoneColliderGroup, List<VRM10SpringBoneCollider>> item in dictionary) { item.Key.Colliders = item.Value; } VRM10SpringBoneJoint[] componentsInChildren2 = ((Component)component).GetComponentsInChildren<VRM10SpringBoneJoint>(true); foreach (VRM10SpringBoneJoint val4 in componentsInChildren2) { VRM10SpringBoneJoint obj = MapComponent<VRM10SpringBoneJoint>(val4, transforms); obj.m_stiffnessForce = val4.m_stiffnessForce; obj.m_gravityPower = val4.m_gravityPower; obj.m_gravityDir = val4.m_gravityDir; obj.m_dragForce = val4.m_dragForce; obj.m_jointRadius = val4.m_jointRadius; } VRM10SpringBoneCollider[] componentsInChildren3 = ((Component)component).GetComponentsInChildren<VRM10SpringBoneCollider>(true); foreach (VRM10SpringBoneCollider val5 in componentsInChildren3) { VRM10SpringBoneCollider obj2 = MapComponent<VRM10SpringBoneCollider>(val5, transforms); obj2.ColliderType = val5.ColliderType; obj2.Offset = val5.Offset; obj2.Tail = val5.Tail; obj2.Radius = val5.Radius; } foreach (KeyValuePair<Transform, TransformState> item2 in dictionary3) { dictionary2[item2.Key] = item2.Value; } component2.SpringBone = val; if (RuntimeField != null && RuntimeField.GetValue(component2) != null) { component2.Runtime.ReconstructSpringBone(); } return num; } private static void MapHierarchy(Transform source, Transform clone, Dictionary<Transform, Transform> map) { if (source.childCount > clone.childCount) { throw new InvalidOperationException("Clone hierarchy is shorter than template."); } map.Add(source, clone); for (int i = 0; i < source.childCount; i++) { Transform child = source.GetChild(i); Transform child2 = clone.GetChild(i); if (((Object)child).name != ((Object)child2).name) { throw new InvalidOperationException("Clone hierarchy differs at child " + i + " of " + ((Object)source).name); } MapHierarchy(child, child2, map); } } private static T MapComponent<T>(T source, Dictionary<Transform, Transform> map) where T : Component { if ((Object)(object)source == (Object)null) { return default(T); } int num = Array.IndexOf(((Component)source).GetComponents<T>(), source); T[] components = ((Component)map[((Component)source).transform]).GetComponents<T>(); if (num < 0 || num >= components.Length) { throw new InvalidOperationException("Missing cloned component " + typeof(T).Name); } return components[num]; } } internal static class EnhancedVrmCompatibility { internal static bool AllowsVersion(Version version) { if (version != null) { return version.Major == 1; } return false; } } internal static class PackagedAvatarHooks { private static AvatarPackIndex _index; private static FieldInfo _outfitPath; internal static void Install(Assembly enhancedAssembly, ManualLogSource log) { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(enhancedAssembly.GetType("EnhancedValheimVRM.Constants+Vrm", throwOnError: true), "Find", new Type[1] { typeof(string) }, (Type[])null); Type? type = enhancedAssembly.GetType("EnhancedValheimVRM.OutfitController", throwOnError: true); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(type, "Generate", Type.EmptyTypes, (Type[])null); _outfitPath = AccessTools.DeclaredField(type, "_path"); if (methodInfo == null || !methodInfo.IsStatic || methodInfo.ContainsGenericParameters || methodInfo.ReturnType != typeof(string) || methodInfo2 == null || methodInfo2.IsStatic || methodInfo2.ContainsGenericParameters || methodInfo2.ReturnType != typeof(string) || _outfitPath == null || _outfitPath.IsStatic || _outfitPath.FieldType != typeof(string)) { throw new MissingMethodException("Expected EnhancedValheimVRM avatar lookup/write hooks were not found."); } _index = AvatarPackIndex.Build(Paths.PluginPath); foreach (string diagnostic in _index.Diagnostics) { log.LogWarning((object)diagnostic); } Harmony val = new Harmony("local.valheim.vrm1springclonefix.packages"); try { val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(PackagedAvatarHooks), "BeforeGenerate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(PackagedAvatarHooks), "AfterFind", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { val.UnpatchSelf(); throw; } log.LogInfo((object)("Packaged avatars indexed: " + _index.Bindings.Count + ". Explicit package characters override manual files; restart after package changes.")); foreach (AvatarBinding binding in _index.Bindings) { log.LogInfo((object)("Packaged avatar " + binding.Character + " from " + binding.PackId + ": " + binding.ModelPath)); } } private static void AfterFind(string fileName, ref string __result) { if (_index.TryResolve(fileName, out var path)) { __result = path; } } private static bool BeforeGenerate(object __instance, ref string __result) { string path = _outfitPath.GetValue(__instance) as string; if (!_index.IsProtectedPath(path)) { return true; } __result = "Packaged avatars use read-only outfit defaults; outfit generation is disabled for this avatar."; return false; } } public static class BearPawsFix { public sealed class AttachmentPlan { private readonly SkinnedMeshRenderer renderer; private readonly Transform avatarRoot; private readonly Transform[] palette; private readonly List<Attachment> attachments; internal AttachmentPlan(SkinnedMeshRenderer renderer, Transform avatarRoot, Transform[] palette, List<Attachment> attachments) { this.renderer = renderer; this.avatarRoot = avatarRoot; this.palette = palette; this.attachments = attachments; } public void Apply(List<Transform> moved) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) foreach (Attachment attachment in attachments) { attachment.Source.SetParent(attachment.Target, false); attachment.Source.localPosition = Vector3.zero; attachment.Source.localRotation = attachment.Rotation; attachment.Source.localScale = attachment.Scale; if (!moved.Contains(attachment.Source)) { moved.Add(attachment.Source); } } renderer.bones = palette; renderer.rootBone = avatarRoot; renderer.updateWhenOffscreen = true; } } internal sealed class Attachment { internal Transform Source; internal Transform Target; internal Quaternion Rotation; internal Vector3 Scale; } private static FieldInfo AvatarRoot; private static FieldInfo AvatarAnimator; private static FieldInfo Settings; private static FieldInfo ItemName; private static FieldInfo Equipment; private static FieldInfo Moved; private static FieldInfo PiecesAvatar; private static Type PiecesType; private static ManualLogSource Log; private static readonly string[] Names = new string[6] { "LeftArm", "LeftForeArm", "LeftHand", "RightArm", "RightForeArm", "RightHand" }; private static readonly HumanBodyBones[] Targets; internal static void Install(Assembly assembly, Version version, ManualLogSource log) { //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Expected O, but got Unknown Log = log; if (version.Major != 1 || version.Minor != 3 || version.Build != 1) { log.LogInfo((object)"Nordic bear paws fix applies to EnhancedValheimVRM 1.3.1 only; spring and package support retain the 1.x policy."); return; } Type type = assembly.GetType("EnhancedValheimVRM.VrmAnimator", throwOnError: false); MethodInfo methodInfo = ((type == null) ? null : AccessTools.DeclaredMethod(type, "MoveRigOntoAvatar", new Type[1] { typeof(GameObject) }, (Type[])null)); PiecesType = assembly.GetType("EnhancedValheimVRM.RiggedItemPieces", throwOnError: false); AvatarRoot = ((type == null) ? null : AccessTools.DeclaredField(type, "_vrmGo")); AvatarAnimator = ((type == null) ? null : AccessTools.DeclaredField(type, "_vrmGoAnimator")); Settings = ((type == null) ? null : AccessTools.DeclaredField(type, "_vrmSettings")); ItemName = ((type == null) ? null : AccessTools.DeclaredField(type, "_rigItemName")); Equipment = ((type == null) ? null : AccessTools.DeclaredField(type, "_visEquipment")); Moved = ((PiecesType == null) ? null : AccessTools.DeclaredField(PiecesType, "Moved")); PiecesAvatar = ((PiecesType == null) ? null : AccessTools.DeclaredField(PiecesType, "Avatar")); if (methodInfo == null || methodInfo.IsStatic || methodInfo.ReturnType != typeof(void) || AvatarRoot?.FieldType != typeof(GameObject) || AvatarAnimator?.FieldType != typeof(Animator) || ItemName?.FieldType != typeof(string) || Settings == null || Equipment == null || PiecesType == null || !typeof(Component).IsAssignableFrom(PiecesType) || Moved?.FieldType != typeof(List<Transform>) || PiecesAvatar?.FieldType != typeof(Animator)) { log.LogWarning((object)"Nordic bear paws fix inactive: expected equipment hooks unavailable. Other fixes remain active."); return; } new Harmony("local.valheim.vrm1springclonefix.darkurgepaws").Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BearPawsFix), "BeforeMove", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"Paws of the Bear attachment fix enabled for Dark Urge and Sigrid."); } private static bool BeforeMove(object __instance, GameObject rig) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown if (!string.Equals(ItemName.GetValue(__instance) as string, "FistBjornClaw", StringComparison.Ordinal)) { return true; } object? value = AvatarRoot.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if (!IsSupportedAvatar(val)) { return true; } try { object? value2 = AvatarAnimator.GetValue(__instance); Animator val2 = (Animator)((value2 is Animator) ? value2 : null); Component val3 = (((Object)(object)rig == (Object)null) ? null : rig.GetComponent(PiecesType)); if ((Object)(object)val3 != (Object)null && (Object)(Animator)PiecesAvatar.GetValue(val3) == (Object)(object)val2) { return false; } object value3 = Settings.GetValue(__instance); object value4 = Equipment.GetValue(__instance); if (value3 == null || value4 == null) { return true; } FieldInfo fieldInfo = AccessTools.Field(value3.GetType(), "PlayerVrmScale"); PropertyInfo propertyInfo = AccessTools.Property(value3.GetType(), "PlayerVrmScale"); object obj = ((fieldInfo != null) ? fieldInfo.GetValue(value3) : propertyInfo?.GetValue(value3, null)); object? obj2 = AccessTools.Field(value4.GetType(), "m_bodyModel")?.GetValue(value4); SkinnedMeshRenderer val4 = (SkinnedMeshRenderer)((obj2 is SkinnedMeshRenderer) ? obj2 : null); if (!(obj is float scale) || (Object)(object)val4 == (Object)null) { return true; } AttachmentPlan attachmentPlan = Prepare(val, val2, rig, val4.bones, scale); if (attachmentPlan == null) { Log.LogWarning((object)"Nordic bear paws fix skipped: item or avatar rig differs from the validated layout."); return true; } val3 = val3 ?? rig.AddComponent(PiecesType); if (!(Moved.GetValue(val3) is List<Transform> moved)) { return true; } attachmentPlan.Apply(moved); PiecesAvatar.SetValue(val3, val2); Log.LogInfo((object)("Attached bear paws for " + val.GetComponent<Vrm10Instance>().Vrm.Meta.Name + " with calibrated wrist axes and both upper-arm weights.")); return false; } catch (Exception ex) { Log.LogError((object)("Nordic bear paws attachment could not be prepared: " + ex)); return true; } } public static bool IsSupportedAvatar(GameObject root) { Vrm10Instance val = (((Object)(object)root == (Object)null) ? null : root.GetComponent<Vrm10Instance>()); if ((Object)(object)val != (Object)null && (Object)(object)val.Vrm != (Object)null && val.Vrm.Meta != null) { if (!string.Equals(val.Vrm.Meta.Name, "Dark Urge", StringComparison.Ordinal)) { return string.Equals(val.Vrm.Meta.Name, "Sigrid", StringComparison.Ordinal); } return true; } return false; } public static AttachmentPlan Prepare(GameObject root, Animator animator, GameObject rig, Transform[] bodyBones, float scale) { //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0206: 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_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0231: 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_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0299: 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_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) if (!IsSupportedAvatar(root) || (Object)(object)animator == (Object)null || (Object)(object)animator.avatar == (Object)null || !animator.isHuman || (Object)(object)rig == (Object)null || bodyBones == null || !Finite(scale) || scale <= 0f) { return null; } RuntimeGltfInstance component = root.GetComponent<RuntimeGltfInstance>(); if ((Object)(object)component == (Object)null) { return null; } Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>(StringComparer.Ordinal); Transform[] componentsInChildren = rig.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (dictionary.ContainsKey(((Object)val).name)) { return null; } dictionary.Add(((Object)val).name, val); } SkinnedMeshRenderer[] componentsInChildren2 = rig.GetComponentsInChildren<SkinnedMeshRenderer>(true); if (componentsInChildren2.Length != 1) { return null; } SkinnedMeshRenderer val2 = componentsInChildren2[0]; Mesh sharedMesh = val2.sharedMesh; if ((Object)(object)sharedMesh == (Object)null || ((Object)sharedMesh).name != "BerserkerClaws" || sharedMesh.vertexCount != 631 || bodyBones.Length != 53 || val2.bones.Length != bodyBones.Length || sharedMesh.bindposes.Length != bodyBones.Length) { return null; } Transform[] array = (Transform[])(object)new Transform[bodyBones.Length]; for (int j = 0; j < array.Length; j++) { if ((Object)(object)bodyBones[j] == (Object)null || !dictionary.TryGetValue(((Object)bodyBones[j]).name, out array[j])) { return null; } } Transform[] array2 = (Transform[])(object)new Transform[Names.Length]; for (int k = 0; k < array2.Length; k++) { if (!dictionary.TryGetValue(Names[k], out array2[k])) { return null; } } List<Attachment> list = new List<Attachment>(); for (int l = 0; l < array2.Length; l++) { int num = Array.IndexOf(array, array2[l]); Transform boneTransform = animator.GetBoneTransform(Targets[l]); if (num < 0 || (Object)(object)boneTransform == (Object)null || !RestRotation(component, root.transform, boneTransform, out var rotation)) { return null; } Matrix4x4 val3 = rig.transform.worldToLocalMatrix * array2[l].localToWorldMatrix; Vector3 lossyScale = ((Matrix4x4)(ref val3)).lossyScale; Vector3 lossyScale2 = boneTransform.lossyScale; if (!PositiveUniform(lossyScale) || !PositiveUniform(lossyScale2) || ((Matrix4x4)(ref val3)).determinant <= 0f) { return null; } Quaternion val4 = Quaternion.Inverse(rotation) * ((Matrix4x4)(ref val3)).rotation; if (!Finite(val4.x) || !Finite(val4.y) || !Finite(val4.z) || !Finite(val4.w)) { return null; } list.Add(new Attachment { Source = array2[l], Target = boneTransform, Rotation = val4, Scale = new Vector3(lossyScale.x * scale / lossyScale2.x, lossyScale.y * scale / lossyScale2.y, lossyScale.z * scale / lossyScale2.z) }); } return new AttachmentPlan(val2, root.transform, array, list); } private static bool RestRotation(RuntimeGltfInstance gltf, Transform root, Transform bone, out Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) rotation = Quaternion.identity; Transform val = bone; while ((Object)(object)val != (Object)(object)root) { if ((Object)(object)val == (Object)null || !gltf.InitialTransformStates.TryGetValue(val, out var value)) { return false; } rotation = ((TransformState)(ref value)).LocalRotation * rotation; val = val.parent; } return true; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static bool PositiveUniform(Vector3 scale) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (Finite(scale.x) && Finite(scale.y) && Finite(scale.z) && scale.x > 1E-06f && scale.y > 1E-06f && scale.z > 1E-06f && Mathf.Abs(scale.x / scale.y - 1f) < 0.002f) { return Mathf.Abs(scale.x / scale.z - 1f) < 0.002f; } return false; } static BearPawsFix() { HumanBodyBones[] array = new HumanBodyBones[6]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Targets = (HumanBodyBones[])(object)array; } } } namespace LocalValheimFixes.Packages { [DataContract] internal sealed class AvatarPackManifest { [DataMember(Name = "schemaVersion", IsRequired = true)] public int SchemaVersion { get; set; } [DataMember(Name = "packId", IsRequired = true)] public string PackId { get; set; } [DataMember(Name = "avatars", IsRequired = true)] public AvatarPackEntry[] Avatars { get; set; } } [DataContract] internal sealed class AvatarPackEntry { [DataMember(Name = "character", IsRequired = true)] public string Character { get; set; } [DataMember(Name = "model", IsRequired = true)] public string Model { get; set; } [DataMember(Name = "settings", IsRequired = true)] public string Settings { get; set; } [DataMember(Name = "outfits", EmitDefaultValue = false)] public string Outfits { get; set; } } public sealed class AvatarBinding { public string Character { get; } public string PackId { get; } public string PackDirectory { get; } public string ModelPath { get; } public string SettingsPath { get; } public string OutfitPath { get; } internal AvatarBinding(string character, string packId, string directory, string model, string settings, string outfits) { Character = character; PackId = packId; PackDirectory = directory; ModelPath = model; SettingsPath = settings; OutfitPath = outfits; } } public sealed class AvatarPackIndex { private const string Marker = "avatar-pack.json"; private const string AbsentOutfitDirectory = "__vrm_fixes_no_outfits__"; private readonly IReadOnlyDictionary<string, string> _files; private readonly string[] _protectedDirectories; public IReadOnlyList<AvatarBinding> Bindings { get; } public IReadOnlyList<string> Diagnostics { get; } private AvatarPackIndex(IEnumerable<AvatarBinding> bindings, IEnumerable<string> diagnostics) { AvatarBinding[] array = bindings.OrderBy<AvatarBinding, string>((AvatarBinding x) => x.Character, StringComparer.OrdinalIgnoreCase).ToArray(); Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); AvatarBinding[] array2 = array; foreach (AvatarBinding avatarBinding in array2) { dictionary.Add(avatarBinding.Character + ".vrm", avatarBinding.ModelPath); dictionary.Add("settings_" + avatarBinding.Character + ".txt", avatarBinding.SettingsPath); dictionary.Add("outfits_" + avatarBinding.Character + ".txt", avatarBinding.OutfitPath); } _files = new ReadOnlyDictionary<string, string>(dictionary); _protectedDirectories = array.Select((AvatarBinding x) => WithSeparator(x.PackDirectory)).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray(); Bindings = Array.AsReadOnly(array); Diagnostics = Array.AsReadOnly(diagnostics.ToArray()); } public static AvatarPackIndex Build(string pluginDirectory) { List<string> list = new List<string>(); List<AvatarBinding[]> list2 = new List<AvatarBinding[]>(); if (!Directory.Exists(pluginDirectory)) { return new AvatarPackIndex(Array.Empty<AvatarBinding>(), list); } foreach (string item in FindMarkers(Path.GetFullPath(pluginDirectory), list)) { try { list2.Add(ReadPack(item)); } catch (Exception ex) when (ex is InvalidDataException || ex is IOException || ex is UnauthorizedAccessException || ex is SerializationException || ex is ArgumentException) { list.Add("Ignored avatar pack " + item + ": " + ex.Message); } } HashSet<string> duplicateIds = new HashSet<string>(from x in list2.GroupBy<AvatarBinding[], string>((AvatarBinding[] x) => x[0].PackId, StringComparer.OrdinalIgnoreCase) where x.Count() > 1 select x.Key, StringComparer.OrdinalIgnoreCase); foreach (string item2 in duplicateIds.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase)) { list.Add("Duplicate avatar pack ID " + item2 + "; all copies ignored."); } AvatarBinding[] source = list2.Where((AvatarBinding[] x) => !duplicateIds.Contains(x[0].PackId)).SelectMany((AvatarBinding[] x) => x).ToArray(); List<AvatarBinding> list3 = new List<AvatarBinding>(); foreach (IGrouping<string, AvatarBinding> item3 in source.GroupBy<AvatarBinding, string>((AvatarBinding x) => x.Character, StringComparer.OrdinalIgnoreCase).OrderBy<IGrouping<string, AvatarBinding>, string>((IGrouping<string, AvatarBinding> x) => x.Key, StringComparer.OrdinalIgnoreCase)) { if (item3.Count() == 1) { list3.Add(item3.Single()); continue; } list.Add("Conflicting packaged character " + item3.Key + " in " + string.Join(", ", item3.Select((AvatarBinding x) => x.PackId).OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase)) + "; all package mappings for this character ignored. Manual lookup remains available."); } return new AvatarPackIndex(list3, list); } public bool TryResolve(string fileName, out string path) { path = null; if (!string.IsNullOrEmpty(fileName)) { return _files.TryGetValue(fileName, out path); } return false; } public bool IsProtectedPath(string path) { if (string.IsNullOrEmpty(path)) { return false; } try { string fullPath = Path.GetFullPath(path); return _protectedDirectories.Any((string root) => fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase)); } catch (Exception ex) when (ex is ArgumentException || ex is IOException || ex is NotSupportedException) { return false; } } private static IEnumerable<string> FindMarkers(string directory, List<string> diagnostics) { string[] source; string[] array; try { if (DisabledName(Path.GetFileName(directory)) || IsReparsePoint(directory)) { yield break; } source = Directory.GetFiles(directory).OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ThenBy<string, string>((string x) => x, StringComparer.Ordinal) .ToArray(); array = Directory.GetDirectories(directory).OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ThenBy<string, string>((string x) => x, StringComparer.Ordinal) .ToArray(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { diagnostics.Add("Cannot inspect avatar package directory " + directory + ": " + ex.Message); yield break; } string[] array2 = source.Where((string x) => string.Equals(Path.GetFileName(x), "avatar-pack.json", StringComparison.OrdinalIgnoreCase)).ToArray(); if (array2.Length != 0) { bool flag = false; try { flag = array2.Length == 1 && !IsReparsePoint(array2[0]); } catch (Exception ex2) when (ex2 is IOException || ex2 is UnauthorizedAccessException) { diagnostics.Add("Cannot inspect avatar-pack.json in " + directory + ": " + ex2.Message); } if (flag) { yield return array2[0]; } else { diagnostics.Add("Ambiguous, inaccessible or linked avatar-pack.json in " + directory + "; directory ignored."); } yield break; } string[] array3 = array; foreach (string directory2 in array3) { foreach (string item in FindMarkers(directory2, diagnostics)) { yield return item; } } } private static AvatarBinding[] ReadPack(string marker) { if (new FileInfo(marker).Length > 65536) { throw new InvalidDataException("Manifest exceeds 64 KiB."); } AvatarPackManifest avatarPackManifest; using (FileStream stream = File.OpenRead(marker)) { avatarPackManifest = (AvatarPackManifest)new DataContractJsonSerializer(typeof(AvatarPackManifest)).ReadObject(stream); } if (avatarPackManifest == null || avatarPackManifest.SchemaVersion != 1) { throw new InvalidDataException("Only schemaVersion 1 is supported."); } if (string.IsNullOrEmpty(avatarPackManifest.PackId) || avatarPackManifest.PackId.Length > 128 || avatarPackManifest.PackId.Any((char c) => !char.IsLetterOrDigit(c) && c != '-' && c != '_' && c != '.')) { throw new InvalidDataException("packId must contain letters, digits, dots, hyphens or underscores."); } if (avatarPackManifest.Avatars == null || avatarPackManifest.Avatars.Length == 0 || avatarPackManifest.Avatars.Length > 256) { throw new InvalidDataException("avatars must contain 1 to 256 entries."); } string directoryName = Path.GetDirectoryName(marker); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); List<AvatarBinding> list = new List<AvatarBinding>(); AvatarPackEntry[] avatars = avatarPackManifest.Avatars; foreach (AvatarPackEntry avatarPackEntry in avatars) { if (avatarPackEntry == null || !ValidCharacter(avatarPackEntry.Character) || !hashSet.Add(avatarPackEntry.Character)) { throw new InvalidDataException("Invalid, reserved or duplicate character name."); } string model = ResolveAsset(directoryName, avatarPackEntry.Model, avatarPackEntry.Character + ".vrm"); string settings = ResolveAsset(directoryName, avatarPackEntry.Settings, "settings_" + avatarPackEntry.Character + ".txt"); string outfits; if (avatarPackEntry.Outfits != null) { outfits = ResolveAsset(directoryName, avatarPackEntry.Outfits, "outfits_" + avatarPackEntry.Character + ".txt"); } else { string text = Path.Combine(directoryName, "__vrm_fixes_no_outfits__"); if (Directory.Exists(text) || File.Exists(text)) { throw new InvalidDataException("Reserved absent-outfit path exists in the package."); } outfits = Path.Combine(text, "outfits_" + avatarPackEntry.Character + ".txt"); } list.Add(new AvatarBinding(avatarPackEntry.Character, avatarPackManifest.PackId, directoryName, model, settings, outfits)); } return list.ToArray(); } private static bool ValidCharacter(string name) { if (!string.IsNullOrWhiteSpace(name) && name == name.Trim() && name.Length <= 128 && name != "." && name != ".." && !name.Equals("___Default", StringComparison.OrdinalIgnoreCase)) { return !name.Any((char c) => char.IsControl(c) || "<>:\"/\\|?*".Contains(c)); } return false; } private static string ResolveAsset(string directory, string relativePath, string expectedName) { if (string.IsNullOrWhiteSpace(relativePath) || Path.IsPathRooted(relativePath) || relativePath.Contains(':') || relativePath.Any(char.IsControl)) { throw new InvalidDataException("Asset path must be a relative path inside its pack."); } string[] array = relativePath.Replace('\\', '/').Split('/'); if (array.Any((string x) => x.Length == 0 || x == "." || x == ".." || DisabledName(x))) { throw new InvalidDataException("Asset path contains an invalid or disabled segment."); } if (!array.Last().Equals(expectedName, StringComparison.OrdinalIgnoreCase)) { throw new InvalidDataException("Expected payload basename " + expectedName + "."); } string fullPath = Path.GetFullPath(Path.Combine(directory, Path.Combine(array))); if (!fullPath.StartsWith(WithSeparator(directory), StringComparison.OrdinalIgnoreCase)) { throw new InvalidDataException("Asset path escapes its package."); } string text = directory; string[] array2 = array; foreach (string path in array2) { text = Path.Combine(text, path); if (!File.Exists(text) && !Directory.Exists(text)) { throw new InvalidDataException("Required active payload is missing: " + relativePath); } if (IsReparsePoint(text)) { throw new InvalidDataException("Linked asset paths are not supported."); } } if (!File.Exists(fullPath)) { throw new InvalidDataException("Asset is not a regular file: " + relativePath); } return fullPath; } private static bool DisabledName(string name) { return name.EndsWith(".old", StringComparison.OrdinalIgnoreCase); } private static bool IsReparsePoint(string path) { return (File.GetAttributes(path) & FileAttributes.ReparsePoint) != 0; } private static string WithSeparator(string path) { return Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; } } }