using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BoneLib; using BoneLib.BoneMenu; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Marrow; using Il2CppSLZ.VRMK; using Il2CppSystem; using MelonLoader; using Microsoft.CodeAnalysis; using OffsetRemover; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "Head Offset Remover", "1.0.0", "Hiiiiii :3", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OffsetRemover { internal sealed class BonePair { public Transform src; public Transform dst; public bool isHeadSubtree; public Vector3 headRestLocal; } internal sealed class RendererPair { public Renderer src; public Renderer dst; public bool forceDisable; } public class Core : MelonMod { private enum CameraKind { Headset, Spectator, Other } public static GameObject headlessAvatarClone; public static Animator headlessAvatarCloneAnimator; public static bool IsEnabled = true; public static bool ignoreSpectator = true; private static BonePair[] bonePairsArr = new BonePair[0]; private static int bonePairCount = 0; private static RendererPair[] rendererPairsArr = new RendererPair[0]; private static int rendererPairCount = 0; private static readonly Dictionary cameraKindCache = new Dictionary(); private static Transform headBoneOnClone; private static Transform headBoneOnSource; private static Vector3 headLocalRestPosition; private static Quaternion headLocalRestRotation; private static bool hasHeadCorrection; private static Dictionary headSubtreeLocalPositions = new Dictionary(StringComparer.OrdinalIgnoreCase); private static List selfRenderers = new List(64); private static List cloneAvatarRenderers = new List(64); private static int cloneBuiltForAvatarId = 0; private static volatile bool buildInProgress = false; private static float lastBuildAttemptTime = -999f; private const float RetryCooldownSeconds = 3f; private const float MinAcceptableRendererFraction = 0.5f; private static float lastErrorLogTime = -999f; private const float ErrorLogCooldownSeconds = 5f; private static readonly StringBuilder pathSb = new StringBuilder(256); private static readonly string[] nameStack = new string[64]; private static int lastSyncedFrame = -1; private static readonly HashSet ExcludedBoneNames = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet boneCollectScratch = new HashSet(); private static CameraKind ClassifyCamera(Camera cam) { int instanceID = ((Object)cam).GetInstanceID(); if (cameraKindCache.TryGetValue(instanceID, out var value)) { return value; } value = ((!(((Object)cam).name == "Headset")) ? ((((Object)cam).name == "Spectator Camera") ? CameraKind.Spectator : CameraKind.Other) : CameraKind.Headset); cameraKindCache[instanceID] = value; return value; } public override void OnInitializeMelon() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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) MelonLogger.Msg("[OffsetRemover] Community Patch loaded."); RenderPipelineManager.beginCameraRendering += Action.op_Implicit((Action)OnBeginCameraRendering); Hooking.OnSwitchAvatarPostfix += delegate { if (IsEnabled) { MelonCoroutines.Start(RebuildClone(Player.RigManager)); } }; Page obj = Page.Root.CreatePage("OffsetRemover", Color.green, 0, true); obj.CreateBool("Enable OffsetRemover", Color.white, IsEnabled, (Action)delegate(bool v) { IsEnabled = v; if (!v) { DisableAndCleanUp(); ApplyVisibilityToAllCameras(); } else { ForceRebuild(); ApplyVisibilityToAllCameras(); } }); obj.CreateBool("Don't Fix Spectator Camera", Color.yellow, ignoreSpectator, (Action)delegate(bool v) { ignoreSpectator = v; ApplyVisibilityToAllCameras(); }); obj.CreateFunction("Rebuild Clone", Color.red, (Action)ForceRebuild); MelonCoroutines.Start(SelfHealLoop()); } private static void DisableAndCleanUp() { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager != (Object)null && Object.op_Implicit((Object)(object)rigManager.avatar)) { Il2CppArrayBase componentsInChildren = ((Component)rigManager.avatar).gameObject.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!((Object)(object)componentsInChildren[i] == (Object)null)) { try { componentsInChildren[i].forceRenderingOff = false; } catch { } } } } if ((Object)(object)headlessAvatarClone != (Object)null) { Object.DestroyImmediate((Object)(object)headlessAvatarClone); } ResetCloneState(); } private static void ApplyVisibilityToAllCameras() { try { foreach (Camera item in (Il2CppArrayBase)(object)Camera.allCameras) { if ((Object)(object)item != (Object)null) { CheckRenderLoop(ClassifyCamera(item)); } } } catch { } } private static void OnBeginCameraRendering(ScriptableRenderContext ctx, Camera cam) { if (!IsEnabled) { return; } try { CameraKind num = ClassifyCamera(cam); if (num != CameraKind.Headset) { SyncCloneIfNeeded(); } CheckRenderLoop(num); } catch (Exception value) { if (Time.time - lastErrorLogTime > 5f) { lastErrorLogTime = Time.time; MelonLogger.Error($"[OffsetRemover] Render hook error: {value}"); } } } private static IEnumerator SelfHealLoop() { while (true) { yield return (object)new WaitForSeconds(2f); if (!IsEnabled) { continue; } RigManager rigManager = Player.RigManager; if (!((Object)(object)rigManager == (Object)null) && Object.op_Implicit((Object)(object)rigManager.avatar)) { int instanceID = ((Object)rigManager.avatar).GetInstanceID(); if ((!((Object)(object)headlessAvatarClone != (Object)null) || cloneBuiltForAvatarId != instanceID) && !buildInProgress && Time.time - lastBuildAttemptTime > 3f) { MelonCoroutines.Start(RebuildClone(rigManager)); } } } } private static void SyncCloneIfNeeded() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)headlessAvatarCloneAnimator == (Object)null || Time.frameCount == lastSyncedFrame) { return; } lastSyncedFrame = Time.frameCount; try { BonePair[] array = bonePairsArr; for (int i = 0; i < bonePairCount; i++) { BonePair bonePair = array[i]; Transform src = bonePair.src; Transform dst = bonePair.dst; if (!((Object)(object)src == (Object)null) && !((Object)(object)dst == (Object)null)) { if (bonePair.isHeadSubtree) { dst.localPosition = bonePair.headRestLocal; dst.localRotation = src.localRotation; } else { dst.SetPositionAndRotation(src.position, src.rotation); } } } RendererPair[] array2 = rendererPairsArr; for (int j = 0; j < rendererPairCount; j++) { RendererPair rendererPair = array2[j]; Renderer src2 = rendererPair.src; Renderer dst2 = rendererPair.dst; if (!((Object)(object)src2 == (Object)null) && !((Object)(object)dst2 == (Object)null)) { if (rendererPair.forceDisable) { dst2.forceRenderingOff = true; continue; } dst2.forceRenderingOff = false; dst2.enabled = src2.enabled && ((Component)src2).gameObject.activeInHierarchy; } } if (hasHeadCorrection && (Object)(object)headBoneOnSource == (Object)null && (Object)(object)headBoneOnClone != (Object)null) { headBoneOnClone.localRotation = headLocalRestRotation; } } catch (Exception ex) { if (Time.time - lastErrorLogTime > 5f) { lastErrorLogTime = Time.time; MelonLogger.Warning("[OffsetRemover] Clone sync failed, rebuilding: " + ex.Message); } if ((Object)(object)headlessAvatarClone != (Object)null) { Object.DestroyImmediate((Object)(object)headlessAvatarClone); } ResetCloneState(); } } public static void ForceRebuild() { if (!IsEnabled) { MelonLogger.Msg("[OffsetRemover] Rebuild ignored -- disabled."); return; } RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null) { MelonLogger.Warning("[OffsetRemover] Rebuild: no RigManager."); } else { MelonCoroutines.Start(RebuildClone(rigManager)); } } private static IEnumerator RebuildClone(RigManager manager) { if (buildInProgress) { yield break; } buildInProgress = true; lastBuildAttemptTime = Time.time; cameraKindCache.Clear(); if ((Object)(object)headlessAvatarClone != (Object)null) { Object.DestroyImmediate((Object)(object)headlessAvatarClone); } ResetCloneState(); float waitStart = Time.time; while ((Object)(object)manager == (Object)null || !Object.op_Implicit((Object)(object)manager.avatar) || (Object)(object)manager.avatar.animator == (Object)null || ((Component)manager.avatar).gameObject.GetComponentsInChildren(true).Length == 0) { if (Time.time - waitStart > 5f) { buildInProgress = false; yield break; } yield return null; } selfRenderers.Clear(); Il2CppArrayBase componentsInChildren = ((Component)manager.avatar).gameObject.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { selfRenderers.Add(componentsInChildren[i]); } GameObject val = null; bool flag = true; try { GameObject val2 = new GameObject("DISABLED CONTAINER"); val2.SetActive(false); val = Object.Instantiate(((Component)manager.avatar).gameObject, val2.transform); CleanClone(val); val.transform.parent = null; Object.Destroy((Object)(object)val2); } catch (Exception ex) { flag = false; _ = "instantiate/clean: " + ex.Message; } if (!flag) { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } ResetCloneState(); buildInProgress = false; yield break; } cloneAvatarRenderers.Clear(); Il2CppArrayBase componentsInChildren2 = val.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { cloneAvatarRenderers.Add(componentsInChildren2[j]); } int length = componentsInChildren.Length; Avatar componentInChildren = val.GetComponentInChildren(); Animator clnAnim = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.animator : null); try { BuildPairings(manager.avatar.animator, clnAnim, ((Component)manager.avatar).gameObject, val); } catch (Exception ex2) { flag = false; _ = "pairing: " + ex2.Message; } if (length > 0 && (float)cloneAvatarRenderers.Count < (float)length * 0.5f) { flag = false; } if (!flag) { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } ResetCloneState(); buildInProgress = false; yield break; } ((Object)val).name = "HEADFIX DISPLAY CLONE"; headlessAvatarClone = val; headlessAvatarCloneAnimator = clnAnim; cloneBuiltForAvatarId = ((Object)manager.avatar).GetInstanceID(); buildInProgress = false; ApplyVisibilityToAllCameras(); MelonLogger.Msg($"[OffsetRemover] Clone built -- bonePairs={bonePairCount}, renderers={cloneAvatarRenderers.Count}, headCorrection={(hasHeadCorrection ? "yes" : "no")}"); } private static void BuildPairings(Animator srcAnim, Animator clnAnim, GameObject srcRoot, GameObject clnRoot) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) headBoneOnClone = null; headBoneOnSource = null; hasHeadCorrection = false; headLocalRestPosition = Vector3.zero; headLocalRestRotation = Quaternion.identity; headSubtreeLocalPositions.Clear(); Transform[] array = CollectSkinnedBones(srcRoot); Transform[] array2 = CollectSkinnedBones(clnRoot); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); Dictionary dictionary2 = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (Transform val in array) { if (!((Object)(object)val == (Object)null)) { string relativePathFast = GetRelativePathFast(val, srcRoot.transform); if (!dictionary.ContainsKey(relativePathFast)) { dictionary[relativePathFast] = val; } } } foreach (Transform val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { string relativePathFast2 = GetRelativePathFast(val2, clnRoot.transform); if (!dictionary2.ContainsKey(relativePathFast2)) { dictionary2[relativePathFast2] = val2; } } } Transform val3 = (((Object)(object)srcAnim != (Object)null && srcAnim.isHuman) ? srcAnim.GetBoneTransform((HumanBodyBones)10) : null); Transform val4 = (((Object)(object)clnAnim != (Object)null && clnAnim.isHuman) ? clnAnim.GetBoneTransform((HumanBodyBones)10) : null); if ((Object)(object)val4 == (Object)null) { foreach (KeyValuePair item in dictionary2) { if (item.Key.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0) { val4 = item.Value; break; } } } if ((Object)(object)val3 == (Object)null) { foreach (KeyValuePair item2 in dictionary) { if (item2.Key.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0) { val3 = item2.Value; break; } } } if ((Object)(object)val4 != (Object)null) { if (clnAnim != null) { clnAnim.Rebind(); } if (clnAnim != null) { clnAnim.Update(0f); } headBoneOnClone = val4; headBoneOnSource = val3; headLocalRestPosition = val4.localPosition; headLocalRestRotation = val4.localRotation; hasHeadCorrection = true; Il2CppArrayBase componentsInChildren = ((Component)val4).GetComponentsInChildren(true); for (int k = 0; k < componentsInChildren.Length; k++) { Transform val5 = componentsInChildren[k]; if (!((Object)(object)val5 == (Object)null) && !headSubtreeLocalPositions.ContainsKey(((Object)val5).name)) { headSubtreeLocalPositions[((Object)val5).name] = val5.localPosition; } } } EnsureBonePairCapacity(array.Length); EnsureRendererPairCapacity(Math.Max(16, clnRendersCountEstimate(clnRoot))); bonePairCount = 0; rendererPairCount = 0; HashSet hashSet = new HashSet(); foreach (KeyValuePair item3 in dictionary) { if (dictionary2.TryGetValue(item3.Key, out var value)) { BonePair bonePair = new BonePair { src = item3.Value, dst = value, isHeadSubtree = IsInHeadSubtreeCached(value) }; if (bonePair.isHeadSubtree && headSubtreeLocalPositions.TryGetValue(((Object)value).name, out var value2)) { bonePair.headRestLocal = value2; } bonePairsArr[bonePairCount++] = bonePair; hashSet.Add(value); } } Dictionary> dictionary3 = BuildNameMap(array); Dictionary> dictionary4 = BuildNameMap(array2); foreach (KeyValuePair> item4 in dictionary3) { List value3 = item4.Value; if (!dictionary4.TryGetValue(item4.Key, out var value4) || value4.Count == 0) { continue; } for (int l = 0; l < value3.Count; l++) { Transform val6 = value3[l]; bool flag = false; for (int m = 0; m < bonePairCount; m++) { if ((Object)(object)bonePairsArr[m].src == (Object)(object)val6) { flag = true; break; } } if (flag) { continue; } Transform val7 = null; for (int n = 0; n < value4.Count; n++) { if (!hashSet.Contains(value4[n])) { val7 = value4[n]; break; } } if ((Object)(object)val7 == (Object)null) { val7 = value4[0]; } if (!((Object)(object)val7 == (Object)null)) { BonePair bonePair2 = new BonePair { src = val6, dst = val7, isHeadSubtree = IsInHeadSubtreeCached(val7) }; if (bonePair2.isHeadSubtree && headSubtreeLocalPositions.TryGetValue(((Object)val7).name, out var value5)) { bonePair2.headRestLocal = value5; } bonePairsArr[bonePairCount++] = bonePair2; hashSet.Add(val7); } } } Il2CppArrayBase componentsInChildren2 = srcRoot.GetComponentsInChildren(true); Il2CppArrayBase componentsInChildren3 = clnRoot.GetComponentsInChildren(true); Dictionary> dictionary5 = new Dictionary>(StringComparer.OrdinalIgnoreCase); for (int num = 0; num < componentsInChildren3.Length; num++) { Renderer val8 = componentsInChildren3[num]; if (!((Object)(object)val8 == (Object)null)) { if (!dictionary5.TryGetValue(((Object)val8).name, out var value6)) { value6 = new List(2); dictionary5[((Object)val8).name] = value6; } value6.Add(val8); } } HashSet hashSet2 = new HashSet(); for (int num2 = 0; num2 < componentsInChildren2.Length; num2++) { Renderer val9 = componentsInChildren2[num2]; if ((Object)(object)val9 == (Object)null || string.IsNullOrEmpty(((Object)val9).name) || !dictionary5.TryGetValue(((Object)val9).name, out var value7) || value7.Count == 0) { continue; } Renderer val10 = null; for (int num3 = 0; num3 < value7.Count; num3++) { if (!hashSet2.Contains(value7[num3])) { val10 = value7[num3]; break; } } if ((Object)(object)val10 == (Object)null) { val10 = value7[0]; } if (!((Object)(object)val10 == (Object)null)) { try { val10.sharedMaterials = val9.sharedMaterials; } catch { } RendererPair rendererPair = new RendererPair { src = val9, dst = val10, forceDisable = ((Object)(object)val9.sharedMaterial != (Object)null && (Object)(object)val9.sharedMaterial.shader != (Object)null && ((Object)val9.sharedMaterial.shader).name == "SLZ/Icon Billboard") }; rendererPairsArr[rendererPairCount++] = rendererPair; hashSet2.Add(val10); } } } private static Transform[] CollectSkinnedBones(GameObject root) { boneCollectScratch.Clear(); Il2CppArrayBase componentsInChildren = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Il2CppReferenceArray bones = componentsInChildren[i].bones; if (bones == null) { continue; } for (int j = 0; j < ((Il2CppArrayBase)(object)bones).Length; j++) { if ((Object)(object)((Il2CppArrayBase)(object)bones)[j] != (Object)null) { boneCollectScratch.Add(((Il2CppArrayBase)(object)bones)[j]); } } } Transform[] array = (Transform[])(object)new Transform[boneCollectScratch.Count]; boneCollectScratch.CopyTo(array); return array; } private static int clnRendersCountEstimate(GameObject clnRoot) { return clnRoot.GetComponentsInChildren(true)?.Length ?? 0; } private static bool IsInHeadSubtreeCached(Transform t) { if (!hasHeadCorrection || (Object)(object)t == (Object)null || (Object)(object)headBoneOnClone == (Object)null) { return false; } Transform val = t; while ((Object)(object)val != (Object)null) { if ((Object)(object)val == (Object)(object)headBoneOnClone) { return true; } val = val.parent; } return false; } private static Dictionary> BuildNameMap(Transform[] arr) { Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (Transform val in arr) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name)) { if (!dictionary.TryGetValue(((Object)val).name, out var value)) { value = new List(2); dictionary[((Object)val).name] = value; } value.Add(val); } } return dictionary; } private static void EnsureBonePairCapacity(int needed) { if (bonePairsArr.Length < needed) { BonePair[] array = new BonePair[Math.Max(needed, Math.Max(8, bonePairsArr.Length * 2))]; for (int i = 0; i < bonePairsArr.Length; i++) { array[i] = bonePairsArr[i]; } bonePairsArr = array; } } private static void EnsureRendererPairCapacity(int needed) { if (rendererPairsArr.Length < needed) { RendererPair[] array = new RendererPair[Math.Max(needed, Math.Max(8, rendererPairsArr.Length * 2))]; for (int i = 0; i < rendererPairsArr.Length; i++) { array[i] = rendererPairsArr[i]; } rendererPairsArr = array; } } private static void ResetCloneState() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) headlessAvatarClone = null; headlessAvatarCloneAnimator = null; headBoneOnClone = null; headBoneOnSource = null; hasHeadCorrection = false; headLocalRestPosition = Vector3.zero; headLocalRestRotation = Quaternion.identity; headSubtreeLocalPositions.Clear(); bonePairCount = 0; rendererPairCount = 0; selfRenderers.Clear(); cloneAvatarRenderers.Clear(); } private static void CleanClone(GameObject clone) { try { SafeDestroyAll(Il2CppArrayBase.op_Implicit(clone.GetComponentsInChildren(true))); } catch { } try { SafeDestroyAll(Il2CppArrayBase.op_Implicit(clone.GetComponentsInChildren(true))); } catch { } try { SafeDestroyAll(Il2CppArrayBase.op_Implicit(clone.GetComponentsInChildren(true))); } catch { } try { SafeDestroyAll(Il2CppArrayBase.op_Implicit(clone.GetComponentsInChildren(true))); } catch { } Il2CppArrayBase componentsInChildren = clone.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { MonoBehaviour val = componentsInChildren[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Il2CppObjectBase)val).TryCast() != (Object)null) { continue; } PlayerAvatarArt val2 = ((Il2CppObjectBase)val).TryCast(); if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = false; continue; } try { Object.DestroyImmediate((Object)(object)val); } catch { } } } private static void SafeDestroyAll(T[] comps) where T : Object { foreach (T val in comps) { if (!((Object)(object)val == (Object)null)) { try { Object.DestroyImmediate((Object)(object)val); } catch { } } } } private static string GetRelativePathFast(Transform t, Transform root) { if ((Object)(object)t == (Object)(object)root) { return ""; } int num = 0; Transform val = t; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root && num < nameStack.Length) { nameStack[num++] = ((Object)val).name; val = val.parent; } pathSb.Clear(); for (int num2 = num - 1; num2 >= 0; num2--) { pathSb.Append(nameStack[num2]); if (num2 > 0) { pathSb.Append('/'); } } return pathSb.ToString(); } private static void CheckRenderLoop(CameraKind kind) { if (!Player.HandsExist || !Object.op_Implicit((Object)(object)Player.Avatar)) { return; } bool flag = kind switch { CameraKind.Headset => true, CameraKind.Spectator => ignoreSpectator, _ => false, }; bool flag2 = (Object)(object)headlessAvatarClone != (Object)null && cloneAvatarRenderers.Count > 0; if (flag || !flag2) { ToggleAvatarVisibility(selfRenderers, visible: true); if ((Object)(object)headlessAvatarClone != (Object)null) { ToggleAvatarVisibility(cloneAvatarRenderers, visible: false); } } else { ToggleAvatarVisibility(selfRenderers, visible: false); ToggleAvatarVisibility(cloneAvatarRenderers, visible: true); } } private static void ToggleAvatarVisibility(List renderers, bool visible) { for (int i = 0; i < renderers.Count; i++) { Renderer val = renderers[i]; if (!((Object)(object)val == (Object)null)) { try { val.forceRenderingOff = !visible; } catch { } } } } } }