Decompiled source of PeakSkin v1.1.0
PeakSkin/PeakSkin.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers.Binary; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.Rendering; using ZstdSharp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] namespace PeakSkin; internal static class BonePairs { public static readonly string[,] Pairs = new string[20, 2] { { "Hip", "hips" }, { "Mid", "spine" }, { "AimJoint", "chest" }, { "Head", "head" }, { "S_Shoulder_L", "shoulder.L" }, { "Arm_L", "upper_arm.L" }, { "Elbow_L", "lower_arm.L" }, { "Hand_L", "hand.L" }, { "S_Shoulder_R", "shoulder.R" }, { "Arm_R", "upper_arm.R" }, { "Elbow_R", "lower_arm.R" }, { "Hand_R", "hand.R" }, { "Leg_L", "upper_leg.L" }, { "Knee_L", "lower_leg.L" }, { "Foot_L", "foot.L" }, { "S_Toe_1_L", "toes.L" }, { "Leg_R", "upper_leg.R" }, { "Knee_R", "lower_leg.R" }, { "Foot_R", "foot.R" }, { "S_Toe_1_R", "toes.R" } }; } internal sealed class AvatarManager : MonoBehaviour { public static AvatarManager Instance; public VrmModel Model; private const string LocalId = "local"; private readonly List<VrmAvatar> _avatars = new List<VrmAvatar>(); private readonly Dictionary<string, VrmModel> _peer = new Dictionary<string, VrmModel>(4, StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _failed = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _warned = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private const int MaxPeerModels = 6; private float _next; private int _lastCount = -1; private string _lastLocal = "<none>"; private float _nextDiag; private void Awake() { Instance = this; } private void Update() { if (Model != Plugin.CurrentModel) { SwapModel(); } if (ModConfig.PanelEnabled && Input.GetKeyDown((KeyCode)107) && (Object)(object)SkinPanel.Instance != (Object)null) { SkinPanel.Instance.ToggleVisible(); } float unscaledTime = Time.unscaledTime; if (unscaledTime < _next) { return; } _next = unscaledTime + 0.5f; try { NetSync.Tick(); } catch (Exception ex) { Plugin.Log("[net] tick failed: " + ex.Message); } try { Scan(); } catch (Exception ex2) { Plugin.Err("scan failed: " + ex2); } } private void SwapModel() { Plugin.Log((Plugin.CurrentModel == null) ? "[model] 原版装扮 — tearing down every PeakSkin avatar" : ("[model] rebuild avatars for " + (Plugin.CurrentModelPath ?? "<null>"))); for (int num = _avatars.Count - 1; num >= 0; num--) { DestroyAvatar(_avatars[num]); } _avatars.Clear(); Model = Plugin.CurrentModel; _lastCount = -1; _lastLocal = "<none>"; } private void DestroyAvatar(VrmAvatar av) { if ((Object)(object)av == (Object)null) { return; } try { if (av.Hidden != null) { for (int i = 0; i < av.Hidden.Length; i++) { if ((Object)(object)av.Hidden[i] != (Object)null) { av.Hidden[i].forceRenderingOff = false; } } } } catch { } try { ((Component)av).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)av).gameObject); } catch { } } private void DropAvatar(Character c) { VrmAvatar vrmAvatar = FindAvatar(c); if (!((Object)(object)vrmAvatar == (Object)null)) { _avatars.Remove(vrmAvatar); DestroyAvatar(vrmAvatar); } } private bool PickModel(Character c, bool local, out VrmModel want, out string modelId) { want = null; modelId = null; if (local) { if (Model == null) { return false; } want = Model; modelId = "local"; return true; } int num = ActorOf(c); string text = (ModConfig.ShowOtherModels ? NetSync.IdOfActor(num) : null); if (string.Equals(text, "none", StringComparison.OrdinalIgnoreCase)) { return false; } if (!string.IsNullOrEmpty(text)) { VrmModel vrmModel = PeerModel(text); if (vrmModel != null) { want = vrmModel; modelId = text; return true; } WarnMissing(num, text); return false; } if (ModConfig.ReplaceOthers && Model != null) { want = Model; modelId = "local"; return true; } return false; } private static Tune PickTune(VrmAvatar av) { if (ModConfig.ShowOtherModels && NetSync.TryGetTuneOfActor(av.ActorNumber, out var tune)) { return tune; } if (!(av.ModelId == "local")) { return Tune.Identity; } return Tune.FromConfig(); } private VrmModel PeerModel(string id) { if (string.IsNullOrEmpty(id)) { return null; } if (Model != null && string.Equals(NetSync.OwnId, id, StringComparison.OrdinalIgnoreCase)) { return Model; } if (_peer.TryGetValue(id, out var value) && value != null && (Object)(object)value.Root != (Object)null) { return value; } string text = ModelCatalog.PathOf(id); if (text == null) { return null; } if (_failed.Contains(id)) { return null; } if (_peer.Count >= 6) { Plugin.Log("[net] peer model limit reached (" + 6 + "), ignoring " + Path.GetFileName(text)); _failed.Add(id); return null; } Plugin.Log("[net] loading peer model " + Path.GetFileName(text) + " (" + id + ")"); try { value = Plugin.LoadModel(text); } catch (Exception ex) { Plugin.Log("[net] peer model load failed: " + ex.Message); value = null; } if (value == null) { _failed.Add(id); Plugin.Log("[net] giving up on " + Path.GetFileName(text) + " — it will stay vanilla this session"); return null; } _peer[id] = value; return value; } private void WarnMissing(int actor, string id) { if (_warned.Add(id)) { string text = ModelCatalog.PathOf(id); Plugin.Log("[net] actor " + actor + " wears " + id + ((text == null) ? " — not on this machine; put the same model in the skin folder to see them" : " — that file failed to load")); } } private static int ActorOf(Character c) { try { PhotonView photonView = ((MonoBehaviourPun)c).photonView; if ((Object)(object)photonView == (Object)null) { return -1; } if (photonView.Owner != null) { return photonView.Owner.ActorNumber; } return photonView.OwnerActorNr; } catch { return -1; } } private void Scan() { if (Model == null && !ModConfig.ShowOtherModels) { Diag("model is null"); return; } Character[] array = Object.FindObjectsOfType<Character>(); Character val = null; try { val = Character.localCharacter; } catch { } string text = (((Object)(object)val == (Object)null) ? "<none>" : ((Object)((Component)val).gameObject).name); if (array.Length != _lastCount || text != _lastLocal || Time.unscaledTime >= _nextDiag) { _nextDiag = Time.unscaledTime + 5f; if (array.Length != _lastCount || text != _lastLocal) { _lastCount = array.Length; _lastLocal = text; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < array.Length && i < 8; i++) { stringBuilder.Append(' ').Append(((Object)(object)array[i] == (Object)null) ? "<null>" : ((Object)((Component)array[i]).gameObject).name); } Diag("characters=" + array.Length + " local=" + text + " names:" + stringBuilder); } } foreach (Character val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } bool flag = IsLocal(val2); if (!flag && !ModConfig.ReplaceOthers && !ModConfig.ShowOtherModels) { continue; } if (!PickModel(val2, flag, out var want, out var modelId)) { DropAvatar(val2); continue; } VrmAvatar vrmAvatar = FindAvatar(val2); if ((Object)(object)vrmAvatar != (Object)null) { if (vrmAvatar.SourceModel == want && vrmAvatar.ModelId == modelId) { continue; } Plugin.Log("[net] " + ((Object)((Component)val2).gameObject).name + " switched to " + (modelId ?? "?") + " — rebuilding avatar"); _avatars.Remove(vrmAvatar); DestroyAvatar(vrmAvatar); } try { Attach(val2, want, modelId); } catch (Exception ex) { Plugin.Err("attach failed on " + ((Object)val2).name + ": " + ex); } } for (int num = _avatars.Count - 1; num >= 0; num--) { VrmAvatar vrmAvatar2 = _avatars[num]; if ((Object)(object)vrmAvatar2 == (Object)null || (Object)(object)vrmAvatar2.Character == (Object)null) { if ((Object)(object)vrmAvatar2 != (Object)null) { Object.Destroy((Object)(object)((Component)vrmAvatar2).gameObject); } _avatars.RemoveAt(num); } else { vrmAvatar2.ReapplyHiding(); if (!vrmAvatar2.IsLocalPlayer) { Tune live = PickTune(vrmAvatar2); if (!live.Same(vrmAvatar2.Live)) { Plugin.Log("[net] " + ((Object)((Component)vrmAvatar2.Character).gameObject).name + " tune " + live.Describe()); vrmAvatar2.Live = live; } } if (!vrmAvatar2.DiagDone && Time.unscaledTime > vrmAvatar2.DiagAt) { vrmAvatar2.DiagDone = true; Diag(vrmAvatar2.Diagnose()); } } } } private VrmAvatar FindAvatar(Character c) { for (int i = 0; i < _avatars.Count; i++) { VrmAvatar vrmAvatar = _avatars[i]; if ((Object)(object)vrmAvatar != (Object)null && (Object)(object)vrmAvatar.Character == (Object)(object)c) { return vrmAvatar; } } return null; } private static bool IsLocal(Character c) { try { return (Object)(object)Character.localCharacter == (Object)(object)c; } catch { return false; } } private void Attach(Character c, VrmModel model, string modelId) { //IL_1273: Unknown result type (might be due to invalid IL or missing references) //IL_1274: Unknown result type (might be due to invalid IL or missing references) //IL_14c5: Unknown result type (might be due to invalid IL or missing references) //IL_14c7: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_1361: Unknown result type (might be due to invalid IL or missing references) //IL_1366: Unknown result type (might be due to invalid IL or missing references) //IL_136a: Unknown result type (might be due to invalid IL or missing references) //IL_1384: Unknown result type (might be due to invalid IL or missing references) //IL_13a0: Unknown result type (might be due to invalid IL or missing references) //IL_13b4: Unknown result type (might be due to invalid IL or missing references) //IL_13cc: 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) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_0fa4: Unknown result type (might be due to invalid IL or missing references) //IL_0faa: Invalid comparison between Unknown and I4 //IL_00fc: 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_1077: Unknown result type (might be due to invalid IL or missing references) //IL_107c: Unknown result type (might be due to invalid IL or missing references) //IL_1631: Unknown result type (might be due to invalid IL or missing references) //IL_1636: Unknown result type (might be due to invalid IL or missing references) //IL_10b9: Unknown result type (might be due to invalid IL or missing references) //IL_10c7: Unknown result type (might be due to invalid IL or missing references) //IL_10d4: Unknown result type (might be due to invalid IL or missing references) //IL_10de: Unknown result type (might be due to invalid IL or missing references) //IL_10eb: Unknown result type (might be due to invalid IL or missing references) //IL_10f5: Unknown result type (might be due to invalid IL or missing references) //IL_1102: Unknown result type (might be due to invalid IL or missing references) //IL_1148: Unknown result type (might be due to invalid IL or missing references) //IL_0372: 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_037e: Unknown result type (might be due to invalid IL or missing references) //IL_173e: Unknown result type (might be due to invalid IL or missing references) //IL_174c: Unknown result type (might be due to invalid IL or missing references) //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_063e: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_0648: Unknown result type (might be due to invalid IL or missing references) //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_064f: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_0547: Unknown result type (might be due to invalid IL or missing references) //IL_054c: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_0690: Unknown result type (might be due to invalid IL or missing references) //IL_0692: Unknown result type (might be due to invalid IL or missing references) //IL_0694: Unknown result type (might be due to invalid IL or missing references) //IL_0699: Unknown result type (might be due to invalid IL or missing references) //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_0702: Unknown result type (might be due to invalid IL or missing references) //IL_0704: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Unknown result type (might be due to invalid IL or missing references) //IL_070c: Unknown result type (might be due to invalid IL or missing references) //IL_0712: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) //IL_071c: Unknown result type (might be due to invalid IL or missing references) //IL_0721: Unknown result type (might be due to invalid IL or missing references) //IL_0729: Unknown result type (might be due to invalid IL or missing references) //IL_072e: Unknown result type (might be due to invalid IL or missing references) //IL_0906: Unknown result type (might be due to invalid IL or missing references) //IL_0912: Unknown result type (might be due to invalid IL or missing references) //IL_0917: Unknown result type (might be due to invalid IL or missing references) //IL_091c: Unknown result type (might be due to invalid IL or missing references) //IL_0753: Unknown result type (might be due to invalid IL or missing references) //IL_0745: Unknown result type (might be due to invalid IL or missing references) //IL_0974: Unknown result type (might be due to invalid IL or missing references) //IL_0985: Unknown result type (might be due to invalid IL or missing references) //IL_098a: Unknown result type (might be due to invalid IL or missing references) //IL_098f: Unknown result type (might be due to invalid IL or missing references) //IL_0938: Unknown result type (might be due to invalid IL or missing references) //IL_093d: Unknown result type (might be due to invalid IL or missing references) //IL_0942: Unknown result type (might be due to invalid IL or missing references) //IL_0944: Unknown result type (might be due to invalid IL or missing references) //IL_0949: Unknown result type (might be due to invalid IL or missing references) //IL_094d: Unknown result type (might be due to invalid IL or missing references) //IL_0952: Unknown result type (might be due to invalid IL or missing references) //IL_0cda: Unknown result type (might be due to invalid IL or missing references) //IL_0cdf: Unknown result type (might be due to invalid IL or missing references) //IL_0ce3: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_09a8: Unknown result type (might be due to invalid IL or missing references) //IL_09ad: Unknown result type (might be due to invalid IL or missing references) //IL_09b2: Unknown result type (might be due to invalid IL or missing references) //IL_09b4: Unknown result type (might be due to invalid IL or missing references) //IL_09b9: Unknown result type (might be due to invalid IL or missing references) //IL_09bd: Unknown result type (might be due to invalid IL or missing references) //IL_09c2: Unknown result type (might be due to invalid IL or missing references) //IL_07b7: Unknown result type (might be due to invalid IL or missing references) //IL_07ed: Unknown result type (might be due to invalid IL or missing references) //IL_0802: Unknown result type (might be due to invalid IL or missing references) //IL_0815: Unknown result type (might be due to invalid IL or missing references) if (model == null || (Object)(object)model.Root == (Object)null) { Diag("attach skip: no model for " + ((Object)((Component)c).gameObject).name); return; } CharacterRefs refs = c.refs; if (refs == null) { Diag("attach skip: refs null on " + ((Object)((Component)c).gameObject).name); return; } SkinnedMeshRenderer mainRenderer = refs.mainRenderer; if ((Object)(object)mainRenderer == (Object)null || mainRenderer.bones == null || mainRenderer.bones.Length == 0) { Diag("attach skip: mainRenderer/bones missing on " + ((Object)((Component)c).gameObject).name); return; } if ((Object)(object)refs.customization == (Object)null) { Diag("attach skip: customization null on " + ((Object)((Component)c).gameObject).name); return; } CustomizationRefs refs2 = refs.customization.refs; if ((Object)(object)refs2 == (Object)null) { Diag("attach skip: CustomizationRefs null on " + ((Object)((Component)c).gameObject).name); return; } Quaternion align = Quaternion.Euler(0f, ModConfig.YawOffset + model.SpecYaw, 0f); Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>(128); Transform[] bones = mainRenderer.bones; for (int i = 0; i < bones.Length; i++) { AddBone(dictionary, bones[i]); } Transform[] componentsInChildren = ((Component)c).GetComponentsInChildren<Transform>(true); for (int j = 0; j < componentsInChildren.Length; j++) { AddBone(dictionary, componentsInChildren[j]); } GameObject val = Object.Instantiate<GameObject>(model.Root); ((Object)val).name = "PhoebeVrm_" + ((Object)((Component)c).gameObject).name; val.transform.SetParent(((Component)c).transform, false); val.SetActive(true); try { Object.DontDestroyOnLoad((Object)(object)val); } catch { } SkinnedMeshRenderer[] componentsInChildren2 = val.GetComponentsInChildren<SkinnedMeshRenderer>(true); Renderer[] componentsInChildren3 = val.GetComponentsInChildren<Renderer>(true); List<Renderer> list = new List<Renderer>(componentsInChildren3.Length); foreach (Renderer val2 in componentsInChildren3) { if (!((Object)(object)val2 == (Object)null) && !(val2 is ParticleSystemRenderer) && !(val2 is LineRenderer) && !(val2 is TrailRenderer)) { list.Add(val2); } } componentsInChildren3 = list.ToArray(); Dictionary<string, Transform> dictionary2 = new Dictionary<string, Transform>(128); foreach (SkinnedMeshRenderer val3 in componentsInChildren2) { if ((Object)(object)val3 == (Object)null) { continue; } Transform[] bones2 = val3.bones; if (bones2 == null) { continue; } foreach (Transform val4 in bones2) { if (!((Object)(object)val4 == (Object)null)) { string key = Norm(((Object)val4).name); if (!dictionary2.ContainsKey(key)) { dictionary2[key] = val4; } } } } Vector3 modelHipLocal = Vector3.zero; bool flag = false; if (dictionary2.TryGetValue(Norm("hips"), out var value) && (Object)(object)value != (Object)null) { flag = true; modelHipLocal = val.transform.InverseTransformPoint(value.position); } Quaternion val5 = Quaternion.Inverse(ModConfig.GameMeshRest); Dictionary<string, Quaternion> dictionary3 = new Dictionary<string, Quaternion>(128); Dictionary<string, Quaternion> dictionary4 = new Dictionary<string, Quaternion>(128); if ((Object)(object)mainRenderer.sharedMesh != (Object)null) { Matrix4x4[] bindposes = mainRenderer.sharedMesh.bindposes; if (bindposes != null) { int num = Mathf.Min(bindposes.Length, bones.Length); for (int n = 0; n < num; n++) { Transform val6 = bones[n]; if (!((Object)(object)val6 == (Object)null)) { string key2 = Norm(((Object)val6).name); if (!dictionary3.ContainsKey(key2)) { dictionary3[key2] = Glb.ExtractRotation(bindposes[n]) * val5; } if (!dictionary4.ContainsKey(key2)) { dictionary4[key2] = Glb.ExtractRotation(bindposes[n]); } } } } } Vector3 val8; if ((Object)(object)mainRenderer.sharedMesh != (Object)null) { Matrix4x4[] bindposes2 = mainRenderer.sharedMesh.bindposes; if (bindposes2 != null) { int num2 = Mathf.Min(bindposes2.Length, bones.Length); for (int num3 = 0; num3 < num2; num3++) { if (!((Object)(object)bones[num3] == (Object)null)) { string text = Norm(((Object)bones[num3]).name); if (!(text != "hip") || !(text != "head") || !(text != "handl") || !(text != "handr") || !(text != "arml") || !(text != "legl") || !(text != "footl") || !(text != "toe1l") || !(text != "kneel") || !(text != "torso")) { Quaternion val7 = Glb.ExtractRotation(bindposes2[num3]); object[] obj2 = new object[6] { ((Object)bones[num3]).name, ((Matrix4x4)(ref bindposes2[num3])).determinant, null, null, null, null }; val8 = ((Quaternion)(ref val7)).eulerAngles; obj2[2] = ((Vector3)(ref val8)).ToString("F1"); Quaternion rotation = ((Matrix4x4)(ref bindposes2[num3])).rotation; val8 = ((Quaternion)(ref rotation)).eulerAngles; obj2[3] = ((Vector3)(ref val8)).ToString("F1"); obj2[4] = Quaternion.Angle(val7, ((Matrix4x4)(ref bindposes2[num3])).rotation); val8 = bones[num3].lossyScale; obj2[5] = ((Vector3)(ref val8)).ToString("F2"); Plugin.Log(string.Format("[bp] {0} det={1:F3} mine={2} unity={3} angErr={4:F1} boneLossy={5}", obj2)); } } } } } List<BoneBinding> list2 = new List<BoneBinding>(32); StringBuilder stringBuilder = new StringBuilder(); for (int num4 = 0; num4 < BonePairs.Pairs.GetLength(0); num4++) { string text2 = BonePairs.Pairs[num4, 0]; string text3 = BonePairs.Pairs[num4, 1]; if (!dictionary.TryGetValue(Norm(text2), out var value2)) { stringBuilder.Append(" game:").Append(text2); continue; } if (!dictionary2.TryGetValue(Norm(text3), out var value3)) { stringBuilder.Append(" vrm:").Append(text3); continue; } if (!dictionary3.TryGetValue(Norm(text2), out var value4)) { stringBuilder.Append(" bind:").Append(text2); continue; } Quaternion val9 = Quaternion.Inverse(val.transform.rotation) * value3.rotation; Quaternion lG = Quaternion.identity; bool flag2 = false; if (dictionary4.TryGetValue(Norm(text2), out var value5)) { Transform parent = value2.parent; if ((Object)(object)parent != (Object)null && dictionary4.TryGetValue(Norm(((Object)parent).name), out var value6)) { lG = value6 * Quaternion.Inverse(value5); flag2 = true; } } bool flag3 = Norm(text2) == "head" || Norm(text3) == "head"; if (flag3 && !flag2) { Plugin.Log("[head] no bind partner for " + text2 + " -> the head stays on aim"); } list2.Add(new BoneBinding { Game = value2, Our = value3, K = value4, W0 = val9, LG = lG, LO = value3.localRotation, GRest = value2.rotation, GPRest = (((Object)(object)value2.parent != (Object)null) ? value2.parent.rotation : value2.rotation), IsHead = flag3, Local = (!flag3 && flag2 && ModConfig.Retarget == "local") }); if (num4 == 2 || num4 == 6 || num4 == 8) { Quaternion value7; string text4 = (dictionary4.TryGetValue(Norm(text2), out value7) ? VrmAvatar.Q(value7) : "?"); Plugin.Log("[rb] " + text2 + " bp=" + text4 + " worldO=" + VrmAvatar.Q(value3.rotation) + " w0=" + VrmAvatar.Q(val9) + " bpGForMeshRest=" + VrmAvatar.Q(ModConfig.GameMeshRest)); } } for (int num5 = 0; num5 < list2.Count; num5++) { BoneBinding boneBinding = list2[num5]; if ((Object)(object)boneBinding.Game == (Object)null || (Object)(object)boneBinding.Our == (Object)null) { continue; } for (int num6 = 0; num6 < list2.Count; num6++) { BoneBinding boneBinding2 = list2[num6]; if ((Object)(object)boneBinding2.Game != (Object)null && (Object)(object)boneBinding2.Our != (Object)null && (Object)(object)boneBinding2.Game.parent == (Object)(object)boneBinding.Game) { boneBinding.GameChild = boneBinding2.Game; boneBinding.OurChild = boneBinding2.Our; break; } } if ((Object)(object)boneBinding.OurChild != (Object)null) { Vector3 val10 = boneBinding.OurChild.position - boneBinding.Our.position; if (((Vector3)(ref val10)).sqrMagnitude > 1E-08f) { val8 = Quaternion.Inverse(boneBinding.Our.rotation) * val10; boneBinding.RestDirLocal = ((Vector3)(ref val8)).normalized; } } else if ((Object)(object)boneBinding.Our.parent != (Object)null) { Vector3 val11 = boneBinding.Our.position - boneBinding.Our.parent.position; if (((Vector3)(ref val11)).sqrMagnitude > 1E-08f) { val8 = Quaternion.Inverse(boneBinding.Our.rotation) * val11; boneBinding.RestDirLocal = ((Vector3)(ref val8)).normalized; boneBinding.AimSelf = true; } } string text5 = (((Object)(object)boneBinding.Our != (Object)null) ? ((Object)boneBinding.Our).name.ToLowerInvariant() : ""); boneBinding.ArmsDown = ModConfig.ArmsDown && text5.Contains("upper_arm"); boneBinding.ArmsDownSide = (text5.EndsWith(".l") ? (-1f) : 1f); boneBinding.NoAim = text5.StartsWith("foot.") || text5.StartsWith("toes."); boneBinding.ReachArm = text5 == "upper_arm.r" || text5 == "lower_arm.r"; boneBinding.Aim = ModConfig.Retarget == "aim" && ((Object)(object)boneBinding.GameChild != (Object)null || boneBinding.AimSelf) && ((Vector3)(ref boneBinding.RestDirLocal)).sqrMagnitude > 0.5f && text5 != "head"; } StringBuilder stringBuilder2 = new StringBuilder("[aim]"); int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; for (int num11 = 0; num11 < list2.Count; num11++) { BoneBinding boneBinding3 = list2[num11]; if ((Object)(object)boneBinding3.Our == (Object)null) { continue; } if (boneBinding3.Aim) { if (boneBinding3.AimSelf) { num8++; } else { num7++; } } else if (boneBinding3.Local) { num10++; } else { num9++; } } stringBuilder2.Append(" child=").Append(num7).Append(" self=") .Append(num8) .Append(" delta=") .Append(num10) .Append(" world=") .Append(num9); stringBuilder2.Append(" armsDown=").Append(ModConfig.ArmsDown ? "on" : "off"); stringBuilder2.Append(" fpRadius=").Append(ModConfig.FirstPersonRadius.ToString("F2")); stringBuilder2.Append(" |"); for (int num12 = 0; num12 < list2.Count; num12++) { BoneBinding boneBinding4 = list2[num12]; if (!((Object)(object)boneBinding4.Our == (Object)null)) { stringBuilder2.Append(' ').Append(((Object)boneBinding4.Our).name).Append('=') .Append(boneBinding4.IsHead ? "head-euler" : ((!boneBinding4.Aim) ? (boneBinding4.Local ? "delta" : "world") : (boneBinding4.AimSelf ? "self" : "aim"))); } } Plugin.Log(stringBuilder2.ToString()); LogRestArm(dictionary2, "upper_arm.L", "lower_arm.L", "L"); LogRestArm(dictionary2, "upper_arm.R", "lower_arm.R", "R"); Bounds bounds = ((Renderer)mainRenderer).bounds; float y = ((Bounds)(ref bounds)).size.y; float height = model.Height; float num13 = ((ModConfig.AutoFit && y > 0.2f && height > 0.2f) ? (y / height) : 1f); float num14 = ModConfig.Scale * num13; List<Renderer> list3 = new List<Renderer>(32); AddR(list3, (Renderer)(object)refs2.mainRenderer); AddR(list3, (Renderer)(object)refs2.mainRendererShadow); AddR(list3, refs2.mouthRenderer); AddR(list3, refs2.accessoryRenderer); AddR(list3, refs2.shorts); AddR(list3, refs2.skirt); AddR(list3, refs2.skirtShadow); AddR(list3, refs2.shortsShadow); AddR(list3, refs2.sashRenderer); AddR(list3, refs2.medalRenderer); AddR(list3, refs2.blindRenderer); AddR(list3, refs2.chickenRenderer); AddR(list3, refs2.headShadow); AddR(list3, refs2.skeletonRenderer); AddRs(list3, refs2.PlayerRenderers); AddRs(list3, refs2.EyeRenderers); AddRs(list3, refs2.playerHats); AddRs(list3, refs2.stoneRenderers); AddRs(list3, refs2.AllRenderers); if ((Object)(object)refs2.thirdEye != (Object)null) { AddRs(list3, refs2.thirdEye.GetComponentsInChildren<Renderer>(true)); } if (ModConfig.HideAllRenderers) { Renderer[] componentsInChildren4 = ((Component)c).GetComponentsInChildren<Renderer>(true); foreach (Renderer val12 in componentsInChildren4) { if (!((Object)(object)val12 == (Object)null) && !(val12 is ParticleSystemRenderer) && (!((Object)(object)val != (Object)null) || !((Component)val12).transform.IsChildOf(val.transform))) { AddR(list3, val12); } } } int num16 = 0; try { HideTheBody hideTheBody = refs.hideTheBody; if ((Object)(object)hideTheBody != (Object)null) { if ((Object)(object)hideTheBody.shadowCaster != (Object)null) { AddRs(list3, hideTheBody.shadowCaster.GetComponentsInChildren<Renderer>(true)); num16++; } if ((Object)(object)hideTheBody.shadowCasterHat != (Object)null) { AddRs(list3, hideTheBody.shadowCasterHat.GetComponentsInChildren<Renderer>(true)); num16++; } } if ((Object)(object)refs2.hatShadowMeshFilter != (Object)null) { AddR(list3, ((Component)refs2.hatShadowMeshFilter).GetComponent<Renderer>()); } } catch (Exception ex) { Diag("[shadow] hideTheBody: " + ex.Message); } try { Renderer[] componentsInChildren5 = ((Component)c).GetComponentsInChildren<Renderer>(true); foreach (Renderer val13 in componentsInChildren5) { if (!((Object)(object)val13 == (Object)null) && !(val13 is ParticleSystemRenderer) && (!((Object)(object)val != (Object)null) || !((Component)val13).transform.IsChildOf(val.transform))) { Material sharedMaterial = val13.sharedMaterial; if ((int)val13.shadowCastingMode == 3 || ((Object)(object)sharedMaterial != (Object)null && ((Object)sharedMaterial).name.StartsWith("Shadow", StringComparison.OrdinalIgnoreCase))) { AddR(list3, val13); } } } } catch (Exception ex2) { Diag("[shadow] sweep: " + ex2.Message); } int num18 = 0; try { foreach (Renderer val14 in componentsInChildren3) { if (!((Object)(object)val14 == (Object)null)) { val14.shadowCastingMode = (ShadowCastingMode)0; SkinnedMeshRenderer val15 = (SkinnedMeshRenderer)(object)((val14 is SkinnedMeshRenderer) ? val14 : null); if (!((Object)(object)val15 == (Object)null) && !((Object)(object)val15.sharedMesh == (Object)null) && !IsTransparent(((Renderer)val15).sharedMaterial)) { GameObject val16 = new GameObject(((Object)val15).name + "_shadow") { layer = ((Component)val15).gameObject.layer }; Transform val17 = (((Object)(object)((Component)val15).transform.parent != (Object)null) ? ((Component)val15).transform.parent : val.transform); val16.transform.SetParent(val17, false); val16.transform.localPosition = ((Component)val15).transform.localPosition; val16.transform.localRotation = ((Component)val15).transform.localRotation; val16.transform.localScale = ((Component)val15).transform.localScale; SkinnedMeshRenderer obj3 = val16.AddComponent<SkinnedMeshRenderer>(); obj3.sharedMesh = val15.sharedMesh; obj3.bones = val15.bones; obj3.rootBone = val15.rootBone; ((Renderer)obj3).sharedMaterial = ((Renderer)val15).sharedMaterial; ((Renderer)obj3).localBounds = ((Renderer)val15).localBounds; obj3.updateWhenOffscreen = true; ((Renderer)obj3).receiveShadows = false; ((Renderer)obj3).shadowCastingMode = (ShadowCastingMode)3; num18++; } } } } catch (Exception ex3) { Diag("[shadow] proxy: " + ex3.Message); } Plugin.Log("[shadow] fake casters hidden=" + num16 + " (hide list " + list3.Count + ") | ours " + componentsInChildren3.Length + ": cast=Off, shadowsOnly=" + num18); VrmAvatar vrmAvatar = val.AddComponent<VrmAvatar>(); vrmAvatar.ModelRoot = val.transform; vrmAvatar.GameRef = ((Component)mainRenderer).transform; vrmAvatar.GameRoot = ((Component)c).transform; vrmAvatar.GameSignal = (Renderer)(object)mainRenderer; vrmAvatar.HideWithGame = ModConfig.HideWithGameBody; vrmAvatar.OurRenderers = componentsInChildren3; vrmAvatar.Hidden = list3.ToArray(); vrmAvatar.Bindings = list2.ToArray(); vrmAvatar.CaptureRest(); vrmAvatar.Align = align; vrmAvatar.AutoFitScale = num13; vrmAvatar.Scale = num14; vrmAvatar.YOffset = ModConfig.YOffset; vrmAvatar.AnchorToHip = ModConfig.AnchorToHip; vrmAvatar.OffsetForward = ModConfig.OffsetForward; vrmAvatar.OffsetRight = ModConfig.OffsetRight; vrmAvatar.IsLocalPlayer = IsLocal(c); vrmAvatar.ActorNumber = ActorOf(c); vrmAvatar.Character = c; vrmAvatar.SourceModel = model; vrmAvatar.ModelId = modelId; vrmAvatar.Live = (vrmAvatar.IsLocalPlayer ? Tune.FromConfig() : PickTune(vrmAvatar)); if (dictionary2.TryGetValue(Norm("head"), out var value8)) { vrmAvatar.HeadBone = value8; } if (dictionary2.TryGetValue(Norm("hips"), out var value9)) { vrmAvatar.HipBone = value9; } vrmAvatar.DiagAt = Time.unscaledTime + 2f; float num20 = 0f; try { Bounds bounds2 = ((Renderer)mainRenderer).bounds; num20 = ((Bounds)(ref bounds2)).min.y - model.MinY * num14 - ((Component)c).transform.position.y; Plugin.Log($"[anchor] gameBounds y={((Bounds)(ref bounds2)).min.y:F3}..{((Bounds)(ref bounds2)).max.y:F3} rootY={((Component)c).transform.position.y:F3} ourMinY={model.MinY:F3} anchorY={num20:F3}"); } catch (Exception ex4) { Plugin.Log("[anchor] bounds failed: " + ex4.Message); } vrmAvatar.AnchorY = num20; Transform val18 = null; try { if ((Object)(object)refs.hip != (Object)null) { val18 = refs.hip.transform; } } catch { } if ((Object)(object)val18 == (Object)null && dictionary.TryGetValue("hip", out var value10)) { val18 = value10; } vrmAvatar.GameHip = val18; try { if ((Object)(object)refs.head != (Object)null) { vrmAvatar.GameHead = refs.head.transform; } } catch { } if ((Object)(object)vrmAvatar.GameHead == (Object)null && dictionary.TryGetValue("head", out var value11)) { vrmAvatar.GameHead = value11; } vrmAvatar.HasModelHip = flag; vrmAvatar.ModelHipLocal = modelHipLocal; try { if ((Object)(object)refs.rigCreator != (Object)null) { vrmAvatar.GameRig = ((Component)refs.rigCreator).transform; } } catch { } if ((Object)(object)vrmAvatar.GameRig == (Object)null && (Object)(object)vrmAvatar.GameHip != (Object)null) { Transform val19 = vrmAvatar.GameHip; for (int num21 = 0; num21 < 16; num21++) { if (!((Object)(object)val19.parent != (Object)null)) { break; } if (!((Object)(object)val19.parent != (Object)(object)((Component)c).transform)) { break; } val19 = val19.parent; } if ((Object)(object)val19 != (Object)null && (Object)(object)val19.parent == (Object)(object)((Component)c).transform) { vrmAvatar.GameRig = val19; } } Plugin.Log("[body] rig=" + (((Object)(object)vrmAvatar.GameRig == (Object)null) ? "NULL" : ((Object)vrmAvatar.GameRig).name) + " yaw=" + vrmAvatar.BodyYaw().ToString("F0") + " (absolute heading; 0 = world +Z, the face follows this)"); object[] obj7 = new object[4] { ((Object)(object)val18 == (Object)null) ? "NULL" : ((Object)val18).name, flag ? "yes" : "no", ((Vector3)(ref modelHipLocal)).ToString("F3"), null }; val8 = ((Component)c).transform.position; obj7[3] = ((Vector3)(ref val8)).ToString("F2"); Plugin.Log(string.Format("[anchor] hip={0} ourHips={1} local=({2}) charRoot=({3})", obj7)); vrmAvatar.Sort(); vrmAvatar.ReapplyHiding(); _avatars.Add(vrmAvatar); Plugin.Log(string.Format("[attach] {0} local={1} bones={2}/{3} scale={4:F3} (gameH={5:F3} ourH={6:F3}) hidden={7} ourRenderers={8}{9}", ((Object)((Component)c).gameObject).name, IsLocal(c), list2.Count, BonePairs.Pairs.GetLength(0), num14, y, height, list3.Count, componentsInChildren2.Length, (stringBuilder.Length > 0) ? (" missing:" + stringBuilder) : "")); float num22 = 0f; string arg = "-"; StringBuilder stringBuilder3 = new StringBuilder(); for (int num23 = 0; num23 < list2.Count; num23++) { float num24 = Quaternion.Angle(Quaternion.identity, list2[num23].W0); if (num24 > num22) { num22 = num24; arg = ((Object)list2[num23].Our).name; } if (num24 >= 1f) { stringBuilder3.AppendFormat("{0}={1:F0} ", ((Object)list2[num23].Our).name, num24); } } Plugin.Log(string.Format("[rest] W0 max={0:F1}@ {1} affected={2}", num22, arg, (stringBuilder3.Length == 0) ? "none (identity-rest model, W0 is a no-op)" : stringBuilder3.ToString())); } private static void Diag(string msg) { Plugin.Log("[scan] " + msg); } private static void AddBone(Dictionary<string, Transform> dict, Transform t) { if (!((Object)(object)t == (Object)null)) { string key = Norm(((Object)t).name); if (!dict.ContainsKey(key)) { dict[key] = t; } } } private static void AddR(List<Renderer> list, Renderer r) { if ((Object)(object)r == (Object)null) { return; } for (int i = 0; i < list.Count; i++) { if ((Object)(object)list[i] == (Object)(object)r) { return; } } list.Add(r); } private static void AddRs(List<Renderer> list, Renderer[] rs) { if (rs != null) { for (int i = 0; i < rs.Length; i++) { AddR(list, rs[i]); } } } private static bool IsTransparent(Material m) { if ((Object)(object)m == (Object)null) { return true; } if (m.renderQueue >= 3000) { return true; } if (m.HasProperty("_Surface") && m.GetFloat("_Surface") > 0.5f) { return true; } return false; } public static string Norm(string s) { if (string.IsNullOrEmpty(s)) { return ""; } StringBuilder stringBuilder = new StringBuilder(s.Length); for (int i = 0; i < s.Length; i++) { char c = s[i]; if (c >= 'A' && c <= 'Z') { c = (char)(c + 32); } if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private static void LogRestArm(Dictionary<string, Transform> bones, string a, string b, string side) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) if (bones.TryGetValue(Norm(a), out var value) && bones.TryGetValue(Norm(b), out var value2) && !((Object)(object)value == (Object)null) && !((Object)(object)value2 == (Object)null)) { Vector3 val = value2.position - value.position; float magnitude = ((Vector3)(ref val)).magnitude; if (!(magnitude < 1E-06f)) { Plugin.Log($"[rest] {side} {a}->{b}: elev={Mathf.Asin(Mathf.Clamp(val.y / magnitude, -1f, 1f)) * 57.29578f:F1} deg len={magnitude:F3}"); } } } } internal static class CameraVisibility { private static readonly List<VrmAvatar> Avatars = new List<VrmAvatar>(); private static bool _hooked; private static int _applyCount; public static void Register(VrmAvatar a) { if (!((Object)(object)a == (Object)null)) { EnsureHook(); if (!Avatars.Contains(a)) { Avatars.Add(a); } } } public static void Unregister(VrmAvatar a) { if (!((Object)(object)a == (Object)null)) { Avatars.Remove(a); } } private static void EnsureHook() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown if (_hooked) { return; } _hooked = true; try { RenderPipelineManager.beginCameraRendering += OnBeginCamera; Plugin.Log("[mirror] per-camera visibility hook installed (" + (((Object)(object)GraphicsSettings.currentRenderPipeline != (Object)null) ? "SRP" : "built-in") + ")"); } catch (Exception ex) { Plugin.Log("[mirror] beginCameraRendering hook failed: " + ex.Message); } try { Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull)); } catch (Exception ex2) { Plugin.Log("[mirror] onPreCull hook failed: " + ex2.Message); } } private static void OnBeginCamera(ScriptableRenderContext context, Camera cam) { Apply(cam); } private static void OnPreCull(Camera cam) { if ((Object)(object)GraphicsSettings.currentRenderPipeline == (Object)null) { Apply(cam); } } public static string Audit(Renderer[] ours, Renderer gameSignal) { //IL_0135: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); int num = -1; if (ours != null) { for (int i = 0; i < ours.Length; i++) { if ((Object)(object)ours[i] != (Object)null) { num = ((Component)ours[i]).gameObject.layer; break; } } } int num2 = (((Object)(object)gameSignal != (Object)null) ? ((Component)gameSignal).gameObject.layer : (-1)); Camera main = Camera.main; stringBuilder.AppendFormat("[mirror] ourLayer={0}({1}) gameBodyLayer={2}({3}) mainCam={4} mainMask=0x{5:X8}\n", num, LayerMask.LayerToName(num), num2, LayerMask.LayerToName(num2), ((Object)(object)main == (Object)null) ? "null" : ((Object)main).name, (!((Object)(object)main == (Object)null)) ? main.cullingMask : 0); Camera[] array = Resources.FindObjectsOfTypeAll<Camera>(); foreach (Camera val in array) { if (!((Object)(object)val == (Object)null)) { int cullingMask = val.cullingMask; stringBuilder.AppendFormat("[mirror] cam '{0}' enabled={1} active={2} depth={3:F2} type={4} mask=0x{5:X8} seesOurs={6} seesBody={7} rt={8}\n", ((Object)val).name, ((Behaviour)val).enabled, ((Behaviour)val).isActiveAndEnabled, val.depth, val.cameraType, cullingMask, (num < 0) ? "?" : ((cullingMask & (1 << num)) != 0).ToString(), (num2 < 0) ? "?" : ((cullingMask & (1 << num2)) != 0).ToString(), ((Object)(object)val.targetTexture == (Object)null) ? "-" : ((Object)val.targetTexture).name); } } return stringBuilder.ToString(); } public static string AlignLayer(Renderer[] ours, Renderer gameSignal) { if (ours == null || (Object)(object)gameSignal == (Object)null) { return "[mirror] align skipped: no avatar or no game body"; } int num = -1; for (int i = 0; i < ours.Length; i++) { if ((Object)(object)ours[i] != (Object)null) { num = ((Component)ours[i]).gameObject.layer; break; } } if (num < 0) { return "[mirror] align skipped: no renderer"; } int layer = ((Component)gameSignal).gameObject.layer; if (num == layer) { return "[mirror] align ok: already on body layer " + layer; } Camera main = Camera.main; if ((Object)(object)main != (Object)null && (main.cullingMask & (1 << layer)) == 0) { return "[mirror] align refused: layer " + layer + " not in main camera mask"; } int num2 = 0; for (int j = 0; j < ours.Length; j++) { if (!((Object)(object)ours[j] == (Object)null)) { GameObject gameObject = ((Component)ours[j]).gameObject; if ((Object)(object)gameObject != (Object)null && gameObject.layer != layer) { gameObject.layer = layer; num2++; } } } return "[mirror] align layer " + num + " -> " + layer + " on " + num2 + " renderer(s)"; } private static void Apply(Camera cam) { for (int num = Avatars.Count - 1; num >= 0; num--) { VrmAvatar vrmAvatar = Avatars[num]; if ((Object)(object)vrmAvatar == (Object)null) { Avatars.RemoveAt(num); } else { try { vrmAvatar.ApplyVisibilityFor(cam); } catch (Exception ex) { if (_applyCount++ < 3) { Plugin.Log("[mirror] apply failed: " + ex.Message); } } } } } } internal static class FreeMouse { private static float _nextTick; private static bool _wasActive; public static bool IsActive() { SkinPanel instance = SkinPanel.Instance; if ((Object)(object)instance != (Object)null && instance.Visible) { return true; } ModelEditor instance2 = ModelEditor.Instance; if ((Object)(object)instance2 != (Object)null) { return instance2.Visible; } return false; } internal static void Telemetry() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) bool flag = IsActive(); if (flag != _wasActive) { _wasActive = flag; Plugin.Log("[free] " + (flag ? "cursor freed" : "cursor restored") + " lock=" + ((object)Cursor.lockState/*cast due to .constrained prefix*/).ToString() + " visible=" + Cursor.visible); } if (flag && Time.unscaledTime > _nextTick) { _nextTick = Time.unscaledTime + 5f; Vector3 mousePosition = Input.mousePosition; Plugin.Log("[free] holding: lock=" + ((object)Cursor.lockState/*cast due to .constrained prefix*/).ToString() + " visible=" + Cursor.visible + " mouse=" + (int)mousePosition.x + "," + (int)mousePosition.y + " screen=" + Screen.width + "x" + Screen.height); } } } internal sealed class FreeMouseProbe : MonoBehaviour { private void Update() { FreeMouse.Telemetry(); } } [HarmonyPatch(typeof(CursorHandler), "Update")] internal static class PatchCursorHandlerUpdate { private static void Postfix() { if (FreeMouse.IsActive()) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } } } [HarmonyPatch(typeof(CharacterMovement), "CameraLook")] internal static class PatchCameraLook { private static bool Prefix() { return !FreeMouse.IsActive(); } } [HarmonyPatch(typeof(CharacterInput), "Sample")] internal static class PatchCharacterInputSample { private static void Postfix(CharacterInput __instance) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (FreeMouse.IsActive()) { __instance.lookInput = Vector2.zero; __instance.scrollInput = 0f; __instance.pauseWasPressed = false; __instance.jumpWasPressed = false; __instance.jumpIsPressed = false; __instance.interactWasPressed = false; __instance.interactWasReleased = false; __instance.dropWasPressed = false; __instance.dropIsPressed = false; __instance.dropWasReleased = false; __instance.usePrimaryWasPressed = false; __instance.usePrimaryIsPressed = false; __instance.usePrimaryWasReleased = false; __instance.useSecondaryWasPressed = false; __instance.useSecondaryIsPressed = false; __instance.useSecondaryWasReleased = false; __instance.pingWasPressed = false; __instance.selectBackpackWasPressed = false; __instance.unselectSlotWasPressed = false; __instance.selectSlotForwardWasPressed = false; __instance.selectSlotBackwardWasPressed = false; __instance.spectateLeftWasPressed = false; __instance.spectateRightWasPressed = false; } } } [HarmonyPatch(typeof(CharacterInput), "HotbarKeyWasPressed")] internal static class PatchHotbarKeyWasPressed { private static bool Prefix(ref bool __result) { if (!FreeMouse.IsActive()) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(CharacterInput), "HotbarKeyIsPressed")] internal static class PatchHotbarKeyIsPressed { private static bool Prefix(ref bool __result) { if (!FreeMouse.IsActive()) { return true; } __result = false; return false; } } internal sealed class GlbAccessor { public int BufferView = -1; public int ByteOffset; public int ComponentType; public int Count; public int NumComp; public int Stride; public bool Normalized; public string Type; } internal sealed class GlbView { public int ByteOffset; public int ByteLength; public int Stride; } internal sealed class Glb { public JNode Root; public byte[] Bin; public readonly List<GlbAccessor> Accessors = new List<GlbAccessor>(); public readonly List<GlbView> Views = new List<GlbView>(); public int BufferBase; public bool IsVrm1 { get { try { JNode jNode = Root["extensions"]; if (jNode.Has("VRMC_vrm") || jNode.Has("VRMCVrm")) { return true; } JNode jNode2 = Root["extensionsUsed"]; if (jNode2.IsArray) { for (int i = 0; i < jNode2.Count; i++) { string str = jNode2[i].Str; if (str != null && str.StartsWith("VRMC_vrm")) { return true; } } } } catch { } return false; } } public static Glb Load(byte[] bytes, Action<string> log) { if (bytes == null || bytes.Length < 20) { throw new Exception("glb too small: " + ((bytes != null) ? bytes.Length : 0)); } uint num = BitConverter.ToUInt32(bytes, 0); if (num != 1179937895) { throw new Exception("not a GLB: bad magic 0x" + num.ToString("x8")); } uint num2 = BitConverter.ToUInt32(bytes, 4); int num3 = 12; string text = null; byte[] array = null; while (num3 + 8 <= bytes.Length) { uint num4 = BitConverter.ToUInt32(bytes, num3); uint num5 = BitConverter.ToUInt32(bytes, num3 + 4); int num6 = num3 + 8; int num7 = bytes.Length - num6; int num8 = (int)Math.Min(num4, num7); if (num8 < 0) { num8 = 0; } switch (num5) { case 1313821514u: text = Encoding.UTF8.GetString(bytes, num6, num8); break; case 5130562u: array = new byte[num8]; Buffer.BlockCopy(bytes, num6, array, 0, num8); break; } num3 = num6 + num8; } if (text == null) { throw new Exception("glb: no JSON chunk (version " + num2 + ")"); } Glb glb = new Glb(); glb.Root = Json.Parse(text); glb.Bin = array ?? new byte[0]; JNode jNode = glb.Root["buffers"]; if (jNode.Count > 0) { glb.BufferBase = jNode[0].IntOr("byteOffset", 0); } JNode jNode2 = glb.Root["bufferViews"]; for (int i = 0; i < jNode2.Count; i++) { JNode jNode3 = jNode2[i]; glb.Views.Add(new GlbView { ByteOffset = jNode3.IntOr("byteOffset", 0), ByteLength = jNode3.IntOr("byteLength", 0), Stride = jNode3.IntOr("byteStride", 0) }); } JNode jNode4 = glb.Root["accessors"]; for (int j = 0; j < jNode4.Count; j++) { JNode jNode5 = jNode4[j]; GlbAccessor glbAccessor = new GlbAccessor { BufferView = jNode5.IntOr("bufferView", -1), ByteOffset = jNode5.IntOr("byteOffset", 0), ComponentType = jNode5.IntOr("componentType", 5126), Count = jNode5.IntOr("count", 0), Type = jNode5.StringOr("type", "SCALAR"), Normalized = jNode5.BoolOr("normalized", dflt: false) }; glbAccessor.NumComp = CompCount(glbAccessor.Type); if (glbAccessor.BufferView >= 0 && glbAccessor.BufferView < glb.Views.Count) { glbAccessor.Stride = glb.Views[glbAccessor.BufferView].Stride; } glb.Accessors.Add(glbAccessor); } return glb; } private static int CompCount(string type) { return type switch { "SCALAR" => 1, "VEC2" => 2, "VEC3" => 3, "VEC4" => 4, "MAT2" => 4, "MAT3" => 9, "MAT4" => 16, _ => 1, }; } private static int CompSize(int ct) { return ct switch { 5120 => 1, 5121 => 1, 5122 => 2, 5123 => 2, 5125 => 4, 5126 => 4, _ => 4, }; } private int OffsetOf(GlbAccessor a, int elem, int comp) { int num = CompSize(a.ComponentType); int num2 = num * a.NumComp; int num3 = ((a.Stride > 0) ? a.Stride : num2); GlbView glbView = Views[a.BufferView]; return BufferBase + glbView.ByteOffset + a.ByteOffset + elem * num3 + comp * num; } public int CompI(int acc, int elem, int comp) { GlbAccessor glbAccessor = Accessors[acc]; int num = OffsetOf(glbAccessor, elem, comp); return glbAccessor.ComponentType switch { 5120 => (sbyte)Bin[num], 5121 => Bin[num], 5122 => BitConverter.ToInt16(Bin, num), 5123 => BitConverter.ToUInt16(Bin, num), 5125 => (int)BitConverter.ToUInt32(Bin, num), 5126 => (int)BitConverter.ToSingle(Bin, num), _ => 0, }; } public float CompF(int acc, int elem, int comp) { GlbAccessor glbAccessor = Accessors[acc]; int num = OffsetOf(glbAccessor, elem, comp); switch (glbAccessor.ComponentType) { case 5120: { sbyte b2 = (sbyte)Bin[num]; if (!glbAccessor.Normalized) { return b2; } return Mathf.Max((float)b2 / 127f, -1f); } case 5121: { byte b = Bin[num]; if (!glbAccessor.Normalized) { return (int)b; } return (float)(int)b / 255f; } case 5122: { short num3 = BitConverter.ToInt16(Bin, num); if (!glbAccessor.Normalized) { return num3; } return Mathf.Max((float)num3 / 32767f, -1f); } case 5123: { ushort num2 = BitConverter.ToUInt16(Bin, num); if (!glbAccessor.Normalized) { return (int)num2; } return (float)(int)num2 / 65535f; } case 5125: return BitConverter.ToUInt32(Bin, num); case 5126: return BitConverter.ToSingle(Bin, num); default: return 0f; } } public int Count(int acc) { if (acc < 0 || acc >= Accessors.Count) { return 0; } return Accessors[acc].Count; } public int NumComp(int acc) { if (acc < 0 || acc >= Accessors.Count) { return 0; } return Accessors[acc].NumComp; } public static Vector3 ToUnityPos(float x, float y, float z) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) return new Vector3(x, y, 0f - z); } public static Vector3 ToUnityDir(float x, float y, float z) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) return new Vector3(x, y, 0f - z); } public static Quaternion ToUnityQuat(float x, float y, float z, float w) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return new Quaternion(0f - x, 0f - y, z, w); } public static Matrix4x4 FlipZ(Matrix4x4 m) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 4; i++) { ((Matrix4x4)(ref m))[2, i] = 0f - ((Matrix4x4)(ref m))[2, i]; } for (int j = 0; j < 4; j++) { ((Matrix4x4)(ref m))[j, 2] = 0f - ((Matrix4x4)(ref m))[j, 2]; } return m; } public Matrix4x4 ReadMatrix(int acc, int elem) { //IL_000f: 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_0044: Unknown result type (might be due to invalid IL or missing references) _ = Accessors[acc]; Matrix4x4 m = default(Matrix4x4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { ((Matrix4x4)(ref m))[j, i] = CompF(acc, elem, i * 4 + j); } } return FlipZ(m); } public Vector3 Vec3At(int acc, int elem) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) return ToUnityPos(CompF(acc, elem, 0), CompF(acc, elem, 1), CompF(acc, elem, 2)); } public static Quaternion ExtractRotation(Matrix4x4 m) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(m.m00, m.m10, m.m20); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(m.m01, m.m11, m.m21); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(m.m02, m.m12, m.m22); if (((Vector3)(ref val)).sqrMagnitude < 1E-12f) { return Quaternion.identity; } ((Vector3)(ref val)).Normalize(); val2 -= Vector3.Dot(val2, val) * val; if (((Vector3)(ref val2)).sqrMagnitude < 1E-10f) { Vector3 val4 = ((Mathf.Abs(val.y) < 0.9f) ? Vector3.up : Vector3.right); val2 = val4 - Vector3.Dot(val4, val) * val; } ((Vector3)(ref val2)).Normalize(); val3 = Vector3.Cross(val, val2); Vector3 val5 = default(Vector3); ((Vector3)(ref val5))..ctor(m.m02, m.m12, m.m22); if (Vector3.Dot(val3, val5) < 0f) { val3 = -val3; } Matrix4x4 identity = Matrix4x4.identity; ((Matrix4x4)(ref identity)).SetColumn(0, Vector4.op_Implicit(val)); ((Matrix4x4)(ref identity)).SetColumn(1, Vector4.op_Implicit(val2)); ((Matrix4x4)(ref identity)).SetColumn(2, Vector4.op_Implicit(val3)); return ((Matrix4x4)(ref identity)).rotation; } } internal enum JKind { Null, Bool, Number, String, Array, Object } internal sealed class JNode { public JKind Kind; public bool Bool; public double Num; public string Str; public List<JNode> Arr; public Dictionary<string, JNode> Obj; public static readonly JNode Nil = new JNode(); public bool IsNull => Kind == JKind.Null; public bool IsArray => Kind == JKind.Array; public bool IsObject => Kind == JKind.Object; public bool IsString => Kind == JKind.String; public int Count { get { if (Arr == null) { return 0; } return Arr.Count; } } public JNode this[string key] { get { if (Obj != null && key != null && Obj.TryGetValue(key, out var value) && value != null) { return value; } return Nil; } } public JNode this[int index] { get { if (Arr != null && index >= 0 && index < Arr.Count && Arr[index] != null) { return Arr[index]; } return Nil; } } public int I => (int)Num; public float F => (float)Num; public bool Has(string key) { if (Obj != null && key != null) { return Obj.ContainsKey(key); } return false; } public int IAt(int i) { return (int)this[i].Num; } public float FAt(int i) { return (float)this[i].Num; } public int IntOr(string key, int dflt) { JNode jNode = this[key]; if (!jNode.IsNull) { return (int)jNode.Num; } return dflt; } public float FloatOr(string key, float dflt) { JNode jNode = this[key]; if (!jNode.IsNull) { return (float)jNode.Num; } return dflt; } public bool BoolOr(string key, bool dflt) { JNode jNode = this[key]; if (!jNode.IsNull) { return jNode.Bool; } return dflt; } public string StringOr(string key, string dflt) { JNode jNode = this[key]; if (jNode.IsNull || jNode.Str == null) { return dflt; } return jNode.Str; } } internal static class Json { public static JNode Parse(string text) { int i = 0; return ParseValue(text, ref i) ?? JNode.Nil; } private static void SkipWs(string s, ref int i) { while (i < s.Length) { char c = s[i]; if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { i++; continue; } break; } } private static JNode ParseValue(string s, ref int i) { SkipWs(s, ref i); if (i >= s.Length) { return JNode.Nil; } switch (s[i]) { case '{': return ParseObject(s, ref i); case '[': return ParseArray(s, ref i); case '"': return new JNode { Kind = JKind.String, Str = ParseString(s, ref i) }; case 't': i += 4; return new JNode { Kind = JKind.Bool, Bool = true }; case 'f': i += 5; return new JNode { Kind = JKind.Bool, Bool = false }; case 'n': i += 4; return JNode.Nil; default: return ParseNumber(s, ref i); } } private static JNode ParseObject(string s, ref int i) { JNode jNode = new JNode { Kind = JKind.Object, Obj = new Dictionary<string, JNode>(32) }; i++; SkipWs(s, ref i); if (i < s.Length && s[i] == '}') { i++; return jNode; } while (i < s.Length) { SkipWs(s, ref i); if (i >= s.Length || s[i] != '"') { break; } string key = ParseString(s, ref i); SkipWs(s, ref i); if (i < s.Length && s[i] == ':') { i++; } jNode.Obj[key] = ParseValue(s, ref i); SkipWs(s, ref i); if (i < s.Length && s[i] == ',') { i++; continue; } if (i < s.Length && s[i] == '}') { i++; } break; } return jNode; } private static JNode ParseArray(string s, ref int i) { JNode jNode = new JNode { Kind = JKind.Array, Arr = new List<JNode>(16) }; i++; SkipWs(s, ref i); if (i < s.Length && s[i] == ']') { i++; return jNode; } while (i < s.Length) { jNode.Arr.Add(ParseValue(s, ref i)); SkipWs(s, ref i); if (i < s.Length && s[i] == ',') { i++; continue; } if (i < s.Length && s[i] == ']') { i++; } break; } return jNode; } private static string ParseString(string s, ref int i) { i++; StringBuilder stringBuilder = new StringBuilder(32); while (i < s.Length) { char c = s[i++]; switch (c) { default: stringBuilder.Append(c); continue; case '\\': { if (i >= s.Length) { break; } char c2 = s[i++]; switch (c2) { case '"': stringBuilder.Append('"'); break; case '\\': stringBuilder.Append('\\'); break; case '/': stringBuilder.Append('/'); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case 'u': if (i + 4 <= s.Length) { int num = 0; for (int j = 0; j < 4; j++) { num = num * 16 + HexVal(s[i + j]); } stringBuilder.Append((char)num); i += 4; } break; default: stringBuilder.Append(c2); break; } continue; } case '"': break; } break; } return stringBuilder.ToString(); } private static int HexVal(char c) { if (c >= '0' && c <= '9') { return c - 48; } if (c >= 'a' && c <= 'f') { return c - 97 + 10; } if (c >= 'A' && c <= 'F') { return c - 65 + 10; } return 0; } private static JNode ParseNumber(string s, ref int i) { int num = i; while (i < s.Length) { char c = s[i]; if ((c < '0' || c > '9') && c != '-' && c != '+' && c != '.' && c != 'e' && c != 'E') { break; } i++; } double result = 0.0; if (i > num) { double.TryParse(s.Substring(num, i - num), NumberStyles.Float, CultureInfo.InvariantCulture, out result); } return new JNode { Kind = JKind.Number, Num = result }; } } public static class ModConfig { public static bool Enabled = true; public static string VrmPath = ""; public static bool ReplaceOthers = false; public static bool SyncOwnModel = true; public static bool ShowOtherModels = true; public static bool PanelEnabled = true; public static bool Vanilla = false; public static bool AutoFit = true; public static float Scale = 1f; public static float ScaleWidth = 1f; public static float ScaleHeight = 1f; public static float RotX = 0f; public static float RotY = 0f; public static float RotZ = 0f; public static float YOffset = 0f; public static float YawOffset = 0f; public static bool AnchorToHip = true; public static float OffsetForward = 0f; public static float OffsetRight = 0f; public static bool GroundFeet = true; public static bool FlipV = true; public static string ShaderName = ""; public static bool DumpShaders = false; public static bool HideAllRenderers = false; public static bool HideWithGameBody = true; public static bool FirstPersonBody = true; public static float FirstPersonNearClip = 0.05f; private const string FpKeepDefault = "lower_arm,hand,thumb,wrist,finger,lower_leg,foot,toe,toes,ankle"; private const string FpKeepLegacy = "hand,thumb,foot,toe,ankle,wrist,finger"; public static string FirstPersonKeepBones = "lower_arm,hand,thumb,wrist,finger,lower_leg,foot,toe,toes,ankle"; public static float FirstPersonRadius = 0.18f; public static bool ArmsDown = true; public static string GameMeshRestEuler = "-90,0,0"; public static string Retarget = "world"; public static Quaternion GameMeshRest = Quaternion.Euler(-90f, 0f, 0f); private static ConfigFile _cfg; private static ConfigEntry<string> _vrmEntry; private static ConfigEntry<bool> _vanillaEntry; private static ConfigEntry<float> _scaleEntry; private static ConfigEntry<float> _scaleWidthEntry; private static ConfigEntry<float> _scaleHeightEntry; private static ConfigEntry<float> _rotXEntry; private static ConfigEntry<float> _rotYEntry; private static ConfigEntry<float> _rotZEntry; private static ConfigEntry<float> _yEntry; private static ConfigEntry<float> _fwdEntry; private static ConfigEntry<float> _rightEntry; public static void Bind(ConfigFile cfg) { //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_04e2: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_051b: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Expected O, but got Unknown //IL_0537: Unknown result type (might be due to invalid IL or missing references) //IL_0541: Expected O, but got Unknown _cfg = cfg; Enabled = cfg.Bind<bool>("1.General", "Enabled", true, "启用换模").Value; _vrmEntry = cfg.Bind<string>("1.General", "VrmPath", "", "当前模型文件路径;按 K 在面板里切换会自动写回这里"); VrmPath = _vrmEntry.Value; _vanillaEntry = cfg.Bind<bool>("1.General", "Vanilla", false, "穿 PEAK 原版装扮,不替换自己的模型。面板里点「原版 PEAK 装扮」也会改这里;点任意一个模型文件就自动关掉"); Vanilla = _vanillaEntry.Value; ReplaceOthers = cfg.Bind<bool>("1.General", "ReplaceOtherPlayers", false, "替换其他玩家:对方也装了 PeakSkin 且本地有同一份模型时,显示他自己选的模型;否则退回显示你当前这个模型。关掉就完全不碰别人").Value; SyncOwnModel = cfg.Bind<bool>("1.General", "SyncOwnModel", true, "联机时告诉同房间的 PeakSkin 用户你穿的哪个模型(只发一个文件指纹,不发模型文件本体)").Value; ShowOtherModels = cfg.Bind<bool>("1.General", "ShowOtherModels", true, "用对方自己选的模型显示别人。你本地没有那份模型时,对方的模型会保持原版(不会套错模型)").Value; PanelEnabled = cfg.Bind<bool>("1.General", "PanelKeyEnabled", true, "允许用 K 键打开换模面板").Value; AutoFit = cfg.Bind<bool>("2.Transform", "AutoFit", true, "按游戏角色身高自动缩放(推荐)").Value; _scaleEntry = cfg.Bind<float>("2.Transform", "Scale", 1f, "额外缩放倍率(AutoFit 生效时是相对值)"); Scale = _scaleEntry.Value; _scaleWidthEntry = cfg.Bind<float>("2.Transform", "ScaleWidth", 1f, "横向(X/Z)缩放倍率,和 Scale 一起决定宽高比。面板里的模型编辑器会实时改这里"); ScaleWidth = _scaleWidthEntry.Value; _scaleHeightEntry = cfg.Bind<float>("2.Transform", "ScaleHeight", 1f, "竖向(Y)缩放倍率,和 Scale 一起决定宽高比。面板里的模型编辑器会实时改这里"); ScaleHeight = _scaleHeightEntry.Value; _rotXEntry = cfg.Bind<float>("2.Transform", "RotX", 0f, "整体俯仰(度,正=前倾)。模型编辑器实时改"); RotX = _rotXEntry.Value; _rotYEntry = cfg.Bind<float>("2.Transform", "RotY", 0f, "整体朝向(度)。和 YawOffset 的区别:这个不用重进游戏,滑块即时生效"); RotY = _rotYEntry.Value; _rotZEntry = cfg.Bind<float>("2.Transform", "RotZ", 0f, "整体侧倾(度,正=向右倒)。模型编辑器实时改"); RotZ = _rotZEntry.Value; _yEntry = cfg.Bind<float>("2.Transform", "YOffset", 0f, "上下偏移(米)"); YOffset = _yEntry.Value; YawOffset = cfg.Bind<float>("2.Transform", "YawOffset", 0f, "朝向偏移(度,180=掉头)").Value; AnchorToHip = cfg.Bind<bool>("2.Transform", "AnchorToHip", true, "钉在角色髋骨上(默认开)。PEAK 的角色是物理布娃娃,Character.transform 根本不移动,只有髋骨跟着人跑;关掉会退回旧锚点,模型就会停在原地不跟随").Value; _fwdEntry = cfg.Bind<float>("2.Transform", "OffsetForward", 0f, "前后微调(米,相对模型自身朝向;模型比实际位置偏前/偏后时用它)"); OffsetForward = _fwdEntry.Value; _rightEntry = cfg.Bind<float>("2.Transform", "OffsetRight", 0f, "左右微调(米,相对模型自身朝向)"); OffsetRight = _rightEntry.Value; GroundFeet = cfg.Bind<bool>("2.Transform", "GroundFeet", true, "脚落地(默认开):髋部仍跟着游戏髋骨,但高度改成让模型自己的最低点(脚底)贴在游戏角色的最低点上。PEAK 的腿占身高 47%,这些模型只占 10-19%,只钉髋骨的话脚会悬空 0.3-0.9 米。第一人称不生效(那个视角的高度是另外框定的)。关掉=退回旧行为,模型会比地面高出一截").Value; FlipV = cfg.Bind<bool>("3.Render", "FlipV", true, "贴图 V 轴翻转(贴图上下颠倒时改这里)").Value; ShaderName = cfg.Bind<string>("3.Render", "Shader", "", "强制指定着色器名,例如 Universal Render Pipeline/Lit;留空自动挑").Value; DumpShaders = cfg.Bind<bool>("3.Render", "DumpShaderNames", false, "启动时把所有可用着色器名写进日志(排查用)").Value; HideAllRenderers = cfg.Bind<bool>("3.Render", "HideAllCharacterRenderers", false, "隐藏角色下所有渲染器(含手持物品,慎用)").Value; HideWithGameBody = cfg.Bind<bool>("3.Render", "HideWithGameBody", true, "第一人称相机进入模型内部时自动隐藏(关掉会看到模型内部,一般不要关)").Value; FirstPersonBody = cfg.Bind<bool>("3.Render", "FirstPersonBody", true, "第一人称保留身体:只裁掉头部,手/脚/躯干照常显示(关掉=旧行为,相机进入模型内部就整只隐藏)").Value; FirstPersonNearClip = cfg.Bind<float>("3.Render", "FirstPersonNearClip", 0.05f, "第一人称保留身体时的近裁剪距离(米)。相机钻进头部空腔后,比这个距离更近的东西会被裁掉").Value; ConfigEntry<string> val = cfg.Bind<string>("3.Render", "FirstPersonKeepBones", "lower_arm,hand,thumb,wrist,finger,lower_leg,foot,toe,toes,ankle", "第一人称保留哪些部位(逗号分隔,按骨骼名包含匹配)。默认留手腕以下加小腿,因为模型的掌心权重常落在 lower_arm、整条小腿(含脚)落在 lower_leg,只留 hand/foot 会缺一块"); if (string.Equals(val.Value.Trim(), "hand,thumb,foot,toe,ankle,wrist,finger", StringComparison.OrdinalIgnoreCase)) { val.Value = "lower_arm,hand,thumb,wrist,finger,lower_leg,foot,toe,toes,ankle"; try { cfg.Save(); } catch { } } FirstPersonKeepBones = val.Value; FirstPersonRadius = cfg.Bind<float>("3.Render", "FirstPersonRadius", 0.18f, "第一人称保留的顶点还必须离自己那根骨头这么近(米)。Tripo 系模型(蓝色小肥鱼)把身体/裙摆/鱼尾的一大块权重刷到了手脚骨上(权重>0.5、最远 0.8 米),只按骨骼名筛会把它们拖到眼前。0=不限距离").Value; ArmsDown = cfg.Bind<bool>("3.Render", "ArmsDown", true, "待机双手垂在身侧:游戏上臂朝上或水平时,把模型上臂改成朝下(游戏本来就在下垂时不干预)").Value; GameMeshRestEuler = cfg.Bind<string>("3.Render", "GameMeshRestEuler", "-90,0,0", "游戏网格节点 bind 时的世界欧拉角(PEAK 骨架是 Rx(-90),一般不用动)").Value; GameMeshRest = Quaternion.Euler(ParseEuler(GameMeshRestEuler, new Vector3(-90f, 0f, 0f))); Retarget = cfg.Bind<string>("3.Render", "Retarget", "aim", "绑骨方式:aim=让我们的骨头指向游戏同一节骨头的方向(推荐,不受模型 rest 姿势差异影响);world=世界旋转直抄(旧版;VRM1.0/Blender 导出的模型手臂会举起来);local=按关节角度差回放(对这些模型会变成手朝后);right/conj=两种备选对齐摆法").Value; try { cfg.Remove(new ConfigDefinition("4.Mouse", "FreeMouseKey")); } catch { } try { cfg.Remove(new ConfigDefinition("4.Mouse", "FreeMouseWithPanel")); } catch { } if (true) { try { cfg.Save(); } catch { } } } public static void SetVrmPath(string path) { VrmPath = path; if (_vrmEntry == null) { return; } try { _vrmEntry.Value = path; if (_cfg != null) { _cfg.Save(); } } catch { } } public static void SetVanilla(bool on) { Vanilla = on; if (_vanillaEntry == null) { return; } try { _vanillaEntry.Value = on; if (_cfg != null) { _cfg.Save(); } } catch { } } public static void SaveTransform() { try { if (_scaleEntry != null) { _scaleEntry.Value = Scale; } if (_scaleWidthEntry != null) { _scaleWidthEntry.Value = ScaleWidth; } if (_scaleHeightEntry != null) { _scaleHeightEntry.Value = ScaleHeight; } if (_rotXEntry != null) { _rotXEntry.Value = RotX; } if (_rotYEntry != null) { _rotYEntry.Value = RotY; } if (_rotZEntry != null) { _rotZEntry.Value = RotZ; } if (_yEntry != null) { _yEntry.Value = YOffset; } if (_fwdEntry != null) { _fwdEntry.Value = OffsetForward; } if (_rightEntry != null) { _rightEntry.Value = OffsetRight; } if (_cfg != null) { _cfg.Save(); } } catch { } } public static void Save() { try { if (_cfg != null) { _cfg.Save(); } } catch { } } public static Vector3 ParseEuler(string s, Vector3 fallback) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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) if (string.IsNullOrEmpty(s)) { return fallback; } string[] array = s.Split(','); if (array.Length != 3) { return fallback; } if (!float.TryParse(array[0].Trim(), out var result)) { return fallback; } if (!float.TryParse(array[1].Trim(), out var result2)) { return fallback; } if (!float.TryParse(array[2].Trim(), out var result3)) { return fallback; } return new Vector3(result, result2, result3); } } internal static class ModelCatalog { private const int Chunk = 65536; private const ulong FnvOffset = 14695981039346656037uL; private const ulong FnvPrime = 1099511628211uL; private static readonly Dictionary<string, string> Id2Path = new Dictionary<string, string>(8, StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, string> Path2Id = new Dictionary<string, string>(8, StringComparer.OrdinalIgnoreCase); public static int Count => Id2Path.Count; public static void Rebuild(List<string> files) { Id2Path.Clear(); Path2Id.Clear(); if (files == null) { return; } for (int i = 0; i < files.Count; i++) { string text = files[i]; if (!string.IsNullOrEmpty(text)) { string text2 = IdOf(text); if (text2 != null) { Id2Path[text2] = text; } } } Plugin.Log("[net] catalog indexed " + Id2Path.Count + " model(s)"); } public static string IdOf(string path) { if (string.IsNullOrEmpty(path)) { return null; } string text = Safe(path); if (Path2Id.TryGetValue(text, out var value)) { return value; } string text2 = null; try { if (File.Exists(text)) { text2 = Compute(text); } } catch (Exception ex) { Plugin.Log("[net] id failed for " + path + ": " + ex.Message); } if (text2 != null) { Path2Id[text] = text2; Id2Path[text2] = text; } return text2; } public static string PathOf(string id) { if (string.IsNullOrEmpty(id)) { return null; } if (!Id2Path.TryGetValue(id, out var value)) { return null; } return value; } public static bool Has(string id) { return PathOf(id) != null; } private static string Safe(string p) { try { return Path.GetFullPath(p); } catch { return p; } } private static string Compute(string path) { long length = new FileInfo(path).Length; ulong num = 14695981039346656037uL; byte[] array = new byte[65536]; using (FileStream fileStream = File.OpenRead(path)) { int num2 = fileStream.Read(array, 0, 65536); for (int i = 0; i < num2; i++) { num ^= array[i]; num *= 1099511628211L; } if (length > 131072) { fileStream.Seek(-65536L, SeekOrigin.End); num2 = fileStream.Read(array, 0, 65536); for (int j = 0; j < num2; j++) { num ^= array[j]; num *= 1099511628211L; } } } StringBuilder stringBuilder = new StringBuilder(24); stringBuilder.Append(length.ToString("x")); stringBuilder.Append('-').Append(num.ToString("x16")); return stringBuilder.ToString(); } } internal sealed class ModelEditor : MonoBehaviour { private sealed class Param { public string Name; public float Min; public float Max; public Func<float> Get; public Action<float> Set; public string Fmt; } public static ModelEditor Instance; public bool Visible; private const float BoxX = 458f; private const float PadX = 12f; private const float PadY = 10f; private const float BtnH = 30f; private const float SliderMinW = 170f; private GUIStyle _label; private GUIStyle _val; private GUIStyle _btn; private Param[] _params; private float _labelW; private float _valW; private float _rowStep; private float _boxW; private void Awake() { Instance = this; } public void Show() { Visible = true; Plugin.Log("[editor] open"); } public void Hide() { if (Visible) { ModConfig.SaveTransform(); Visible = false; Plugin.Log("[editor] closed"); } } private static Param Row(string name, float min, float max, Func<float> get, Action<float> set, string fmt) { return new Param { Name = name, Min = min, Max = max, Get = get, Set = set, Fmt = fmt }; } private void EnsureParams() { if (_params == null) { _params = new Param[9] { Row("大小", 0.1f, 2.5f, () => ModConfig.Scale, delegate(float v) { ModConfig.Scale = v; }, "F2"), Row("宽 XZ", 0.3f, 2f, () => ModConfig.ScaleWidth, delegate(float v) { ModConfig.ScaleWidth = v; }, "F2"), Row("高 Y", 0.3f, 2f, () => ModConfig.ScaleHeight, delegate(float v) { ModConfig.ScaleHeight = v; }, "F2"), Row("旋转X", -180f, 180f, () => ModConfig.RotX, delegate(float v) { ModConfig.RotX = v; }, "F0"), Row("旋转Y", -180f, 180f, () => ModConfig.RotY, delegate(float v) { ModConfig.RotY = v; }, "F0"), Row("旋转Z", -180f, 180f, () => ModConfig.RotZ, delegate(float v) { ModConfig.RotZ = v; }, "F0"), Row("上下", -0.8f, 0.8f, () => ModConfig.YOffset, delegate(float v) { ModConfig.YOffset = v; }, "F2"), Row("前后", -0.8f, 0.8f, () => ModConfig.OffsetForward, delegate(float v) { ModConfig.OffsetForward = v; }, "F2"), Row("左右", -0.8f, 0.8f, () => ModConfig.OffsetRight, delegate(float v) { ModConfig.OffsetRight = v; }, "F2") }; } } private void BuildStyles() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown if (_label == null) { Font val = null; try { val = Font.CreateDynamicFontFromOSFont(new string[4] { "Microsoft YaHei", "SimHei", "Arial Unicode MS", "Arial" }, 14); } catch { } _label = MakeStyle(GUI.skin.label, (TextAnchor)3); _val = MakeStyle(GUI.skin.label, (TextAnchor)5); _btn = MakeStyle(GUI.skin.button, (TextAnchor)4); _btn.padding = new RectOffset(4, 4, 4, 4); if ((Object)(object)val != (Object)null) { _label.font = val; _val.font = val; _btn.font = val; } } } private static GUIStyle MakeStyle(GUIStyle src, TextAnchor anchor) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0032: 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_0041: Expected O, but got Unknown //IL_0042: Expected O, but got Unknown return new GUIStyle(src) { fontSize = 14, alignment = anchor, wordWrap = false, clipping = (TextClipping)0, padding = new RectOffset(0, 0, 0, 0), margin = new RectOffset(0, 0, 0, 0) }; } private void Measure() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) if (!(_rowStep > 0f)) { float num = _label.CalcSize(new GUIContent("国")).y; if (num <= 0f) { num = 19f; } _rowStep = Mathf.Ceil(Mathf.Max(24f, num + 8f)); float num2 = 0f; for (int i = 0; i < _params.Length; i++) { num2 = Mathf.Max(num2, _label.CalcSize(new GUIContent(_params[i].Name)).x); } _labelW = Mathf.Ceil(Mathf.Max(num2, 40f)) + 4f; float num3 = Mathf.Max(_val.CalcSize(new GUIContent("-180")).x, _val.CalcSize(new GUIContent("0.00")).x); _valW = Mathf.Ceil(Mathf.Max(num3, 26f)) + 4f; _boxW = Mathf.Ceil(Mathf.Max(340f, 24f + _labelW + 8f + 170f + 8f + _valW)); } } private void ResetAll() { ModConfig.Scale = 1f; ModConfig.ScaleWidth = 1f; ModConfig.ScaleHeight = 1f; ModConfig.RotX = (ModConfig.RotY = (ModConfig.RotZ = 0f)); ModConfig.YOffset = (ModConfig.OffsetForward = (ModConfig.OffsetRight = 0f)); ModConfig.SaveTransform(); Plugin.Log("[editor] 已重置为默认"); } private void OnGUI() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) if (!Visible) { return; } BuildStyles(); EnsureParams(); Measure(); int num = _params.Length; float num2 = 20f + (float)num * _rowStep + 8f + 30f; float num3 = Mathf.Clamp(458f, 8f, Mathf.Max(8f, (float)Screen.width - _boxW - 8f)); Rect val = default(Rect); ((Rect)(ref val))..ctor(num3, 16f, _boxW, num2); GUI.color = new Color(0f, 0f, 0f, 0.86f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; GUI.Box(val, GUIContent.none); float num4 = ((Rect)(ref val)).x + 12f; float num5 = _boxW - 24f; float num6 = num4 + _labelW + 8f; float num7 = Mathf.Max(60f, num5 - _labelW - 8f - _valW - 8f); float num8 = num6 + num7 + 8f; float num9 = ((Rect)(ref val)).y + 10f; for (int i = 0; i < num; i++) { Param param = _params[i]; GUI.Label(new Rect(num4, num9, _labelW, _rowStep), param.Name, _label); float num10 = GUI.HorizontalSlider(new Rect(num6, num9, num7, _rowStep), param.Get(), param.Min, param.Max); num10 = Mathf.Round(num10 * 100f) / 100f; if (!Mathf.Approximately(num10, param.Get())) { param.Set(num10); } GUI.Label(new Rect(num8, num9, _valW, _rowStep), param.Get().ToString(param.Fmt), _val); num9 += _rowStep; } num9 += 8f; float num11 = (num5 - 12f) / 3f; if (GUI.Button(new Rect(num4, num9, num11, 30f), "重置", _btn)) { ResetAll(); } if (GUI.Button(new Rect(num4 + num11 + 6f, num9, num11, 30f), "保存", _btn)) { ModConfig.SaveTransform(); Plugin.Log($"[editor] 已保存 scale={ModConfig.Scale:F2} wxz={ModConfig.ScaleWidth:F2} hy={ModConfig.ScaleHeight:F2} rot=({ModConfig.RotX:F0},{ModConfig.RotY:F0},{ModConfig.RotZ:F0})"); } if (GUI.Button(new Rect(num4 + (num11 + 6f) * 2f, num9, num11, 30f), "关闭", _btn)) { Hide(); } } private void OnDisable() { Visible = false; } } internal static class BlendReader { private sealed class ObjInfo { public string Name = "object"; public int Type; public Block Block; public long BlockAddr; public int DataOff; public Block Data; public long ParentAddr; public Matrix4x4 LocalB = Ident(); public Matrix4x4 WorldB = Ident(); public Matrix4x4 WorldU = Ident(); public Matrix4x4 ParentInv = Ident(); public bool Resolved; public bool Resolving; } private sealed class BoneInfo { public string Name = "bone"; public long Addr; public long ParentAddr; public BoneInfo Parent; public Matrix4x4 WorldU = Ident(); } private sealed class Geo { public int VCount; public int PCount; public int LCount; public Vector3[] Pos; public int[] Corner; public int[] PolyStart; public int[] PolyMat; public Vector2[] Uv; public int[] DStart; public int[] DBone; public float[] DWeight; } private sealed class CDLayer { public int Type; public string Name = ""; public long Data; } private sealed class Attr { public string Name = ""; public int Type; public int Domain; public long Data; } private struct GroupStat { public float Weight; public Vector3 Sum; } private struct VKey : IEquatable<VKey> { public int Vert; public int Ux; public int Uy; public bool Equals(VKey o) { if (o.Vert == Vert && o.Ux == Ux) { return o.Uy == Uy; } return false; } public override bool Equals(object o) { if (o is VKey) { return Equals((VKey)o); } return false; } public override int GetHashCode() { return (Vert * 73856093) ^ (Ux * 19349663) ^ (Uy * 83492791); } } private sealed class Block { public string Code = "?"; public long Old; public int Data; public int Len; public int Nr; } private sealed class Field { public string Name = ""; public string Type = ""; public int Offset; public int Count = 1; public bool Ptr; } private sealed class FieldMap { public int Size; private readonly Dictionary<string, Field> byName = new Dictionary<string, Field>(); public Field Get(string n) { if (!byName.TryGetValue(n, out var value)) { return null; } return value; } public static FieldMap Of(Blend f, DnaStruct s) { if (s == null) { return null; } if (f.fieldCache.TryGetValue(s, out var value)) { return value; } value = new FieldMap(); value.Size = s.Size; for (int i = 0; i < s.Fields.Length; i++) { Field field = s.Fields[i]; if (!value.byName.ContainsKey(field.Name)) { value.byName[field.Name] = field; } } f.fieldCache[s] = value; return value; } } private sealed class DnaStruct { public string Name = ""; public int Size; public Field[] Fields = new Field[0]; } private sealed class Dna { public string[] Names = new string[0]; public string[] Types = new string[0]; public int[] Lens = new int[0]; public List<DnaStruct> Structs = new List<DnaStruct>(); public Dictionary<string, DnaStruct> Map = new Dictionary<string, DnaStruct>(); public string Layout = "?"; public DnaStruct Find(string name) { if (!Map.TryGetValue(name, out var value)) { return null; } return value; } public static Dna Parse(byte[] b, int start, int len, bool be, int ptr) { int end = start + len; int num = start; if (!Tag(b, num, "SDNA")) { throw new FormatException("no SDNA tag"); } num += 4; if (!Tag(b, num, "NAME")) { throw new FormatException("no NAME tag"); } num += 4; int num2 = I32(b, num, be); num += 4; if (num2 < 0 || num2 > 400000) { throw new FormatException("bad name count " + num2); } string[] array = new string[num2]; for (int i = 0; i < num2; i++) { int num3 = Nul(b, num, end); if (num3 < 0) { throw new FormatException("name table truncated"); } array[i] = Ascii(b, num, num3 - num); num = num3 + 1; } num = Align4(num, start); if (!Tag(b, num, "TYPE")) { throw new FormatException("no TYPE tag"); } num += 4; int num4 = I32(b, num, be); num += 4; if (num4 < 0 || num4 > 400000) { throw new FormatException("bad type count " + num4); } string[] array2 = new string[num4]; for (int j = 0; j < num4; j++) { int num5 = Nul(b, num, end); if (num5 < 0) { throw new FormatException("type table truncated"); } array2[j] = Ascii(b, num, num5 - num); num = num5 + 1; } num = Align4(num, start); if (!Tag(b, num, "TLEN")) { throw new FormatException("no TLEN tag"); } num += 4; int[] array3 = new int[num4]; for (int k = 0; k < num4; k++) { array3[k] = I16(b, num, be); num += 2; } num = Align4(num, start); if (!Tag(b, num, "STRC")) { throw new FormatException("no STRC tag"); } num += 4; Dna dna = new Dna(); dna.Names = array; dna.Types = array2; dna.Lens = array3; List<DnaStruct> list = TryModern(b, num, end, ptr, be, array2, array3, array); if (list != null) { dna.Layout = "modern"; dna.Structs = list; } else { dna.Layout = "classic"; dna.Structs = ParseClassic(b, num, end, ptr, be, array2, array3, array); } for (int l = 0; l < dna.Structs.Count; l++) { DnaStruct dnaStruct = dna.Structs[l]; if (!dna.Map.ContainsKey(dnaStruct.Name)) { dna.Map[dnaStruct.Name] = dnaStruct; } } return dna; } private static List<DnaStruct> TryModern(byte[] b, int p, int end, int ptr, bool be, string[] types, int[] lens, string[] names) { try { int num = p; int num2 = I32(b, num, be); num += 4; if (num2 <= 0 || num2 > 200000) { return null; } List<DnaStruct> list = new List<DnaStruct>(num2); for (int i = 0; i < num2; i++) { if (num + 4 > end) { return null; } int num3 = I16(b, num, be); int num4 = I16(b, num + 2, be); num += 4; if (num3 < 0 || num3 >= types.Length || num4 < 0 || num4 > 8192) { return null; } DnaStruct dnaStruct = new DnaStruct(); dnaStruct.Name = types[num3]; dnaStruct.Size = lens[num3]; dnaStruct.Fields = ReadFields(b, ref num, end, num4, ptr, be, types, lens, names); if (dnaStruct.Fields == null) { return null; } list.Add(dnaStruct); } return (num == end) ? list : null; } catch { return null; } } private static List<DnaStruct> ParseClassic(byte[] b, int p, int end, int ptr, bool be, string[] types, int[] lens, string[] names) { int num = p; if (num + 2 > end) { throw new FormatException("struct table truncated"); } int num2 = I16(b, num, be); num += 2; if (num2 <= 0 || num2 > 200000) { throw new FormatException("bad struct count " + num2); } if (num + num2 * 4 > end) { throw new FormatException("struct index table truncated"); } int[] array = new int[num2]; for (int i = 0; i < num2; i++) { array[i] = I16(b, num + i * 2, be); } num += num2 * 2; int[] array2 = new int[num2]; for (int j = 0; j < num2; j++) { array2[j] = I16(b, num + j * 2, be); } num += num2 * 2; List<DnaStruct> list = new List<DnaStruct>(num2); for (int k = 0; k < num2; k++) { if (num + 2 > end) { throw new FormatException("field table truncated"); } int nf = I16(b, num, be); num += 2; DnaStruct dnaStruct = new DnaStruct(); dnaStruct.Name = ((array2[k] >= 0 && array2[k] < types.Length) ? types[array2[k]] : "?"); dnaStruct.Size = array[k]; dnaStruct.Fields = ReadFields(b, ref num, end, nf, ptr, be, types, lens, names); if (dnaStruct.Fields == null) { throw new FormatException("field table truncated"); } list.Add(dnaStruct); } return list; } private static Field[] ReadFields(byte[] b, ref int q, int end, int nf, int ptr, bool be, string[] types, int[] lens, string[] names) { Field[] array = new Field[nf]; int num = 0; for (int i = 0; i < nf; i++) { if (q + 4 > end) { return null; } int num2 = I16(b, q, be); int num3 = I16(b, q + 2, be); q += 4; if (num2 < 0 || num2 >= types.Length |