using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using UniGLTF; using UniGLTF.Extensions.VRMC_materials_mtoon; using UniVRM10; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using VRMShaders; using VRMShaders.VRM10.MToon10.Runtime; [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("Zch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("MIT License")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+11aa5fb10bb35be08ba329f32fb0c9eb326e7be3")] [assembly: AssemblyProduct("BettererLethalVRM")] [assembly: AssemblyTitle("Zch.BettererLethalVRM")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 Zch { public static class MyPluginInfo { public const string PLUGIN_GUID = "Zch.BettererLethalVRM"; public const string PLUGIN_NAME = "BettererLethalVRM"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace Zch.BettererLethalVRM { [BepInPlugin("Zch.BettererLethalVRM", "BettererLethalVRM", "1.0.0")] public class BetterLethalVRMManager : BaseUnityPlugin { internal struct FaceSettings { public int BlinkBlendshapeIndex; public int MouthBlendshapeIndex; public float BlinkIntervalMin; public float BlinkIntervalMax; public float BlinkDuration; } private const string MODEL_PATH = "VRMs"; private readonly SortedDictionary Instances = new SortedDictionary(); private readonly SortedDictionary PlayersBySteamID = new SortedDictionary(); private Material HDRP_BaseMaterial; private GameObject PlayerPrefab; private float PlayerPrefabHeight; private PlayerControllerB[] PlayerControllers; private bool RequirePlayerUpdate; private GameObject _helmetModel; private DissonanceComms _dissonanceComms; private float _nextDissonanceLookup; internal static BetterLethalVRMManager Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; private set; } internal ConfigEntry ScaleSize { get; private set; } internal ConfigEntry BlinkBlendshapeIndex { get; private set; } internal ConfigEntry BlinkIntervalMin { get; private set; } internal ConfigEntry BlinkIntervalMax { get; private set; } internal ConfigEntry BlinkDuration { get; private set; } internal ConfigEntry MouthBlendshapeIndex { get; private set; } internal ConfigEntry LipSyncSensitivitySelf { get; private set; } internal ConfigEntry LipSyncSensitivityOthers { get; private set; } internal ConfigEntry FreeLookTerminalLadder { get; private set; } internal ConfigEntry FreeLookSensitivity { get; private set; } internal ConfigEntry HideHelmetForVRM { get; private set; } internal Dictionary PlayersScale { get; } = new Dictionary(); internal Dictionary PlayersFaceSettings { get; } = new Dictionary(); internal DissonanceComms GetDissonanceComms() { if ((Object)(object)_dissonanceComms == (Object)null && Time.unscaledTime >= _nextDissonanceLookup) { _dissonanceComms = Object.FindObjectOfType(); _nextDissonanceLookup = Time.unscaledTime + 1f; } return _dissonanceComms; } public void Awake() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Patch(); CameraPatch.Initialize(); AssetBundle val = null; try { UriBuilder uriBuilder = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase); string fileName = Uri.UnescapeDataString(uriBuilder.Path); string text = Path.Combine(new FileInfo(fileName).Directory.FullName, "bundle.asset"); if (File.Exists(text)) { val = AssetBundle.LoadFromFile(text); } } catch (Exception) { val = null; } if ((Object)(object)val == (Object)null) { ((Behaviour)this).enabled = false; Debug.LogError((object)"BettererLethalVRM failed to load it's asset bundle, this mod will not function"); return; } HDRPVrm10MToonMaterialImporter.MToonReplacementShader = (Shader)val.LoadAsset("MToonParameterShader"); if ((Object)(object)HDRPVrm10MToonMaterialImporter.MToonReplacementShader == (Object)null) { ((Behaviour)this).enabled = false; Debug.LogError((object)"BettererLethalVRM failed to load the MToon replacement shader, this mod will not function"); return; } SceneManager.sceneLoaded += delegate { SceneLoad(); }; RenderPipelineManager.beginFrameRendering += OnBeginFrameRendering; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; if (!Directory.Exists("VRMs")) { Directory.CreateDirectory("VRMs"); } if (!Directory.Exists("VRMs")) { ((Behaviour)this).enabled = false; Debug.LogError((object)"BettererLethalVRM failed to create directory for models, this mod will not function"); } ScaleSize = ((BaseUnityPlugin)this).Config.Bind("General", "scaleSize", 1f, "Scale size of VRM models, between 0.1 and 1.5"); BlinkBlendshapeIndex = ((BaseUnityPlugin)this).Config.Bind("Blink", "BlinkBlendshapeIndex", -1, "Blendshape index for blinking.\n-1 to disable.\nIgnored if the model has a \"Blink\" VRM expression with blendshape bindings."); BlinkIntervalMin = ((BaseUnityPlugin)this).Config.Bind("Blink", "BlinkIntervalMin", 2f, "Minimum seconds between blinks."); BlinkIntervalMax = ((BaseUnityPlugin)this).Config.Bind("Blink", "BlinkIntervalMax", 6f, "Maximum seconds between blinks."); BlinkDuration = ((BaseUnityPlugin)this).Config.Bind("Blink", "BlinkDuration", 0.15f, "Duration of each blink in seconds."); MouthBlendshapeIndex = ((BaseUnityPlugin)this).Config.Bind("LipSync", "MouthBlendshapeIndex", -1, "Blendshape index for mouth open when talking.\n-1 to disable.\nIgnored if the model has an \"A\" VRM expression with blendshape bindings."); LipSyncSensitivitySelf = ((BaseUnityPlugin)this).Config.Bind("LipSync", "LipSyncSensitivitySelf", 2f, "Mouth sensitivity for your own voice (Dissonance amplitude, range 0-1). Higher = opens more for quiet sounds."); LipSyncSensitivityOthers = ((BaseUnityPlugin)this).Config.Bind("LipSync", "LipSyncSensitivityOthers", 2f, "Mouth sensitivity for other players' voices (audio RMS). Higher = opens more for quiet sounds."); FreeLookTerminalLadder = ((BaseUnityPlugin)this).Config.Bind("General", "FreeLookTerminalLadder", true, "Allow free camera look while using the terminal or climbing ladders."); FreeLookSensitivity = ((BaseUnityPlugin)this).Config.Bind("General", "FreeLookSensitivity", 1f, "Mouse sensitivity for free look while in terminal or on ladder. 1.0 = default feel."); HideHelmetForVRM = ((BaseUnityPlugin)this).Config.Bind("General", "HideHelmetForVRM", true, "Hide the default helmet model when a VRM is loaded for the local player."); } internal static void Patch() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("Zch.BettererLethalVRM"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } private void LateUpdate() { FindUpdatedIDs(); FindMaskEnemies(); AnimateBonePairs(); if (RequirePlayerUpdate) { FindPlayerControllers(); RequirePlayerUpdate = false; } UpdateHelmetVisibility(); } private void UpdateHelmetVisibility() { if ((Object)(object)_helmetModel == (Object)null) { _helmetModel = GameObject.Find("Systems/Rendering/PlayerHUDHelmetModel"); } if (!((Object)(object)_helmetModel == (Object)null)) { PlayerControllerB val = StartOfRound.Instance?.localPlayerController; bool flag = (Object)(object)val != (Object)null && Instances.ContainsKey(GetTrackingId(val)) && HideHelmetForVRM.Value; _helmetModel.SetActive(!flag); } } private void SceneLoad() { _helmetModel = null; GameNetworkManager instance = GameNetworkManager.Instance; if (instance == null || !instance.currentLobby.HasValue) { foreach (BetterLethalVRMInstance value in Instances.Values) { if ((Object)(object)value.Vrm10Instance != (Object)null && (Object)(object)((Component)value.Vrm10Instance).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)value.Vrm10Instance).gameObject); } } PlayersBySteamID.Clear(); Instances.Clear(); } FindPlayerControllers(); PreparePrefabs(); RequirePlayerUpdate = true; } private void PreparePrefabs() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00d8: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: 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_02be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)PlayerPrefab == (Object)null) { PlayerControllerB val = ((IEnumerable)PlayerControllers).FirstOrDefault((Func)((PlayerControllerB x) => ((Object)x).name == "Player")); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); PlayerPrefab = Object.Instantiate(((Component)val).gameObject); ((Object)PlayerPrefab).name = "VRM T Pose Match"; ((Object)PlayerPrefab).hideFlags = (HideFlags)61; Material material = ((Renderer)GameObject.Find("CatwalkShip").GetComponent()).material; HDRP_BaseMaterial = new Material(material); HDRP_BaseMaterial.SetFloat("_Smoothness", 0f); HDRP_BaseMaterial.SetFloat("_Metallic", 0f); HDRP_BaseMaterial.SetTextureScale("_BaseColorMap", Vector2.one); ((Component)val).gameObject.SetActive(true); ((Behaviour)PlayerPrefab.GetComponentInChildren()).enabled = false; UnityExtensions.FindDescendant(PlayerPrefab.transform, "arm.L_upper").localRotation = Quaternion.Euler(0f, 90f, -10f); UnityExtensions.FindDescendant(PlayerPrefab.transform, "arm.R_upper").localRotation = Quaternion.Euler(-10f, 0f, 0f); UnityExtensions.FindDescendant(PlayerPrefab.transform, "thigh.L").localRotation = Quaternion.Euler(20f, 180f, 180f); UnityExtensions.FindDescendant(PlayerPrefab.transform, "thigh.R").localRotation = Quaternion.Euler(20f, 180f, 180f); UnityExtensions.FindDescendant(PlayerPrefab.transform, "hand.R").localRotation = Quaternion.Euler(0f, 90f, 0f); UnityExtensions.FindDescendant(PlayerPrefab.transform, "hand.L").localRotation = Quaternion.Euler(0f, 270f, 0f); Transform val2 = UnityExtensions.FindDescendant(PlayerPrefab.transform, "foot.L"); Transform val3 = UnityExtensions.FindDescendant(PlayerPrefab.transform, "foot.R"); Transform val4 = UnityExtensions.FindDescendant(PlayerPrefab.transform, "spine.004_end"); Vector3 val5 = default(Vector3); ((Vector3)(ref val5))..ctor(0f, ((val2.position + val3.position) / 2f).y, 0f); Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(0f, val4.position.y, 0f); PlayerPrefabHeight = Vector3.Distance(val5, val6); PlayerPrefab.transform.rotation = Quaternion.identity; Debug.Log((object)$"BettererLethalVRM base prefab set to {((Object)PlayerPrefab).name}, has a height of {PlayerPrefabHeight:0.###}"); } } } private void FindPlayerControllers() { PlayerControllers = Object.FindObjectsOfType(true); Debug.Log((object)$"BettererLethalVRM found {PlayerControllers.Length} player controllers"); } private static ulong GetTrackingId(PlayerControllerB player) { if (player.playerSteamId == 0L) { return player.playerClientId; } return player.playerSteamId; } private void FindUpdatedIDs() { PlayerControllerB[] playerControllers = PlayerControllers; foreach (PlayerControllerB val in playerControllers) { if (!val.isPlayerControlled && val.playerSteamId == 0L) { continue; } ulong trackingId = GetTrackingId(val); if (PlayersBySteamID.ContainsKey(trackingId)) { if (!val.disconnectedMidGame) { NetworkObject networkObject = ((NetworkBehaviour)val).NetworkObject; if (networkObject == null || networkObject.OwnerClientId != 0 || !(((Object)val).name != "Player")) { goto IL_00be; } } if (Instances.TryGetValue(trackingId, out BetterLethalVRMInstance value) && (Object)(object)value.Vrm10Instance != (Object)null) { Object.Destroy((Object)(object)((Component)value.Vrm10Instance).gameObject); } PlayersBySteamID.Remove(trackingId); Instances.Remove(trackingId); continue; } goto IL_00be; IL_00be: NetworkObject networkObject2 = ((NetworkBehaviour)val).NetworkObject; if ((networkObject2 != null && networkObject2.OwnerClientId == 0 && ((Object)val).name != "Player") || !PlayersBySteamID.TryAdd(trackingId, val)) { continue; } if (val.playerSteamId != 0L && !File.Exists(string.Format("{0}/{1}_{2}.txt", "VRMs", val.playerSteamId, val.playerUsername))) { File.WriteAllText(string.Format("{0}/{1}_{2}.txt", "VRMs", val.playerSteamId, val.playerUsername), $"{val.playerSteamId} seen as {val.playerUsername}"); } if (!Instances.ContainsKey(trackingId)) { string text = null; if (val.playerSteamId != 0L && File.Exists(string.Format("{0}/{1}.vrm", "VRMs", val.playerSteamId))) { text = string.Format("{0}/{1}.vrm", "VRMs", val.playerSteamId); } else if (!string.IsNullOrEmpty(val.playerUsername) && File.Exists("VRMs/" + val.playerUsername + ".vrm")) { text = "VRMs/" + val.playerUsername + ".vrm"; } else if (File.Exists("VRMs/fallback.vrm")) { text = "VRMs/fallback.vrm"; } if (text != null) { Debug.Log((object)("BettererLethalVRM trying to load model for path " + text)); LoadModelToPlayer(text, val); } } } } private void FindMaskEnemies() { } private async void LoadModelToPlayer(string Path, PlayerControllerB Player) { Vrm10Instance val = await Vrm10.LoadPathAsync(Path, true, (ControlRigGenerationOption)1, true, (IAwaitCaller)null, (ITextureDeserializer)null, (IMaterialDescriptorGenerator)(object)new HDRPVrm10MaterialDescriptorGenerator(), (VrmMetaInformationCallback)null, default(CancellationToken)); if ((Object)(object)val == (Object)null) { ((Behaviour)this).enabled = false; Debug.LogError((object)("BettererLethalVRM had an error loading the VRM at " + Path + ", this mod will not function")); return; } if (Instances.ContainsKey(GetTrackingId(Player))) { Debug.Log((object)$"BettererLethalVRM duplicate load for {GetTrackingId(Player)}, destroying orphan"); Object.Destroy((Object)(object)((Component)val).gameObject); return; } ((Object)val).name = $"BettererLethalVRM Character Model {Player.playerUsername} {Player.playerSteamId}"; ((Component)val).transform.position = ((Component)Player).transform.position; BetterLethalVRMInstance betterLethalVRMInstance = new BetterLethalVRMInstance(); if ((Object)(object)HDRP_BaseMaterial == (Object)null) { ((Behaviour)this).enabled = false; Debug.LogError((object)"BettererLethalVRM had some error loading the Lethal Company shader material, this mod will not function"); Object.Destroy((Object)(object)((Component)val).gameObject); return; } Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { betterLethalVRMInstance.Renderers.Add(val2); val2.receiveShadows = true; val2.shadowCastingMode = (ShadowCastingMode)2; SkinnedMeshRenderer val3 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if (val3 != null) { val3.updateWhenOffscreen = true; } Material[] array = (Material[])(object)new Material[val2.materials.Length]; for (int j = 0; j < val2.materials.Length; j++) { Material val4 = val2.materials[j]; Material val5 = new Material(HDRP_BaseMaterial) { name = ((Object)val4).name, mainTexture = val4.mainTexture }; if (val4.HasProperty("_M_CullMode")) { val5.SetFloat("_CullMode", val4.GetFloat("_M_CullMode")); } if (val4.HasProperty("_BumpMap")) { val5.SetTexture("_NormalMap", val4.GetTexture("_BumpMap")); } array[j] = val5; } val2.materials = array; } SkinnedMeshRenderer val6 = null; int num = 0; foreach (Renderer renderer in betterLethalVRMInstance.Renderers) { SkinnedMeshRenderer val7 = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val7 != null && (Object)(object)val7.sharedMesh != (Object)null) { int blendShapeCount = val7.sharedMesh.blendShapeCount; if (blendShapeCount > num) { num = blendShapeCount; val6 = val7; } } } betterLethalVRMInstance.FaceMeshRenderer = val6; if ((Object)(object)val6 != (Object)null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"BettererLethalVRM {Path} face mesh: \"{((Object)val6).name}\" ({num} blendshapes)"); for (int k = 0; k < num; k++) { stringBuilder.AppendLine($" [{k}] {val6.sharedMesh.GetBlendShapeName(k)}"); } Debug.Log((object)stringBuilder.ToString()); } Animator controlRigAnimator = val.Runtime.ControlRig.ControlRigAnimator; ((Behaviour)controlRigAnimator).enabled = false; val.Runtime.VrmAnimation = null; (string, HumanBodyBones)[] array2 = new(string, HumanBodyBones)[49] { ("spine", (HumanBodyBones)0), ("spine.001", (HumanBodyBones)7), ("spine.002", (HumanBodyBones)8), ("spine.003", (HumanBodyBones)54), ("spine.004", (HumanBodyBones)9), ("shoulder.R", (HumanBodyBones)12), ("arm.R_upper", (HumanBodyBones)14), ("arm.R_lower", (HumanBodyBones)16), ("hand.R", (HumanBodyBones)18), ("shoulder.L", (HumanBodyBones)11), ("arm.L_upper", (HumanBodyBones)13), ("arm.L_lower", (HumanBodyBones)15), ("hand.L", (HumanBodyBones)17), ("thigh.R", (HumanBodyBones)2), ("shin.R", (HumanBodyBones)4), ("foot.R", (HumanBodyBones)6), ("thigh.L", (HumanBodyBones)1), ("shin.L", (HumanBodyBones)3), ("foot.L", (HumanBodyBones)5), ("finger1.L", (HumanBodyBones)24), ("finger1.L.001", (HumanBodyBones)25), ("finger1.L.001_end", (HumanBodyBones)26), ("finger2.L", (HumanBodyBones)27), ("finger2.L.001", (HumanBodyBones)28), ("finger2.L.001_end", (HumanBodyBones)29), ("finger3.L", (HumanBodyBones)30), ("finger3.L.001", (HumanBodyBones)31), ("finger3.L.001_end", (HumanBodyBones)32), ("finger4.L", (HumanBodyBones)33), ("finger4.L.001", (HumanBodyBones)34), ("finger4.L.001_end", (HumanBodyBones)35), ("finger5.L", (HumanBodyBones)36), ("finger5.L.001", (HumanBodyBones)37), ("finger5.L.001_end", (HumanBodyBones)38), ("finger1.R", (HumanBodyBones)39), ("finger1.R.001", (HumanBodyBones)40), ("finger1.R.001_end", (HumanBodyBones)41), ("finger2.R", (HumanBodyBones)42), ("finger2.R.001", (HumanBodyBones)43), ("finger2.R.001_end", (HumanBodyBones)44), ("finger3.R", (HumanBodyBones)45), ("finger3.R.001", (HumanBodyBones)46), ("finger3.R.001_end", (HumanBodyBones)47), ("finger4.R", (HumanBodyBones)48), ("finger4.R.001", (HumanBodyBones)49), ("finger4.R.001_end", (HumanBodyBones)50), ("finger5.R", (HumanBodyBones)51), ("finger5.R.001", (HumanBodyBones)52), ("finger5.R.001_end", (HumanBodyBones)53) }; if ((Object)(object)PlayerPrefab == (Object)null) { ((Behaviour)this).enabled = false; Debug.LogError((object)"BettererLethalVRM failed to find the player prefab, this mod will not function"); Object.Destroy((Object)(object)((Component)val).gameObject); return; } HashSet<(Transform, Transform, Quaternion)> hashSet = new HashSet<(Transform, Transform, Quaternion)>(); (string, HumanBodyBones)[] array3 = array2; for (int l = 0; l < array3.Length; l++) { (string, HumanBodyBones) tuple = array3[l]; Transform boneTransform = controlRigAnimator.GetBoneTransform(tuple.Item2); if ((Object)(object)boneTransform == (Object)null) { Debug.Log((object)$"BettererLethalVRM {Path} missing bone {tuple.Item2} ({tuple.Item1})"); continue; } Transform val8 = UnityExtensions.FindDescendant(((Component)Player).transform, tuple.Item1); Transform val9 = UnityExtensions.FindDescendant(PlayerPrefab.transform, tuple.Item1); Transform transform = new GameObject("VRM Rotation Bone").transform; transform.parent = val9; transform.position = val9.position; transform.rotation = boneTransform.rotation; Quaternion localRotation = transform.localRotation; transform.parent = val8; transform.position = val8.position; transform.localRotation = localRotation; hashSet.Add((boneTransform, transform, localRotation)); } float num2 = 1f; if (PlayersScale.ContainsKey(Player.playerClientId)) { num2 = PlayersScale[Player.playerClientId]; } Vector3 val10 = default(Vector3); ((Vector3)(ref val10))..ctor(0f, val.Humanoid.Head.position.y, 0f); Vector3 val11 = default(Vector3); ((Vector3)(ref val11))..ctor(0f, ((Component)val).transform.position.y, 0f); float num3 = Vector3.Distance(val10, val11); float num4 = PlayerPrefabHeight / num3 * num2; ((Component)val).transform.localScale = new Vector3(num4, num4, num4); Debug.Log((object)$"BettererLethalVRM {Path} has a height of: {num3:0.###}, scaling to {num4:0.###}"); float num5 = Vector3.Distance(val.Humanoid.Hips.position, (val.Humanoid.LeftFoot.position + val.Humanoid.RightFoot.position) / 2f); Transform val12 = UnityExtensions.FindDescendant(PlayerPrefab.transform, "spine"); Transform val13 = UnityExtensions.FindDescendant(PlayerPrefab.transform, "foot.L"); Transform val14 = UnityExtensions.FindDescendant(PlayerPrefab.transform, "foot.R"); float num6 = Vector3.Distance(val12.position, (val13.position + val14.position) / 2f) * num2; ((Component)UnityExtensions.FindDescendant(((Component)Player).transform, "LOD1")).gameObject.SetActive(false); ((Component)UnityExtensions.FindDescendant(((Component)Player).transform, "LOD2")).gameObject.SetActive(false); ((Component)UnityExtensions.FindDescendant(((Component)Player).transform, "LOD3")).gameObject.SetActive(false); ((Component)UnityExtensions.FindDescendant(((Component)Player).transform, "LevelSticker")).gameObject.SetActive(false); ((Component)UnityExtensions.FindDescendant(((Component)Player).transform, "BetaBadge")).gameObject.SetActive(false); foreach (Spring spring in val.SpringBone.Springs) { spring.Center = null; foreach (VRM10SpringBoneJoint joint in spring.Joints) { joint.m_stiffnessForce *= 10f; } } val.Runtime.ReconstructSpringBone(); try { IEnumerable<(ExpressionPreset, VRM10Expression)> clips = val.Vrm.Expression.Clips; (ExpressionPreset, VRM10Expression) tuple2 = clips.FirstOrDefault<(ExpressionPreset, VRM10Expression)>(((ExpressionPreset Preset, VRM10Expression Clip) c) => (int)c.Preset == 11); (ExpressionPreset, VRM10Expression) tuple3 = clips.FirstOrDefault<(ExpressionPreset, VRM10Expression)>(((ExpressionPreset Preset, VRM10Expression Clip) c) => (int)c.Preset == 6); betterLethalVRMInstance.UseVrmBlinkExpression = (Object)(object)tuple2.Item2 != (Object)null && tuple2.Item2.MorphTargetBindings.Any(); betterLethalVRMInstance.UseVrmMouthExpression = (Object)(object)tuple3.Item2 != (Object)null && tuple3.Item2.MorphTargetBindings.Any(); } catch (Exception arg) { Debug.LogError((object)$"BettererLethalVRM {Path} expression auto-detect failed, falling back to config blendshape indices: {arg}"); betterLethalVRMInstance.UseVrmBlinkExpression = false; betterLethalVRMInstance.UseVrmMouthExpression = false; } Debug.Log((object)$"BettererLethalVRM {Path} expressions: blink={betterLethalVRMInstance.UseVrmBlinkExpression}, mouth={betterLethalVRMInstance.UseVrmMouthExpression}"); FaceSettings value; if (((NetworkBehaviour)Player).IsOwner) { betterLethalVRMInstance.BlinkBlendshapeIndex = BlinkBlendshapeIndex.Value; betterLethalVRMInstance.MouthBlendshapeIndex = MouthBlendshapeIndex.Value; betterLethalVRMInstance.BlinkIntervalMin = BlinkIntervalMin.Value; betterLethalVRMInstance.BlinkIntervalMax = BlinkIntervalMax.Value; betterLethalVRMInstance.BlinkDuration = BlinkDuration.Value; } else if (PlayersFaceSettings.TryGetValue(Player.playerClientId, out value)) { betterLethalVRMInstance.BlinkBlendshapeIndex = value.BlinkBlendshapeIndex; betterLethalVRMInstance.MouthBlendshapeIndex = value.MouthBlendshapeIndex; betterLethalVRMInstance.BlinkIntervalMin = value.BlinkIntervalMin; betterLethalVRMInstance.BlinkIntervalMax = value.BlinkIntervalMax; betterLethalVRMInstance.BlinkDuration = value.BlinkDuration; } else { betterLethalVRMInstance.BlinkBlendshapeIndex = -1; betterLethalVRMInstance.MouthBlendshapeIndex = -1; betterLethalVRMInstance.BlinkIntervalMin = BlinkIntervalMin.Value; betterLethalVRMInstance.BlinkIntervalMax = BlinkIntervalMax.Value; betterLethalVRMInstance.BlinkDuration = BlinkDuration.Value; } betterLethalVRMInstance.Vrm10Instance = val; betterLethalVRMInstance.PlayerControllerB = Player; betterLethalVRMInstance.HipOffset = num5 - num6; betterLethalVRMInstance.BoneTranslation = hashSet; Instances.Add(GetTrackingId(betterLethalVRMInstance.PlayerControllerB), betterLethalVRMInstance); Debug.Log((object)("BettererLethalVRM finished loading " + Path)); } private void AnimateBonePairs() { //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (BetterLethalVRMInstance value in Instances.Values) { if ((Object)(object)value.Vrm10Instance == (Object)null || (Object)(object)value.PlayerControllerB == (Object)null) { list.Add(value); continue; } if ((Object)(object)value.DeadBodyRoot == (Object)null) { value.DeadMap = null; value.DeadBodyRoot = null; } bool flag = false; foreach (var item in value.BoneTranslation) { if ((Object)(object)item.target == (Object)null || (Object)(object)item.source == (Object)null) { list.Add(value); flag = true; break; } if (value.DeadMap != null && (Object)(object)value.DeadMap[item.source] == (Object)null) { value.DeadMap = null; value.DeadBodyRoot = null; } } if (flag) { continue; } if (!value.PlayerControllerB.isPlayerDead || (Object)(object)value.DeadBodyRoot == (Object)null) { value.DeadMap = null; value.DeadBodyRoot = null; } if (value.PlayerControllerB.isPlayerDead && (Object)(object)value.DeadBodyRoot == (Object)null && (Object)(object)value.PlayerControllerB.deadBody != (Object)null) { value.SetSkeletonMimic(((Component)value.PlayerControllerB.deadBody).transform); } foreach (var item2 in value.BoneTranslation) { item2.target.rotation = ((value.DeadMap != null) ? value.DeadMap[item2.source].rotation : item2.source.rotation); if (((Object)item2.source.parent).name == "spine") { item2.target.position = ((value.DeadMap != null) ? value.DeadMap[item2.source].position : item2.source.position); var (val, _, _) = item2; val.position += item2.target.up * value.HipOffset; } } value.UpdateVisibility(); } if (!list.Any()) { return; } foreach (BetterLethalVRMInstance item3 in list) { Instances.Remove(GetTrackingId(item3.PlayerControllerB)); PlayersBySteamID.Remove(GetTrackingId(item3.PlayerControllerB)); } } private void OnBeginFrameRendering(ScriptableRenderContext context, Camera[] cameras) { foreach (BetterLethalVRMInstance value in Instances.Values) { if (!((Object)(object)value.Vrm10Instance == (Object)null) && !((Object)(object)value.PlayerControllerB == (Object)null)) { try { value.UpdateBlink(); value.UpdateLipSync(LipSyncSensitivitySelf.Value, LipSyncSensitivityOthers.Value); } catch (Exception arg) { Debug.LogError((object)$"BettererLethalVRM face update failed for {value.PlayerControllerB?.playerUsername}: {arg}"); } } } } internal IEnumerable GetInstances() { return Instances.Values; } private void OnDestroy() { RenderPipelineManager.beginFrameRendering -= OnBeginFrameRendering; CameraPatch.Cleanup(); } } internal class BetterLethalVRMInstance { private const int FirstPersonLayer = 23; private const int ThirdPersonLayer = 0; public readonly HashSet Renderers = new HashSet(); public HashSet<(Transform target, Transform source, Quaternion localRotation)> BoneTranslation = new HashSet<(Transform, Transform, Quaternion)>(); public Transform DeadBodyRoot; public Dictionary DeadMap; public float HipOffset; public PlayerControllerB PlayerControllerB; public Vrm10Instance Vrm10Instance; public bool UseVrmBlinkExpression; public bool UseVrmMouthExpression; public int BlinkBlendshapeIndex; public int MouthBlendshapeIndex; public float BlinkIntervalMin; public float BlinkIntervalMax; public float BlinkDuration; public SkinnedMeshRenderer FaceMeshRenderer; private float _nextBlinkTime = -1f; private float _blinkEndTime; private static readonly float[] _voiceSamples = new float[256]; public void UpdateBlink() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if ((!UseVrmBlinkExpression && (BlinkBlendshapeIndex < 0 || (Object)(object)FaceMeshRenderer == (Object)null || (Object)(object)FaceMeshRenderer.sharedMesh == (Object)null)) || (!UseVrmBlinkExpression && BlinkBlendshapeIndex >= FaceMeshRenderer.sharedMesh.blendShapeCount)) { return; } float time = Time.time; if (_nextBlinkTime < 0f) { _nextBlinkTime = time + Random.Range(BlinkIntervalMin, BlinkIntervalMax); } float num; if (time < _blinkEndTime) { num = 100f; } else { num = 0f; if (time >= _nextBlinkTime) { _blinkEndTime = time + BlinkDuration; _nextBlinkTime = _blinkEndTime + Random.Range(BlinkIntervalMin, BlinkIntervalMax); } } if (UseVrmBlinkExpression) { Vrm10Instance.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset((ExpressionPreset)11), num / 100f); } else { FaceMeshRenderer.SetBlendShapeWeight(BlinkBlendshapeIndex, num); } } public void UpdateLipSync(float sensitivitySelf, float sensitivityOthers) { //IL_0146: Unknown result type (might be due to invalid IL or missing references) if ((!UseVrmMouthExpression && (MouthBlendshapeIndex < 0 || (Object)(object)FaceMeshRenderer == (Object)null || (Object)(object)FaceMeshRenderer.sharedMesh == (Object)null)) || (!UseVrmMouthExpression && MouthBlendshapeIndex >= FaceMeshRenderer.sharedMesh.blendShapeCount)) { return; } float num2; if (((NetworkBehaviour)PlayerControllerB).IsOwner) { DissonanceComms dissonanceComms = BetterLethalVRMManager.Instance.GetDissonanceComms(); VoicePlayerState val = ((dissonanceComms != null) ? dissonanceComms.FindPlayer(dissonanceComms.LocalPlayerName) : null); float num = ((val != null) ? val.Amplitude : 0f); num2 = Mathf.Clamp01(num * sensitivitySelf) * 100f; } else { AudioSource currentVoiceChatAudioSource = PlayerControllerB.currentVoiceChatAudioSource; if ((Object)(object)currentVoiceChatAudioSource != (Object)null && currentVoiceChatAudioSource.isPlaying) { currentVoiceChatAudioSource.GetOutputData(_voiceSamples, 0); float num3 = 0f; float[] voiceSamples = _voiceSamples; foreach (float num4 in voiceSamples) { num3 += num4 * num4; } float num5 = Mathf.Sqrt(num3 / (float)_voiceSamples.Length); num2 = Mathf.Clamp01(num5 * sensitivityOthers) * 100f; } else { num2 = 0f; } } if (UseVrmMouthExpression) { Vrm10Instance.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset((ExpressionPreset)6), num2 / 100f); } else { FaceMeshRenderer.SetBlendShapeWeight(MouthBlendshapeIndex, num2); } } public void SetSkeletonMimic(Transform Root) { //IL_007a: 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_009a: Unknown result type (might be due to invalid IL or missing references) DeadBodyRoot = Root; DeadMap = new Dictionary(); if ((Object)(object)PlayerControllerB.deadBody != (Object)null && (Object)(object)((Component)PlayerControllerB.deadBody).transform == (Object)(object)Root) { ((Object)Root).name = "spine"; } foreach (var item in BoneTranslation) { Transform val = UnityExtensions.FindDescendant(Root, ((Object)item.source.parent).name); Transform transform = new GameObject("VRM Rotation Bone").transform; transform.parent = val; transform.position = val.position; transform.localRotation = item.localRotation; DeadMap[item.source] = transform; } Renderer[] componentsInChildren = ((Component)Root).GetComponentsInChildren(); foreach (Renderer val2 in componentsInChildren) { bool flag = (Object)(object)PlayerControllerB.deadBody != (Object)null && (Object)(object)((Component)PlayerControllerB.deadBody).transform == (Object)(object)Root; bool flag2 = flag; if (!flag2) { bool flag3; switch (((Object)val2).name) { case "LOD1": case "LOD2": case "LOD3": case "LevelSticker": case "BetaBadge": flag3 = true; break; default: flag3 = false; break; } flag2 = flag3; } if (flag2) { val2.enabled = false; } } } public void UpdateVisibility() { bool enabled = !PlayerControllerB.isPlayerDead || ((Object)(object)DeadBodyRoot != (Object)null && (Object)(object)PlayerControllerB.deadBody != (Object)null); bool flag = !((Behaviour)PlayerControllerB.gameplayCamera).enabled; foreach (Renderer renderer in Renderers) { ((Component)renderer).gameObject.layer = ((!flag) ? 23 : 0); renderer.enabled = enabled; } } } [HarmonyPatch(typeof(PlayerControllerB))] public static class CameraPatch { private static float _freeLookH; private static float _freeLookV; private static bool _wasRestricted; private static Vector3 _entryLocalEuler; private static Vector3 _entryLocalPos; internal static void Initialize() { } internal static void Cleanup() { } [HarmonyPatch("LateUpdate")] [HarmonyPostfix] public static void LateUpdatePostfix(PlayerControllerB __instance) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_00ba: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance != (Object)(object)StartOfRound.Instance?.localPlayerController) { return; } BetterLethalVRMManager instance = BetterLethalVRMManager.Instance; if (instance == null || !(instance.FreeLookTerminalLadder?.Value).GetValueOrDefault() || (Object)(object)__instance.gameplayCamera == (Object)null) { return; } Transform transform = ((Component)__instance.gameplayCamera).transform; if (!__instance.inTerminalMenu && !__instance.isClimbingLadder) { if (_wasRestricted) { if (transform.localPosition != _entryLocalPos) { transform.localPosition = _entryLocalPos; } if (transform.localEulerAngles != _entryLocalEuler) { transform.localEulerAngles = _entryLocalEuler; } _freeLookH = 0f; _freeLookV = 0f; } _wasRestricted = false; return; } if (!_wasRestricted) { Vector3 localEulerAngles = transform.localEulerAngles; _entryLocalEuler = new Vector3((localEulerAngles.x > 180f) ? (localEulerAngles.x - 360f) : localEulerAngles.x, localEulerAngles.y, localEulerAngles.z); _entryLocalPos = transform.localPosition; _freeLookH = 0f; _freeLookV = 0f; } _wasRestricted = true; float num = BetterLethalVRMManager.Instance.FreeLookSensitivity.Value * 0.06f; Mouse current = Mouse.current; Vector2 val = ((current != null) ? ((InputControl)(object)((Pointer)current).delta).ReadValue() : Vector2.zero); _freeLookH += val.x * num; _freeLookV -= val.y * num; _freeLookV = Mathf.Clamp(_freeLookV, -80f, 80f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(_entryLocalEuler.x + _freeLookV, _entryLocalEuler.y + _freeLookH, _entryLocalEuler.z); if (transform.localPosition != _entryLocalPos) { transform.localPosition = _entryLocalPos; } if (transform.localEulerAngles != val2) { transform.localEulerAngles = val2; } } catch (Exception arg) { Debug.LogError((object)$"BettererLethalVRM free-look camera update failed: {arg}"); } } } public static class HDRPGltfPbrMaterialImporter { private enum BlendMode { Opaque, Cutout, Fade, Transparent } public const string ShaderName = "HDRP/Lit"; private static readonly int SrcBlend = Shader.PropertyToID("_SrcBlend"); private static readonly int DstBlend = Shader.PropertyToID("_DstBlend"); private static readonly int ZWrite = Shader.PropertyToID("_ZWrite"); private static readonly int Cutoff = Shader.PropertyToID("_Cutoff"); public static Shader Shader => Shader.Find("HDRP/Lit"); public static bool TryCreateParam(GltfData Data, int i, out MaterialDescriptor MatDesc) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Expected O, but got Unknown //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0388: 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_03ca: Unknown result type (might be due to invalid IL or missing references) if (i < 0 || i >= Data.GLTF.materials.Count) { MatDesc = null; return false; } Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); Dictionary dictionary3 = new Dictionary(); Dictionary dictionary4 = new Dictionary(); List> list = new List>(); glTFMaterial tSrc = Data.GLTF.materials[i]; TextureDescriptor? val = null; if (tSrc.pbrMetallicRoughness != null || tSrc.occlusionTexture != null) { SubAssetKey val2 = default(SubAssetKey); TextureDescriptor val3 = default(TextureDescriptor); if ((tSrc.pbrMetallicRoughness.metallicRoughnessTexture != null || tSrc.occlusionTexture != null) && GltfPbrTextureImporter.TryStandardTexture(Data, tSrc, ref val2, ref val3)) { if (string.IsNullOrEmpty(val3.UnityObjectName)) { throw new ArgumentNullException(); } val = val3; } if (tSrc.pbrMetallicRoughness.baseColorFactor != null && tSrc.pbrMetallicRoughness.baseColorFactor.Length == 4) { dictionary3.Add("_BaseColor", ColorConversionExtensions.ToColor4(tSrc.pbrMetallicRoughness.baseColorFactor, (ColorSpace)1, (ColorSpace)0)); } SubAssetKey val4 = default(SubAssetKey); TextureDescriptor value = default(TextureDescriptor); if (tSrc.pbrMetallicRoughness.baseColorTexture != null && ((glTFTextureInfo)tSrc.pbrMetallicRoughness.baseColorTexture).index != -1 && GltfPbrTextureImporter.TryBaseColorTexture(Data, tSrc, ref val4, ref value)) { dictionary.Add("_BaseMap", value); } if (tSrc.pbrMetallicRoughness.metallicRoughnessTexture != null && ((glTFTextureInfo)tSrc.pbrMetallicRoughness.metallicRoughnessTexture).index != -1 && val.HasValue) { list.Add(delegate(Material material) { material.EnableKeyword("_METALLICSPECGLOSSMAP"); }); dictionary.Add("_MetallicGlossMap", val.Value); dictionary2.Add("_Metallic", 1f); dictionary2.Add("_GlossMapScale", 1f); dictionary2.Add("_Smoothness", 1f); } else { dictionary2.Add("_Metallic", tSrc.pbrMetallicRoughness.metallicFactor); dictionary2.Add("_Smoothness", 1f - tSrc.pbrMetallicRoughness.roughnessFactor); } } if (tSrc.normalTexture != null && ((glTFTextureInfo)tSrc.normalTexture).index != -1) { list.Add(delegate(Material material) { material.EnableKeyword("_NORMALMAP"); }); SubAssetKey val5 = default(SubAssetKey); TextureDescriptor value2 = default(TextureDescriptor); if (GltfPbrTextureImporter.TryNormalTexture(Data, tSrc, ref val5, ref value2)) { dictionary.Add("_BumpMap", value2); dictionary2.Add("_BumpScale", tSrc.normalTexture.scale); } } if (tSrc.occlusionTexture != null && ((glTFTextureInfo)tSrc.occlusionTexture).index != -1 && val.HasValue) { dictionary.Add("_OcclusionMap", val.Value); dictionary2.Add("_OcclusionStrength", tSrc.occlusionTexture.strength); } if (tSrc.emissiveFactor != null || (tSrc.emissiveTexture != null && ((glTFTextureInfo)tSrc.emissiveTexture).index != -1)) { list.Add(delegate(Material material) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) material.EnableKeyword("_EMISSION"); material.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)(material.globalIlluminationFlags & -5); }); Color? val6 = GltfMaterialImportUtils.ImportLinearEmissiveFactor(Data, tSrc); if (val6.HasValue) { dictionary3.Add("_EmissionColor", val6.Value); } SubAssetKey val7 = default(SubAssetKey); TextureDescriptor value3 = default(TextureDescriptor); if (tSrc.emissiveTexture != null && ((glTFTextureInfo)tSrc.emissiveTexture).index != -1 && GltfPbrTextureImporter.TryEmissiveTexture(Data, tSrc, ref val7, ref value3)) { dictionary.Add("_EmissionMap", value3); } } list.Add(delegate(Material material) { BlendMode blendMode = BlendMode.Opaque; string alphaMode = tSrc.alphaMode; if (!(alphaMode == "BLEND")) { if (alphaMode == "MASK") { blendMode = BlendMode.Cutout; material.SetOverrideTag("RenderType", "TransparentCutout"); material.SetInt(SrcBlend, 1); material.SetInt(DstBlend, 0); material.SetInt(ZWrite, 1); material.SetFloat(Cutoff, tSrc.alphaCutoff); material.EnableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 2450; } else { blendMode = BlendMode.Opaque; material.SetOverrideTag("RenderType", ""); material.SetInt(SrcBlend, 1); material.SetInt(DstBlend, 0); material.SetInt(ZWrite, 1); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = -1; } } else { blendMode = BlendMode.Fade; material.SetOverrideTag("RenderType", "Transparent"); material.SetInt(SrcBlend, 5); material.SetInt(DstBlend, 10); material.SetInt(ZWrite, 0); material.DisableKeyword("_ALPHATEST_ON"); material.EnableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 3000; } material.SetFloat("_Mode", (float)blendMode); }); MatDesc = new MaterialDescriptor(GltfMaterialImportUtils.ImportMaterialName(i, tSrc), Shader, (int?)null, (IReadOnlyDictionary)dictionary, (IReadOnlyDictionary)dictionary2, (IReadOnlyDictionary)dictionary3, (IReadOnlyDictionary)dictionary4, (IReadOnlyList>)list); return true; } } public sealed class HDRPVrm10MaterialDescriptorGenerator : IMaterialDescriptorGenerator { public MaterialDescriptor Get(GltfData Data, int i) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown if (HDRPVrm10MToonMaterialImporter.TryCreateParam(Data, i, out MaterialDescriptor MatDesc) || HDRPVrm10MToonMaterialImporter.TryCreateParam(Data, i, out MatDesc) || HDRPVrm10MToonMaterialImporter.TryCreateParam(Data, i, out MatDesc)) { return MatDesc; } Debug.LogWarning((object)$"vrm material: {i} out of range. fallback"); Debug.LogError((object)"BettererLethalVRM fallback materials are not supported, try exporting your VRM again using the MToon shader"); return new MaterialDescriptor(GltfMaterialImportUtils.ImportMaterialName(i, (glTFMaterial)null), HDRPGltfPbrMaterialImporter.Shader, (int?)null, (IReadOnlyDictionary)new Dictionary(), (IReadOnlyDictionary)new Dictionary(), (IReadOnlyDictionary)new Dictionary(), (IReadOnlyDictionary)new Dictionary(), (IReadOnlyList>)new Action[0]); } public MaterialDescriptor GetGltfDefault() { return UrpGltfDefaultMaterialImporter.CreateParam(); } } public static class HDRPVrm10MToonMaterialImporter { public static Shader MToonReplacementShader; public static bool TryCreateParam(GltfData Data, int i, out MaterialDescriptor MatDesc) { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown glTFMaterial val = Data.GLTF.materials[i]; VRMC_materials_mtoon val2 = default(VRMC_materials_mtoon); if (!GltfDeserializer.TryGet(val.extensions, ref val2)) { MatDesc = null; return false; } MatDesc = new MaterialDescriptor(val.name, MToonReplacementShader, (int?)null, (IReadOnlyDictionary)Vrm10MToonTextureImporter.EnumerateAllTextures(Data, val, val2).ToDictionary<(string, (SubAssetKey, TextureDescriptor)), string, TextureDescriptor>(((string key, (SubAssetKey, TextureDescriptor)) tuple) => tuple.key, ((string key, (SubAssetKey, TextureDescriptor)) tuple) => tuple.Item2.Item2), (IReadOnlyDictionary)BuiltInVrm10MToonMaterialImporter.TryGetAllFloats(val, val2).ToDictionary<(string, float), string, float>(((string key, float value) tuple) => tuple.key, ((string key, float value) tuple) => tuple.value), (IReadOnlyDictionary)BuiltInVrm10MToonMaterialImporter.TryGetAllColors(val, val2).ToDictionary<(string, Color), string, Color>(((string key, Color value) tuple) => tuple.key, ((string key, Color value) tuple) => tuple.value), (IReadOnlyDictionary)BuiltInVrm10MToonMaterialImporter.TryGetAllFloatArrays(val, val2).ToDictionary<(string, Vector4), string, Vector4>(((string key, Vector4 value) tuple) => tuple.key, ((string key, Vector4 value) tuple) => tuple.value), (IReadOnlyList>)new Action[1] { delegate(Material material) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) new MToonValidator(material).Validate(); } }); return true; } } [HarmonyPatch] public static class MessagePatch { private const char SPERATOR = ';'; private const string FACE_PREFIX = "[bettererlethalvrm.face]"; private static MethodInfo addTextMessageServerRpc = AccessTools.Method(typeof(HUDManager), "AddTextMessageServerRpc", (Type[])null, (Type[])null); private static string BuildFaceMessage(ulong targetId, ulong ownerId, int blinkIdx, int mouthIdx, float min, float max, float dur) { return string.Join(';'.ToString(), "[bettererlethalvrm.face]", targetId, ownerId, blinkIdx, mouthIdx, min.ToString(CultureInfo.InvariantCulture), max.ToString(CultureInfo.InvariantCulture), dur.ToString(CultureInfo.InvariantCulture)); } private static void SendFaceSettings(ulong targetClientId, ulong ownerClientId) { BetterLethalVRMManager instance = BetterLethalVRMManager.Instance; addTextMessageServerRpc?.Invoke(HUDManager.Instance, new object[1] { BuildFaceMessage(targetClientId, ownerClientId, instance.BlinkBlendshapeIndex.Value, instance.MouthBlendshapeIndex.Value, instance.BlinkIntervalMin.Value, instance.BlinkIntervalMax.Value, instance.BlinkDuration.Value) }); } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] public static void ConnectClientToPlayerObject_postfix(PlayerControllerB __instance) { try { BetterLethalVRMManager.Instance.PlayersScale.Clear(); BetterLethalVRMManager.Instance.PlayersFaceSettings.Clear(); addTextMessageServerRpc?.Invoke(HUDManager.Instance, new object[1] { $"[bettererlethalvrm.size];{ulong.MaxValue};{__instance.playerClientId};{BetterLethalVRMManager.Instance.ScaleSize.Value}" }); SendFaceSettings(ulong.MaxValue, __instance.playerClientId); } catch (Exception arg) { Debug.LogError((object)$"BettererLethalVRM connect postfix failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(HUDManager), "AddTextMessageServerRpc")] public static void AddTextMessagesServerRpc_postfix(HUDManager __instance, string chatMessage) { try { NetworkManager networkManager = ((NetworkBehaviour)__instance).NetworkManager; if ((Object)(object)networkManager == (Object)null || !networkManager.IsListening) { return; } if (chatMessage.StartsWith("[bettererlethalvrm.size]")) { Debug.Log((object)("BettererLethalVRM: server get message: " + chatMessage)); if (!networkManager.IsHost) { return; } string[] array = chatMessage.Split(';'); ulong num = ulong.Parse(array[1]); ulong num2 = ulong.Parse(array[2]); if (num != ulong.MaxValue) { return; } { foreach (KeyValuePair item in BetterLethalVRMManager.Instance.PlayersScale.ToList()) { if (item.Key != num2) { addTextMessageServerRpc?.Invoke(__instance, new object[1] { $"[bettererlethalvrm.size];{num2};{item.Key};{item.Value}" }); } } return; } } if (!chatMessage.StartsWith("[bettererlethalvrm.face]")) { return; } Debug.Log((object)("BettererLethalVRM: server get message: " + chatMessage)); if (!networkManager.IsHost) { return; } string[] array2 = chatMessage.Split(';'); ulong num3 = ulong.Parse(array2[1]); ulong num4 = ulong.Parse(array2[2]); if (num3 != ulong.MaxValue) { return; } foreach (KeyValuePair item2 in BetterLethalVRMManager.Instance.PlayersFaceSettings.ToList()) { if (item2.Key != num4) { BetterLethalVRMManager.FaceSettings value = item2.Value; addTextMessageServerRpc?.Invoke(__instance, new object[1] { BuildFaceMessage(num4, item2.Key, value.BlinkBlendshapeIndex, value.MouthBlendshapeIndex, value.BlinkIntervalMin, value.BlinkIntervalMax, value.BlinkDuration) }); } } } catch (Exception arg) { Debug.LogError((object)$"BettererLethalVRM server message handler failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(HUDManager), "AddTextMessageClientRpc")] public static void AddTextMessageClientRpc_postfix(HUDManager __instance, string chatMessage) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) try { NetworkManager networkManager = ((NetworkBehaviour)__instance).NetworkManager; if ((Object)(object)networkManager == (Object)null || !networkManager.IsListening) { return; } if (chatMessage.StartsWith("[bettererlethalvrm.size]")) { Debug.Log((object)("BettererLethalVRM: client get message: " + chatMessage)); if (networkManager.IsClient || networkManager.IsHost) { string[] array = chatMessage.Split(';'); ulong num = ulong.Parse(array[1]); ulong num2 = ulong.Parse(array[2]); float num3 = float.Parse(array[3]); if (num == ulong.MaxValue || num == Convert.ToUInt64(StartOfRound.Instance.thisClientPlayerId)) { BetterLethalVRMManager.Instance.PlayersScale[num2] = num3; StartOfRound.Instance.allPlayerObjects[num2].transform.localScale = new Vector3(num3, num3, num3); } } } else { if (!chatMessage.StartsWith("[bettererlethalvrm.face]")) { return; } Debug.Log((object)("BettererLethalVRM: client get message: " + chatMessage)); if (!networkManager.IsClient && !networkManager.IsHost) { return; } string[] array2 = chatMessage.Split(';'); ulong num4 = ulong.Parse(array2[1]); ulong num5 = ulong.Parse(array2[2]); if (num4 != ulong.MaxValue && num4 != Convert.ToUInt64(StartOfRound.Instance.thisClientPlayerId)) { return; } BetterLethalVRMManager.FaceSettings faceSettings = default(BetterLethalVRMManager.FaceSettings); faceSettings.BlinkBlendshapeIndex = int.Parse(array2[3]); faceSettings.MouthBlendshapeIndex = int.Parse(array2[4]); faceSettings.BlinkIntervalMin = float.Parse(array2[5], CultureInfo.InvariantCulture); faceSettings.BlinkIntervalMax = float.Parse(array2[6], CultureInfo.InvariantCulture); faceSettings.BlinkDuration = float.Parse(array2[7], CultureInfo.InvariantCulture); BetterLethalVRMManager.FaceSettings value = faceSettings; BetterLethalVRMManager.Instance.PlayersFaceSettings[num5] = value; { foreach (BetterLethalVRMInstance instance in BetterLethalVRMManager.Instance.GetInstances()) { if (instance.PlayerControllerB.playerClientId == num5) { instance.BlinkBlendshapeIndex = value.BlinkBlendshapeIndex; instance.MouthBlendshapeIndex = value.MouthBlendshapeIndex; instance.BlinkIntervalMin = value.BlinkIntervalMin; instance.BlinkIntervalMax = value.BlinkIntervalMax; instance.BlinkDuration = value.BlinkDuration; break; } } return; } } } catch (Exception arg) { Debug.LogError((object)$"BettererLethalVRM client message handler failed: {arg}"); } } } }