using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.VRMK;
using Il2CppSystem.Collections.Generic;
using InvisibleTouch;
using LabFusion.Entities;
using LabFusion.Marrow.Extenders;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.SDK.Metadata;
using LabFusion.SDK.Modules;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Preferences;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("InvisibleTouch")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: MelonInfo(typeof(Main), "Invisible Touch", "1.0.0", "MyFirstTeam", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace InvisibleTouch;
public enum ControllerBinding
{
LeftStickClick,
RightStickClick,
Disabled
}
public enum HapticPattern
{
OneOnTwoOff,
TwoOnOneOff,
SinglePulse,
DoublePulse
}
public enum HapticTarget
{
Auto,
Left,
Right,
Both
}
public static class InvisibilityManager
{
private sealed class RemoteState
{
public bool Invisible;
public ItemHidingMode ItemHiding = ItemHidingMode.HeldAndHolstered;
}
private sealed class RemoteVisualHide
{
public int RigId;
public readonly List<Renderer> DisabledRenderers = new List<Renderer>();
}
private sealed class RemoteItemHide
{
public byte SmallId;
public readonly List<Renderer> DisabledRenderers = new List<Renderer>();
}
private sealed class HandMeshSwap
{
public SkinnedMeshRenderer Renderer;
public Mesh OriginalMesh;
public Mesh HandMesh;
public int RendererId;
}
public const string MetadataKey = "InvisibleTouch_IsInvisible";
internal const string ItemHidingMetadataKey = "InvisibleTouch_ItemHiding";
private const float ReconcileIntervalSeconds = 0.5f;
private const float HapticPulseGapSeconds = 0.09f;
private static int _cooldownSeconds = 5;
private static float _hapticStrength = 1f;
private static readonly Dictionary<byte, RemoteState> _remoteStates = new Dictionary<byte, RemoteState>();
private static readonly Dictionary<byte, RemoteVisualHide> _remoteVisualHides = new Dictionary<byte, RemoteVisualHide>();
private static readonly Dictionary<ushort, RemoteItemHide> _remoteItemHides = new Dictionary<ushort, RemoteItemHide>();
private static readonly List<Renderer> _hiddenSelfRenderers = new List<Renderer>();
private static readonly List<HandMeshSwap> _handMeshSwaps = new List<HandMeshSwap>();
private static readonly Dictionary<string, Mesh> _handMeshCache = new Dictionary<string, Mesh>();
private static readonly HashSet<string> _handMeshFailures = new HashSet<string>();
private static bool _fusionHooksInitialized = false;
private static bool _previousBindingPressed = false;
private static float _nextReconcileTime = 0f;
private static float _lastToggleTime = float.NegativeInfinity;
private static float _nextToggleAllowedTime = 0f;
private static bool _reconcileWarningLogged = false;
private static bool _itemWarningLogged = false;
private static bool _visualHideWarningLogged = false;
private static bool _hapticsWarningLogged = false;
private static bool _handMeshWarningLogged = false;
private static string _lastHandsOnlyLogSignature = null;
public static bool IsInvisible { get; private set; }
public static SelfViewMode SelfView { get; set; } = SelfViewMode.FullBody;
public static bool ShowSelf
{
get
{
return SelfView != SelfViewMode.Hidden;
}
set
{
SelfView = ((!value) ? SelfViewMode.Hidden : SelfViewMode.FullBody);
}
}
public static ControllerBinding Binding { get; set; } = ControllerBinding.LeftStickClick;
public static ItemHidingMode ItemHiding { get; set; } = ItemHidingMode.HeldAndHolstered;
public static int CooldownSeconds
{
get
{
return _cooldownSeconds;
}
set
{
_cooldownSeconds = Mathf.Clamp(value, 0, 60);
}
}
public static bool HapticsEnabled { get; set; } = true;
public static HapticPattern HapticPattern { get; set; } = HapticPattern.OneOnTwoOff;
public static HapticTarget HapticTarget { get; set; } = HapticTarget.Auto;
public static float HapticStrength
{
get
{
return _hapticStrength;
}
set
{
_hapticStrength = ((float.IsNaN(value) || float.IsInfinity(value)) ? 1f : Mathf.Clamp(value, 0.25f, 2f));
}
}
internal static Instance Log { get; set; }
public static event Action<bool> OnLocalInvisibleChanged;
public static void Toggle()
{
SetInvisible(!IsInvisible, "toggle");
}
private static void ToggleFromController()
{
SetInvisible(!IsInvisible, "controller", fromController: true);
}
public static void SetInvisible(bool value, string source = null, bool fromController = false)
{
if (IsInvisible == value)
{
return;
}
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (realtimeSinceStartup < _nextToggleAllowedTime)
{
InvisibilityManager.OnLocalInvisibleChanged?.Invoke(IsInvisible);
Instance log = Log;
if (log != null)
{
log.Msg($"Invisibility toggle blocked by cooldown ({_nextToggleAllowedTime - realtimeSinceStartup:0.0}s left).");
}
return;
}
_lastToggleTime = realtimeSinceStartup;
_nextToggleAllowedTime = realtimeSinceStartup + (float)CooldownSeconds;
IsInvisible = value;
PublishLocalState();
ApplySelfVisibility();
PlayToggleHaptics(value, fromController);
InvisibilityManager.OnLocalInvisibleChanged?.Invoke(value);
Instance log2 = Log;
if (log2 != null)
{
log2.Msg("Invisibility " + (value ? "ON" : "OFF") + ((source != null) ? (" (" + source + ")") : string.Empty) + (NetworkInfo.HasServer ? string.Empty : " - not in a server, state will apply on join"));
}
}
public static void OnSelfViewChanged()
{
ApplySelfVisibility();
}
public static void OnShowSelfChanged()
{
OnSelfViewChanged();
}
public static void OnCooldownChanged()
{
if (float.IsNegativeInfinity(_lastToggleTime))
{
_nextToggleAllowedTime = 0f;
}
else
{
_nextToggleAllowedTime = _lastToggleTime + (float)CooldownSeconds;
}
}
public static void OnItemHidingChanged()
{
PublishLocalState();
}
private static void PublishLocalState()
{
TryPublishMetadata("InvisibleTouch_IsInvisible", IsInvisible.ToString());
TryPublishMetadata("InvisibleTouch_ItemHiding", ItemHiding.ToString());
}
private static void TryPublishMetadata(string key, string value)
{
try
{
PlayerMetadata metadata = LocalPlayer.Metadata;
if (metadata != null)
{
NetworkMetadata metadata2 = metadata.Metadata;
if (metadata2 != null)
{
metadata2.TrySetMetadata(key, value);
}
}
}
catch (Exception ex)
{
Instance log = Log;
if (log != null)
{
log.Warning("Failed to publish invisibility metadata '" + key + "': " + ex.Message);
}
}
}
internal static void InitializeFusionHooks()
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Expected O, but got Unknown
if (!_fusionHooksInitialized)
{
_fusionHooksInitialized = true;
PlayerID.OnMetadataChangedEvent += OnRemoteMetadataChanged;
PlayerID.OnMetadataRemovedEvent += OnRemoteMetadataRemoved;
NetworkPlayer.OnNetworkPlayerRegistered += OnNetworkPlayerRegistered;
NetworkPlayer.OnNetworkRigCreated += OnNetworkRigCreated;
LocalPlayer.OnApplyInitialMetadata += PublishLocalState;
MultiplayerHooking.OnPlayerLeft += new PlayerUpdate(OnPlayerLeft);
MultiplayerHooking.OnJoinedServer += new ServerEvent(OnJoinedServer);
MultiplayerHooking.OnDisconnected += new ServerEvent(OnDisconnected);
MultiplayerHooking.OnMainSceneInitialized += new UpdateEvent(OnMainSceneInitialized);
PublishLocalState();
}
}
private static void OnRemoteMetadataChanged(PlayerID playerId, string key, string value)
{
if (playerId != null && !playerId.IsMe && IsOurMetadataKey(key))
{
RemoteState orCreateRemoteState = GetOrCreateRemoteState(playerId.SmallID);
ItemHidingMode result2;
if (key == "InvisibleTouch_IsInvisible")
{
orCreateRemoteState.Invisible = bool.TryParse(value, out var result) && result;
}
else if (key == "InvisibleTouch_ItemHiding" && Enum.TryParse<ItemHidingMode>(value, out result2) && Enum.IsDefined(typeof(ItemHidingMode), result2))
{
orCreateRemoteState.ItemHiding = result2;
}
NetworkPlayer player = default(NetworkPlayer);
if (NetworkPlayerManager.TryGetPlayer(playerId.SmallID, ref player))
{
ApplyRemote(player, orCreateRemoteState);
}
}
}
private static void OnRemoteMetadataRemoved(PlayerID playerId, string key, string value)
{
if (playerId != null && !playerId.IsMe && IsOurMetadataKey(key))
{
RemoteState orCreateRemoteState = GetOrCreateRemoteState(playerId.SmallID);
if (key == "InvisibleTouch_IsInvisible")
{
orCreateRemoteState.Invisible = false;
}
else if (key == "InvisibleTouch_ItemHiding")
{
orCreateRemoteState.ItemHiding = ItemHidingMode.HeldAndHolstered;
}
NetworkPlayer player = default(NetworkPlayer);
if (NetworkPlayerManager.TryGetPlayer(playerId.SmallID, ref player))
{
ApplyRemote(player, orCreateRemoteState);
}
}
}
private static bool IsOurMetadataKey(string key)
{
if (!(key == "InvisibleTouch_IsInvisible"))
{
return key == "InvisibleTouch_ItemHiding";
}
return true;
}
private static RemoteState GetOrCreateRemoteState(byte smallId)
{
if (!_remoteStates.TryGetValue(smallId, out var value))
{
value = new RemoteState();
_remoteStates[smallId] = value;
}
return value;
}
private static void OnNetworkPlayerRegistered(NetworkPlayer player)
{
if (((player != null) ? player.PlayerID : null) != null && player.NetworkEntity != null && !player.NetworkEntity.IsOwner && TryReadDesired(player, out var state))
{
_remoteStates[player.PlayerID.SmallID] = state;
ApplyRemote(player, state);
}
}
private static void OnNetworkRigCreated(NetworkPlayer player, RigManager rigManager)
{
if (((player != null) ? player.PlayerID : null) != null && player.NetworkEntity != null && !player.NetworkEntity.IsOwner)
{
RemoteState value;
if (TryReadDesired(player, out var state))
{
_remoteStates[player.PlayerID.SmallID] = state;
ApplyRemote(player, state);
}
else if (_remoteStates.TryGetValue(player.PlayerID.SmallID, out value))
{
ApplyRemote(player, value);
}
}
}
private static void OnJoinedServer()
{
PublishLocalState();
}
private static void OnMainSceneInitialized()
{
if (IsInvisible)
{
PublishLocalState();
ApplySelfVisibility();
}
}
private static void OnPlayerLeft(PlayerID playerId)
{
if (playerId != null)
{
_remoteStates.Remove(playerId.SmallID);
_remoteVisualHides.Remove(playerId.SmallID);
RestoreRemoteItemHidesForPlayer(playerId.SmallID);
}
}
private static void OnDisconnected()
{
_remoteStates.Clear();
_remoteVisualHides.Clear();
RestoreAllRemoteItemHides();
}
private static bool TryReadDesired(NetworkPlayer player, out RemoteState state)
{
state = new RemoteState();
PlayerID playerID = player.PlayerID;
object obj;
if (playerID == null)
{
obj = null;
}
else
{
PlayerMetadata metadata = playerID.Metadata;
obj = ((metadata != null) ? metadata.Metadata : null);
}
NetworkMetadata val = (NetworkMetadata)obj;
string text = ((val != null) ? val.GetMetadata("InvisibleTouch_IsInvisible") : null);
if (text == null)
{
return false;
}
state.Invisible = bool.TryParse(text, out var result) && result;
if (Enum.TryParse<ItemHidingMode>((val != null) ? val.GetMetadata("InvisibleTouch_ItemHiding") : null, out var result2) && Enum.IsDefined(typeof(ItemHidingMode), result2))
{
state.ItemHiding = result2;
}
return true;
}
private static void ApplyRemote(NetworkPlayer player, RemoteState state)
{
if (((player != null) ? player.PlayerID : null) != null && state != null)
{
if (!state.Invisible)
{
RestoreRemoteVisualHide(player);
}
else if (!player.ForceHide)
{
ApplyRemoteVisualHide(player);
}
else
{
RestoreRemoteVisualHide(player);
}
}
}
private static void ApplyRemoteVisualHide(NetworkPlayer player)
{
try
{
if (((player != null) ? player.PlayerID : null) == null || !player.HasRig)
{
return;
}
RigRefs rigRefs = player.RigRefs;
RigManager val = ((rigRefs != null) ? rigRefs.RigManager : null);
if ((Object)(object)val == (Object)null || (Object)(object)val.physicsRig == (Object)null)
{
return;
}
byte smallID = player.PlayerID.SmallID;
int instanceID = ((Object)val).GetInstanceID();
if (!_remoteVisualHides.TryGetValue(smallID, out var value) || value.RigId != instanceID)
{
value = new RemoteVisualHide
{
RigId = instanceID
};
_remoteVisualHides[smallID] = value;
}
try
{
if (player.HeadUI != null)
{
player.HeadUI.Visible = false;
}
}
catch
{
}
HashSet<int> hashSet = new HashSet<int>();
foreach (Renderer disabledRenderer in value.DisabledRenderers)
{
int num = SafeInstanceId((Object)(object)disabledRenderer);
if (num != int.MinValue)
{
hashSet.Add(num);
}
}
MarrowEntity marrowEntity = val.physicsRig.marrowEntity;
List<Component> list = new List<Component> { (Component)(object)val.physicsRig };
if ((Object)(object)val.avatar != (Object)null)
{
list.Add((Component)(object)val.avatar);
}
foreach (Component item in list)
{
bool flag = (Object)(object)val.avatar != (Object)null && SafeInstanceId((Object)(object)item) == SafeInstanceId((Object)(object)val.avatar);
foreach (Renderer componentsInChild in item.GetComponentsInChildren<Renderer>(true))
{
if ((Object)(object)componentsInChild == (Object)null || !componentsInChild.enabled)
{
continue;
}
int instanceID2 = ((Object)componentsInChild).GetInstanceID();
if (flag || IsRigOwnedComponent((Component)(object)componentsInChild, marrowEntity))
{
if (!hashSet.Contains(instanceID2))
{
value.DisabledRenderers.Add(componentsInChild);
hashSet.Add(instanceID2);
}
componentsInChild.enabled = false;
}
}
}
}
catch (Exception ex)
{
if (!_visualHideWarningLogged)
{
_visualHideWarningLogged = true;
Instance log = Log;
if (log != null)
{
log.Warning("Remote visual hide failed (logged once): " + ex.Message);
}
}
}
}
private static void RestoreRemoteVisualHide(NetworkPlayer player)
{
if (((player != null) ? player.PlayerID : null) == null || !_remoteVisualHides.Remove(player.PlayerID.SmallID, out var value))
{
return;
}
foreach (Renderer disabledRenderer in value.DisabledRenderers)
{
try
{
if ((Object)(object)disabledRenderer != (Object)null)
{
disabledRenderer.enabled = true;
}
}
catch
{
}
}
try
{
if (player.HeadUI != null && !player.IsCulled && !player.ForceHide)
{
player.HeadUI.Visible = true;
}
}
catch
{
}
}
private static void RestoreAllRemoteVisualHides()
{
try
{
foreach (NetworkPlayer item in new List<NetworkPlayer>(NetworkPlayer.Players))
{
RestoreRemoteVisualHide(item);
}
}
catch
{
}
_remoteVisualHides.Clear();
}
private static bool IsRigOwnedComponent(Component component, MarrowEntity rigEntity)
{
if ((Object)(object)component == (Object)null || (Object)(object)rigEntity == (Object)null)
{
return true;
}
try
{
MarrowEntity componentInParent = component.GetComponentInParent<MarrowEntity>();
return (Object)(object)componentInParent == (Object)null || SafeInstanceId((Object)(object)componentInParent) == SafeInstanceId((Object)(object)rigEntity);
}
catch
{
return true;
}
}
private static void Reconcile()
{
try
{
foreach (NetworkPlayer item in new List<NetworkPlayer>(NetworkPlayer.Players))
{
if (((item != null) ? item.PlayerID : null) != null && item.NetworkEntity != null && !item.NetworkEntity.IsOwner)
{
RemoteState value;
if (TryReadDesired(item, out var state))
{
_remoteStates[item.PlayerID.SmallID] = state;
ApplyRemote(item, state);
}
else if (_remoteStates.TryGetValue(item.PlayerID.SmallID, out value))
{
ApplyRemote(item, value);
}
}
}
}
catch (Exception value2)
{
if (!_reconcileWarningLogged)
{
_reconcileWarningLogged = true;
Instance log = Log;
if (log != null)
{
log.Warning($"Reconcile failed (logged once): {value2}");
}
}
}
if (IsInvisible && SelfView != SelfViewMode.FullBody)
{
HideSelfRenderers(SelfView == SelfViewMode.HandsOnly);
}
ReconcileRemoteItemHides();
}
private static void CollectHeldProps(RigManager rigManager, HashSet<ushort> target)
{
PhysicsRig val = ((rigManager != null) ? rigManager.physicsRig : null);
if (!((Object)(object)val == (Object)null))
{
AddHeldProp(val.leftHand, target);
AddHeldProp(val.rightHand, target);
}
}
private static void AddHeldProp(Hand hand, HashSet<ushort> target)
{
try
{
object obj;
if (hand == null)
{
obj = null;
}
else
{
HandReciever attachedReceiver = hand.AttachedReceiver;
obj = ((attachedReceiver != null) ? ((Il2CppObjectBase)attachedReceiver).TryCast<Grip>() : null);
}
Grip val = (Grip)obj;
NetworkEntity entity = default(NetworkEntity);
if ((Object)(object)val != (Object)null && GripExtender.Cache.TryGet(val, ref entity))
{
AddPropEntity(entity, target);
}
}
catch
{
}
}
private static void CollectHolsteredProps(NetworkPlayer player, RigManager rigManager, HashSet<ushort> target)
{
List<InventorySlotReceiver> list = new List<InventorySlotReceiver>();
try
{
object obj;
if (player == null)
{
obj = null;
}
else
{
NetworkEntity networkEntity = player.NetworkEntity;
obj = ((networkEntity != null) ? networkEntity.GetExtender<InventorySlotReceiverExtender>() : null);
}
InventorySlotReceiverExtender val = (InventorySlotReceiverExtender)obj;
if (((EntityComponentArrayExtender<InventorySlotReceiver>)(object)val)?.Components != null)
{
list.AddRange(((EntityComponentArrayExtender<InventorySlotReceiver>)(object)val).Components);
}
}
catch
{
}
if (list.Count == 0)
{
try
{
if ((Object)(object)rigManager != (Object)null)
{
list.AddRange((IEnumerable<InventorySlotReceiver>)((Component)rigManager).GetComponentsInChildren<InventorySlotReceiver>(true));
}
}
catch
{
}
}
NetworkEntity entity = default(NetworkEntity);
foreach (InventorySlotReceiver item in list)
{
try
{
WeaponSlot val2 = ((item != null) ? item._slottedWeapon : null);
if ((Object)(object)val2 != (Object)null && WeaponSlotExtender.Cache.TryGet(val2, ref entity))
{
AddPropEntity(entity, target);
}
}
catch
{
}
}
}
private static void AddPropEntity(NetworkEntity entity, HashSet<ushort> target)
{
try
{
if (entity != null && entity.IsRegistered && entity.GetExtender<NetworkProp>() != null)
{
target.Add(entity.ID);
}
}
catch
{
}
}
private static void ExpandCarriedProps(HashSet<ushort> target)
{
if (target.Count == 0)
{
return;
}
NetworkEntity entity2 = default(NetworkEntity);
foreach (ushort item in new List<ushort>(target))
{
try
{
NetworkEntity entity = NetworkEntityManager.IDManager.RegisteredEntities.GetEntity(item);
AmmoSocket obj = ((entity == null) ? null : ((EntityComponentExtender<AmmoSocket>)(object)entity.GetExtender<AmmoSocketExtender>())?.Component);
object obj2;
if (obj == null)
{
obj2 = null;
}
else
{
AmmoPlug magazinePlug = obj._magazinePlug;
obj2 = ((magazinePlug != null) ? magazinePlug.magazine : null);
}
Magazine val = (Magazine)obj2;
if ((Object)(object)val != (Object)null && MagazineExtender.Cache.TryGet(val, ref entity2))
{
AddPropEntity(entity2, target);
}
}
catch
{
}
}
List<Transform> list = new List<Transform>();
HashSet<int> hashSet = new HashSet<int>();
foreach (ushort item2 in new List<ushort>(target))
{
try
{
NetworkEntity entity3 = NetworkEntityManager.IDManager.RegisteredEntities.GetEntity(item2);
object obj4;
if (entity3 == null)
{
obj4 = null;
}
else
{
NetworkProp extender = entity3.GetExtender<NetworkProp>();
if (extender == null)
{
obj4 = null;
}
else
{
MarrowEntity marrowEntity = extender.MarrowEntity;
obj4 = ((marrowEntity != null) ? ((Component)marrowEntity).transform : null);
}
}
Transform val2 = (Transform)obj4;
if (!((Object)(object)val2 == (Object)null))
{
list.Add(val2);
hashSet.Add(((Object)val2).GetInstanceID());
}
}
catch
{
}
}
if (list.Count == 0)
{
return;
}
foreach (NetworkEntity item3 in new List<NetworkEntity>(NetworkEntityManager.IDManager.RegisteredEntities.IDEntityLookup.Values))
{
try
{
if (item3 == null || target.Contains(item3.ID))
{
continue;
}
NetworkProp extender2 = item3.GetExtender<NetworkProp>();
object obj6;
if (extender2 == null)
{
obj6 = null;
}
else
{
MarrowEntity marrowEntity2 = extender2.MarrowEntity;
obj6 = ((marrowEntity2 != null) ? ((Component)marrowEntity2).transform : null);
}
Transform val3 = (Transform)obj6;
if ((Object)(object)val3 == (Object)null)
{
continue;
}
bool flag = IsDescendantOfAny(val3, hashSet);
bool flag2 = false;
if (!flag)
{
HashSet<int> rootIds = new HashSet<int> { ((Object)val3).GetInstanceID() };
foreach (Transform item4 in list)
{
if (IsDescendantOfAny(item4, rootIds))
{
flag2 = true;
break;
}
}
}
if (flag || flag2)
{
target.Add(item3.ID);
}
}
catch
{
}
}
}
private static void ReconcileRemoteItemHides()
{
Dictionary<ushort, byte> dictionary = new Dictionary<ushort, byte>();
try
{
RigManager rigManager = Player.RigManager;
foreach (NetworkPlayer item in new List<NetworkPlayer>(NetworkPlayer.Players))
{
if (((item != null) ? item.PlayerID : null) == null || item.NetworkEntity == null || item.NetworkEntity.IsOwner || !item.HasRig || !_remoteStates.TryGetValue(item.PlayerID.SmallID, out var value) || !value.Invisible || value.ItemHiding == ItemHidingMode.Off)
{
continue;
}
RigRefs rigRefs = item.RigRefs;
RigManager rigManager2 = ((rigRefs != null) ? rigRefs.RigManager : null);
HashSet<ushort> hashSet = new HashSet<ushort>();
CollectHeldProps(rigManager2, hashSet);
if (value.ItemHiding == ItemHidingMode.HeldAndHolstered)
{
CollectHolsteredProps(item, rigManager2, hashSet);
}
ExpandCarriedProps(hashSet);
foreach (ushort item2 in hashSet)
{
NetworkEntity entity = NetworkEntityManager.IDManager.RegisteredEntities.GetEntity(item2);
if (entity != null && !IsHeldByLocalPlayer(entity, rigManager))
{
dictionary[item2] = item.PlayerID.SmallID;
}
}
}
}
catch (Exception ex)
{
if (!_itemWarningLogged)
{
_itemWarningLogged = true;
Instance log = Log;
if (log != null)
{
log.Warning("Remote item scan failed (logged once): " + ex.Message);
}
}
}
foreach (ushort item3 in new List<ushort>(_remoteItemHides.Keys))
{
if (!dictionary.TryGetValue(item3, out var value2) || _remoteItemHides[item3].SmallId != value2)
{
RestoreRemoteItemHide(item3);
}
}
foreach (KeyValuePair<ushort, byte> item4 in dictionary)
{
ApplyRemoteItemHide(item4.Key, item4.Value);
}
}
private static bool IsHeldByLocalPlayer(NetworkEntity entity, RigManager localRig)
{
if (entity == null || (Object)(object)localRig == (Object)null)
{
return false;
}
try
{
GripExtender extender = entity.GetExtender<GripExtender>();
return extender != null && extender.IsHeldBy(localRig);
}
catch
{
return false;
}
}
private static void ApplyRemoteItemHide(ushort entityId, byte smallId)
{
try
{
NetworkEntity entity = NetworkEntityManager.IDManager.RegisteredEntities.GetEntity(entityId);
object obj;
if (entity == null)
{
obj = null;
}
else
{
NetworkProp extender = entity.GetExtender<NetworkProp>();
obj = ((extender != null) ? extender.MarrowEntity : null);
}
MarrowEntity val = (MarrowEntity)obj;
if ((Object)(object)val == (Object)null)
{
return;
}
if (!_remoteItemHides.TryGetValue(entityId, out var value))
{
value = new RemoteItemHide();
_remoteItemHides[entityId] = value;
}
value.SmallId = smallId;
HashSet<int> hashSet = new HashSet<int>();
foreach (Renderer disabledRenderer in value.DisabledRenderers)
{
int num = SafeInstanceId((Object)(object)disabledRenderer);
if (num != int.MinValue)
{
hashSet.Add(num);
}
}
foreach (Renderer componentsInChild in ((Component)val).GetComponentsInChildren<Renderer>(true))
{
if (!((Object)(object)componentsInChild == (Object)null) && componentsInChild.enabled)
{
int instanceID = ((Object)componentsInChild).GetInstanceID();
if (!hashSet.Contains(instanceID))
{
value.DisabledRenderers.Add(componentsInChild);
hashSet.Add(instanceID);
}
componentsInChild.enabled = false;
}
}
}
catch
{
}
}
private static void RestoreRemoteItemHide(ushort entityId)
{
if (!_remoteItemHides.Remove(entityId, out var value))
{
return;
}
foreach (Renderer disabledRenderer in value.DisabledRenderers)
{
try
{
if ((Object)(object)disabledRenderer != (Object)null)
{
disabledRenderer.enabled = true;
}
}
catch
{
}
}
}
private static void RestoreRemoteItemHidesForPlayer(byte smallId)
{
foreach (ushort item in new List<ushort>(_remoteItemHides.Keys))
{
if (_remoteItemHides[item].SmallId == smallId)
{
RestoreRemoteItemHide(item);
}
}
}
private static void RestoreAllRemoteItemHides()
{
foreach (ushort item in new List<ushort>(_remoteItemHides.Keys))
{
RestoreRemoteItemHide(item);
}
}
private static void ApplySelfVisibility()
{
RestoreSelfRenderers();
if (IsInvisible && SelfView != SelfViewMode.FullBody)
{
HideSelfRenderers(SelfView == SelfViewMode.HandsOnly);
}
}
private static void HideSelfRenderers(bool handsOnly = false)
{
try
{
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
return;
}
List<Component> list = new List<Component>();
if ((Object)(object)rigManager.physicsRig != (Object)null)
{
list.Add((Component)(object)rigManager.physicsRig);
}
if ((Object)(object)rigManager.avatar != (Object)null)
{
list.Add((Component)(object)rigManager.avatar);
}
HashSet<int> hashSet = null;
if (handsOnly)
{
HashSet<int> handRootIds = CollectHandRootIds(rigManager);
hashSet = CollectHandRendererIds(rigManager, list, handRootIds);
ApplyHandOnlyMeshSwaps(list, handRootIds, hashSet);
}
foreach (Component item in list)
{
foreach (Renderer componentsInChild in item.GetComponentsInChildren<Renderer>(true))
{
if ((Object)(object)componentsInChild == (Object)null || !componentsInChild.enabled)
{
continue;
}
int instanceID = ((Object)componentsInChild).GetInstanceID();
if (hashSet != null && hashSet.Contains(instanceID))
{
continue;
}
bool flag = false;
foreach (Renderer hiddenSelfRenderer in _hiddenSelfRenderers)
{
if ((Object)(object)hiddenSelfRenderer != (Object)null && ((Object)hiddenSelfRenderer).GetInstanceID() == instanceID)
{
flag = true;
break;
}
}
if (!flag)
{
_hiddenSelfRenderers.Add(componentsInChild);
}
componentsInChild.enabled = false;
}
}
if (handsOnly)
{
LogHandsOnlyResult(rigManager, hashSet?.Count ?? 0);
}
}
catch (Exception ex)
{
Instance log = Log;
if (log != null)
{
log.Warning("HideSelf failed: " + ex.Message);
}
}
}
private static HashSet<int> CollectHandRendererIds(RigManager rigManager, List<Component> roots, HashSet<int> handRootIds)
{
HashSet<int> hashSet = new HashSet<int>();
foreach (Component root in roots)
{
if ((Object)(object)root == (Object)null)
{
continue;
}
try
{
foreach (Renderer componentsInChild in root.GetComponentsInChildren<Renderer>(true))
{
if ((Object)(object)componentsInChild != (Object)null && IsDescendantOfAny(((Component)componentsInChild).transform, handRootIds))
{
hashSet.Add(((Object)componentsInChild).GetInstanceID());
}
}
}
catch
{
}
try
{
foreach (SkinnedMeshRenderer componentsInChild2 in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
{
if ((Object)(object)componentsInChild2 != (Object)null && IsHandOnlySkinnedRenderer(componentsInChild2, handRootIds))
{
hashSet.Add(((Object)componentsInChild2).GetInstanceID());
}
}
}
catch
{
}
}
return hashSet;
}
private static void ApplyHandOnlyMeshSwaps(List<Component> roots, HashSet<int> handRootIds, HashSet<int> handRendererIds)
{
HashSet<int> hashSet = new HashSet<int>();
foreach (Component root in roots)
{
if ((Object)(object)root == (Object)null)
{
continue;
}
try
{
foreach (SkinnedMeshRenderer componentsInChild in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
{
if ((Object)(object)componentsInChild == (Object)null)
{
continue;
}
int instanceID;
try
{
instanceID = ((Object)componentsInChild).GetInstanceID();
}
catch
{
continue;
}
if (!hashSet.Add(instanceID) || handRendererIds.Contains(instanceID))
{
continue;
}
try
{
if (!((Renderer)componentsInChild).enabled)
{
continue;
}
}
catch
{
continue;
}
HandMeshSwap handMeshSwap = null;
foreach (HandMeshSwap handMeshSwap2 in _handMeshSwaps)
{
if (handMeshSwap2.RendererId == instanceID)
{
handMeshSwap = handMeshSwap2;
break;
}
}
Mesh val = null;
try
{
val = componentsInChild.sharedMesh;
}
catch
{
}
if ((Object)(object)val == (Object)null)
{
continue;
}
Mesh originalMesh = val;
if (handMeshSwap != null)
{
int num = SafeInstanceId((Object)(object)val);
int num2 = SafeInstanceId((Object)(object)handMeshSwap.HandMesh);
int num3 = SafeInstanceId((Object)(object)handMeshSwap.OriginalMesh);
if (num != int.MinValue && num == num2)
{
handRendererIds.Add(instanceID);
continue;
}
if (num != int.MinValue && num == num3)
{
originalMesh = handMeshSwap.OriginalMesh;
}
else
{
_handMeshSwaps.Remove(handMeshSwap);
handMeshSwap = null;
originalMesh = val;
}
}
if (TryGetOrCreateHandOnlyMesh(componentsInChild, originalMesh, handRootIds, out var handMesh) && !((Object)(object)handMesh == (Object)null))
{
try
{
componentsInChild.sharedMesh = handMesh;
}
catch
{
continue;
}
if (handMeshSwap == null)
{
handMeshSwap = new HandMeshSwap
{
RendererId = instanceID
};
_handMeshSwaps.Add(handMeshSwap);
}
handMeshSwap.Renderer = componentsInChild;
handMeshSwap.OriginalMesh = originalMesh;
handMeshSwap.HandMesh = handMesh;
handRendererIds.Add(instanceID);
}
}
}
catch
{
}
}
}
private static bool TryGetOrCreateHandOnlyMesh(SkinnedMeshRenderer renderer, Mesh originalMesh, HashSet<int> handRootIds, out Mesh handMesh)
{
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
handMesh = null;
if ((Object)(object)renderer == (Object)null || (Object)(object)originalMesh == (Object)null)
{
return false;
}
List<bool> list = new List<bool>();
List<int> list2 = new List<int>();
try
{
Il2CppReferenceArray<Transform> bones = renderer.bones;
if (bones == null)
{
return false;
}
foreach (Transform item in (Il2CppArrayBase<Transform>)(object)bones)
{
bool flag = (Object)(object)item != (Object)null && IsHandBone(item, handRootIds);
if (flag)
{
list2.Add(list.Count);
}
list.Add(flag);
}
}
catch
{
return false;
}
if (list2.Count == 0)
{
return false;
}
string text = SafeInstanceId((Object)(object)originalMesh) + ":" + string.Join(",", list2);
if (_handMeshCache.TryGetValue(text, out handMesh))
{
return (Object)(object)handMesh != (Object)null;
}
if (_handMeshFailures.Contains(text))
{
return false;
}
Mesh val = null;
try
{
val = Object.Instantiate<Mesh>(originalMesh);
if ((Object)(object)val == (Object)null)
{
_handMeshFailures.Add(text);
return false;
}
((Object)val).name = ((Object)originalMesh).name + "_InvisibleTouch_HandsOnly";
Il2CppStructArray<BoneWeight> boneWeights = val.boneWeights;
if (boneWeights == null || ((Il2CppArrayBase<BoneWeight>)(object)boneWeights).Length == 0)
{
Object.Destroy((Object)(object)val);
_handMeshFailures.Add(text);
return false;
}
bool[] array = new bool[((Il2CppArrayBase<BoneWeight>)(object)boneWeights).Length];
int num = 0;
for (int i = 0; i < ((Il2CppArrayBase<BoneWeight>)(object)boneWeights).Length; i++)
{
BoneWeight val2 = ((Il2CppArrayBase<BoneWeight>)(object)boneWeights)[i];
if (HandBoneWeight(((BoneWeight)(ref val2)).boneIndex0, ((BoneWeight)(ref val2)).weight0, list) + HandBoneWeight(((BoneWeight)(ref val2)).boneIndex1, ((BoneWeight)(ref val2)).weight1, list) + HandBoneWeight(((BoneWeight)(ref val2)).boneIndex2, ((BoneWeight)(ref val2)).weight2, list) + HandBoneWeight(((BoneWeight)(ref val2)).boneIndex3, ((BoneWeight)(ref val2)).weight3, list) >= 0.5f)
{
array[i] = true;
num++;
}
}
if (num == 0)
{
Object.Destroy((Object)(object)val);
_handMeshFailures.Add(text);
return false;
}
int num2 = 0;
int subMeshCount = val.subMeshCount;
for (int j = 0; j < subMeshCount; j++)
{
List<int> val3 = new List<int>();
val.GetTriangles(val3, j);
List<int> val4 = new List<int>();
for (int k = 0; k + 2 < val3.Count; k += 3)
{
int num3 = val3[k];
int num4 = val3[k + 1];
int num5 = val3[k + 2];
if (IsHandVertex(num3, array) && IsHandVertex(num4, array) && IsHandVertex(num5, array))
{
val4.Add(num3);
val4.Add(num4);
val4.Add(num5);
num2++;
}
}
val.SetTriangles(val4, j);
}
if (num2 == 0)
{
Object.Destroy((Object)(object)val);
_handMeshFailures.Add(text);
return false;
}
_handMeshCache[text] = val;
handMesh = val;
return true;
}
catch (Exception ex)
{
if ((Object)(object)val != (Object)null)
{
try
{
Object.Destroy((Object)(object)val);
}
catch
{
}
}
_handMeshFailures.Add(text);
if (!_handMeshWarningLogged)
{
_handMeshWarningLogged = true;
Instance log = Log;
if (log != null)
{
log.Warning("Self View Hands Only mesh filtering failed (logged once): " + ex.Message);
}
}
return false;
}
}
private static float HandBoneWeight(int boneIndex, float weight, List<bool> handBoneFlags)
{
if (boneIndex < 0 || boneIndex >= handBoneFlags.Count || !handBoneFlags[boneIndex])
{
return 0f;
}
return weight;
}
private static bool IsHandVertex(int vertexIndex, bool[] vertexIsHand)
{
if (vertexIndex >= 0 && vertexIndex < vertexIsHand.Length)
{
return vertexIsHand[vertexIndex];
}
return false;
}
private static int SafeInstanceId(Object obj)
{
if (obj == (Object)null)
{
return int.MinValue;
}
try
{
return obj.GetInstanceID();
}
catch
{
return int.MinValue;
}
}
private static HashSet<int> CollectHandRootIds(RigManager rigManager)
{
HashSet<int> hashSet = new HashSet<int>();
try
{
PhysicsRig physicsRig = rigManager.physicsRig;
if ((Object)(object)physicsRig != (Object)null)
{
AddPhysicsHandRoots(hashSet, physicsRig.leftHand);
AddPhysicsHandRoots(hashSet, physicsRig.rightHand);
}
}
catch
{
}
try
{
Avatar avatar = rigManager.avatar;
if ((Object)(object)avatar != (Object)null)
{
AddHandRoot(hashSet, avatar.wristLf);
AddHandRoot(hashSet, avatar.wristRt);
AddHandRoot(hashSet, avatar.carpalLf);
AddHandRoot(hashSet, avatar.carpalRt);
try
{
ArtTransforms artTransforms = avatar.artTransforms;
if (artTransforms != null)
{
AddHandRoot(hashSet, artTransforms.leftHand);
AddHandRoot(hashSet, artTransforms.rightHand);
}
}
catch
{
}
}
}
catch
{
}
try
{
ArtRig componentInChildren = ((Component)rigManager).GetComponentInChildren<ArtRig>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
AddHandRoot(hashSet, componentInChildren.artHandLf);
AddHandRoot(hashSet, componentInChildren.artHandRt);
AddHandRoot(hashSet, componentInChildren.artWristLf);
AddHandRoot(hashSet, componentInChildren.artWristRt);
AddHandRoot(hashSet, componentInChildren.artCarpalLf);
AddHandRoot(hashSet, componentInChildren.artCarpalRt);
}
}
catch
{
}
try
{
foreach (HandPoseAnimator componentsInChild in ((Component)rigManager).GetComponentsInChildren<HandPoseAnimator>(true))
{
if (!((Object)(object)componentsInChild == (Object)null))
{
AddHandRoot(hashSet, ((Component)componentsInChild).transform);
try
{
AddHandRoot(hashSet, componentsInChild.hand2Art);
}
catch
{
}
try
{
AddHandRoot(hashSet, componentsInChild.handle);
}
catch
{
}
}
}
}
catch
{
}
return hashSet;
}
private static void AddPhysicsHandRoots(HashSet<int> rootIds, Hand hand)
{
if ((Object)(object)hand == (Object)null)
{
return;
}
AddHandRoot(rootIds, ((Component)hand).transform);
try
{
PhysHand physHand = hand.physHand;
AddHandRoot(rootIds, (physHand != null) ? ((Component)physHand).transform : null);
}
catch
{
}
try
{
SkeletonHand skeleton = hand.Skeleton;
AddHandRoot(rootIds, (skeleton != null) ? ((Component)skeleton).transform : null);
}
catch
{
}
}
private static void AddHandRoot(HashSet<int> rootIds, Transform transform)
{
if ((Object)(object)transform != (Object)null)
{
rootIds.Add(((Object)transform).GetInstanceID());
}
}
private static bool IsDescendantOfAny(Transform transform, HashSet<int> rootIds)
{
if ((Object)(object)transform == (Object)null || rootIds == null || rootIds.Count == 0)
{
return false;
}
Transform val = transform;
while ((Object)(object)val != (Object)null)
{
if (rootIds.Contains(((Object)val).GetInstanceID()))
{
return true;
}
val = val.parent;
}
return false;
}
private static bool IsHandOnlySkinnedRenderer(SkinnedMeshRenderer renderer, HashSet<int> handRootIds)
{
if (IsDescendantOfAny(((Component)renderer).transform, handRootIds))
{
return true;
}
try
{
GameObject gameObject = ((Component)renderer).gameObject;
string text = ((gameObject != null) ? ((Object)gameObject).name : null);
if (!string.IsNullOrEmpty(text))
{
string text2 = text.ToLowerInvariant();
bool num = text2.Contains("hand") || text2.Contains("glove") || text2.Contains("finger");
bool flag = text2.Contains("body") || text2.Contains("avatar") || text2.Contains("full");
if (num && !flag)
{
return true;
}
}
}
catch
{
}
try
{
Il2CppReferenceArray<Transform> bones = renderer.bones;
if (bones == null)
{
return false;
}
Transform val = null;
int num2 = int.MinValue;
try
{
val = renderer.rootBone;
if ((Object)(object)val != (Object)null)
{
num2 = ((Object)val).GetInstanceID();
}
}
catch
{
}
int num3 = 0;
int num4 = 0;
foreach (Transform item in (Il2CppArrayBase<Transform>)(object)bones)
{
if (!((Object)(object)item == (Object)null) && ((Object)item).GetInstanceID() != num2)
{
num3++;
if (IsHandBone(item, handRootIds))
{
num4++;
}
}
}
if (num3 == 0)
{
return (Object)(object)val != (Object)null && IsHandBone(val, handRootIds);
}
if (num4 == 0)
{
return false;
}
int num5 = num3 - num4;
return num5 == 0 || (num4 >= 4 && num5 <= 3 && (float)num4 / (float)num3 >= 0.75f);
}
catch
{
return false;
}
}
private static bool IsHandBone(Transform bone, HashSet<int> handRootIds)
{
if ((Object)(object)bone == (Object)null)
{
return false;
}
if (IsDescendantOfAny(bone, handRootIds))
{
return true;
}
string name = ((Object)bone).name;
if (string.IsNullOrEmpty(name))
{
return false;
}
string text = name.ToLowerInvariant();
if (!text.Contains("hand") && !text.Contains("finger") && !text.Contains("thumb") && !text.Contains("index") && !text.Contains("middle") && !text.Contains("ring") && !text.Contains("pinky") && !text.Contains("little") && !text.Contains("palm") && !text.Contains("digit") && !text.Contains("wrist") && !text.Contains("carpal"))
{
return text.Contains("metacarpal");
}
return true;
}
private static void LogHandsOnlyResult(RigManager rigManager, int preservedRendererCount)
{
int value = (((Object)(object)rigManager != (Object)null) ? ((Object)rigManager).GetInstanceID() : 0);
int value2 = 0;
try
{
if ((Object)(object)((rigManager != null) ? rigManager.avatar : null) != (Object)null)
{
value2 = ((Object)rigManager.avatar).GetInstanceID();
}
}
catch
{
}
string text = $"{value}:{value2}:{preservedRendererCount}";
if (text == _lastHandsOnlyLogSignature)
{
return;
}
_lastHandsOnlyLogSignature = text;
if (preservedRendererCount > 0)
{
Instance log = Log;
if (log != null)
{
log.Msg($"Self View Hands Only: keeping {preservedRendererCount} hand renderer(s) visible.");
}
}
else
{
Instance log2 = Log;
if (log2 != null)
{
log2.Warning("Self View Hands Only: no usable hand renderers or hand-weighted mesh geometry were found on this avatar, so the local body is fully hidden.");
}
}
}
private static void RestoreHandMeshSwaps()
{
foreach (HandMeshSwap handMeshSwap in _handMeshSwaps)
{
try
{
if (!((Object)(object)handMeshSwap.Renderer == (Object)null) && !((Object)(object)handMeshSwap.OriginalMesh == (Object)null) && !((Object)(object)handMeshSwap.HandMesh == (Object)null) && SafeInstanceId((Object)(object)handMeshSwap.Renderer.sharedMesh) == SafeInstanceId((Object)(object)handMeshSwap.HandMesh))
{
handMeshSwap.Renderer.sharedMesh = handMeshSwap.OriginalMesh;
}
}
catch
{
}
}
_handMeshSwaps.Clear();
}
private static void DestroyCachedHandMeshes()
{
foreach (Mesh value in _handMeshCache.Values)
{
try
{
if ((Object)(object)value != (Object)null)
{
Object.Destroy((Object)(object)value);
}
}
catch
{
}
}
_handMeshCache.Clear();
_handMeshFailures.Clear();
}
private static void RestoreSelfRenderers()
{
RestoreHandMeshSwaps();
foreach (Renderer hiddenSelfRenderer in _hiddenSelfRenderers)
{
try
{
if ((Object)(object)hiddenSelfRenderer != (Object)null)
{
hiddenSelfRenderer.enabled = true;
}
}
catch
{
}
}
_hiddenSelfRenderers.Clear();
}
private static void PlayToggleHaptics(bool invisible, bool fromController)
{
if (!HapticsEnabled)
{
return;
}
int pulses = HapticPattern switch
{
HapticPattern.OneOnTwoOff => invisible ? 1 : 2,
HapticPattern.TwoOnOneOff => (!invisible) ? 1 : 2,
HapticPattern.SinglePulse => 1,
HapticPattern.DoublePulse => 2,
_ => invisible ? 1 : 2,
};
float initialDelay = (fromController ? 0f : 0.15f);
foreach (BaseController hapticController in GetHapticControllers(fromController))
{
PlayHapticPulses(hapticController, pulses, initialDelay);
}
}
private static List<BaseController> GetHapticControllers(bool fromController)
{
List<BaseController> list = new List<BaseController>();
try
{
switch (HapticTarget)
{
case HapticTarget.Left:
AddHapticController(list, Player.LeftController);
return list;
case HapticTarget.Right:
AddHapticController(list, Player.RightController);
return list;
case HapticTarget.Both:
AddHapticController(list, Player.LeftController);
AddHapticController(list, Player.RightController);
return list;
}
}
catch
{
}
if (fromController && Binding != ControllerBinding.Disabled)
{
try
{
AddHapticController(list, (Binding == ControllerBinding.LeftStickClick) ? Player.LeftController : Player.RightController);
}
catch
{
}
if (list.Count > 0)
{
return list;
}
}
try
{
AddHapticController(list, Player.LeftController);
}
catch
{
}
try
{
AddHapticController(list, Player.RightController);
}
catch
{
}
return list;
}
private static void AddHapticController(List<BaseController> controllers, BaseController controller)
{
if ((Object)(object)controller == (Object)null)
{
return;
}
int instanceID = ((Object)controller).GetInstanceID();
foreach (BaseController controller2 in controllers)
{
if ((Object)(object)controller2 != (Object)null && ((Object)controller2).GetInstanceID() == instanceID)
{
return;
}
}
controllers.Add(controller);
}
private static void PlayHapticPulses(BaseController controller, int pulses, float initialDelay)
{
if ((Object)(object)controller == (Object)null || pulses <= 0)
{
return;
}
try
{
float num = 0.08f;
float num2 = 120f;
float num3 = 0.8f;
Haptor val = null;
try
{
val = controller.haptor;
}
catch
{
}
if ((Object)(object)val != (Object)null)
{
try
{
if (val.hap_tap_duration > 0f)
{
num = Mathf.Clamp(val.hap_tap_duration, 0.03f, 0.2f);
}
if (val.hap_tap_frequency > 0f)
{
num2 = Mathf.Clamp(val.hap_tap_frequency, 20f, 320f);
}
if (val.hap_tap_amplitude > 0f)
{
num3 = Mathf.Clamp(val.hap_tap_amplitude, 0.1f, 1f);
}
}
catch
{
}
}
num3 = Mathf.Clamp(num3 * HapticStrength, 0.05f, 1f);
for (int i = 0; i < pulses; i++)
{
float num4 = initialDelay + (float)i * (num + 0.09f);
if ((Object)(object)val != (Object)null)
{
val.SENDHAPTIC(num4, num, num2, num3);
}
else
{
controller.HapticAction(num4, num, num2, num3);
}
}
}
catch (Exception ex)
{
if (!_hapticsWarningLogged)
{
_hapticsWarningLogged = true;
Instance log = Log;
if (log != null)
{
log.Warning("Controller haptics failed (logged once): " + ex.Message);
}
}
}
}
internal static void Shutdown()
{
RestoreSelfRenderers();
RestoreAllRemoteVisualHides();
RestoreAllRemoteItemHides();
DestroyCachedHandMeshes();
}
internal static void OnUpdate()
{
PollControllerInput();
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (realtimeSinceStartup >= _nextReconcileTime)
{
_nextReconcileTime = realtimeSinceStartup + 0.5f;
Reconcile();
}
}
private static void PollControllerInput()
{
bool num = IsBindingPressed();
if (num && !_previousBindingPressed)
{
ToggleFromController();
}
_previousBindingPressed = num;
}
private static bool IsBindingPressed()
{
if (Binding == ControllerBinding.Disabled)
{
return false;
}
try
{
BaseController val = ((Binding == ControllerBinding.LeftStickClick) ? Player.LeftController : Player.RightController);
return (Object)(object)val != (Object)null && val.GetThumbStick();
}
catch
{
return false;
}
}
}
public sealed class InvisibilityModule : Module
{
public override string Name => "Invisible Touch";
public override string Author => "MyFirstTeam";
public override Version Version => new Version(1, 0, 0);
public override ConsoleColor Color => ConsoleColor.Cyan;
protected override void OnModuleRegistered()
{
InvisibilityManager.InitializeFusionHooks();
}
protected override void OnModuleUnregistered()
{
InvisibilityManager.Shutdown();
}
}
public enum ItemHidingMode
{
Off,
HeldOnly,
HeldAndHolstered
}
public sealed class Main : MelonMod
{
private MelonPreferences_Category _prefsCategory;
private MelonPreferences_Entry<bool> _prefShowSelf;
private MelonPreferences_Entry<string> _prefSelfView;
private MelonPreferences_Entry<string> _prefBinding;
private MelonPreferences_Entry<string> _prefItemHiding;
private MelonPreferences_Entry<int> _prefCooldownSeconds;
private MelonPreferences_Entry<bool> _prefHapticsEnabled;
private MelonPreferences_Entry<string> _prefHapticPattern;
private MelonPreferences_Entry<string> _prefHapticTarget;
private MelonPreferences_Entry<float> _prefHapticStrength;
private Page _mainPage;
private Page _settingsPage;
private BoolElement _invisibleElement;
private FunctionElement _toggleElement;
private FunctionElement _selfViewElement;
private FunctionElement _itemHidingElement;
private FunctionElement _bindingElement;
private IntElement _cooldownElement;
private BoolElement _hapticsEnabledElement;
private FunctionElement _hapticPatternElement;
private FunctionElement _hapticTargetElement;
private FloatElement _hapticStrengthElement;
private bool _menuCreated;
public override void OnInitializeMelon()
{
InvisibilityManager.Log = ((MelonBase)this).LoggerInstance;
CreatePreferences();
TryCreateMenu();
InvisibilityManager.OnLocalInvisibleChanged += delegate(bool value2)
{
if (_invisibleElement != null)
{
_invisibleElement.Value = value2;
}
};
try
{
ModuleManager.RegisterModule<InvisibilityModule>();
}
catch (Exception value)
{
((MelonBase)this).LoggerInstance.Error($"Failed to register the Fusion module. Is LabFusion installed and loaded? {value}");
}
((MelonBase)this).LoggerInstance.Msg("Invisible Touch loaded. BoneMenu -> Invisible Touch");
}
public override void OnUpdate()
{
if (!_menuCreated)
{
TryCreateMenu();
}
InvisibilityManager.OnUpdate();
}
public override void OnDeinitializeMelon()
{
InvisibilityManager.Shutdown();
MelonPreferences.Save();
}
private void CreatePreferences()
{
_prefsCategory = MelonPreferences.CreateCategory("InvisibleTouch");
_prefShowSelf = _prefsCategory.CreateEntry<bool>("ShowSelf", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
SelfViewMode selfView = ((!_prefShowSelf.Value) ? SelfViewMode.Hidden : SelfViewMode.FullBody);
_prefSelfView = _prefsCategory.CreateEntry<string>("SelfView", selfView.ToString(), (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefBinding = _prefsCategory.CreateEntry<string>("ToggleButton", "LeftStickClick", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefItemHiding = _prefsCategory.CreateEntry<string>("ItemHiding", "HeldAndHolstered", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefCooldownSeconds = _prefsCategory.CreateEntry<int>("CooldownSeconds", 5, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefHapticsEnabled = _prefsCategory.CreateEntry<bool>("HapticsEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefHapticPattern = _prefsCategory.CreateEntry<string>("HapticPattern", "OneOnTwoOff", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefHapticTarget = _prefsCategory.CreateEntry<string>("HapticTarget", "Auto", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_prefHapticStrength = _prefsCategory.CreateEntry<float>("HapticStrength", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
if (Enum.TryParse<SelfViewMode>(_prefSelfView.Value, out var result) && Enum.IsDefined(typeof(SelfViewMode), result))
{
InvisibilityManager.SelfView = result;
}
else
{
InvisibilityManager.SelfView = selfView;
_prefSelfView.Value = InvisibilityManager.SelfView.ToString();
}
if (Enum.TryParse<ControllerBinding>(_prefBinding.Value, out var result2) && Enum.IsDefined(typeof(ControllerBinding), result2))
{
InvisibilityManager.Binding = result2;
}
else
{
InvisibilityManager.Binding = ControllerBinding.LeftStickClick;
_prefBinding.Value = InvisibilityManager.Binding.ToString();
}
InvisibilityManager.ItemHiding = ParseEnumPreference(_prefItemHiding, ItemHidingMode.HeldAndHolstered);
InvisibilityManager.CooldownSeconds = _prefCooldownSeconds.Value;
_prefCooldownSeconds.Value = InvisibilityManager.CooldownSeconds;
InvisibilityManager.HapticsEnabled = _prefHapticsEnabled.Value;
InvisibilityManager.HapticPattern = ParseEnumPreference(_prefHapticPattern, HapticPattern.OneOnTwoOff);
InvisibilityManager.HapticTarget = ParseEnumPreference(_prefHapticTarget, HapticTarget.Auto);
InvisibilityManager.HapticStrength = Mathf.Round(_prefHapticStrength.Value * 4f) / 4f;
_prefHapticStrength.Value = InvisibilityManager.HapticStrength;
MelonPreferences.Save();
}
private static T ParseEnumPreference<T>(MelonPreferences_Entry<string> preference, T fallback) where T : struct, Enum
{
if (Enum.TryParse<T>(preference.Value, out var result) && Enum.IsDefined(typeof(T), result))
{
return result;
}
preference.Value = fallback.ToString();
return fallback;
}
private void SavePreferences()
{
_prefSelfView.Value = InvisibilityManager.SelfView.ToString();
_prefShowSelf.Value = InvisibilityManager.SelfView != SelfViewMode.Hidden;
_prefBinding.Value = InvisibilityManager.Binding.ToString();
_prefItemHiding.Value = InvisibilityManager.ItemHiding.ToString();
_prefCooldownSeconds.Value = InvisibilityManager.CooldownSeconds;
_prefHapticsEnabled.Value = InvisibilityManager.HapticsEnabled;
_prefHapticPattern.Value = InvisibilityManager.HapticPattern.ToString();
_prefHapticTarget.Value = InvisibilityManager.HapticTarget.ToString();
_prefHapticStrength.Value = InvisibilityManager.HapticStrength;
MelonPreferences.Save();
}
private static T NextEnum<T>(T value) where T : struct, Enum
{
T[] array = (T[])Enum.GetValues(typeof(T));
int num = Array.IndexOf(array, value);
return array[(num + 1) % array.Length];
}
private void TryCreateMenu()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: 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_012b: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: 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)
if (!_menuCreated && Page.Root != null)
{
_mainPage = Page.Root.CreatePage("Invisible Touch", Color.cyan, 0, true);
_invisibleElement = _mainPage.CreateBool("Invisible", Color.cyan, InvisibilityManager.IsInvisible, (Action<bool>)delegate(bool value)
{
InvisibilityManager.SetInvisible(value, "BoneMenu");
});
_toggleElement = _mainPage.CreateFunction("Toggle Invisibility", Color.white, (Action)delegate
{
InvisibilityManager.Toggle();
});
_settingsPage = _mainPage.CreatePage("Settings", Color.white, 0, true);
_selfViewElement = _settingsPage.CreateFunction(MenuText.SelfViewElementName(InvisibilityManager.SelfView), Color.white, (Action)delegate
{
InvisibilityManager.SelfView = NextEnum(InvisibilityManager.SelfView);
InvisibilityManager.OnSelfViewChanged();
SavePreferences();
RefreshMenuText();
((MelonBase)this).LoggerInstance.Msg($"Self View set to {InvisibilityManager.SelfView}");
});
_itemHidingElement = _settingsPage.CreateFunction(MenuText.ItemHidingElementName(InvisibilityManager.ItemHiding), Color.white, (Action)delegate
{
InvisibilityManager.ItemHiding = NextEnum(InvisibilityManager.ItemHiding);
InvisibilityManager.OnItemHidingChanged();
SavePreferences();
RefreshMenuText();
((MelonBase)this).LoggerInstance.Msg($"Item hiding set to {InvisibilityManager.ItemHiding}");
});
_bindingElement = _settingsPage.CreateFunction(MenuText.BindingElementName(InvisibilityManager.Binding), Color.white, (Action)delegate
{
InvisibilityManager.Binding = NextEnum(InvisibilityManager.Binding);
SavePreferences();
RefreshMenuText();
((MelonBase)this).LoggerInstance.Msg($"Toggle stick set to {InvisibilityManager.Binding}");
});
_cooldownElement = _settingsPage.CreateInt("Cooldown (seconds)", Color.white, InvisibilityManager.CooldownSeconds, 1, 0, 60, (Action<int>)delegate(int value)
{
InvisibilityManager.CooldownSeconds = value;
InvisibilityManager.OnCooldownChanged();
SavePreferences();
((MelonBase)this).LoggerInstance.Msg($"Invisibility cooldown set to {InvisibilityManager.CooldownSeconds}s");
});
_hapticsEnabledElement = _settingsPage.CreateBool("Haptics", Color.white, InvisibilityManager.HapticsEnabled, (Action<bool>)delegate(bool value)
{
InvisibilityManager.HapticsEnabled = value;
SavePreferences();
((MelonBase)this).LoggerInstance.Msg("Toggle haptics: " + (value ? "ON" : "OFF"));
});
_hapticPatternElement = _settingsPage.CreateFunction(MenuText.HapticPatternElementName(InvisibilityManager.HapticPattern), Color.white, (Action)delegate
{
InvisibilityManager.HapticPattern = NextEnum(InvisibilityManager.HapticPattern);
SavePreferences();
RefreshMenuText();
((MelonBase)this).LoggerInstance.Msg($"Haptic pattern set to {InvisibilityManager.HapticPattern}");
});
_hapticTargetElement = _settingsPage.CreateFunction(MenuText.HapticTargetElementName(InvisibilityManager.HapticTarget), Color.white, (Action)delegate
{
InvisibilityManager.HapticTarget = NextEnum(InvisibilityManager.HapticTarget);
SavePreferences();
RefreshMenuText();
((MelonBase)this).LoggerInstance.Msg($"Haptic target set to {InvisibilityManager.HapticTarget}");
});
_hapticStrengthElement = _settingsPage.CreateFloat("Haptic Strength", Color.white, InvisibilityManager.HapticStrength, 0.25f, 0.25f, 2f, (Action<float>)delegate(float value)
{
InvisibilityManager.HapticStrength = value;
SavePreferences();
});
_menuCreated = true;
RefreshMenuText();
}
}
private void RefreshMenuText()
{
if (_mainPage != null)
{
_mainPage.Name = "Invisible Touch";
}
if (_settingsPage != null)
{
_settingsPage.Name = "Settings";
}
if (_invisibleElement != null)
{
((Element)_invisibleElement).ElementName = "Invisible";
}
if (_toggleElement != null)
{
((Element)_toggleElement).ElementName = "Toggle Invisibility";
}
if (_selfViewElement != null)
{
((Element)_selfViewElement).ElementName = MenuText.SelfViewElementName(InvisibilityManager.SelfView);
}
if (_itemHidingElement != null)
{
((Element)_itemHidingElement).ElementName = MenuText.ItemHidingElementName(InvisibilityManager.ItemHiding);
((Element)_itemHidingElement).SetTooltip("Other players must have this mod. Their clients hide carried item renderers while the item remains physical. Holsters also includes body-slot weapons and loaded magazines.");
}
if (_bindingElement != null)
{
((Element)_bindingElement).ElementName = MenuText.BindingElementName(InvisibilityManager.Binding);
}
if (_cooldownElement != null)
{
((Element)_cooldownElement).ElementName = "Cooldown (seconds)";
}
if (_hapticsEnabledElement != null)
{
((Element)_hapticsEnabledElement).ElementName = "Haptics";
((Element)_hapticsEnabledElement).SetTooltip("Auto vibrates the toggle stick for controller toggles and both controllers for BoneMenu toggles.");
}
if (_hapticPatternElement != null)
{
((Element)_hapticPatternElement).ElementName = MenuText.HapticPatternElementName(InvisibilityManager.HapticPattern);
}
if (_hapticTargetElement != null)
{
((Element)_hapticTargetElement).ElementName = MenuText.HapticTargetElementName(InvisibilityManager.HapticTarget);
((Element)_hapticTargetElement).SetTooltip("Auto vibrates the toggle stick for controller toggles and both controllers for BoneMenu toggles.");
}
if (_hapticStrengthElement != null)
{
((Element)_hapticStrengthElement).ElementName = "Haptic Strength";
}
}
}
internal static class MenuText
{
public const string ModPageName = "Invisible Touch";
public const string SettingsPageName = "Settings";
public const string InvisibleLabel = "Invisible";
public const string ToggleLabel = "Toggle Invisibility";
public const string CooldownLabel = "Cooldown (seconds)";
public const string HapticsEnabledLabel = "Haptics";
public const string HapticStrengthLabel = "Haptic Strength";
public const string ItemsTooltip = "Other players must have this mod. Their clients hide carried item renderers while the item remains physical. Holsters also includes body-slot weapons and loaded magazines.";
public const string HapticsTooltip = "Auto vibrates the toggle stick for controller toggles and both controllers for BoneMenu toggles.";
public static string SelfViewName(SelfViewMode value)
{
return value switch
{
SelfViewMode.FullBody => "Full Body",
SelfViewMode.HandsOnly => "Hands Only",
SelfViewMode.Hidden => "Hidden",
_ => value.ToString(),
};
}
public static string SelfViewElementName(SelfViewMode value)
{
return "Self View: " + SelfViewName(value);
}
public static string ItemHidingName(ItemHidingMode value)
{
return value switch
{
ItemHidingMode.Off => "Off",
ItemHidingMode.HeldOnly => "Held Only",
ItemHidingMode.HeldAndHolstered => "Held + Holsters",
_ => value.ToString(),
};
}
public static string ItemHidingElementName(ItemHidingMode value)
{
return "Items: " + ItemHidingName(value);
}
public static string BindingName(ControllerBinding value)
{
return value switch
{
ControllerBinding.LeftStickClick => "Left Click",
ControllerBinding.RightStickClick => "Right Click",
ControllerBinding.Disabled => "Disabled",
_ => value.ToString(),
};
}
public static string BindingElementName(ControllerBinding value)
{
return "Toggle Stick: " + BindingName(value);
}
public static string HapticPatternName(HapticPattern value)
{
return value switch
{
HapticPattern.OneOnTwoOff => "1 ON / 2 OFF",
HapticPattern.TwoOnOneOff => "2 ON / 1 OFF",
HapticPattern.SinglePulse => "Single Pulse",
HapticPattern.DoublePulse => "Double Pulse",
_ => value.ToString(),
};
}
public static string HapticPatternElementName(HapticPattern value)
{
return "Haptic Pattern: " + HapticPatternName(value);
}
public static string HapticTargetName(HapticTarget value)
{
return value switch
{
HapticTarget.Auto => "Auto",
HapticTarget.Left => "Left",
HapticTarget.Right => "Right",
HapticTarget.Both => "Both",
_ => value.ToString(),
};
}
public static string HapticTargetElementName(HapticTarget value)
{
return "Haptic Hand: " + HapticTargetName(value);
}
}
public enum SelfViewMode
{
FullBody,
HandsOnly,
Hidden
}