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 SquadPlayermodels v0.2.0
plugins/SquadPlayermodels.dll
Decompiled 4 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using ModelReplacement; using ModelReplacement.AvatarBodyUpdater; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.SceneManagement; [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("SquadPlayermodels")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+82e8ffefbf7e7576f783034961019a242e6e6c5c")] [assembly: AssemblyProduct("SquadPlayermodels")] [assembly: AssemblyTitle("SquadPlayermodels")] [assembly: AssemblyVersion("0.2.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 SquadPlayermodels { internal sealed class AutoTest : MonoBehaviour { private string _outDir = ""; private bool _hosted; private bool _captured; private bool _choseLaunch; public static void StartIfRequested() { //IL_0035: 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: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (Environment.GetEnvironmentVariable("SQUADPM_AUTOTEST") == "1" || File.Exists(Path.Combine(Paths.ConfigPath, "SquadPlayermodels.autotest"))) { GameObject val = new GameObject("SquadPlayermodels.AutoTest"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<AutoTest>(); } } private void Awake() { _outDir = Path.Combine(Paths.BepInExRootPath, "SquadAutotest"); Directory.CreateDirectory(_outDir); Plugin.Log.LogWarning((object)("AUTOTEST enabled, writing to " + _outDir)); SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode _) { ((MonoBehaviour)this).StartCoroutine(OnScene(((Scene)(ref scene)).name)); }; ((MonoBehaviour)this).StartCoroutine(Timeout()); } private IEnumerator Timeout() { yield return (object)new WaitForSecondsRealtime(900f); Plugin.Log.LogError((object)"AUTOTEST timed out"); Application.Quit(); } private IEnumerator OnScene(string scene) { Plugin.Log.LogInfo((object)("AUTOTEST scene " + scene)); yield return (object)new WaitForSecondsRealtime(1.5f); if (!_choseLaunch) { PreInitSceneScript val = Object.FindObjectOfType<PreInitSceneScript>(); if (val != null) { _choseLaunch = true; val.ChooseLaunchOption(false); yield break; } } if (!_hosted) { MenuManager menu = Object.FindObjectOfType<MenuManager>(); if (menu != null && !menu.isInitScene) { _hosted = true; yield return (object)new WaitForSecondsRealtime(1.5f); menu.lobbyNameInputField.text = "squadpm-autotest"; menu.ConfirmHostButton(); yield break; } } if (!_captured && scene == "SampleSceneRelay") { _captured = true; yield return Capture(); } } private IEnumerator Capture() { PlayerControllerB player = null; while ((Object)(object)player == (Object)null || !player.isPlayerControlled) { player = StartOfRound.Instance?.localPlayerController; yield return (object)new WaitForSecondsRealtime(0.5f); } yield return (object)new WaitForSecondsRealtime(3f); SkinnedMeshRenderer thisPlayerModel = player.thisPlayerModel; Plugin.Log.LogInfo((object)("AUTOTEST player bones: " + string.Join(", ", thisPlayerModel.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "null" : ((Object)b).name)))); Plugin.Log.LogInfo((object)$"AUTOTEST player renderer scale {((Component)thisPlayerModel).transform.lossyScale}, material {((Object)((Renderer)thisPlayerModel).sharedMaterial.shader).name}"); ((Component)player).transform.Rotate(0f, 90f, 0f); yield return null; Shot(player, "vanilla_front", 0f, 0.55f); yield return null; List<UnlockableItem> suits = StartOfRound.Instance.unlockablesList.unlockables; string suitName = Plugin.Models[0].Suit; int num = suits.FindIndex((UnlockableItem u) => u.unlockableName == suitName); Plugin.Log.LogInfo((object)$"AUTOTEST suit '{suitName}' id {num}"); if (num < 0) { Plugin.Log.LogError((object)("AUTOTEST suit not found. Suits: " + string.Join(", ", suits.Select((UnlockableItem u) => u.unlockableName)))); Application.Quit(); yield break; } UnlockableSuit.SwitchSuitForPlayer(player, num, false); yield return (object)new WaitForSecondsRealtime(4f); (string, float, float)[] array = new(string, float, float)[5] { ("front", 0f, 0.55f), ("side", 90f, 0.55f), ("back", 180f, 0.55f), ("threequarter", 35f, 0.55f), ("face", 15f, 1f) }; for (int num2 = 0; num2 < array.Length; num2++) { var (text, angle, height) = array[num2]; Shot(player, text, angle, height, (text == "face") ? 0.45f : 1.9f); yield return null; } player.Crouch(true); yield return (object)new WaitForSecondsRealtime(1.5f); Shot(player, "crouch_side", 70f, 0.4f); player.Crouch(false); yield return (object)new WaitForSecondsRealtime(1f); player.performingEmote = true; player.playerBodyAnimator.SetInteger("emoteNumber", 1); player.StartPerformingEmoteServerRpc(); yield return (object)new WaitForSecondsRealtime(1.2f); Shot(player, "emote_front", 20f, 0.55f); player.performingEmote = false; player.playerBodyAnimator.SetInteger("emoteNumber", 0); yield return (object)new WaitForSecondsRealtime(1f); foreach (ModelDefinition def in Plugin.Models) { int num3 = suits.FindIndex((UnlockableItem u) => u.unlockableName == def.Suit); if (num3 < 0) { Plugin.Log.LogError((object)("AUTOTEST suit '" + def.Suit + "' not found")); continue; } UnlockableSuit.SwitchSuitForPlayer(player, num3, false); yield return (object)new WaitForSecondsRealtime(1.5f); Shot(player, "model_" + def.Id, 20f, 0.55f); } File.WriteAllText(Path.Combine(_outDir, "done.txt"), DateTime.Now.ToString("O")); Plugin.Log.LogWarning((object)"AUTOTEST finished"); yield return (object)new WaitForSecondsRealtime(1f); Application.Quit(); } private void Shot(PlayerControllerB player, string name, float angle, float height, float distance = 1.9f) { //IL_004d: 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_006a: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Expected O, but got Unknown //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Expected O, but got Unknown //IL_02b6: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)player).transform; Transform val = ((IEnumerable<Transform>)player.thisPlayerModel.bones).FirstOrDefault((Func<Transform, bool>)((Transform b) => (Object)(object)b != (Object)null && ((Object)b).name == "spine.004")); float num = (((Object)(object)val != (Object)null) ? Mathf.Max(0.5f, val.position.y - transform.position.y) : 2f); Vector3 val2 = transform.position + Vector3.up * (height * num); distance *= num; Vector3 val3 = Quaternion.AngleAxis(angle, Vector3.up) * transform.forward; List<Renderer> list = new List<Renderer>(); GameObject val4 = GameObject.Find("Systems/Rendering/PlayerHUDHelmetModel"); if ((Object)(object)val4 != (Object)null) { list.AddRange(val4.GetComponentsInChildren<Renderer>()); } if ((Object)(object)player.thisPlayerModelArms != (Object)null) { list.Add((Renderer)(object)player.thisPlayerModelArms); } BodyReplacementBase component = ((Component)player).GetComponent<BodyReplacementBase>(); if (component != null) { GameObject replacementViewModel = component.replacementViewModel; if (replacementViewModel != null) { list.AddRange(replacementViewModel.GetComponentsInChildren<Renderer>()); } } list = list.Where((Renderer x) => x.enabled).ToList(); foreach (Renderer item in list) { item.enabled = false; } GameObject val5 = new GameObject("AutoTestCamera"); try { val5.transform.position = val2 + val3 * distance + Vector3.up * (0.08f * num); val5.transform.LookAt(val2); Camera val6 = val5.AddComponent<Camera>(); val5.AddComponent<HDAdditionalCameraData>(); val6.fieldOfView = 45f; val6.nearClipPlane = 0.05f; int num2 = player.gameplayCamera.cullingMask | (1 << ((Component)player.thisPlayerModel).gameObject.layer); component = ((Component)player).GetComponent<BodyReplacementBase>(); if (component != null) { GameObject replacementModel = component.replacementModel; if (replacementModel != null) { Renderer[] componentsInChildren = replacementModel.GetComponentsInChildren<Renderer>(); foreach (Renderer val7 in componentsInChildren) { num2 |= 1 << ((Component)val7).gameObject.layer; } } } val6.cullingMask = num2; RenderTexture val8 = (val6.targetTexture = new RenderTexture(960, 1080, 24, (RenderTextureFormat)0)); val6.Render(); RenderTexture active = RenderTexture.active; RenderTexture.active = val8; Texture2D val10 = new Texture2D(960, 1080, (TextureFormat)3, false); val10.ReadPixels(new Rect(0f, 0f, 960f, 1080f), 0, 0); val10.Apply(); RenderTexture.active = active; File.WriteAllBytes(Path.Combine(_outDir, name + ".png"), ImageConversion.EncodeToPNG(val10)); val6.targetTexture = null; Object.Destroy((Object)(object)val10); val8.Release(); } catch (Exception arg) { Plugin.Log.LogError((object)$"AUTOTEST shot {name} failed: {arg}"); } finally { Object.Destroy((Object)(object)val5); foreach (Renderer item2 in list) { item2.enabled = true; } } } } internal static class ModelBuilder { private static readonly Dictionary<HumanBodyBones, string> SquadHumanoid = BuildSquadHumanoidMap(); private static readonly Dictionary<string, HumanBodyBones> LcHumanoid = new Dictionary<string, HumanBodyBones> { ["spine"] = (HumanBodyBones)0, ["spine.001"] = (HumanBodyBones)7, ["spine.002"] = (HumanBodyBones)8, ["spine.003"] = (HumanBodyBones)54, ["spine.004"] = (HumanBodyBones)10, ["shoulder.L"] = (HumanBodyBones)11, ["arm.L_upper"] = (HumanBodyBones)13, ["arm.L_lower"] = (HumanBodyBones)15, ["hand.L"] = (HumanBodyBones)17, ["shoulder.R"] = (HumanBodyBones)12, ["arm.R_upper"] = (HumanBodyBones)14, ["arm.R_lower"] = (HumanBodyBones)16, ["hand.R"] = (HumanBodyBones)18, ["thigh.L"] = (HumanBodyBones)1, ["shin.L"] = (HumanBodyBones)3, ["foot.L"] = (HumanBodyBones)5, ["toe.L"] = (HumanBodyBones)19, ["thigh.R"] = (HumanBodyBones)2, ["shin.R"] = (HumanBodyBones)4, ["foot.R"] = (HumanBodyBones)6, ["toe.R"] = (HumanBodyBones)20, ["finger1.L"] = (HumanBodyBones)24, ["finger1.L.001"] = (HumanBodyBones)26, ["finger2.L"] = (HumanBodyBones)27, ["finger2.L.001"] = (HumanBodyBones)28, ["finger3.L"] = (HumanBodyBones)30, ["finger3.L.001"] = (HumanBodyBones)31, ["finger4.L"] = (HumanBodyBones)33, ["finger4.L.001"] = (HumanBodyBones)34, ["finger5.L"] = (HumanBodyBones)36, ["finger5.L.001"] = (HumanBodyBones)37, ["finger1.R"] = (HumanBodyBones)39, ["finger1.R.001"] = (HumanBodyBones)41, ["finger2.R"] = (HumanBodyBones)42, ["finger2.R.001"] = (HumanBodyBones)43, ["finger3.R"] = (HumanBodyBones)45, ["finger3.R.001"] = (HumanBodyBones)46, ["finger4.R"] = (HumanBodyBones)48, ["finger4.R.001"] = (HumanBodyBones)49, ["finger5.R"] = (HumanBodyBones)51, ["finger5.R.001"] = (HumanBodyBones)52 }; private static readonly (HumanBodyBones bone, HumanBodyBones target, string lcBone, string lcTarget)[] PoseChain = new(HumanBodyBones, HumanBodyBones, string, string)[27] { ((HumanBodyBones)7, (HumanBodyBones)8, "spine.001", "spine.002"), ((HumanBodyBones)8, (HumanBodyBones)54, "spine.002", "spine.003"), ((HumanBodyBones)54, (HumanBodyBones)9, "spine.003", "spine.004"), ((HumanBodyBones)1, (HumanBodyBones)3, "thigh.L", "shin.L"), ((HumanBodyBones)3, (HumanBodyBones)5, "shin.L", "foot.L"), ((HumanBodyBones)5, (HumanBodyBones)19, "foot.L", "toe.L"), ((HumanBodyBones)2, (HumanBodyBones)4, "thigh.R", "shin.R"), ((HumanBodyBones)4, (HumanBodyBones)6, "shin.R", "foot.R"), ((HumanBodyBones)6, (HumanBodyBones)20, "foot.R", "toe.R"), ((HumanBodyBones)11, (HumanBodyBones)13, "shoulder.L", "arm.L_upper"), ((HumanBodyBones)13, (HumanBodyBones)15, "arm.L_upper", "arm.L_lower"), ((HumanBodyBones)15, (HumanBodyBones)17, "arm.L_lower", "hand.L"), ((HumanBodyBones)17, (HumanBodyBones)30, "hand.L", "finger3.L"), ((HumanBodyBones)24, (HumanBodyBones)25, "finger1.L", "finger1.L.001"), ((HumanBodyBones)27, (HumanBodyBones)28, "finger2.L", "finger2.L.001"), ((HumanBodyBones)30, (HumanBodyBones)31, "finger3.L", "finger3.L.001"), ((HumanBodyBones)33, (HumanBodyBones)34, "finger4.L", "finger4.L.001"), ((HumanBodyBones)36, (HumanBodyBones)37, "finger5.L", "finger5.L.001"), ((HumanBodyBones)12, (HumanBodyBones)14, "shoulder.R", "arm.R_upper"), ((HumanBodyBones)14, (HumanBodyBones)16, "arm.R_upper", "arm.R_lower"), ((HumanBodyBones)16, (HumanBodyBones)18, "arm.R_lower", "hand.R"), ((HumanBodyBones)18, (HumanBodyBones)45, "hand.R", "finger3.R"), ((HumanBodyBones)39, (HumanBodyBones)40, "finger1.R", "finger1.R.001"), ((HumanBodyBones)42, (HumanBodyBones)43, "finger2.R", "finger2.R.001"), ((HumanBodyBones)45, (HumanBodyBones)46, "finger3.R", "finger3.R.001"), ((HumanBodyBones)48, (HumanBodyBones)49, "finger4.R", "finger4.R.001"), ((HumanBodyBones)51, (HumanBodyBones)52, "finger5.R", "finger5.R.001") }; private static readonly Dictionary<string, Texture2D> TextureCache = new Dictionary<string, Texture2D>(); public static GameObject Build(ModelDefinition def, SkinnedMeshRenderer playerRenderer) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Expected O, but got Unknown //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: 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_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_0597: Unknown result type (might be due to invalid IL or missing references) //IL_05a4: Unknown result type (might be due to invalid IL or missing references) //IL_05a9: Unknown result type (might be due to invalid IL or missing references) //IL_05b3: Unknown result type (might be due to invalid IL or missing references) //IL_05b8: Unknown result type (might be due to invalid IL or missing references) //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Unknown result type (might be due to invalid IL or missing references) //IL_05cb: Unknown result type (might be due to invalid IL or missing references) //IL_05d1: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_05f0: Unknown result type (might be due to invalid IL or missing references) //IL_05f6: Unknown result type (might be due to invalid IL or missing references) //IL_063f: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0568: Unknown result type (might be due to invalid IL or missing references) LcRestPose lcRestPose = LcRestPose.FromRenderer(playerRenderer); SqpmFile file = SqpmFile.Load(Path.Combine(def.Folder, def.Mesh)); GameObject val = new GameObject("SquadModel_" + def.Id); val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); Transform transform = new GameObject("Armature").transform; transform.SetParent(val.transform, false); Transform[] array = (Transform[])(object)new Transform[file.BoneNames.Length]; for (int i = 0; i < array.Length; i++) { array[i] = new GameObject(file.BoneNames[i]).transform; } for (int j = 0; j < array.Length; j++) { int num = file.BoneParents[j]; array[j].SetParent((num >= 0) ? array[num] : transform, false); array[j].localPosition = file.BonePositions[j]; array[j].localRotation = file.BoneRotations[j]; array[j].localScale = file.BoneScales[j]; } Dictionary<string, Transform> byName = array.ToDictionary((Transform b) => ((Object)b).name, (Transform b) => b); Dictionary<string, MaterialDefinition> mats = (from m in def.Materials group m by m.Name).ToDictionary((IGrouping<string, MaterialDefinition> g) => g.Key, (IGrouping<string, MaterialDefinition> g) => g.First()); MaterialDefinition value2; List<int> list = (from s in Enumerable.Range(0, file.SubmeshMaterials.Length) where !mats.TryGetValue(file.SubmeshMaterials[s], out value2) || !value2.Hidden select s).ToList(); Mesh val2 = new Mesh { name = def.Id, indexFormat = (IndexFormat)1 }; val2.vertices = file.Positions; val2.normals = file.Normals; val2.uv = file.UVs; val2.boneWeights = file.Weights; val2.bindposes = file.BindPoses; val2.subMeshCount = list.Count; for (int num2 = 0; num2 < list.Count; num2++) { val2.SetTriangles(file.SubmeshIndices[list[num2]], num2, false); } val2.RecalculateTangents(); val2.RecalculateBounds(); val2.UploadMeshData(true); GameObject val3 = new GameObject("Body"); val3.transform.SetParent(transform, false); SkinnedMeshRenderer obj = val3.AddComponent<SkinnedMeshRenderer>(); obj.sharedMesh = val2; obj.bones = array; obj.rootBone = H((HumanBodyBones)0); ((Renderer)obj).sharedMaterials = list.Select((int s) => CreateMaterial(def, mats.TryGetValue(file.SubmeshMaterials[s], out value2) ? value2 : null, ((Renderer)playerRenderer).sharedMaterial)).ToArray(); obj.updateWhenOffscreen = true; ((Renderer)obj).forceRenderingOff = true; Vector3 up = Local(val, H((HumanBodyBones)10)) - Local(val, H((HumanBodyBones)0)); Vector3 right = Local(val, H((HumanBodyBones)14)) - Local(val, H((HumanBodyBones)13)); transform.localRotation = Basis(lcRestPose.Right, lcRestPose.Up) * Quaternion.Inverse(Basis(right, up)); (HumanBodyBones, HumanBodyBones, string, string)[] poseChain = PoseChain; for (int num3 = 0; num3 < poseChain.Length; num3++) { var (hb, hb2, bone, bone2) = poseChain[num3]; if (lcRestPose.Has(bone) && lcRestPose.Has(bone2)) { Transform val4 = H(hb); Vector3 val5 = Local(val, H(hb2)) - Local(val, val4); Vector3 val6 = lcRestPose.Position(bone2) - lcRestPose.Position(bone); if (!(((Vector3)(ref val5)).sqrMagnitude < 1E-10f) && !(((Vector3)(ref val6)).sqrMagnitude < 1E-10f)) { val4.rotation = Quaternion.FromToRotation(val5, val6) * val4.rotation; } } } Animator obj2 = val.AddComponent<Animator>(); obj2.avatar = BuildAvatar(val); obj2.cullingMode = (AnimatorCullingMode)0; foreach (KeyValuePair<string, HumanBodyBones> item in LcHumanoid) { if (lcRestPose.Has(item.Key) && SquadHumanoid.TryGetValue(item.Value, out string value)) { Transform val7 = byName[value]; (((Component)val7).gameObject.GetComponent<RotationOffset>() ?? ((Component)val7).gameObject.AddComponent<RotationOffset>()).offset = Quaternion.Inverse(lcRestPose.Rotation(item.Key)) * val7.rotation; } } SquadModelInfo squadModelInfo = val.AddComponent<SquadModelInfo>(); Vector3 val8 = (Local(val, H((HumanBodyBones)5)) + Local(val, H((HumanBodyBones)6))) * 0.5f; squadModelInfo.HeadHeight = Vector3.Dot(Local(val, H((HumanBodyBones)10)) - val8, lcRestPose.Up); squadModelInfo.HipsHeight = Vector3.Dot(Local(val, H((HumanBodyBones)0)) - val8, lcRestPose.Up); squadModelInfo.ModelId = def.Id; val.AddComponent<OffsetBuilder>().GenerateViewModel = Plugin.FirstPersonArms.Value; val.transform.position = new Vector3(0f, -2000f, 0f); val.SetActive(true); return val; Transform H(HumanBodyBones key) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return byName[SquadHumanoid[key]]; } } private static Vector3 Local(GameObject root, Transform t) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return root.transform.InverseTransformPoint(t.position); } private static Quaternion Basis(Vector3 right, Vector3 up) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) return Quaternion.LookRotation(Vector3.Cross(right, up), up); } private static Avatar BuildAvatar(GameObject root) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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) SkeletonBone[] skeleton = ((IEnumerable<Transform>)root.GetComponentsInChildren<Transform>(true)).Select((Func<Transform, SkeletonBone>)((Transform t) => new SkeletonBone { name = ((Object)t).name, position = t.localPosition, rotation = t.localRotation, scale = t.localScale })).ToArray(); string[] humanNames = HumanTrait.BoneName; HumanBone[] human = SquadHumanoid.Select<KeyValuePair<HumanBodyBones, string>, HumanBone>(delegate(KeyValuePair<HumanBodyBones, string> kv) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) //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) HumanBone result = default(HumanBone); ((HumanBone)(ref result)).humanName = humanNames[kv.Key]; ((HumanBone)(ref result)).boneName = kv.Value; HumanLimit limit = default(HumanLimit); ((HumanLimit)(ref limit)).useDefaultValues = true; result.limit = limit; return result; }).ToArray(); HumanDescription val = new HumanDescription { skeleton = skeleton, human = human }; ((HumanDescription)(ref val)).upperArmTwist = 0.5f; ((HumanDescription)(ref val)).lowerArmTwist = 0.5f; ((HumanDescription)(ref val)).upperLegTwist = 0.5f; ((HumanDescription)(ref val)).lowerLegTwist = 0.5f; ((HumanDescription)(ref val)).armStretch = 0.05f; ((HumanDescription)(ref val)).legStretch = 0.05f; ((HumanDescription)(ref val)).feetSpacing = 0f; ((HumanDescription)(ref val)).hasTranslationDoF = false; HumanDescription val2 = val; Avatar val3 = AvatarBuilder.BuildHumanAvatar(root, val2); ((Object)val3).name = ((Object)root).name + "Avatar"; if (!val3.isValid || !val3.isHuman) { Plugin.Log.LogError((object)$"Humanoid avatar for {((Object)root).name} is invalid (valid={val3.isValid}, human={val3.isHuman})"); } return val3; } private static Material CreateMaterial(ModelDefinition def, MaterialDefinition? md, Material playerMaterial) { //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_0022: Expected O, but got Unknown //IL_0097: 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_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) Material val = new Material(playerMaterial) { name = (md?.Name ?? "SquadDefault") }; string[] array = new string[6] { "_DetailMap", "_EmissiveColorMap", "_BentNormalMap", "_SpecularColorMap", "_ThicknessMap", "_CoatMaskMap" }; foreach (string text in array) { if (val.HasProperty(text)) { val.SetTexture(text, (Texture)null); } } if (val.HasProperty("_EmissiveColor")) { val.SetColor("_EmissiveColor", Color.black); } val.DisableKeyword("_DETAIL_MAP"); val.DisableKeyword("_EMISSIVE_COLOR_MAP"); if (md == null) { md = new MaterialDefinition(); } Color val2 = default(Color); ((Color)(ref val2))..ctor(md.Color[0], md.Color[1], md.Color[2], (md.Color.Length > 3) ? md.Color[3] : 1f); val.SetColor("_BaseColor", val2); val.color = val2; Texture2D val3 = (Texture2D)((md.Albedo != null) ? ((object)LoadTexture(def, md.Albedo, linear: false)) : ((object)Texture2D.whiteTexture)); val.SetTexture("_BaseColorMap", (Texture)(object)val3); val.mainTexture = (Texture)(object)val3; val.SetTextureScale("_BaseColorMap", Vector2.one); val.SetTextureOffset("_BaseColorMap", Vector2.zero); if (md.Normal != null) { val.SetTexture("_NormalMap", (Texture)(object)LoadTexture(def, md.Normal, linear: true)); val.SetFloat("_NormalScale", 1f); val.EnableKeyword("_NORMALMAP"); val.EnableKeyword("_NORMALMAP_TANGENT_SPACE"); } else { val.SetTexture("_NormalMap", (Texture)null); val.DisableKeyword("_NORMALMAP"); } if (md.Mask != null) { val.SetTexture("_MaskMap", (Texture)(object)LoadTexture(def, md.Mask, linear: true)); val.EnableKeyword("_MASKMAP"); val.SetFloat("_MetallicRemapMin", 0f); val.SetFloat("_MetallicRemapMax", md.Metallic); val.SetFloat("_SmoothnessRemapMin", 0f); val.SetFloat("_SmoothnessRemapMax", md.Smoothness); val.SetFloat("_AORemapMin", 0f); val.SetFloat("_AORemapMax", 1f); } else { val.SetTexture("_MaskMap", (Texture)null); val.DisableKeyword("_MASKMAP"); val.SetFloat("_Metallic", md.Metallic); val.SetFloat("_Smoothness", md.Smoothness); } val.SetFloat("_AlphaCutoffEnable", md.Cutout ? 1f : 0f); val.SetFloat("_AlphaCutoff", 0.5f); if (md.Cutout) { val.EnableKeyword("_ALPHATEST_ON"); } else { val.DisableKeyword("_ALPHATEST_ON"); } val.SetFloat("_DoubleSidedEnable", md.DoubleSided ? 1f : 0f); val.SetFloat("_CullMode", md.DoubleSided ? 0f : 2f); val.SetFloat("_CullModeForward", md.DoubleSided ? 0f : 2f); val.doubleSidedGI = md.DoubleSided; HDMaterial.ValidateMaterial(val); return val; } private static Texture2D LoadTexture(ModelDefinition def, string file, bool linear) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown string fullPath = Path.GetFullPath(Path.Combine(def.Folder, file)); string key = fullPath + (linear ? "|lin" : "|srgb"); if (TextureCache.TryGetValue(key, out Texture2D value) && (Object)(object)value != (Object)null) { return value; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear) { name = Path.GetFileNameWithoutExtension(file) }; if (!ImageConversion.LoadImage(val, File.ReadAllBytes(fullPath), false)) { Plugin.Log.LogError((object)("Could not load texture " + fullPath)); return Texture2D.whiteTexture; } ((Texture)val).wrapMode = (TextureWrapMode)0; ((Texture)val).filterMode = (FilterMode)2; ((Texture)val).anisoLevel = 4; val.Compress(true); val.Apply(true, true); Object.DontDestroyOnLoad((Object)(object)val); TextureCache[key] = val; return val; } private static Dictionary<HumanBodyBones, string> BuildSquadHumanoidMap() { Dictionary<HumanBodyBones, string> map = new Dictionary<HumanBodyBones, string> { [(HumanBodyBones)0] = "Bip01_Pelvis", [(HumanBodyBones)7] = "Bip01_Spine", [(HumanBodyBones)8] = "Bip01_Spine1", [(HumanBodyBones)54] = "Bip01_Spine2", [(HumanBodyBones)9] = "Bip01_Neck", [(HumanBodyBones)10] = "Bip01_Head" }; (string, string)[] array = new(string, string)[2] { ("Left", "L"), ("Right", "R") }; for (int i = 0; i < array.Length; i++) { var (side, s) = array[i]; Add("UpperLeg", "Thigh"); Add("LowerLeg", "Calf"); Add("Foot", "Foot"); Add("Toes", "Toe0"); Add("Shoulder", "Clavicle"); Add("UpperArm", "UpperArm"); Add("LowerArm", "Forearm"); Add("Hand", "Hand"); string[] array2 = new string[5] { "Thumb", "Index", "Middle", "Ring", "Little" }; string[] array3 = new string[3] { "Proximal", "Intermediate", "Distal" }; for (int j = 0; j < 5; j++) { for (int k = 0; k < 3; k++) { Add(array2[j] + array3[k], (k == 0) ? $"Finger{j}" : $"Finger{j}{k}"); } } void Add(string human, string bone) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) map[(HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), side + human)] = "Bip01_" + s + "_" + bone; } } return map; } } internal sealed class LcRestPose { private readonly Dictionary<string, Matrix4x4> _rest = new Dictionary<string, Matrix4x4>(); private readonly Dictionary<string, Matrix4x4> _bind = new Dictionary<string, Matrix4x4>(); public Vector3 Up { get; private set; } public Vector3 Right { get; private set; } public static LcRestPose FromRenderer(SkinnedMeshRenderer r) { //IL_00a9: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) LcRestPose lcRestPose = new LcRestPose(); Matrix4x4[] bindposes = r.sharedMesh.bindposes; Transform[] bones = r.bones; for (int i = 0; i < bones.Length && i < bindposes.Length; i++) { if (!((Object)(object)bones[i] == (Object)null)) { string text = ((Object)bones[i]).name; if (text.Contains("PlayerRagdoll") && !lcRestPose._rest.ContainsKey("spine")) { text = "spine"; } lcRestPose._rest[text] = ((Matrix4x4)(ref bindposes[i])).inverse; lcRestPose._bind[text] = bindposes[i]; } } Vector3 val = lcRestPose.Position("spine.004") - lcRestPose.Position("spine"); lcRestPose.Up = ((Vector3)(ref val)).normalized; Vector3 val2 = lcRestPose.Position("arm.R_upper") - lcRestPose.Position("arm.L_upper"); val = Vector3.ProjectOnPlane(val2, lcRestPose.Up); lcRestPose.Right = ((Vector3)(ref val)).normalized; return lcRestPose; } public bool Has(string bone) { return _rest.ContainsKey(bone); } public Vector3 Position(string bone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0015: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 val = _rest[bone]; return Vector4.op_Implicit(((Matrix4x4)(ref val)).GetColumn(3)); } public Quaternion Rotation(string bone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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) Matrix4x4 val = _rest[bone]; return ((Matrix4x4)(ref val)).rotation; } public Matrix4x4 BindPose(string bone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return _bind[bone]; } } internal sealed class ModelDefinition { [JsonProperty("id")] public string Id = ""; [JsonProperty("suit")] public string Suit = ""; [JsonProperty("source")] public string Source = ""; [JsonProperty("mesh")] public string Mesh = "model.sqpm"; [JsonProperty("materials")] public List<MaterialDefinition> Materials = new List<MaterialDefinition>(); [JsonIgnore] public string Folder = ""; public static ModelDefinition Load(string folder) { ModelDefinition obj = JsonConvert.DeserializeObject<ModelDefinition>(File.ReadAllText(Path.Combine(folder, "model.json"))) ?? throw new InvalidDataException("Empty model.json in " + folder); obj.Folder = folder; return obj; } } internal sealed class MaterialDefinition { [JsonProperty("name")] public string Name = ""; [JsonProperty("albedo")] public string? Albedo; [JsonProperty("normal")] public string? Normal; [JsonProperty("mask")] public string? Mask; [JsonProperty("color")] public float[] Color = new float[4] { 1f, 1f, 1f, 1f }; [JsonProperty("smoothness")] public float Smoothness = 0.35f; [JsonProperty("metallic")] public float Metallic; [JsonProperty("cutout")] public bool Cutout; [JsonProperty("doubleSided")] public bool DoubleSided; [JsonProperty("hidden")] public bool Hidden; } [BepInPlugin("pauluteli.SquadPlayermodels", "SquadPlayermodels", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "pauluteli.SquadPlayermodels"; public const string Name = "SquadPlayermodels"; public const string Version = "0.2.0"; internal static ManualLogSource Log = null; internal static readonly List<ModelDefinition> Models = new List<ModelDefinition>(); internal static ConfigEntry<bool> FirstPersonArms = null; internal static ConfigEntry<float> ModelScale = null; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; FirstPersonArms = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FirstPersonArms", true, "Show the Squad model's own arms in first person instead of the vanilla arms."); ModelScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ModelScale", 1f, "Size of Squad models relative to the vanilla player's height."); string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "SquadPlayermodels"); if (!Directory.Exists(text)) { Log.LogError((object)("Model folder not found: " + text)); return; } foreach (string item in Directory.GetDirectories(text).OrderBy<string, string>((string f) => f, StringComparer.OrdinalIgnoreCase)) { if (!File.Exists(Path.Combine(item, "model.json"))) { continue; } if (Models.Count >= SquadModelSlots.Types.Length) { Log.LogWarning((object)$"Only {SquadModelSlots.Types.Length} Squad models are supported; skipping {item}"); continue; } try { ModelDefinition modelDefinition = ModelDefinition.Load(item); ModelReplacementAPI.RegisterSuitModelReplacement(modelDefinition.Suit, SquadModelSlots.Types[Models.Count]); Models.Add(modelDefinition); Log.LogInfo((object)("Registered suit \"" + modelDefinition.Suit + "\" -> " + modelDefinition.Id)); } catch (Exception arg) { Log.LogError((object)$"Could not load model in {item}: {arg}"); } } if (Models.Count > 0) { AutoTest.StartIfRequested(); } } } internal sealed class SqpmFile { public string[] BoneNames = Array.Empty<string>(); public int[] BoneParents = Array.Empty<int>(); public Vector3[] BonePositions = Array.Empty<Vector3>(); public Quaternion[] BoneRotations = Array.Empty<Quaternion>(); public Vector3[] BoneScales = Array.Empty<Vector3>(); public Matrix4x4[] BindPoses = Array.Empty<Matrix4x4>(); public Vector3[] Positions = Array.Empty<Vector3>(); public Vector3[] Normals = Array.Empty<Vector3>(); public Vector2[] UVs = Array.Empty<Vector2>(); public BoneWeight[] Weights = Array.Empty<BoneWeight>(); public string[] SubmeshMaterials = Array.Empty<string>(); public int[][] SubmeshIndices = Array.Empty<int[]>(); public static SqpmFile Load(string path) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) using FileStream fileStream = File.OpenRead(path); BinaryReader binaryReader = new BinaryReader(fileStream); if (new string(binaryReader.ReadChars(4)) != "SQPM") { throw new InvalidDataException(path + " is not a .sqpm file"); } int num = binaryReader.ReadInt32(); if (num != 2) { throw new InvalidDataException($"{path}: unsupported version {num}, rebuild with tools/build.sh"); } using BinaryReader binaryReader2 = new BinaryReader(new BufferedStream(new DeflateStream(fileStream, CompressionMode.Decompress), 65536)); SqpmFile sqpmFile = new SqpmFile(); int num2 = binaryReader2.ReadInt32(); sqpmFile.BoneNames = new string[num2]; sqpmFile.BoneParents = new int[num2]; sqpmFile.BonePositions = (Vector3[])(object)new Vector3[num2]; sqpmFile.BoneRotations = (Quaternion[])(object)new Quaternion[num2]; sqpmFile.BoneScales = (Vector3[])(object)new Vector3[num2]; sqpmFile.BindPoses = (Matrix4x4[])(object)new Matrix4x4[num2]; for (int i = 0; i < num2; i++) { sqpmFile.BoneNames[i] = binaryReader2.ReadString(); sqpmFile.BoneParents[i] = binaryReader2.ReadInt32(); sqpmFile.BonePositions[i] = ReadV3(binaryReader2); sqpmFile.BoneRotations[i] = new Quaternion(binaryReader2.ReadSingle(), binaryReader2.ReadSingle(), binaryReader2.ReadSingle(), binaryReader2.ReadSingle()); sqpmFile.BoneScales[i] = ReadV3(binaryReader2); Matrix4x4 val = default(Matrix4x4); for (int j = 0; j < 16; j++) { ((Matrix4x4)(ref val))[j] = binaryReader2.ReadSingle(); } sqpmFile.BindPoses[i] = val; } int num3 = binaryReader2.ReadInt32(); sqpmFile.Positions = (Vector3[])(object)new Vector3[num3]; sqpmFile.Normals = (Vector3[])(object)new Vector3[num3]; sqpmFile.UVs = (Vector2[])(object)new Vector2[num3]; sqpmFile.Weights = (BoneWeight[])(object)new BoneWeight[num3]; for (int k = 0; k < num3; k++) { sqpmFile.Positions[k] = ReadV3(binaryReader2); } for (int l = 0; l < num3; l++) { sqpmFile.Normals[l] = new Vector3((float)binaryReader2.ReadInt16(), (float)binaryReader2.ReadInt16(), (float)binaryReader2.ReadInt16()) / 32767f; } for (int m = 0; m < num3; m++) { sqpmFile.UVs[m] = new Vector2(Mathf.HalfToFloat(binaryReader2.ReadUInt16()), Mathf.HalfToFloat(binaryReader2.ReadUInt16())); } byte[] array = binaryReader2.ReadBytes(num3 * 4); byte[] array2 = binaryReader2.ReadBytes(num3 * 4); for (int n = 0; n < num3; n++) { int num4 = n * 4; BoneWeight[] weights = sqpmFile.Weights; int num5 = n; BoneWeight val2 = default(BoneWeight); ((BoneWeight)(ref val2)).boneIndex0 = array[num4]; ((BoneWeight)(ref val2)).weight0 = (float)(int)array2[num4] / 255f; ((BoneWeight)(ref val2)).boneIndex1 = array[num4 + 1]; ((BoneWeight)(ref val2)).weight1 = (float)(int)array2[num4 + 1] / 255f; ((BoneWeight)(ref val2)).boneIndex2 = array[num4 + 2]; ((BoneWeight)(ref val2)).weight2 = (float)(int)array2[num4 + 2] / 255f; ((BoneWeight)(ref val2)).boneIndex3 = array[num4 + 3]; ((BoneWeight)(ref val2)).weight3 = (float)(int)array2[num4 + 3] / 255f; weights[num5] = val2; } int num6 = binaryReader2.ReadInt32(); bool flag = binaryReader2.ReadByte() == 4; sqpmFile.SubmeshMaterials = new string[num6]; sqpmFile.SubmeshIndices = new int[num6][]; for (int num7 = 0; num7 < num6; num7++) { sqpmFile.SubmeshMaterials[num7] = binaryReader2.ReadString(); int num8 = binaryReader2.ReadInt32(); int[] array3 = new int[num8]; for (int num9 = 0; num9 < num8; num9++) { array3[num9] = (int)(flag ? binaryReader2.ReadUInt32() : binaryReader2.ReadUInt16()); } sqpmFile.SubmeshIndices[num7] = array3; } return sqpmFile; } private static Vector3 ReadV3(BinaryReader r) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); } } public sealed class SquadModelInfo : MonoBehaviour { public string ModelId = ""; public float HeadHeight; public float HipsHeight; } public abstract class SquadBodyReplacement : BodyReplacementBase { private static readonly Dictionary<string, GameObject> Templates = new Dictionary<string, GameObject>(); protected abstract int Slot { get; } protected override GameObject LoadAssetsAndReturnModel() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) ModelDefinition modelDefinition = Plugin.Models[Slot]; if (!Templates.TryGetValue(modelDefinition.Id, out GameObject value) || (Object)(object)value == (Object)null) { float realtimeSinceStartup = Time.realtimeSinceStartup; value = ModelBuilder.Build(modelDefinition, ((BodyReplacementBase)this).controller.thisPlayerModel); Templates[modelDefinition.Id] = value; Plugin.Log.LogInfo((object)$"Built model {modelDefinition.Id} in {Time.realtimeSinceStartup - realtimeSinceStartup:0.00}s"); } value.transform.localScale = Vector3.one; return value; } protected override void AddModelScripts() { try { FitToPlayer(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Could not fit Squad model to player: {arg}"); } } private void FitToPlayer() { //IL_0063: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00af: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = base.replacementModel.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].forceRenderingOff = false; } SquadModelInfo component = base.replacementModel.GetComponent<SquadModelInfo>(); OffsetBuilder component2 = base.replacementModel.GetComponent<OffsetBuilder>(); SkinnedMeshRenderer thisPlayerModel = ((BodyReplacementBase)this).controller.thisPlayerModel; LcRestPose lcRestPose = LcRestPose.FromRenderer(thisPlayerModel); float num = WorldPerRestUnit(thisPlayerModel, lcRestPose); Vector3 val = (lcRestPose.Position("foot.L") + lcRestPose.Position("foot.R")) * 0.5f; float num2 = Vector3.Dot(lcRestPose.Position("spine.004") - val, lcRestPose.Up) * num; float num3 = Vector3.Dot(lcRestPose.Position("spine") - val, lcRestPose.Up) * num; float num4 = num2 / component.HeadHeight * Plugin.ModelScale.Value; base.replacementModel.transform.localScale = Vector3.one * num4; float num5 = component.HipsHeight * num4 - num3; Transform val2 = thisPlayerModel.bones.First((Transform b) => (Object)(object)b != (Object)null && ((Object)b).name == "spine"); Matrix4x4 val3 = lcRestPose.BindPose("spine"); Vector3 val4 = ((Matrix4x4)(ref val3)).MultiplyVector(lcRestPose.Up); Vector3 normalized = ((Vector3)(ref val4)).normalized; val4 = val2.TransformVector(normalized); component2.rootPositionOffset = normalized * (num5 / ((Vector3)(ref val4)).magnitude); Plugin.Log.LogInfo((object)$"{component.ModelId}: world/rest {num:0.####}, head {num2:0.###}, scale {num4:0.###}, hips raise {num5:0.###}"); } private static float WorldPerRestUnit(SkinnedMeshRenderer pr, LcRestPose lc) { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, Transform> dictionary = (from b in pr.bones where (Object)(object)b != (Object)null group b by ((Object)b).name).ToDictionary((IGrouping<string, Transform> g) => g.Key, (IGrouping<string, Transform> g) => g.First()); float num = 0f; float num2 = 0f; (string, string)[] array = new(string, string)[7] { ("thigh.L", "shin.L"), ("shin.L", "foot.L"), ("thigh.R", "shin.R"), ("shin.R", "foot.R"), ("arm.L_upper", "arm.L_lower"), ("arm.R_upper", "arm.R_lower"), ("spine.001", "spine.002") }; for (int num3 = 0; num3 < array.Length; num3++) { var (text, text2) = array[num3]; if (lc.Has(text) && lc.Has(text2) && dictionary.ContainsKey(text) && dictionary.ContainsKey(text2)) { float num4 = num; Vector3 val = lc.Position(text2) - lc.Position(text); num = num4 + ((Vector3)(ref val)).magnitude; float num5 = num2; val = dictionary[text2].position - dictionary[text].position; num2 = num5 + ((Vector3)(ref val)).magnitude; } } if (!(num > 0f)) { return ((Component)pr).transform.lossyScale.y; } return num2 / num; } } public sealed class SquadModel000 : SquadBodyReplacement { protected override int Slot => 0; } public sealed class SquadModel001 : SquadBodyReplacement { protected override int Slot => 1; } public sealed class SquadModel002 : SquadBodyReplacement { protected override int Slot => 2; } public sealed class SquadModel003 : SquadBodyReplacement { protected override int Slot => 3; } public sealed class SquadModel004 : SquadBodyReplacement { protected override int Slot => 4; } public sealed class SquadModel005 : SquadBodyReplacement { protected override int Slot => 5; } public sealed class SquadModel006 : SquadBodyReplacement { protected override int Slot => 6; } public sealed class SquadModel007 : SquadBodyReplacement { protected override int Slot => 7; } public sealed class SquadModel008 : SquadBodyReplacement { protected override int Slot => 8; } public sealed class SquadModel009 : SquadBodyReplacement { protected override int Slot => 9; } public sealed class SquadModel010 : SquadBodyReplacement { protected override int Slot => 10; } public sealed class SquadModel011 : SquadBodyReplacement { protected override int Slot => 11; } public sealed class SquadModel012 : SquadBodyReplacement { protected override int Slot => 12; } public sealed class SquadModel013 : SquadBodyReplacement { protected override int Slot => 13; } public sealed class SquadModel014 : SquadBodyReplacement { protected override int Slot => 14; } public sealed class SquadModel015 : SquadBodyReplacement { protected override int Slot => 15; } public sealed class SquadModel016 : SquadBodyReplacement { protected override int Slot => 16; } public sealed class SquadModel017 : SquadBodyReplacement { protected override int Slot => 17; } public sealed class SquadModel018 : SquadBodyReplacement { protected override int Slot => 18; } public sealed class SquadModel019 : SquadBodyReplacement { protected override int Slot => 19; } public sealed class SquadModel020 : SquadBodyReplacement { protected override int Slot => 20; } public sealed class SquadModel021 : SquadBodyReplacement { protected override int Slot => 21; } public sealed class SquadModel022 : SquadBodyReplacement { protected override int Slot => 22; } public sealed class SquadModel023 : SquadBodyReplacement { protected override int Slot => 23; } public sealed class SquadModel024 : SquadBodyReplacement { protected override int Slot => 24; } public sealed class SquadModel025 : SquadBodyReplacement { protected override int Slot => 25; } public sealed class SquadModel026 : SquadBodyReplacement { protected override int Slot => 26; } public sealed class SquadModel027 : SquadBodyReplacement { protected override int Slot => 27; } public sealed class SquadModel028 : SquadBodyReplacement { protected override int Slot => 28; } public sealed class SquadModel029 : SquadBodyReplacement { protected override int Slot => 29; } public sealed class SquadModel030 : SquadBodyReplacement { protected override int Slot => 30; } public sealed class SquadModel031 : SquadBodyReplacement { protected override int Slot => 31; } public sealed class SquadModel032 : SquadBodyReplacement { protected override int Slot => 32; } public sealed class SquadModel033 : SquadBodyReplacement { protected override int Slot => 33; } public sealed class SquadModel034 : SquadBodyReplacement { protected override int Slot => 34; } public sealed class SquadModel035 : SquadBodyReplacement { protected override int Slot => 35; } public sealed class SquadModel036 : SquadBodyReplacement { protected override int Slot => 36; } public sealed class SquadModel037 : SquadBodyReplacement { protected override int Slot => 37; } public sealed class SquadModel038 : SquadBodyReplacement { protected override int Slot => 38; } public sealed class SquadModel039 : SquadBodyReplacement { protected override int Slot => 39; } public sealed class SquadModel040 : SquadBodyReplacement { protected override int Slot => 40; } public sealed class SquadModel041 : SquadBodyReplacement { protected override int Slot => 41; } public sealed class SquadModel042 : SquadBodyReplacement { protected override int Slot => 42; } public sealed class SquadModel043 : SquadBodyReplacement { protected override int Slot => 43; } public sealed class SquadModel044 : SquadBodyReplacement { protected override int Slot => 44; } public sealed class SquadModel045 : SquadBodyReplacement { protected override int Slot => 45; } public sealed class SquadModel046 : SquadBodyReplacement { protected override int Slot => 46; } public sealed class SquadModel047 : SquadBodyReplacement { protected override int Slot => 47; } public sealed class SquadModel048 : SquadBodyReplacement { protected override int Slot => 48; } public sealed class SquadModel049 : SquadBodyReplacement { protected override int Slot => 49; } public sealed class SquadModel050 : SquadBodyReplacement { protected override int Slot => 50; } public sealed class SquadModel051 : SquadBodyReplacement { protected override int Slot => 51; } public sealed class SquadModel052 : SquadBodyReplacement { protected override int Slot => 52; } public sealed class SquadModel053 : SquadBodyReplacement { protected override int Slot => 53; } public sealed class SquadModel054 : SquadBodyReplacement { protected override int Slot => 54; } public sealed class SquadModel055 : SquadBodyReplacement { protected override int Slot => 55; } public sealed class SquadModel056 : SquadBodyReplacement { protected override int Slot => 56; } public sealed class SquadModel057 : SquadBodyReplacement { protected override int Slot => 57; } public sealed class SquadModel058 : SquadBodyReplacement { protected override int Slot => 58; } public sealed class SquadModel059 : SquadBodyReplacement { protected override int Slot => 59; } public sealed class SquadModel060 : SquadBodyReplacement { protected override int Slot => 60; } public sealed class SquadModel061 : SquadBodyReplacement { protected override int Slot => 61; } public sealed class SquadModel062 : SquadBodyReplacement { protected override int Slot => 62; } public sealed class SquadModel063 : SquadBodyReplacement { protected override int Slot => 63; } public sealed class SquadModel064 : SquadBodyReplacement { protected override int Slot => 64; } public sealed class SquadModel065 : SquadBodyReplacement { protected override int Slot => 65; } public sealed class SquadModel066 : SquadBodyReplacement { protected override int Slot => 66; } public sealed class SquadModel067 : SquadBodyReplacement { protected override int Slot => 67; } public sealed class SquadModel068 : SquadBodyReplacement { protected override int Slot => 68; } public sealed class SquadModel069 : SquadBodyReplacement { protected override int Slot => 69; } public sealed class SquadModel070 : SquadBodyReplacement { protected override int Slot => 70; } public sealed class SquadModel071 : SquadBodyReplacement { protected override int Slot => 71; } public sealed class SquadModel072 : SquadBodyReplacement { protected override int Slot => 72; } public sealed class SquadModel073 : SquadBodyReplacement { protected override int Slot => 73; } public sealed class SquadModel074 : SquadBodyReplacement { protected override int Slot => 74; } public sealed class SquadModel075 : SquadBodyReplacement { protected override int Slot => 75; } public sealed class SquadModel076 : SquadBodyReplacement { protected override int Slot => 76; } public sealed class SquadModel077 : SquadBodyReplacement { protected override int Slot => 77; } public sealed class SquadModel078 : SquadBodyReplacement { protected override int Slot => 78; } public sealed class SquadModel079 : SquadBodyReplacement { protected override int Slot => 79; } public sealed class SquadModel080 : SquadBodyReplacement { protected override int Slot => 80; } public sealed class SquadModel081 : SquadBodyReplacement { protected override int Slot => 81; } public sealed class SquadModel082 : SquadBodyReplacement { protected override int Slot => 82; } public sealed class SquadModel083 : SquadBodyReplacement { protected override int Slot => 83; } public sealed class SquadModel084 : SquadBodyReplacement { protected override int Slot => 84; } public sealed class SquadModel085 : SquadBodyReplacement { protected override int Slot => 85; } public sealed class SquadModel086 : SquadBodyReplacement { protected override int Slot => 86; } public sealed class SquadModel087 : SquadBodyReplacement { protected override int Slot => 87; } public sealed class SquadModel088 : SquadBodyReplacement { protected override int Slot => 88; } public sealed class SquadModel089 : SquadBodyReplacement { protected override int Slot => 89; } public sealed class SquadModel090 : SquadBodyReplacement { protected override int Slot => 90; } public sealed class SquadModel091 : SquadBodyReplacement { protected override int Slot => 91; } public sealed class SquadModel092 : SquadBodyReplacement { protected override int Slot => 92; } public sealed class SquadModel093 : SquadBodyReplacement { protected override int Slot => 93; } public sealed class SquadModel094 : SquadBodyReplacement { protected override int Slot => 94; } public sealed class SquadModel095 : SquadBodyReplacement { protected override int Slot => 95; } public sealed class SquadModel096 : SquadBodyReplacement { protected override int Slot => 96; } public sealed class SquadModel097 : SquadBodyReplacement { protected override int Slot => 97; } public sealed class SquadModel098 : SquadBodyReplacement { protected override int Slot => 98; } public sealed class SquadModel099 : SquadBodyReplacement { protected override int Slot => 99; } public sealed class SquadModel100 : SquadBodyReplacement { protected override int Slot => 100; } public sealed class SquadModel101 : SquadBodyReplacement { protected override int Slot => 101; } public sealed class SquadModel102 : SquadBodyReplacement { protected override int Slot => 102; } public sealed class SquadModel103 : SquadBodyReplacement { protected override int Slot => 103; } public sealed class SquadModel104 : SquadBodyReplacement { protected override int Slot => 104; } public sealed class SquadModel105 : SquadBodyReplacement { protected override int Slot => 105; } public sealed class SquadModel106 : SquadBodyReplacement { protected override int Slot => 106; } public sealed class SquadModel107 : SquadBodyReplacement { protected override int Slot => 107; } public sealed class SquadModel108 : SquadBodyReplacement { protected override int Slot => 108; } public sealed class SquadModel109 : SquadBodyReplacement { protected override int Slot => 109; } public sealed class SquadModel110 : SquadBodyReplacement { protected override int Slot => 110; } public sealed class SquadModel111 : SquadBodyReplacement { protected override int Slot => 111; } public sealed class SquadModel112 : SquadBodyReplacement { protected override int Slot => 112; } public sealed class SquadModel113 : SquadBodyReplacement { protected override int Slot => 113; } public sealed class SquadModel114 : SquadBodyReplacement { protected override int Slot => 114; } public sealed class SquadModel115 : SquadBodyReplacement { protected override int Slot => 115; } public sealed class SquadModel116 : SquadBodyReplacement { protected override int Slot => 116; } public sealed class SquadModel117 : SquadBodyReplacement { protected override int Slot => 117; } public sealed class SquadModel118 : SquadBodyReplacement { protected override int Slot => 118; } public sealed class SquadModel119 : SquadBodyReplacement { protected override int Slot => 119; } public sealed class SquadModel120 : SquadBodyReplacement { protected override int Slot => 120; } public sealed class SquadModel121 : SquadBodyReplacement { protected override int Slot => 121; } public sealed class SquadModel122 : SquadBodyReplacement { protected override int Slot => 122; } public sealed class SquadModel123 : SquadBodyReplacement { protected override int Slot => 123; } public sealed class SquadModel124 : SquadBodyReplacement { protected override int Slot => 124; } public sealed class SquadModel125 : SquadBodyReplacement { protected override int Slot => 125; } public sealed class SquadModel126 : SquadBodyReplacement { protected override int Slot => 126; } public sealed class SquadModel127 : SquadBodyReplacement { protected override int Slot => 127; } internal static class SquadModelSlots { public static readonly Type[] Types = new Type[128] { typeof(SquadModel000), typeof(SquadModel001), typeof(SquadModel002), typeof(SquadModel003), typeof(SquadModel004), typeof(SquadModel005), typeof(SquadModel006), typeof(SquadModel007), typeof(SquadModel008), typeof(SquadModel009), typeof(SquadModel010), typeof(SquadModel011), typeof(SquadModel012), typeof(SquadModel013), typeof(SquadModel014), typeof(SquadModel015), typeof(SquadModel016), typeof(SquadModel017), typeof(SquadModel018), typeof(SquadModel019), typeof(SquadModel020), typeof(SquadModel021), typeof(SquadModel022), typeof(SquadModel023), typeof(SquadModel024), typeof(SquadModel025), typeof(SquadModel026), typeof(SquadModel027), typeof(SquadModel028), typeof(SquadModel029), typeof(SquadModel030), typeof(SquadModel031), typeof(SquadModel032), typeof(SquadModel033), typeof(SquadModel034), typeof(SquadModel035), typeof(SquadModel036), typeof(SquadModel037), typeof(SquadModel038), typeof(SquadModel039), typeof(SquadModel040), typeof(SquadModel041), typeof(SquadModel042), typeof(SquadModel043), typeof(SquadModel044), typeof(SquadModel045), typeof(SquadModel046), typeof(SquadModel047), typeof(SquadModel048), typeof(SquadModel049), typeof(SquadModel050), typeof(SquadModel051), typeof(SquadModel052), typeof(SquadModel053), typeof(SquadModel054), typeof(SquadModel055), typeof(SquadModel056), typeof(SquadModel057), typeof(SquadModel058), typeof(SquadModel059), typeof(SquadModel060), typeof(SquadModel061), typeof(SquadModel062), typeof(SquadModel063), typeof(SquadModel064), typeof(SquadModel065), typeof(SquadModel066), typeof(SquadModel067), typeof(SquadModel068), typeof(SquadModel069), typeof(SquadModel070), typeof(SquadModel071), typeof(SquadModel072), typeof(SquadModel073), typeof(SquadModel074), typeof(SquadModel075), typeof(SquadModel076), typeof(SquadModel077), typeof(SquadModel078), typeof(SquadModel079), typeof(SquadModel080), typeof(SquadModel081), typeof(SquadModel082), typeof(SquadModel083), typeof(SquadModel084), typeof(SquadModel085), typeof(SquadModel086), typeof(SquadModel087), typeof(SquadModel088), typeof(SquadModel089), typeof(SquadModel090), typeof(SquadModel091), typeof(SquadModel092), typeof(SquadModel093), typeof(SquadModel094), typeof(SquadModel095), typeof(SquadModel096), typeof(SquadModel097), typeof(SquadModel098), typeof(SquadModel099), typeof(SquadModel100), typeof(SquadModel101), typeof(SquadModel102), typeof(SquadModel103), typeof(SquadModel104), typeof(SquadModel105), typeof(SquadModel106), typeof(SquadModel107), typeof(SquadModel108), typeof(SquadModel109), typeof(SquadModel110), typeof(SquadModel111), typeof(SquadModel112), typeof(SquadModel113), typeof(SquadModel114), typeof(SquadModel115), typeof(SquadModel116), typeof(SquadModel117), typeof(SquadModel118), typeof(SquadModel119), typeof(SquadModel120), typeof(SquadModel121), typeof(SquadModel122), typeof(SquadModel123), typeof(SquadModel124), typeof(SquadModel125), typeof(SquadModel126), typeof(SquadModel127) }; } }