Decompiled source of DeadPiece v0.7.9
Mods/Deadpiece.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; 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.Text; using AudioImportLib; using BoneLib; using BoneLib.BoneMenu; using DeadPiece; using DeadPiece.Networking; using DeadPiece.Networking.Messages; using HarmonyLib; using Il2CppCysharp.Threading.Tasks; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Data; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.AI; using Il2CppSLZ.Marrow.Combat; using Il2CppSLZ.Marrow.Data; using Il2CppSLZ.Marrow.Pool; using Il2CppSLZ.Marrow.PuppetMasta; using Il2CppSLZ.Marrow.VoidLogic; using Il2CppSLZ.Marrow.Warehouse; using Il2CppSLZ.VRMK; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using LabFusion.Entities; using LabFusion.Marrow.Extenders; using LabFusion.Network; using LabFusion.Network.Serialization; using LabFusion.Player; using LabFusion.Representation; using LabFusion.SDK.Modules; using LabFusion.UI; using LabFusion.Utilities; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: MelonColor(255, 139, 0, 0)] [assembly: MelonInfo(typeof(DeadPieceMod), "DeadPiece", "0.7.6", "VoidIndustries", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: MelonPlatform(/*Could not decode attribute arguments.*/)] [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 DeadPiece { public static class AvatarHealthResolver { public const float DefaultUnsetHealth = 100f; public static float Resolve(RigManager rm, float fallbackHp) { if ((Object)(object)rm == (Object)null) { return Mathf.Max(0.0001f, fallbackHp); } float num = Mathf.Max(0.0001f, fallbackHp); float num2 = ReadMarrowHealth(rm.health); float num3 = ReadVitalityHealth(rm.avatar); float num4 = ReadCurrentHealth(rm.health); if (num4 > num2 && num4 > num3) { return ClampHealth(num4, num); } if (num2 > 0f) { if (num3 > 0f && (num3 > num2 || LooksLikeStaleDefaultHealth(num2, num3))) { return ClampHealth(num3, num); } return ClampHealth(num2, num); } if (num3 > 0f) { return ClampHealth(num3, num); } return num; } public static float ReadVitalityHealth(Avatar avatar) { if ((Object)(object)avatar == (Object)null) { return -1f; } float vitality = avatar.vitality; if (vitality <= 0f || float.IsNaN(vitality) || float.IsInfinity(vitality)) { return -1f; } return vitality; } private static float ReadMarrowHealth(Health health) { if ((Object)(object)health == (Object)null) { return -1f; } float max_Health = health.max_Health; if (max_Health <= 0f || float.IsNaN(max_Health) || float.IsInfinity(max_Health)) { return -1f; } return max_Health; } private static float ReadCurrentHealth(Health health) { if ((Object)(object)health == (Object)null) { return -1f; } float curr_Health = health.curr_Health; if (curr_Health <= 0f || float.IsNaN(curr_Health) || float.IsInfinity(curr_Health)) { return -1f; } return curr_Health; } private static bool LooksLikeStaleDefaultHealth(float marrowHp, float vitalityHp) { if (Mathf.Abs(marrowHp - 100f) > 0.5f) { return false; } return Mathf.Abs(vitalityHp - marrowHp) > 0.0001f; } private static float ClampHealth(float hp, float fallback) { if (hp <= 0f || float.IsNaN(hp) || float.IsInfinity(hp)) { return fallback; } return Mathf.Max(0.0001f, hp); } } [HarmonyPatch(typeof(RemapRig), "CrouchHold")] internal static class CrouchHoldPrefixPatch { private static void Prefix(RemapRig __instance, ref bool crouchInput) { RigManager rigManager = Player.RigManager; if (!((Object)(object)rigManager == (Object)null) && DeadPieceMod.Instance != null && !((Object)(object)rigManager.remapHeptaRig != (Object)(object)__instance) && DeadPieceMod.Instance.ShouldApplyLocalNoLegEffects(rigManager) && !DeadPieceMod.Instance.IsAutoInjectorUseActiveOrRecent() && !DeadPieceMod.Instance.IsHoldingNimbusGun(rigManager)) { crouchInput = true; } } } [HarmonyPatch(typeof(PlayerDamageReceiver), "ReceiveAttack")] [HarmonyPriority(800)] public static class DamageInterceptor { internal static void Prefix(PlayerDamageReceiver __instance, ref Attack attack, out bool __state) { __state = false; try { __state = DeadPieceMod.Instance != null && DeadPieceMod.Instance.TryConsumeNonFatalAttack(__instance, attack); if (__state) { attack.damage = 0.1f; } } catch (Exception ex) { MelonLogger.Error("[DeadPiece] Damage prefix failed: " + ex); } } internal static void Postfix(PlayerDamageReceiver __instance, Attack attack, bool __state) { if (__state) { return; } try { Health health = __instance.health; RigManager val = ((health != null) ? health._rigManager : null); bool flag = (Object)(object)val != (Object)null && DeadPieceMod.Instance != null && DeadPieceMod.Instance.IsBothLegsGone(val); DeadPieceMod.Instance?.OnAttackReceived(__instance, attack); bool flag2 = (Object)(object)val != (Object)null && DeadPieceMod.Instance != null && DeadPieceMod.Instance.IsBothLegsGone(val); if (!flag && flag2) { DeadPieceMod.Instance?.SyncLegState(val, 3); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece] Damage postfix failed: " + ex); } } } [RegisterTypeInIl2Cpp] public sealed class StumpDamageVolume : MonoBehaviour { private float _damagePerSecond; private float _lifetime; private float _spawnTime; private float _nextTickTime; private float _lastErrorTime = -999f; private bool _initialized; public StumpDamageVolume(IntPtr pointer) : base(pointer) { } public void Initialize(float damagePerSecond, float lifetime) { _damagePerSecond = damagePerSecond; _lifetime = lifetime; _spawnTime = Time.time; _nextTickTime = 0f; _initialized = true; } private void Update() { if (_initialized && Time.time - _spawnTime >= _lifetime) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void OnTriggerStay(Collider other) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (!_initialized || (Object)(object)other == (Object)null || _damagePerSecond == 0f || Time.time < _nextTickTime) { return; } _nextTickTime = Time.time + 0.25f; try { PlayerDamageReceiver componentInParent = ((Component)other).GetComponentInParent<PlayerDamageReceiver>(); if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent.health == (Object)null || !componentInParent.health.alive) { return; } Vector3 val = ((Component)other).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val)).Normalize(); } Attack val2 = new Attack(); val2.damage = _damagePerSecond * 0.25f; val2.origin = ((Component)this).transform.position; val2.direction = val; val2.normal = -val; val2.collider = other; val2.attackType = (AttackType)64; DamageVolumeContextPatch.EnterFallbackBody(); try { componentInParent.ReceiveAttack(val2); } finally { DamageVolumeContextPatch.ExitFallbackBody(); } } catch (Exception ex) { if (Time.time - _lastErrorTime > 1f) { _lastErrorTime = Time.time; MelonLogger.Warning("[DeadPiece] Stump damage volume failed: " + ex.Message); } } } } [HarmonyPatch(typeof(DamageVolume), "ProcessDamage")] internal static class DamageVolumeContextPatch { private sealed class Contact { public DamageVolume Volume; public RigManager Rig; public Rigidbody Rigidbody; public Collider Collider; public float Damage; public bool AttackHandled; public bool ApplyLimb; } [ThreadStatic] private static int _depth; [ThreadStatic] private static int _fallbackBodyDepth; [ThreadStatic] private static bool _nativeProcess; [ThreadStatic] private static bool _processAttackHandled; [ThreadStatic] private static Collider _processCollider; [ThreadStatic] private static DamageVolume _updateVolume; [ThreadStatic] private static List<Contact> _contacts; [ThreadStatic] private static float _updateLastTickTime; private static readonly Dictionary<DamageVolume, HashSet<Collider>> TrackedColliders = new Dictionary<DamageVolume, HashSet<Collider>>(); internal static bool IsActive => _depth > 0; internal static bool ShouldDeferLimbDamage => _nativeProcess || _fallbackBodyDepth > 0; internal static void Enter() { _depth++; } internal static void Exit() { if (_depth > 0) { _depth--; } } internal static void EnterFallbackBody() { Enter(); _fallbackBodyDepth++; } internal static void ExitFallbackBody() { if (_fallbackBodyDepth > 0) { _fallbackBodyDepth--; } Exit(); } internal static void MarkAttackHandled(RigManager rigManager) { if (_nativeProcess && (Object)(object)rigManager != (Object)null) { _processAttackHandled = true; } } internal static void BeginUpdate(DamageVolume volume) { _updateVolume = volume; _contacts = new List<Contact>(); _updateLastTickTime = (((Object)(object)volume != (Object)null) ? volume._lastTickTime : 0f); } internal static void EndUpdate(DamageVolume volume) { if (!((Object)(object)_updateVolume != (Object)(object)volume)) { List<Contact> contacts = _contacts; _contacts = null; _updateVolume = null; if (contacts.Count > 0 || volume._lastTickTime != _updateLastTickTime) { AppendTrackedContacts(volume, contacts); } FlushContacts(contacts); } } internal static void TrackCollider(DamageVolume volume, Collider collider, bool entered) { if ((Object)(object)volume == (Object)null || (Object)(object)collider == (Object)null) { return; } HashSet<Collider> value2; if (entered) { if (!collider.isTrigger) { if (!TrackedColliders.TryGetValue(volume, out var value)) { value = new HashSet<Collider>(); TrackedColliders[volume] = value; } value.Add(collider); } } else if (TrackedColliders.TryGetValue(volume, out value2)) { value2.Remove(collider); } } internal static void ForgetVolume(DamageVolume volume) { if ((Object)(object)volume != (Object)null) { TrackedColliders.Remove(volume); } } internal static void ResetTracking() { TrackedColliders.Clear(); _contacts = null; _updateVolume = null; _nativeProcess = false; _processAttackHandled = false; _processCollider = null; _fallbackBodyDepth = 0; _depth = 0; } private static void BeginProcess(Collider collider) { Enter(); _nativeProcess = true; _processAttackHandled = false; _processCollider = collider; } private static void RegisterContact(DamageVolume volume, Rigidbody rb, float mult) { if ((Object)(object)volume == (Object)null || (Object)(object)rb == (Object)null) { return; } RigManager val = ResolveRigManager(rb); if (!((Object)(object)val == (Object)null)) { Contact item = new Contact { Volume = volume, Rig = val, Rigidbody = rb, Collider = _processCollider, Damage = volume._damage * mult, AttackHandled = _processAttackHandled, ApplyLimb = true }; if ((Object)(object)_updateVolume == (Object)(object)volume && _contacts != null) { _contacts.Add(item); return; } FlushContacts(new List<Contact> { item }); } } private static void EndProcess() { _nativeProcess = false; _processAttackHandled = false; _processCollider = null; Exit(); } private static bool TryGetActiveTrackedCollider(DamageVolume volume, Rigidbody rb, out Collider activeCollider) { activeCollider = null; if ((Object)(object)volume == (Object)null || (Object)(object)rb == (Object)null || (Object)(object)ResolveRigManager(rb) == (Object)null) { return true; } if (!TrackedColliders.TryGetValue(volume, out var value)) { return true; } Collider[] array = (Collider[])(object)new Collider[value.Count]; value.CopyTo(array); Collider[] array2 = array; foreach (Collider val in array2) { if ((Object)(object)val == (Object)null || !val.enabled || !((Component)val).gameObject.activeInHierarchy) { value.Remove(val); continue; } Rigidbody val2 = val.attachedRigidbody ?? ((Component)val).GetComponentInParent<Rigidbody>(); if ((Object)(object)val2 == (Object)(object)rb) { activeCollider = val; return true; } } return false; } private static RigManager ResolveRigManager(Rigidbody rb) { RigManager componentInParent = ((Component)rb).GetComponentInParent<RigManager>(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } PlayerDamageReceiver componentInChildren = ((Component)rb).GetComponentInChildren<PlayerDamageReceiver>(true); object result; if (componentInChildren == null) { result = null; } else { Health health = componentInChildren.health; result = ((health != null) ? health._rigManager : null); } return (RigManager)result; } private static void AppendTrackedContacts(DamageVolume volume, List<Contact> contacts) { if ((Object)(object)volume == (Object)null || contacts == null || !TrackedColliders.TryGetValue(volume, out var value)) { return; } Collider[] array = (Collider[])(object)new Collider[value.Count]; value.CopyTo(array); Collider[] array2 = array; foreach (Collider val in array2) { if ((Object)(object)val == (Object)null || !val.enabled || !((Component)val).gameObject.activeInHierarchy) { value.Remove(val); continue; } Rigidbody val2 = val.attachedRigidbody ?? ((Component)val).GetComponentInParent<Rigidbody>(); if ((Object)(object)val2 == (Object)null) { continue; } RigManager val3 = ResolveRigManager(val2); if ((Object)(object)val3 == (Object)null) { continue; } float damage = volume._damage * volume._damageScale; bool flag = false; foreach (Contact contact in contacts) { if ((Object)(object)contact.Rig == (Object)(object)val3) { flag |= contact.AttackHandled; } if ((Object)(object)contact.Rigidbody == (Object)(object)val2) { damage = contact.Damage; if ((Object)(object)contact.Collider == (Object)null) { contact.ApplyLimb = false; } } } contacts.Add(new Contact { Volume = volume, Rig = val3, Rigidbody = val2, Collider = val, Damage = damage, AttackHandled = flag, ApplyLimb = true }); } } private static void FlushContacts(List<Contact> contacts) { if (contacts == null || contacts.Count == 0 || DeadPieceMod.Instance == null) { return; } Dictionary<RigManager, List<Contact>> dictionary = new Dictionary<RigManager, List<Contact>>(); foreach (Contact contact in contacts) { if (!((Object)(object)contact?.Rig == (Object)null)) { if (!dictionary.TryGetValue(contact.Rig, out var value)) { value = new List<Contact>(); dictionary[contact.Rig] = value; } value.Add(contact); } } foreach (KeyValuePair<RigManager, List<Contact>> item in dictionary) { bool flag = false; foreach (Contact item2 in item.Value) { flag |= item2.AttackHandled; } bool flag2 = flag; HashSet<HumanBodyBones> damagedBones = new HashSet<HumanBodyBones>(); foreach (Contact item3 in item.Value) { try { bool flag3 = DeadPieceMod.Instance.HandleDamageVolumeContact(item3.Volume, item3.Rig, item3.Rigidbody, item3.Collider, item3.Damage, !flag2, item3.ApplyLimb, damagedBones); flag2 = flag2 || flag3; } catch (Exception) { } } } } [HarmonyPrefix] private static bool Prefix(DamageVolume __instance, Rigidbody rb, out bool __state) { __state = TryGetActiveTrackedCollider(__instance, rb, out var activeCollider); if (!__state) { return false; } BeginProcess(activeCollider); return true; } [HarmonyPostfix] private static void Postfix(DamageVolume __instance, Rigidbody rb, float mult, bool __state) { if (__state) { RegisterContact(__instance, rb, mult); } } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { EndProcess(); } return __exception; } } [HarmonyPatch(typeof(DamageVolume), "OnTriggerEnter")] internal static class DamageVolumeEnterPatch { [HarmonyPrefix] private static void Prefix(DamageVolume __instance, Collider other) { DamageVolumeContextPatch.TrackCollider(__instance, other, entered: true); } } [HarmonyPatch(typeof(DamageVolume), "OnTriggerExit")] internal static class DamageVolumeExitPatch { [HarmonyPrefix] private static void Prefix(DamageVolume __instance, Collider other) { DamageVolumeContextPatch.TrackCollider(__instance, other, entered: false); } } [HarmonyPatch(typeof(DamageVolume), "OnDisable")] internal static class DamageVolumeDisablePatch { [HarmonyPrefix] private static void Prefix(DamageVolume __instance) { DamageVolumeContextPatch.ForgetVolume(__instance); } } [HarmonyPatch(typeof(DamageVolume), "Update")] internal static class DamageVolumeUpdatePatch { [HarmonyPrefix] private static void Prefix(DamageVolume __instance) { DamageVolumeContextPatch.BeginUpdate(__instance); } [HarmonyPostfix] private static void Postfix(DamageVolume __instance) { DamageVolumeContextPatch.EndUpdate(__instance); } [HarmonyFinalizer] private static Exception Finalizer(DamageVolume __instance, Exception __exception) { DamageVolumeContextPatch.EndUpdate(__instance); return __exception; } } public class DeadPieceMod : MelonMod { private struct PendingNetworkState { public ushort Sequence; public uint GoneBoneMask; public bool IsFallen; } private struct OneHpHealthSnapshot { public Health Health; public int AvatarHash; public float MaxHealth; public float CurrentHealth; public float ResolvedHealthBase; } [Flags] private enum LimbGoneMask : byte { None = 0, LeftArm = 1, RightArm = 2, LeftLeg = 4, RightLeg = 8, Spine = 0x10, Hips = 0x20 } private enum ManagedFatalOutcome : byte { None, DirectDelay, NativeDying } private sealed class RigRuntimeCache { public int AvatarHash; public bool Initialized; public bool LimbDamageBlocked; public int LimbDamageBlockFrame; public bool HasMissingLimbs; public LimbGoneMask LimbGoneFlags; public Transform[] BoneTransforms; public VisualDamageController VisualDamage; } private struct HudPartState { public bool Valid; public bool Destroyed; public float Ratio; } private sealed class PlayerHealthBarView { public NetworkPlayer Player; public RigHealthBar Bar; public Transform Root; public Image Fill; public Color OriginalFillColor; public bool HasOriginalFillColor; public TMP_Text Text; public Color OriginalTextColor; public bool HasOriginalTextColor; public float LastHealth = float.NaN; public float LastMaximum = float.NaN; public string LastText; public bool SpawnRequested; } private sealed class NpcLimbState { public PuppetMaster PuppetMaster; public SubBehaviourHealth Health; public AIBrain Brain; public Animator Animator; public Poolee CachedPoolee; public ushort CachedEntityId; public bool HasCachedEntityId; public float NextPooleeResolveTime; public float HealthBase; public uint GoneMask; public readonly Dictionary<HumanBodyBones, Transform> Bones = new Dictionary<HumanBodyBones, Transform>(); public readonly Dictionary<HumanBodyBones, Vector3> OriginalScales = new Dictionary<HumanBodyBones, Vector3>(); public readonly Dictionary<HumanBodyBones, List<Transform>> VisualBones = new Dictionary<HumanBodyBones, List<Transform>>(); public readonly Dictionary<Transform, Vector3> VisualScales = new Dictionary<Transform, Vector3>(); public readonly HashSet<Transform> HiddenVisualBones = new HashSet<Transform>(); public readonly Dictionary<HumanBodyBones, List<Renderer>> VisualRenderers = new Dictionary<HumanBodyBones, List<Renderer>>(); public readonly Dictionary<Renderer, bool> RendererForceOffStates = new Dictionary<Renderer, bool>(); public readonly Dictionary<Renderer, bool> PendingRendererForceOffStates = new Dictionary<Renderer, bool>(); public readonly List<NpcVisualMeshState> VisualMeshes = new List<NpcVisualMeshState>(); public readonly Dictionary<Renderer, float> VisualMeshRetryTimes = new Dictionary<Renderer, float>(); public readonly Dictionary<Renderer, int> VisualMeshFailureCounts = new Dictionary<Renderer, int>(); public readonly Dictionary<SkinnedMeshRenderer, bool> NpcRendererUpdateStates = new Dictionary<SkinnedMeshRenderer, bool>(); public readonly HashSet<SkinnedMeshRenderer> NpcClothUpdateRenderers = new HashSet<SkinnedMeshRenderer>(); public readonly Dictionary<Animator, AnimatorCullingMode> NpcAnimatorCullingStates = new Dictionary<Animator, AnimatorCullingMode>(); public bool VisualMeshesInitialized; public Renderer[] PendingVisualRenderers; public int NextVisualRendererIndex; public bool PendingVisualBonesRefresh; public int VisualMeshScanPassCount; public int VisualScanFailureCount; public float NextVisualMeshScanTime; public float NextVisualRendererCheckTime; public int VisualRendererSignature; public float NextDeferredProxyBakeTime; public float NextEnforceTime; public int EnforceFailureCount; public readonly Dictionary<HumanBodyBones, float> LimbHealth = new Dictionary<HumanBodyBones, float>(); public readonly Dictionary<HumanBodyBones, float> LastDamageTimes = new Dictionary<HumanBodyBones, float>(); public readonly Dictionary<Collider, bool> ColliderStates = new Dictionary<Collider, bool>(); public uint ColliderMaskApplied; public readonly List<GameObject> BloodEffects = new List<GameObject>(); public Color NativeBloodColor; public bool HasNativeBloodColor; } private struct PendingNpcNetworkState { public uint Mask; public bool PlayBlood; public float ExpiresAt; } private struct NpcVertexWeights { public uint Bone0; public uint Bone1; public uint Bone2; public uint Bone3; public float Weight0; public float Weight1; public float Weight2; public float Weight3; } private sealed class NpcVisualMeshState { public NpcLimbState OwnerState; public SkinnedMeshRenderer Renderer; public Mesh OriginalMesh; public Mesh RuntimeMesh; public Mesh StagingMesh; public uint[] RendererBoneMasks; public NpcVertexWeights[] VertexWeights; public int[][] OriginalTriangles; public bool UsesBakedProxy; public GameObject ProxyObject; public MeshFilter ProxyFilter; public MeshRenderer ProxyRenderer; public Il2CppStructArray<int>[] ProxyTriangles; public int ProxyVertexCount; public MaterialPropertyBlock ProxyPropertyBlock; public LODGroup ProxyLodGroup; public bool ProxyLodReplaced; public bool ProxyLodBindingRequired; public bool ProxyLodRestorePending; public float NextProxyRendererSyncTime; public float NextProxyBakeTime; public float NextProxyLodBindTime; public bool HasRendererForceState; public bool RendererForceState; public bool StagingMeshPrepared; public uint StagingMask = uint.MaxValue; public int CreatedFrame; public uint AppliedMask = uint.MaxValue; } private struct PlayerInteractionStats { public float Strength; public float Height; public float Mass; } private struct RecentGrabEvidence { public byte TargetPlayerId; public HumanBodyBones Bone; public float Time; public bool Active; public int ReceiverId; } private struct RecentNpcGrabEvidence { public ushort EntityId; public HumanBodyBones Bone; public float Time; public bool Active; public bool Consumed; public int ReceiverId; } private struct RecentCrushEvidence { public float Time; } private struct PendingPlayerInteraction { public byte SourcePlayerId; public byte TargetPlayerId; public byte Kind; public byte BoneIndex; public byte Detail; public Vector3 Point; public float ExpiresAt; } private struct PendingNpcInteraction { public byte SourcePlayerId; public ushort EntityId; public byte Kind; public byte BoneIndex; public byte Detail; public Vector3 Point; public float ExpiresAt; } public static MelonPreferences_Category Category; public static MelonPreferences_Entry<float> MaxLimbHealth; public static MelonPreferences_Entry<float> DamageMultiplier; public static MelonPreferences_Entry<bool> EnableSoundEffects; public static MelonPreferences_Entry<bool> EnableDualStickDeathReset; public static MelonPreferences_Entry<float> SeveredLimbBleedDamagePerSecond; public static MelonPreferences_Entry<bool> EnableVrEyeBlindness; public static MelonPreferences_Entry<bool> EnableHeadSever; public static MelonPreferences_Entry<bool> EnableVisualCuts; public static MelonPreferences_Entry<bool> EnableAttackTypeBalancing; public static MelonPreferences_Entry<float> PiercingDamageMultiplier; public static MelonPreferences_Entry<float> BluntDamageMultiplier; public static MelonPreferences_Entry<float> SlashDamageMultiplier; public static MelonPreferences_Entry<float> StabDamageMultiplier; public static MelonPreferences_Entry<float> FireDamageMultiplier; public static MelonPreferences_Entry<float> ExplosionRadius; public static MelonPreferences_Entry<bool> EnableBlastLimbDamage; public static MelonPreferences_Entry<bool> EnableImpactBlood; public static MelonPreferences_Entry<bool> EnableBloodEffects; public static MelonPreferences_Entry<bool> EnableGameBloodEffects; public static MelonPreferences_Entry<bool> EnableFallbackBloodEffects; public static MelonPreferences_Entry<string> BloodColorOverride; public static MelonPreferences_Entry<bool> EnableMovementPenalty; public static MelonPreferences_Entry<bool> EnableSecondLegRagdoll; public static MelonPreferences_Entry<bool> HostEnabled; public static MelonPreferences_Entry<bool> LimbsEnabled; public static MelonPreferences_Entry<bool> OneHpMode; public static DeadPieceMod Instance; private DataCardReference<SurfaceDataCard> _fleshSurfaceCard; private bool _fleshCardFound; private readonly List<string> _gameBloodSpawnableBarcodes = new List<string>(); private bool _bloodSpawnablesScanned; private ParticleSystem _gameBloodParticlePrefab; private float _lastGameBloodParticleSearchTime = -999f; private bool _loggedMissingGameBloodParticles; private bool _loggedVanillaBloodSpawnable; private bool _loggedVanillaBloodSpawnableFailure; private Spawnable _smallBloodSplatterSpawnable; private Spawnable _largeBloodSplatterSpawnable; private Spawnable _bloodBagBlasterSpawnable; private bool _vanillaBloodSpawnablesRegistered; public ParticleSystem BloodPrefab; private bool _limitsSaved; private const float DefaultLocomotionMaxVelocity = 4.5f; private float _savedLocomotionMaxVelocity = 4.5f; private float _savedLocomotionCurrentMaxVelocity = 4.5f; private bool _savedLocomotionJumpEnabled = true; private bool _savedLocomotionDoubleJump; private bool _locomotionStateSaved; private bool _deadpieceNoLegUsageApplied; private RigManager _deadpieceUsageRig; private Health _deadpieceUsageHealth; private int _deadpieceUsageAvatarHash; private bool _deadpieceJumpBlocked; private RigManager _deadpieceJumpOwnerRig; private RemapRig _deadpieceJumpRig; private bool _deadpieceFallenStateApplied; private int _locomotionRecoveryToken; private float _savedUsageHips = 1f; private float _savedUsageSpine = 1f; private float _savedUsageLegLf = 1f; private float _savedUsageLegRt = 1f; private float _savedUsageArmLf = 1f; private float _savedUsageArmRt = 1f; private float _suppressNoLegRagdollUntil = -999f; private float _lastLocalRespawnRequestTime = -999f; private bool _localNoLegEffectsPermitted; private Harmony _harmony = new Harmony("com.deadpiece.patches"); private const string MetadataKey = "DeadPieceLimbs"; private const string HostEnabledMetadataKey = "DeadPieceHostEnabled"; private const string LimbsEnabledMetadataKey = "DeadPieceLimbsEnabled"; private const string LegStateMetadataKey = "DeadPieceLegState"; private const string OneHpModeMetadataKey = "DeadPieceOneHpMode"; private const string HealthBaseMetadataKey = "DeadPieceHealthBase"; private const float FusionStateResyncInterval = 5f; private const float StumpBloodEffectInterval = 0.45f; private const float StumpBloodVisualDamage = 3f; private const float VanillaBloodLifetimeSeconds = 10f; private const float AutoInjectorUseWindowSeconds = 0.8f; private const string Explosive_SmallBigDamage = "BaBaCorp.MiscExplosiveDevices.Spawnable.ExplosionSmallBigDamage"; private const string Explosive_MicroNuke = "BaBaCorp.MiscExplosiveDevices.Spawnable.MicroNukeGrenade"; private const string Explosive_TimedNuke = "BaBaCorp.MiscExplosiveDevices.Spawnable.TimedNuke"; private const string Explosive_Dynamite = "BaBaCorp.MiscExplosiveDevices.Spawnable.Dynamite"; private const string Explosive_C4 = "BaBaCorp.MiscExplosiveDevices.Spawnable.CelebratoryC4"; private const string Explosive_Grenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.FragmentationGrenade"; private const string Explosive_TimedC4 = "BaBaCorp.MiscExplosiveDevices.Spawnable.TimedC4"; private const string Explosive_ProxMine = "BaBaCorp.MiscExplosiveDevices.Spawnable.ProxMine"; private const string Explosive_GiftMine = "BaBaCorp.MiscExplosiveDevices.Spawnable.GiftMine"; private const string Explosive_FragGrenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.FragmentationGrenade"; private const string Explosive_GasGrenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.GasGrenade"; private const string Explosive_SmokeGrenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.SmokeGrenade"; private const string Explosive_Flare = "BaBaCorp.MiscExplosiveDevices.Spawnable.Flare"; private const string Explosive_PropaneTank = "BaBaCorp.MiscExplosiveDevices.Spawnable.PropaneTank"; private const string Explosive_FuelTank = "BaBaCorp.MiscExplosiveDevices.Spawnable.FuelTank"; private const string Explosive_Missile = "BaBaCorp.MiscExplosiveDevices.Spawnable.Missile"; private const string Explosive_MiniMissile = "BaBaCorp.MiscExplosiveDevices.Spawnable.MiniMissile"; private const string Explosive_DivinationGrenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.DivinationGrenade"; private const string Explosive_VoidTunneling = "BaBaCorp.MiscExplosiveDevices.Spawnable.KCB4VoidTunnelingDevice"; private const string Explosive_IncendiaryGrenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.IncendiaryGrenade"; private const string Explosive_FireworkPurple = "BaBaCorp.MiscExplosiveDevices.Spawnable.PurpleFireworkRocket"; private const string Explosive_FireworkGreen = "BaBaCorp.MiscExplosiveDevices.Spawnable.GreenFireworkRocket"; private const string Explosive_FireworkBlue = "BaBaCorp.MiscExplosiveDevices.Spawnable.BlueFireworkRocket"; private const string Explosive_FireworkRed = "BaBaCorp.MiscExplosiveDevices.Spawnable.RedFireworkRocket"; private const string Explosive_Lighter = "BaBaCorp.MiscExplosiveDevices.Spawnable.Lighter"; private const string Explosive_M72Law = "BaBaCorp.MiscExplosiveDevices.Spawnable.M72LAW"; private const string Explosive_M72LawInf = "BaBaCorp.MiscExplosiveDevices.Spawnable.M72LawINF"; private const string Explosive_Stielhandgranate = "BaBaCorp.MiscExplosiveDevices.Spawnable.Stielhandgranate"; private const string Explosive_SmallRocket = "BaBaCorp.MiscExplosiveDevices.Spawnable.SmallRocket"; private const string Explosive_Jarate = "BaBaCorp.MiscExplosiveDevices.Spawnable.Jarate"; private const string Explosive_JoyousGreenGrenade = "BaBaCorp.MiscExplosiveDevices.Spawnable.JoyousGreenGrenade"; private const string Explosive_BatteryAcidGlass = "BaBaCorp.MiscExplosiveDevices.Spawnable.BatteryAcidGlass"; private const string Explosive_CrateWithLid = "BaBaCorp.MiscExplosiveDevices.Spawnable.CrateWithLid"; private const string Explosive_RemoteIED = "BaBaCorp.MiscExplosiveDevices.Spawnable.RemoteIED"; private const string Explosive_ClassicBomb = "BaBaCorp.MiscExplosiveDevices.Spawnable.ClassicBomb"; private const string Explosive_Frank = "BaBaCorp.MiscExplosiveDevices.Spawnable.Frank"; private const string Explosive_BirthdayCake = "BaBaCorp.MiscExplosiveDevices.Spawnable.BirthdayCake"; private const string Explosive_IncinMissile = "BaBaCorp.MiscExplosiveDevices.Spawnable.IncinMissile"; private const string Explosive_TriggeredExplosive = "BaBaCorp.MiscExplosiveDevices.Spawnable.TriggeredExplosive"; private const string Explosive_TimedExplosive6s = "BaBaCorp.MiscExplosiveDevices.Spawnable.TimedExplosive6sec"; private const string Explosive_ImpactExplosive = "BaBaCorp.MiscExplosiveDevices.Spawnable.ImpactExplosive"; private const string Explosive_Pliers = "BaBaCorp.MiscExplosiveDevices.Spawnable.Pliers"; private readonly Dictionary<RigManager, Dictionary<HumanBodyBones, float>> _playersHealth = new Dictionary<RigManager, Dictionary<HumanBodyBones, float>>(); private readonly Dictionary<RigManager, Dictionary<Collider, HumanBodyBones>> _colliderBoneMap = new Dictionary<RigManager, Dictionary<Collider, HumanBodyBones>>(); private readonly Dictionary<RigManager, Dictionary<Collider, float>> _colliderBoneDistanceMap = new Dictionary<RigManager, Dictionary<Collider, float>>(); private readonly Dictionary<RigManager, Dictionary<HumanBodyBones, Vector3>> _originalScales = new Dictionary<RigManager, Dictionary<HumanBodyBones, Vector3>>(); private readonly Dictionary<int, Dictionary<HumanBodyBones, Vector3>> _avatarScaleBaselines = new Dictionary<int, Dictionary<HumanBodyBones, Vector3>>(); private readonly Dictionary<RigManager, uint> _hiddenBoneMasks = new Dictionary<RigManager, uint>(); private readonly Dictionary<RigManager, Dictionary<HumanBodyBones, float>> _lastLimbDamageTimes = new Dictionary<RigManager, Dictionary<HumanBodyBones, float>>(); private readonly Dictionary<RigManager, Dictionary<Collider, bool>> _legColliderOriginalStates = new Dictionary<RigManager, Dictionary<Collider, bool>>(); private readonly Dictionary<RigManager, Dictionary<HumanBodyBones, float>> _lastHitEffectTimes = new Dictionary<RigManager, Dictionary<HumanBodyBones, float>>(); private readonly Dictionary<RigManager, Dictionary<HumanBodyBones, float>> _lastStumpBloodEffectTimes = new Dictionary<RigManager, Dictionary<HumanBodyBones, float>>(); private readonly Dictionary<RigManager, Dictionary<HumanBodyBones, float>> _stumpBloodStartTimes = new Dictionary<RigManager, Dictionary<HumanBodyBones, float>>(); private readonly Dictionary<byte, PendingNetworkState> _pendingNetworkStates = new Dictionary<byte, PendingNetworkState>(); private readonly Dictionary<byte, uint> _appliedStateMasks = new Dictionary<byte, uint>(); private readonly HashSet<byte> _remoteFallenPlayers = new HashSet<byte>(); private bool _lastLeftArmUsable = true; private bool _lastRightArmUsable = true; private readonly Dictionary<byte, ushort> _lastAppliedNetworkSequence = new Dictionary<byte, ushort>(); private ushort _localStateSequence; private uint _lastSentStateMask = uint.MaxValue; private float _lastStateSyncTime = -999f; private readonly List<AudioClip> _dismemberSounds = new List<AudioClip>(); public AudioClip DismemberSound; private string _soundFolder; private readonly Dictionary<RigManager, int> _lastAvatarHashes = new Dictionary<RigManager, int>(); private readonly Dictionary<string, Color> _avatarBloodOverrides = new Dictionary<string, Color>(); private readonly Dictionary<RigManager, Color> _bloodColorOverrides = new Dictionary<RigManager, Color>(); private readonly Dictionary<RigManager, byte> _bloodColorIndexOverrides = new Dictionary<RigManager, byte>(); private string _lastBroadcastedBloodColor = "Auto"; private bool _boneMenuCreated; private BoolElement _hostMenuToggle; private BoolElement _limbsMenuToggle; private BoolElement _oneHpMenuToggle; private bool _serverEnabled = true; private bool _lastPublishedHostEnabled; private bool _lastPublishedLimbsEnabled; private bool _lastPublishedOneHpMode; private float _lastPublishedHealthBase = -1f; private bool _healthBasePublished; private bool _settingsPublished; private bool _wasHostForSettings; private bool _serverOneHpMode; private bool _leftHandDisabledByDeadPiece; private bool _rightHandDisabledByDeadPiece; private readonly Dictionary<byte, bool> _playerLimbsEnabled = new Dictionary<byte, bool>(); private readonly Dictionary<byte, float> _networkHealthBaseOverrides = new Dictionary<byte, float>(); private readonly Dictionary<RigManager, OneHpHealthSnapshot> _oneHpHealthSnapshots = new Dictionary<RigManager, OneHpHealthSnapshot>(); public static readonly HumanBodyBones[] DamageBones; private static readonly HashSet<HumanBodyBones> FatalBones; private static readonly HashSet<HumanBodyBones> TorsoBones; private static readonly HashSet<HumanBodyBones> CoreNearestExcludeBones; private const float NearestBoneMaxDistance = 0.75f; private const float NearestBoneTorsoBias = 0.35f; private const float TorsoBoneMaxHitDistance = 0.4f; private const float MaxColliderBoneWorldDistance = 0.55f; private const float MaxColliderHierarchyDepth = 5f; private const int LimbDamageBlockRecheckFrames = 30; private const float SlowUpdateInterval = 0.5f; private const float LimbHealthRegenDelay = 3f; private const float LimbHealthRegenFractionPerSecond = 0.1f; private const float AvatarSwapCheckInterval = 0.2f; private static readonly HumanBodyBones[] NetworkBones; public static readonly Dictionary<HumanBodyBones, int> BoneToIndexMap; private static readonly string[] GameBloodPositiveKeywords; private static readonly string[] GameBloodNegativeKeywords; private static readonly string[] VanillaBloodSpawnableBarcodes; private const string VanillaBloodBlasterBarcode = "c1534c5a-1ea0-4156-920b-f8a8426c6173"; private const float DualStickResetCooldown = 0.75f; private const float DualStickTapPairMaxGap = 0.25f; private const float DualStickTapWindowDuration = 1.75f; private const int DualStickResetTapCount = 2; private RigManager _cachedRm; private float _lastTrackedBodyHealth = -1f; private float _lastAutoInjectorUseTime = -999f; private float _lastExplosiveUseTime = -999f; private const float ExplosiveUseWindowSeconds = 1.5f; private int _dualStickResetTapCount; private float _dualStickResetTapWindowExpire; private float _lastLeftStickTapTime = -999f; private float _lastRightStickTapTime = -999f; private float _lastDualStickTapRegisteredTime = -999f; private float _lastDualStickResetTime = -999f; private readonly Dictionary<RigManager, bool> _rigWasDead = new Dictionary<RigManager, bool>(); private readonly Dictionary<RigManager, float> _avatarHealthBaseCache = new Dictionary<RigManager, float>(); private readonly Dictionary<RigManager, int> _avatarHealthHashCache = new Dictionary<RigManager, int>(); private readonly HashSet<RigManager> _trackedRigs = new HashSet<RigManager>(); private float _slowUpdateTimer; private float _avatarSwapTimer; private RigManager _vrEyeCacheRig; private bool _vrEyeCamerasCached; private bool _lastAppliedLeftEyeBlind; private bool _lastAppliedRightEyeBlind; private readonly List<Camera> _vrLeftEyeCameras = new List<Camera>(); private readonly List<Camera> _vrRightEyeCameras = new List<Camera>(); private readonly Dictionary<Camera, bool> _vrCameraEnabledBackup = new Dictionary<Camera, bool>(); private readonly Dictionary<Camera, GameObject> _vrEyeBlackoutObjects = new Dictionary<Camera, GameObject>(); private int _updateFrame; private int _sceneGeneration; private bool _localRigInitialized; private bool _startupScheduled; private bool _wasConnected; private readonly HashSet<RigManager> _pendingHealthRefresh = new HashSet<RigManager>(); private readonly HashSet<byte> _pendingRespawnPlayers = new HashSet<byte>(); private readonly HashSet<byte> _activeRespawnRestoreWorkers = new HashSet<byte>(); private readonly HashSet<byte> _hardRespawnRecoveryPlayers = new HashSet<byte>(); private bool _localRespawnRestoreWorkerActive; private bool _hardLocalRespawnRecovery; private bool _healingRestoreInProgress; private ManagedFatalOutcome _managedFatalOutcome; private RigManager _managedFatalRig; private Health _managedFatalHealth; private Player_Health _managedFatalPlayerHealth; private HumanBodyBones _managedFatalBone = (HumanBodyBones)55; private int _managedFatalSceneGeneration = -1; private int _managedFatalToken; private bool _allowManagedDyingEntry; private bool _managedFatalHasSavedPlayerState; private HealthMode _managedFatalSavedHealthMode; private float _managedFatalSavedDeathTimeAmount; private float _managedFatalSavedDeathTimeReduction; private float _managedFatalSavedCurrDeathTime; private bool _managedFatalSavedSlowMoOnDeath; private float _managedFatalSavedCurrentHealth; private readonly Dictionary<RigManager, RigRuntimeCache> _rigCache = new Dictionary<RigManager, RigRuntimeCache>(); private Mesh _bloodQuadMesh; private bool _pluginCallbacksRegistered; private const float DamageVolumeLifetime = 8f; private const float DamageVolumeRadius = 0.12f; private const float DamageVolumeDps = 2f; public static MelonPreferences_Entry<bool> EnableLocalHealthHud; public static MelonPreferences_Entry<bool> EnablePlayerHealthBars; private const float LocalHealthHudUpdateInterval = 0.1f; private const float PlayerHealthBarCleanupTimeout = 30f; private static readonly Vector3 LocalHealthHudOffset; private static readonly Color HudGreen; private static readonly Color HudYellow; private static readonly Color HudRed; private static readonly Color HudViolet; private static readonly Color HudUnavailable; private static readonly HumanBodyBones[] HudHeadBones; private static readonly HumanBodyBones[] HudBodyBones; private static readonly HumanBodyBones[] HudLeftArmBones; private static readonly HumanBodyBones[] HudRightArmBones; private static readonly HumanBodyBones[] HudLeftLegBones; private static readonly HumanBodyBones[] HudRightLegBones; private BoolElement _localHealthHudMenuToggle; private BoolElement _playerHealthBarsMenuToggle; private GameObject _localHealthHudRoot; private Text _localHealthHudText; private RigManager _localHealthHudRig; private Transform _localHealthHudAnchor; private float _localHealthHudTimer; private float _nextLocalHealthHudCreateTime; private readonly Dictionary<byte, PlayerHealthBarView> _playerHealthBarViews = new Dictionary<byte, PlayerHealthBarView>(); private readonly HashSet<byte> _seenPlayerHealthBars = new HashSet<byte>(); private static readonly Color DefaultNpcBloodColor; private Material _npcBloodParticleMaterial; private const float NpcDestroyedBodyDespawnDelay = 1.5f; private const float NpcDestroyedBodyDespawnResolveTimeout = 3.5f; private readonly Dictionary<PuppetMaster, NpcLimbState> _npcLimbStates = new Dictionary<PuppetMaster, NpcLimbState>(); private readonly Dictionary<SubBehaviourHealth, PuppetMaster> _npcHealthOwners = new Dictionary<SubBehaviourHealth, PuppetMaster>(); private readonly Dictionary<ushort, PuppetMaster> _npcEntityLookup = new Dictionary<ushort, PuppetMaster>(); private readonly HashSet<PuppetMaster> _npcPendingBodyDespawns = new HashSet<PuppetMaster>(); private readonly HashSet<PuppetMaster> _npcTerminalBodyDespawns = new HashSet<PuppetMaster>(); private int _npcVisualScanBudget; private int _npcProxyBuildBudget; private int _npcProxyRefreshBudget; private int _npcEnforceCursor; private float _nextNpcStateRepairTime; private const float PendingNpcStateLifetime = 5f; private const int MaxPendingNpcStates = 128; private readonly Dictionary<ushort, PendingNpcNetworkState> _pendingNpcNetworkStates = new Dictionary<ushort, PendingNpcNetworkState>(); private float _lastPendingNpcResolveTime = -999f; private const float LocalInteractionCooldown = 0.8f; private const float HostInteractionCooldown = 1f; private const float InteractionMinimumRatio = 1f; private const float InteractionGuaranteedRatio = 3f; private const float CrushContactResetTime = 0.3f; private const float RipPullHoldTime = 0.15f; private const float CrushOverlapInterval = 0.1f; private const float HostCrushObservationInterval = 0.05f; private const float HostCrushEvidenceLifetime = 1.5f; private const float HostPendingInteractionLifetime = 1.5f; private const string InteractionStatsMetadataKey = "DeadPieceInteractionStats"; private const byte RipRightHandDetail = 1; private const byte RipPullDetail = 2; private const byte CrushFootballDetail = 0; private const byte CrushLeftFootDetail = 1; private const byte CrushRightFootDetail = 2; private readonly Dictionary<ulong, float> _localInteractionCooldowns = new Dictionary<ulong, float>(); private readonly Dictionary<ulong, float> _hostInteractionCooldowns = new Dictionary<ulong, float>(); private readonly Dictionary<ulong, float> _localCrushContactTimes = new Dictionary<ulong, float>(); private readonly Dictionary<ushort, RecentGrabEvidence> _recentGrabEvidence = new Dictionary<ushort, RecentGrabEvidence>(); private readonly Dictionary<ushort, RecentNpcGrabEvidence> _recentNpcGrabEvidence = new Dictionary<ushort, RecentNpcGrabEvidence>(); private readonly Dictionary<ulong, RecentCrushEvidence> _recentPlayerCrushEvidence = new Dictionary<ulong, RecentCrushEvidence>(); private readonly Dictionary<ulong, RecentCrushEvidence> _recentNpcCrushEvidence = new Dictionary<ulong, RecentCrushEvidence>(); private readonly Dictionary<ulong, PendingPlayerInteraction> _pendingPlayerInteractions = new Dictionary<ulong, PendingPlayerInteraction>(); private readonly Dictionary<ulong, PendingNpcInteraction> _pendingNpcInteractions = new Dictionary<ulong, PendingNpcInteraction>(); private readonly Dictionary<byte, PlayerInteractionStats> _networkInteractionStats = new Dictionary<byte, PlayerInteractionStats>(); private static readonly Il2CppReferenceArray<Collider> CrushOverlapBuffer; private float _lastInteractionCooldownPrune = -999f; private HandReciever _leftRipPullReceiver; private HandReciever _rightRipPullReceiver; private float _leftRipPullStart = -1f; private float _rightRipPullStart = -1f; private bool _leftRipPullConsumed; private bool _rightRipPullConsumed; private float _nextCrushOverlapTime; private float _nextHostCrushObservationTime; private PlayerInteractionStats _lastPublishedInteractionStats; private bool _interactionStatsPublished; private static Dictionary<HumanBodyBones, int> BuildBoneToIndexMap() { Dictionary<HumanBodyBones, int> dictionary = new Dictionary<HumanBodyBones, int>(DamageBones.Length); for (int i = 0; i < DamageBones.Length; i++) { dictionary[DamageBones[i]] = i; } return dictionary; } public override void OnUpdate() { NetworkSync.ProcessMainThreadQueue(); ProcessNpcRuntime(Time.deltaTime); ProcessPendingNpcNetworkStates(); _updateFrame++; RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null) { return; } if ((Object)(object)_cachedRm == (Object)null || (Object)(object)_cachedRm != (Object)(object)rigManager) { RigManager cachedRm = _cachedRm; _cachedRm = rigManager; _localRigInitialized = false; _startupScheduled = false; if ((Object)(object)cachedRm != (Object)null) { DestroyLocalHealthHud(); MelonLogger.Msg(ConsoleColor.Gray, "Local player RigManager changed, performing respawn cleanup."); RemoveRigFromCaches(cachedRm); SuppressNoLegRagdollForRespawn(); ResetLocalNoLegRagdollPermission(); _lastTrackedBodyHealth = -1f; RequestLocalRespawnReset(rigManager); } } if (!_localRigInitialized) { if (!_startupScheduled) { _startupScheduled = true; MelonCoroutines.Start(DeferredStartup(rigManager)); } return; } UpdateHealthDisplays(); float deltaTime = Time.deltaTime; _avatarSwapTimer += deltaTime; if (_avatarSwapTimer >= 0.2f) { _avatarSwapTimer = 0f; HandleAvatarSwap(rigManager); RigManager[] array = _trackedRigs.ToArray(); foreach (RigManager val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)rigManager) { HandleAvatarSwap(val); } } } HandleRespawnRestore(rigManager); UpdateManagedFatalOutcome(); if (!NetworkInfo.HasServer || NetworkInfo.IsHost) { SetServerOneHpMode(OneHpMode?.Value ?? false); } MaintainOneHpHealth(rigManager, refill: false); if (NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { PublishLocalHealthBase(force: false); } EnforceLocalFatalState(rigManager); HandleStickInputs(deltaTime); ProcessLocalRipGrabs(); UpdateAutoInjectorUseWindow(); UpdateExplosiveUseWindow(); ProcessPlayerHealing(rigManager); ProcessLimbHealthRegeneration(deltaTime); ProcessSeveredLimbBleed(rigManager, deltaTime); if ((Object)(object)rigManager == (Object)(object)Player.RigManager) { ApplyMovementConstraints(rigManager); } _slowUpdateTimer += deltaTime; if (_slowUpdateTimer >= 0.5f) { _slowUpdateTimer = 0f; try { string text = BloodColorOverride?.Value ?? "Auto"; if (text != _lastBroadcastedBloodColor) { _lastBroadcastedBloodColor = text; BroadcastBloodColor(); } } catch { } bool hasServer = NetworkInfo.HasServer; if (hasServer && !_wasConnected) { _wasConnected = true; NetworkSync.RegisterHandlers(); try { _settingsPublished = false; RefreshSessionSettingsFromMetadata(); PublishLocalSettings(force: true); SyncFullState(); BroadcastBloodColor(); } catch { } } else if (!hasServer && _wasConnected) { _wasConnected = false; NetworkSync.ResetSessionState(); _serverEnabled = HostEnabled?.Value ?? true; SetServerOneHpMode(OneHpMode?.Value ?? false); _settingsPublished = false; _healthBasePublished = false; _interactionStatsPublished = false; _playerLimbsEnabled.Clear(); _networkHealthBaseOverrides.Clear(); _networkInteractionStats.Clear(); ClearPlayerInteractionState(); } if (hasServer) { RefreshSessionSettingsFromMetadata(); PublishLocalSettings(force: false); ResyncLocalStateIfNeeded(); HandleAllRigsRespawnRestore(); if (_pendingNetworkStates.Count > 0) { ApplyPendingNetworkStates(); } } EnforceInvincibleRigsForAllTracked(); ProcessRemoteRigsStumpBlood(deltaTime); PruneTrackedRigs(); if (EnableVrEyeBlindness.Value) { UpdateVrEyeBlindness(rigManager); } } if ((_updateFrame & 7) == 0 && NetworkInfo.HasServer) { EnforceRemoteFallenState(); } if ((_updateFrame & 3) == 0) { EnforceLocalHandUsability(); } } public override void OnLateUpdate() { if (!IsSessionEnabled()) { RestoreAllLegColliderStates(); return; } EnforceDismemberedBones(); EnforceLegColliderStates(); EnforceNpcDismemberment(); } private IEnumerator DeferredStartup(RigManager rigManager) { yield return null; if (!_fleshCardFound) { TryCacheFleshSurface(); } if ((Object)(object)rigManager != (Object)null) { EnsureRigInitialized(rigManager); TrackRig(rigManager); } if (NetworkInfo.HasServer) { SyncExistingRemoteMetadata(); ApplyPendingNetworkStates(); RefreshSessionSettingsFromMetadata(); } _localRigInitialized = true; SetupBoneMenu(); PublishLocalSettings(force: true); if (NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { NetworkSync.SendRespawn(PlayerIDManager.LocalSmallID); } } private void SetupBoneMenu() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01af: 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_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) if (_boneMenuCreated) { return; } _boneMenuCreated = true; try { Page val = Page.Root.CreatePage("Deadpiece", Color.red, 0, true); _hostMenuToggle = val.CreateBool("Host On-Off", Color.red, IsSessionEnabled(), (Action<bool>)OnHostSettingChanged); _limbsMenuToggle = val.CreateBool("Limbs On-Off", Color.red, LimbsEnabled?.Value ?? true, (Action<bool>)OnLimbsSettingChanged); _oneHpMenuToggle = val.CreateBool("All Players 1 HP", Color.red, IsOneHpModeEnabled(), (Action<bool>)OnOneHpSettingChanged); _localHealthHudMenuToggle = val.CreateBool("Health HUD", Color.red, EnableLocalHealthHud?.Value ?? false, (Action<bool>)OnLocalHealthHudSettingChanged); _playerHealthBarsMenuToggle = val.CreateBool("Player HP Bars", Color.red, EnablePlayerHealthBars?.Value ?? false, (Action<bool>)OnPlayerHealthBarsSettingChanged); val.CreateFunction("Red", Color.red, (Action)delegate { SetBloodColor("Red"); }); val.CreateFunction("Green", Color.green, (Action)delegate { SetBloodColor("Green"); }); val.CreateFunction("Blue", Color.blue, (Action)delegate { SetBloodColor("Blue"); }); val.CreateFunction("Yellow", Color.yellow, (Action)delegate { SetBloodColor("Yellow"); }); val.CreateFunction("Black", Color.gray, (Action)delegate { SetBloodColor("Black"); }); val.CreateFunction("White", Color.white, (Action)delegate { SetBloodColor("White"); }); val.CreateFunction("Purple", new Color(0.5f, 0.02f, 0.6f), (Action)delegate { SetBloodColor("Purple"); }); val.CreateFunction("Orange", new Color(1f, 0.5f, 0f), (Action)delegate { SetBloodColor("Orange"); }); val.CreateFunction("Pink", new Color(1f, 0.4f, 0.7f), (Action)delegate { SetBloodColor("Pink"); }); val.CreateFunction("Auto", Color.white, (Action)delegate { SetBloodColor("Auto"); }); MelonLogger.Msg(ConsoleColor.Gray, "BoneMenu registered. Blood Color menu available."); } catch (Exception ex) { MelonLogger.Warning("Failed to setup BoneMenu: " + ex.Message); } } private void SetBloodColor(string color) { BloodColorOverride.Value = color; _lastBroadcastedBloodColor = color; BroadcastBloodColor(); } public bool IsSessionEnabled() { if (!NetworkInfo.HasServer || NetworkInfo.IsHost) { return HostEnabled?.Value ?? true; } return _serverEnabled; } public bool IsOneHpModeEnabled() { if (!NetworkInfo.HasServer || NetworkInfo.IsHost) { return OneHpMode?.Value ?? false; } return _serverOneHpMode; } public bool IsLimbDestructionAllowed(RigManager rm) { if (!IsSessionEnabled() || (Object)(object)rm == (Object)null) { return false; } if ((Object)(object)rm == (Object)(object)Player.RigManager) { return LimbsEnabled?.Value ?? true; } byte playerId; return !TryGetPlayerIdForRig(rm, out playerId) || GetPlayerLimbsEnabled(playerId); } internal bool CanHostApplyNetworkLimbDamage(byte playerId) { if (!IsSessionEnabled() || !GetPlayerLimbsEnabled(playerId)) { return false; } if (!IsOneHpModeEnabled() && NetworkInfo.HasServer && NetworkInfo.IsHost && PlayerIDManager.LocalID != null && playerId != PlayerIDManager.LocalSmallID && !_networkHealthBaseOverrides.ContainsKey(playerId)) { return false; } return true; } internal bool CanHostApplyPlayerInteraction(byte playerId) { return IsSessionEnabled() && GetPlayerLimbsEnabled(playerId); } internal bool CanHostSynchronizeNetworkLimbState(byte playerId) { return IsSessionEnabled() && GetPlayerLimbsEnabled(playerId); } private bool GetPlayerLimbsEnabled(byte playerId) { bool enabled; return !TryGetKnownPlayerLimbsEnabled(playerId, out enabled) || enabled; } private bool TryGetKnownPlayerLimbsEnabled(byte playerId, out bool enabled) { enabled = false; if (PlayerIDManager.LocalID != null && playerId == PlayerIDManager.LocalSmallID) { enabled = LimbsEnabled?.Value ?? true; return true; } if (_playerLimbsEnabled.TryGetValue(playerId, out enabled)) { return true; } try { string value = default(string); foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID == null || playerID.SmallID != playerId) { continue; } PlayerMetadata metadata = playerID.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceLimbsEnabled", ref value)) { enabled = ParseEnabledSetting(value); _playerLimbsEnabled[playerId] = enabled; return true; } break; } } catch { } enabled = false; return false; } private static bool ParseEnabledSetting(string value) { if (string.IsNullOrWhiteSpace(value)) { return true; } return value == "1" || value.Equals("true", StringComparison.OrdinalIgnoreCase) || value.Equals("on", StringComparison.OrdinalIgnoreCase); } private static bool ParseOneHpSetting(string value) { return !string.IsNullOrWhiteSpace(value) && ParseEnabledSetting(value); } private void OnHostSettingChanged(bool enabled) { if (NetworkInfo.HasServer && !NetworkInfo.IsHost) { if (_hostMenuToggle != null) { _hostMenuToggle.Value = _serverEnabled; } return; } HostEnabled.Value = enabled; _serverEnabled = enabled; PublishLocalSettings(force: true); if (!enabled) { ClearPlayerInteractionState(); RestoreAllTrackedLimbStates(NetworkInfo.IsHost); } } private void OnLimbsSettingChanged(bool enabled) { LimbsEnabled.Value = enabled; if (PlayerIDManager.LocalID != null) { _playerLimbsEnabled[PlayerIDManager.LocalSmallID] = enabled; } PublishLocalSettings(force: true); if (!enabled) { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager != (Object)null) { ResetLimbStats(rigManager, restoreBody: true); } if (NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { NetworkSync.SendRespawn(PlayerIDManager.LocalSmallID); } } } private void OnOneHpSettingChanged(bool enabled) { if (NetworkInfo.HasServer && !NetworkInfo.IsHost) { if (_oneHpMenuToggle != null) { _oneHpMenuToggle.Value = _serverOneHpMode; } } else { OneHpMode.Value = enabled; SetServerOneHpMode(enabled); PublishLocalSettings(force: true); } } private void PublishLocalSettings(bool force) { if (PlayerIDManager.LocalID == null) { return; } bool flag = !NetworkInfo.HasServer || NetworkInfo.IsHost; if (flag != _wasHostForSettings) { force = true; _wasHostForSettings = flag; } bool flag2 = LimbsEnabled?.Value ?? true; if (force || !_settingsPublished || flag2 != _lastPublishedLimbsEnabled) { SetLocalMetadataValue("DeadPieceLimbsEnabled", flag2 ? "1" : "0"); _lastPublishedLimbsEnabled = flag2; _playerLimbsEnabled[PlayerIDManager.LocalSmallID] = flag2; } if (flag) { bool flag3 = HostEnabled?.Value ?? true; if (force || !_settingsPublished || flag3 != _lastPublishedHostEnabled) { SetLocalMetadataValue("DeadPieceHostEnabled", flag3 ? "1" : "0"); _lastPublishedHostEnabled = flag3; } _serverEnabled = flag3; bool flag4 = OneHpMode?.Value ?? false; if (force || !_settingsPublished || flag4 != _lastPublishedOneHpMode) { SetLocalMetadataValue("DeadPieceOneHpMode", flag4 ? "1" : "0"); _lastPublishedOneHpMode = flag4; } SetServerOneHpMode(flag4); } PublishLocalHealthBase(force); PublishLocalInteractionStats(force); _settingsPublished = true; } private void RefreshSessionSettingsFromMetadata() { if (!NetworkInfo.HasServer || NetworkInfo.IsHost) { _serverEnabled = HostEnabled?.Value ?? true; SetServerOneHpMode(OneHpMode?.Value ?? false); if (_hostMenuToggle != null) { _hostMenuToggle.Value = _serverEnabled; } return; } bool serverEnabled = true; bool serverOneHpMode = false; try { byte b = 0; string value = default(string); string value2 = default(string); foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID == null || playerID.SmallID != b) { continue; } PlayerMetadata metadata = playerID.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceHostEnabled", ref value)) { serverEnabled = ParseEnabledSetting(value); } PlayerMetadata metadata2 = playerID.Metadata; if (((metadata2 != null) ? metadata2.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceOneHpMode", ref value2)) { serverOneHpMode = ParseOneHpSetting(value2); } break; } } catch { } SetServerEnabled(serverEnabled); SetServerOneHpMode(serverOneHpMode); } private void SetServerEnabled(bool enabled) { bool flag = _serverEnabled != enabled; _serverEnabled = enabled; if (_hostMenuToggle != null) { _hostMenuToggle.Value = enabled; } if (flag && !enabled) { ClearPlayerInteractionState(); RestoreAllTrackedLimbStates(broadcast: false); } } private void SetServerOneHpMode(bool enabled) { bool flag = _serverOneHpMode != enabled; _serverOneHpMode = enabled; if (_oneHpMenuToggle != null) { _oneHpMenuToggle.Value = enabled; } if (flag) { ApplyOneHpModeTransition(enabled); _healthBasePublished = false; } } private void HandlePlayerLimbsSetting(byte playerId, bool enabled) { _playerLimbsEnabled[playerId] = enabled; if (enabled) { return; } _pendingNetworkStates.Remove(playerId); _appliedStateMasks.Remove(playerId); if (TryResolvePlayerRig(playerId, out var rigManager)) { ResetLimbStats(rigManager, restoreBody: true); if (NetworkInfo.IsHost) { NetworkSync.SendFullState(playerId, 0u, GetBloodColorIndexForRig(rigManager), 0); } } } private void PublishLocalHealthBase(bool force) { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null || PlayerIDManager.LocalID == null) { return; } if (IsOneHpModeEnabled()) { MaintainOneHpHealth(rigManager, refill: false); } float num = AvatarHealthResolver.Resolve(rigManager, MaxLimbHealth.Value); if (IsOneHpModeEnabled() && _oneHpHealthSnapshots.TryGetValue(rigManager, out var value) && (Object)(object)value.Health == (Object)(object)rigManager.health) { num = value.ResolvedHealthBase; } if (!(num <= 0f) && !float.IsNaN(num) && !float.IsInfinity(num)) { if (force || !_healthBasePublished || Mathf.Abs(num - _lastPublishedHealthBase) > Mathf.Max(0.0001f, num * 0.0001f)) { SetLocalMetadataValue("DeadPieceHealthBase", num.ToString("R", CultureInfo.InvariantCulture)); _lastPublishedHealthBase = num; _healthBasePublished = true; } _networkHealthBaseOverrides[PlayerIDManager.LocalSmallID] = num; } } private void HandlePlayerHealthBase(byte playerId, string value) { RigManager rigManager2; if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || result <= 0f || float.IsNaN(result) || float.IsInfinity(result)) { if (_networkHealthBaseOverrides.Remove(playerId) && TryResolvePlayerRig(playerId, out var rigManager)) { GetAvatarHealthBase(rigManager); } } else if (TryResolvePlayerRig(playerId, out rigManager2)) { bool flag = _avatarHealthBaseCache.ContainsKey(rigManager2) && _avatarHealthHashCache.ContainsKey(rigManager2); _networkHealthBaseOverrides[playerId] = result; if (flag) { GetAvatarHealthBase(rigManager2); return; } InvalidateAvatarHealthCache(rigManager2); RefreshLimbMaxHealth(rigManager2); } else { _networkHealthBaseOverrides[playerId] = result; } } private void ApplyOneHpModeTransition(bool enabled) { HashSet<RigManager> hashSet = new HashSet<RigManager>(_trackedRigs); if ((Object)(object)Player.RigManager != (Object)null) { hashSet.Add(Player.RigManager); } foreach (RigManager item in hashSet) { if (!((Object)(object)item == (Object)null)) { if (enabled) { MaintainOneHpHealth(item, refill: true); RebaseTrackedLimbHealthForOneHp(item, enabling: true); } else { RestoreOneHpHealth(item); RebaseTrackedLimbHealthForOneHp(item, enabling: false); } } } if (!enabled) { RigManager[] array = _oneHpHealthSnapshots.Keys.ToArray(); for (int i = 0; i < array.Length; i++) { RestoreOneHpHealth(array[i]); } } } private void MaintainOneHpHealth(RigManager rm, bool refill) { if (!IsOneHpModeEnabled() || (Object)(object)rm == (Object)null || (Object)(object)rm.health == (Object)null) { return; } Health health = rm.health; int num = (((Object)(object)rm.avatar != (Object)null) ? ((Object)rm.avatar).GetHashCode() : 0); bool flag = false; if (_oneHpHealthSnapshots.TryGetValue(rm, out var value) && (Object)(object)value.Health != (Object)(object)health) { _oneHpHealthSnapshots.Remove(rm); } else if (_oneHpHealthSnapshots.TryGetValue(rm, out value) && value.AvatarHash != num) { float num2 = ((health.curr_Health > 0f && !float.IsNaN(health.curr_Health) && !float.IsInfinity(health.curr_Health)) ? Mathf.Clamp01(health.curr_Health) : 0f); float num3 = AvatarHealthResolver.ReadVitalityHealth(rm.avatar); float num4 = ((num3 > 0f && !float.IsNaN(num3) && !float.IsInfinity(num3)) ? num3 : value.ResolvedHealthBase); value.AvatarHash = num; value.ResolvedHealthBase = Mathf.Max(0.0001f, num4); value.MaxHealth = value.ResolvedHealthBase; value.CurrentHealth = value.ResolvedHealthBase * num2; _oneHpHealthSnapshots[rm] = value; } if (!_oneHpHealthSnapshots.ContainsKey(rm)) { float num5 = health.max_Health; if (num5 <= 0f || float.IsNaN(num5) || float.IsInfinity(num5)) { num5 = AvatarHealthResolver.Resolve(rm, MaxLimbHealth.Value); } float num6 = health.curr_Health; if (float.IsNaN(num6) || float.IsInfinity(num6)) { num6 = num5; } _oneHpHealthSnapshots[rm] = new OneHpHealthSnapshot { Health = health, AvatarHash = num, MaxHealth = Mathf.Max(0.0001f, num5), CurrentHealth = num6, ResolvedHealthBase = AvatarHealthResolver.Resolve(rm, MaxLimbHealth.Value) }; flag = true; } health.max_Health = 1f; if (health.alive && health.curr_Health > 0f && (refill || flag || health.curr_Health > 1f)) { health.curr_Health = 1f; } InvalidateAvatarHealthCache(rm); } private void RestoreOneHpHealth(RigManager rm) { if ((Object)(object)rm == (Object)null || !_oneHpHealthSnapshots.TryGetValue(rm, out var value)) { return; } _oneHpHealthSnapshots.Remove(rm); Health health = rm.health; int num = (((Object)(object)rm.avatar != (Object)null) ? ((Object)rm.avatar).GetHashCode() : 0); if (!((Object)(object)health == (Object)null) && !((Object)(object)health != (Object)(object)value.Health) && num == value.AvatarHash) { float num2 = ((health.curr_Health > 0f && !float.IsNaN(health.curr_Health) && !float.IsInfinity(health.curr_Health)) ? Mathf.Clamp01(health.curr_Health) : 0f); health.max_Health = Mathf.Max(0.0001f, value.MaxHealth); if (health.alive && health.curr_Health > 0f) { float num3 = ((value.CurrentHealth > 0f && !float.IsNaN(value.CurrentHealth) && !float.IsInfinity(value.CurrentHealth)) ? value.CurrentHealth : health.max_Health); health.curr_Health = Mathf.Clamp(num3 * num2, 0f, health.max_Health); } InvalidateAvatarHealthCache(rm); } } private void RestoreAllOneHpHealthStates() { RigManager[] array = _oneHpHealthSnapshots.Keys.ToArray(); for (int i = 0; i < array.Length; i++) { RestoreOneHpHealth(array[i]); } _oneHpHealthSnapshots.Clear(); } private void RebaseTrackedLimbHealthForOneHp(RigManager rm, bool enabling) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) InvalidateAvatarHealthCache(rm); if ((Object)(object)rm == (Object)null || !_playersHealth.TryGetValue(rm, out var value)) { return; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (value.TryGetValue(val, out var value2)) { if (value2 > 0f && !IsBoneGone(rm, val)) { value[val] = (enabling ? 1f : (GetMaxHealthForBone(rm, val) * Mathf.Clamp01(value2))); } else { value[val] = 0f - GetMaxHealthForBone(rm, val); } } } } private void RestoreAllTrackedLimbStates(bool broadcast) { HashSet<RigManager> hashSet = new HashSet<RigManager>(_trackedRigs); if ((Object)(object)Player.RigManager != (Object)null) { hashSet.Add(Player.RigManager); } foreach (RigManager item in hashSet) { if ((Object)(object)item != (Object)null) { ResetLimbStats(item, restoreBody: true); } } _pendingNetworkStates.Clear(); _appliedStateMasks.Clear(); _remoteFallenPlayers.Clear(); if (!broadcast) { return; } try { foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null) { NetworkSync.SendFullState(playerID.SmallID, 0u, 0, 0); } } } catch { } } private void SetLocalMetadataValue(string key, string value) { try { PlayerMetadata metadata = LocalPlayer.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null) { LocalPlayer.Metadata.Metadata.TrySetMetadata(key, value); return; } } catch { } PlayerID localID = PlayerIDManager.LocalID; object obj2; if (localID == null) { obj2 = null; } else { PlayerMetadata metadata2 = localID.Metadata; obj2 = ((metadata2 != null) ? metadata2.Metadata : null); } if (obj2 != null) { PlayerIDManager.LocalID.Metadata.Metadata.TrySetMetadata(key, value); } } private void SyncExistingRemoteMetadata() { string value = default(string); string value2 = default(string); string value3 = default(string); string value4 = default(string); RigRefs val = default(RigRefs); foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null && !playerID.IsMe) { PlayerMetadata metadata = playerID.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceLimbs", ref value)) { ApplyNetworkState(playerID.SmallID, value); } PlayerMetadata metadata2 = playerID.Metadata; if (((metadata2 != null) ? metadata2.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceLimbsEnabled", ref value2)) { HandlePlayerLimbsSetting(playerID.SmallID, ParseEnabledSetting(value2)); } PlayerMetadata metadata3 = playerID.Metadata; if (((metadata3 != null) ? metadata3.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceHealthBase", ref value3)) { HandlePlayerHealthBase(playerID.SmallID, value3); } PlayerMetadata metadata4 = playerID.Metadata; if (((metadata4 != null) ? metadata4.Metadata : null) != null && playerID.Metadata.Metadata.TryGetMetadata("DeadPieceInteractionStats", ref value4)) { HandlePlayerInteractionStats(playerID.SmallID, value4); } if (PlayerRepUtilities.TryGetReferences(playerID.SmallID, ref val) && (Object)(object)((val != null) ? val.RigManager : null) != (Object)null) { TrackRig(val.RigManager); } } } } public override void OnInitializeMelon() { //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Expected O, but got Unknown //IL_051f: Unknown result type (might be due to invalid IL or missing references) //IL_0529: Expected O, but got Unknown Instance = this; WarnAboutLegacyNetworkPlugin(); InitializeModules(); NetworkSync.Initialize(); _pluginCallbacksRegistered = NetworkSync.RegisterCallbacks(OnPluginLimbHit, OnPluginLimbSever, OnPluginRespawn, OnPluginBloodColor, OnPluginFullState, GetPluginStateMask, OnPluginInteractionRequest, OnPluginInteractionAuthoritative); NetworkSync.RegisterNpcCallbacks(OnPluginNpcInteractionRequest, OnPluginNpcInteractionAuthoritative); try { _harmony.PatchAll(); } catch (Exception ex) { MelonLogger.Warning("Harmony PatchAll failed: " + ex.Message); } Category = MelonPreferences.CreateCategory("DeadPiece", "DeadPiece Settings"); HostEnabled = Category.CreateEntry<bool>("HostEnabled", true, "Host On-Off", "Only the host can enable or disable DeadPiece for the server", false, false, (ValueValidator)null, (string)null); LimbsEnabled = Category.CreateEntry<bool>("LimbsEnabled", true, "Limbs On-Off", "Allow your limbs to be destroyed", false, false, (ValueValidator)null, (string)null); OneHpMode = Category.CreateEntry<bool>("OneHpMode", false, "All Players 1 HP", "Host-only setting that gives every player and limb exactly 1 HP", false, false, (ValueValidator)null, (string)null); EnableLocalHealthHud = Category.CreateEntry<bool>("EnableLocalHealthHud", false, "Health HUD", "Show a compact upper-right readout for your overall and limb health", false, false, (ValueValidator)null, (string)null); EnablePlayerHealthBars = Category.CreateEntry<bool>("EnablePlayerHealthBars", false, "Player HP Bars", "Show overhead health bars for other players on this client", false, false, (ValueValidator)null, (string)null); _serverOneHpMode = OneHpMode.Value; MaxLimbHealth = Category.CreateEntry<float>("MaxLimbHealth", 100f, "Fallback Avatar HP", "Fallback max health when the avatar does not expose player health (limb HP scales from avatar max health)", false, false, (ValueValidator)null, (string)null); DamageMultiplier = Category.CreateEntry<float>("DamageMultiplier", 1f, "Damage Multiplier", "Multiplier for damage dealt to limbs", false, false, (ValueValidator)null, (string)null); EnableImpactBlood = Category.CreateEntry<bool>("EnableImpactBlood", true, "Severed Limb Bleed", "Tiny damage ticks at severed bone tips (vanilla impact blood)", false, false, (ValueValidator)null, (string)null); EnableBloodEffects = Category.CreateEntry<bool>("EnableBloodEffects", true, "Blood Effects", "Enable blood particle effects on dismemberment", false, false, (ValueValidator)null, (string)null); EnableGameBloodEffects = Category.CreateEntry<bool>("EnableGameBloodEffects", true, "Game Blood", "Clone already-loaded BONELAB blood VFX instead of shipping custom particles", false, false, (ValueValidator)null, (string)null); EnableFallbackBloodEffects = Category.CreateEntry<bool>("EnableProceduralFallbackBlood", true, "Procedural Fallback", "Always keep a lightweight procedural blood fallback when native BONELAB blood VFX cannot be spawned", false, false, (ValueValidator)null, (string)null); BloodColorOverride = Category.CreateEntry<string>("BloodColorOverride", "Auto", "Blood Color Override", "Force a specific blood color for all avatars (Auto = use per-avatar rules)", false, false, (ValueValidator)null, (string)null); EnableMovementPenalty = Category.CreateEntry<bool>("EnableMovementPenalty", true, "Movement Penalty", "Apply movement restrictions and body lowering when legs are lost", false, false, (ValueValidator)null, (string)null); EnableSecondLegRagdoll = Category.CreateEntry<bool>("EnableSecondLegRagdoll", false, "Second Leg Ragdoll", "Deprecated; DeadPiece no longer changes player leg physics", false, false, (ValueValidator)null, (string)null); SeveredLimbBleedDamagePerSecond = Category.CreateEntry<float>("SeveredLimbBleedDamagePerSecond", 0.01f, "Bleed DPS", "Damage per second at each severed limb tip", false, false, (ValueValidator)null, (string)null); EnableDualStickDeathReset = Category.CreateEntry<bool>("EnableDualStickDeathReset", true, "Dual Stick Death Reset", "Double-tap both thumbsticks to die and respawn (full reset)", false, false, (ValueValidator)null, (string)null); EnableSoundEffects = Category.CreateEntry<bool>("EnableSoundEffects", true, "Sound Effects", "Enable sound effects on dismemberment", false, false, (ValueValidator)null, (string)null); EnableVrEyeBlindness = Category.CreateEntry<bool>("EnableVrEyeBlindness", true, "VR Eye Blindness", "When an eye is destroyed, blackout that eye in the VR headset (local player only)", false, false, (ValueValidator)null, (string)null); EnableHeadSever = Category.CreateEntry<bool>("EnableHeadSever", true, "Head Sever", "Make lethal head damage use stronger decapitation effects", false, false, (ValueValidator)null, (string)null); EnableVisualCuts = Category.CreateEntry<bool>("EnableAvatarCutMasks", false, "Visual Cuts", "Experimental Marrow cut masks; keep off if the avatar shows square artifacts", false, false, (ValueValidator)null, (string)null); EnableAttackTypeBalancing = Category.CreateEntry<bool>("EnableAttackTypeBalancing", true, "Attack Type Balancing", "Use different limb damage rules for piercing, blunt, sharp, fire, and explosion-like attacks", false, false, (ValueValidator)null, (string)null); PiercingDamageMultiplier = Category.CreateEntry<float>("PiercingDamageMultiplier", 1.35f, "Piercing Damage", "Limb damage multiplier for piercing attacks", false, false, (ValueValidator)null, (string)null); BluntDamageMultiplier = Category.CreateEntry<float>("BluntDamageMultiplier", 0.65f, "Blunt Damage", "Limb damage multiplier for blunt attacks", false, false, (ValueValidator)null, (string)null); SlashDamageMultiplier = Category.CreateEntry<float>("SlashDamageMultiplier", 1.55f, "Slash Damage", "Limb damage multiplier for slicing attacks", false, false, (ValueValidator)null, (string)null); StabDamageMultiplier = Category.CreateEntry<float>("StabDamageMultiplier", 1.75f, "Stab Damage", "Limb damage multiplier for stabbing attacks", false, false, (ValueValidator)null, (string)null); FireDamageMultiplier = Category.CreateEntry<float>("FireDamageMultiplier", 0.25f, "Fire Damage", "Limb damage multiplier for fire attacks", false, false, (ValueValidator)null, (string)null); ExplosionRadius = Category.CreateEntry<float>("ExplosionRadius", 2.25f, "Explosion Radius", "Default blast radius for limb damage when the weapon does not provide one", false, false, (ValueValidator)null, (string)null); EnableBlastLimbDamage = Category.CreateEntry<bool>("EnableBlastLimbDamage", true, "Grenade & Mine Limbs", "Radial limb damage from grenades, mines, and other explosions", false, false, (ValueValidator)null, (string)null); ExplosivePatches.TryRegister(_harmony); FusionRigLoadingFix.TryRegister(_harmony); MultiplayerHooking.OnPlayerJoined += new PlayerUpdate(OnPlayerJoined); MultiplayerHooking.OnPlayerLeft += new PlayerUpdate(OnPlayerLeft); PlayerID.OnMetadataChangedEvent += OnMetadataChanged; NetworkPlayer.OnNetworkRigCreated += OnNetworkRigCreated; PropertyInfo property = typeof(MelonUtils).GetProperty("UserDataDirectory", BindingFlags.Static | BindingFlags.Public); _soundFolder = Path.Combine((string)property.GetValue(null), "DeadPiece", "Sounds"); try { if (!Directory.Exists(_soundFolder)) { Directory.CreateDirectory(_soundFolder); } } catch (Exception ex2) { MelonLogger.Warning("Sound folder setup failed: " + ex2.Message); } LoadBloodColorOverrides(); } private static void WarnAboutLegacyNetworkPlugin() { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { string text = assemblies[i]?.GetName()?.Name ?? string.Empty; if (text.Equals("DeadPiecePlugin", StringComparison.OrdinalIgnoreCase)) { MelonLogger.Error("[DeadPiece] Legacy Plugins/DeadPiecePlugin.dll is loaded. Remove it from every client; it conflicts with the integrated Fusion transport and can break joins."); break; } } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Could not check for the legacy network plugin: " + ex.Message); } } public override void OnLateInitializeMelon() { if (!NetworkSync.RegisterHandlers()) { MelonLogger.Error("[DeadPiece] Fusion network handlers are unavailable; multiplayer sync is disabled."); } } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { RigManager rigManager = Player.RigManager; ResetHealthDisplaysForScene(); ResetNpcRuntimeForScene(); CancelManagedFatalOutcome((Object)(object)_managedFatalHealth != (Object)null && _managedFatalHealth.alive); RestoreAllOneHpHealthStates(); RestoreAllLegColliderStates(); ResetLimbStats(rigManager, restoreBody: true); RestoreDeadpieceLegUsage(rigManager); RestoreNoLegJump(rigManager); RestoreNoLegFallenState(rigManager); _sceneGeneration++; _locomotionRecoveryToken++; _playersHealth.Clear(); _colliderBoneMap.Clear(); _colliderBoneDistanceMap.Clear(); _originalScales.Clear(); _avatarScaleBaselines.Clear(); _hiddenBoneMasks.Clear(); _lastLimbDamageTimes.Clear(); _legColliderOriginalStates.Clear(); _lastHitEffectTimes.Clear(); _lastStumpBloodEffectTimes.Clear(); _stumpBloodStartTimes.Clear(); _lastAvatarHashes.Clear(); _avatarHealthBaseCache.Clear(); _avatarHealthHashCache.Clear(); _trackedRigs.Clear(); _rigCache.Clear(); _localRigInitialized = false; _lastTrackedBodyHealth = -1f; _lastAutoInjectorUseTime = -999f; _lastLocalRespawnRequestTime = -999f; _startupScheduled = false; _pendingHealthRefresh.Clear(); _pendingRespawnPlayers.Clear(); _activeRespawnRestoreWorkers.Clear(); _hardRespawnRecoveryPlayers.Clear(); _localRespawnRestoreWorkerActive = false; _hardLocalRespawnRecovery = false; _healingRestoreInProgress = false; _cachedRm = null; _rigWasDead.Clear(); _pendingNetworkStates.Clear(); _lastAppliedNetworkSequence.Clear(); _appliedStateMasks.Clear(); _remoteFallenPlayers.Clear(); ClearPlayerInteractionState(); _bloodColorOverrides.Clear(); _bloodColorIndexOverrides.Clear(); _playerLimbsEnabled.Clear(); _networkHealthBaseOverrides.Clear(); _networkInteractionStats.Clear(); _oneHpHealthSnapshots.Clear(); _settingsPublished = false; _healthBasePublished = false; _interactionStatsPublished = false; _lastPublishedHealthBase = -1f; _wasHostForSettings = false; _serverEnabled = HostEnabled?.Value ?? true; _serverOneHpMode = OneHpMode?.Value ?? false; _lastLeftArmUsable = true; _lastRightArmUsable = true; _localStateSequence = 0; _lastSentStateMask = uint.MaxValue; _lastStateSyncTime = -999f; _dualStickResetTapCount = 0; _fleshCardFound = false; _gameBloodParticlePrefab = null; _lastGameBloodParticleSearchTime = -999f; _loggedMissingGameBloodParticles = false; _loggedVanillaBloodSpawnable = false; _loggedVanillaBloodSpawnableFailure = false; _smallBloodSplatterSpawnable = null; _largeBloodSplatterSpawnable = null; _bloodBagBlasterSpawnable = null; _vanillaBloodSpawnablesRegistered = false; _locomotionStateSaved = false; _deadpieceNoLegUsageApplied = false; _deadpieceUsageRig = null; _deadpieceUsageHealth = null; _deadpieceUsageAvatarHash = 0; _deadpieceJumpBlocked = false; _deadpieceJumpOwnerRig = null; _deadpieceJumpRig = null; _deadpieceFallenStateApplied = false; _savedUsageHips = 1f; _savedUsageSpine = 1f; _savedUsageLegLf = 1f; _savedUsageLegRt = 1f; _savedUsageArmLf = 1f; _savedUsageArmRt = 1f; SuppressNoLegRagdollForRespawn(); ResetLocalNoLegRagdollPermission(); _savedLocomotionMaxVelocity = 4.5f; _savedLocomotionCurrentMaxVelocity = 4.5f; _savedLocomotionJumpEnabled = true; _savedLocomotionDoubleJump = true; ClearVrEyeCameraCache(); ForceClearNoLegRagdollState(rigManager); _leftHandDisabledByDeadPiece = false; _rightHandDisabledByDeadPiece = false; NetworkSync.ResetSessionState(); DamageVolumeContextPatch.ResetTracking(); if (_dismemberSounds.Count == 0) { MelonCoroutines.Start(LoadDismemberSounds()); } } private void HandleAvatarSwap(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null) { return; } int hashCode = ((Object)rm.avatar).GetHashCode(); int value; bool flag = _lastAvatarHashes.TryGetValue(rm, out value); if ((flag && value == hashCode) || (Object)(object)rm.avatar.animator == (Object)null) { return; } if ((Object)(object)rm == (Object)(object)Player.RigManager && _deadpieceNoLegUsageApplied && _deadpieceUsageAvatarHash != hashCode) { RestoreDeadpieceLegUsage(_deadpieceUsageRig); } if ((Object)(object)rm == (Object)(object)Player.RigManager && flag && _deadpieceJumpBlocked) { RestoreNoLegJump(_deadpieceJumpOwnerRig); } if (OnAvatarSwapped(rm)) { _lastAvatarHashes[rm] = hashCode; MaintainOneHpHealth(rm, refill: true); if ((Object)(object)rm == (Object)(object)Player.RigManager && NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { PublishLocalHealthBase(force: true); PublishLocalInteractionStats(force: true); } } } private void PrepareAvatarSwap(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { RestoreLegColliderState(rm); _originalScales.Remove(rm); _colliderBoneMap.Remove(rm); _colliderBoneDistanceMap.Remove(rm); InvalidateAvatarHealthCache(rm); InvalidateRigCache(rm); _lastAvatarHashes.Remove(rm); if ((Object)(object)rm == (Object)(object)Player.RigManager) { _locomotionStateSaved = false; } } } private bool OnAvatarSwapped(RigManager rm) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) if (!IsRigAvatarReadyForLimbRestore(rm)) { return false; } PrepareAvatarSwap(rm); bool value = default(bool); uint num = ((!((Object)(object)rm.health != (Object)null && rm.health.alive && _rigWasDead.TryGetValue(rm, out value) && value)) ? GetStateMask(rm) : 0u); BuildColliderBoneMap(rm); RebuildBoneCache(rm); LoadAvatarScaleBaseline(rm); if (IsRigLimbDamageBlocked(rm)) { ResetLimbStats(rm, restoreBody: true); if ((Object)(object)rm == (Object)(object)Player.RigManager) { UpdateLimbPenaltyFlag(rm); } return true; } HumanBodyBones[] damageBones = DamageBones; ResetLimbStats(rm, restoreBody: false); if (num == 0) { _hiddenBoneMasks.Remove(rm); } else { _hiddenBoneMasks[rm] = num; } if (_playersHealth.TryGetValue(rm, out var value2)) { for (int i = 0; i < damageBones.Length; i++) { HumanBodyBones val = damageBones[i]; Transform cachedBoneTransform = GetCachedBoneTransform(rm, val); bool flag = (num & (uint)(1 << i)) != 0; if ((Object)(object)cachedBoneTransform != (Object)null && flag) { cachedBoneTransform.localScale = Vector3.zero; } else if ((Object)(object)cachedBoneTransform != (Object)null && ShouldRepairBoneScale(rm, val, cachedBoneTransform)) { cachedBoneTransform.localScale = ResolveRestorableBoneScale(rm, val, cachedBoneTransform); } if (flag) { value2[val] = 0f - GetMaxHealthForBone(rm, val); } } } RebuildLimbGoneFlags(rm); SyncLegColliderState(rm); RefreshLimbMaxHealth(rm); ScheduleDelayedHealthRefresh(rm); if ((Object)(object)rm == (Object)(object)Player.RigManager) { UpdateLimbPenaltyFlag(rm); SetHandUsable(Player.LeftHand, !IsLeftArmGone(rm)); SetHandUsable(Player.RightHand, !IsRightArmGone(rm)); EnforceLocalFatalState(rm); } return true; } public void OnHealthAvatarChanging(Health health) { if (!((Object)(object)health == (Object)null)) { RigManager rigFromHealth = GetRigFromHealth(health); RestoreOneHpHealth(rigFromHealth); RestoreOutgoingAvatarScales(rigFromHealth); if (_deadpieceNoLegUsageApplied && (Object)(object)_deadpieceUsageHealth == (Object)(object)health) { RestoreDeadpieceLegUsage(_deadpieceUsageRig); } if (_deadpieceJumpBlocked && (Object)(object)_deadpieceJumpOwnerRig == (Object)(object)rigFromHealth) { RestoreNoLegJump(rigFromHealth); } PrepareAvatarSwap(rigFromHealth); } } public void OnHealthAvatarSet(Health health, Avatar avatar) { RigManager rigFromHealth = GetRigFromHealth(health); if (!((Object)(object)rigFromHealth == (Object)null)) { TrackRig(rigFromHealth); _lastAvatarHashes.Remove(rigFromHealth); HandleAvatarSwap(rigFromHealth); MaintainOneHpHealth(rigFromHealth, refill: true); ScheduleDelayedHealthRefresh(rigFromHealth); if ((Object)(object)rigFromHealth == (Object)(object)Player.RigManager && NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { PublishLocalHealthBase(force: true); PublishLocalInteractionStats(force: true); } } } private RigManager GetRigFromHealth(Health health) { if ((Object)(object)health == (Object)null) { return null; } return health._rigManager ?? ((Component)health).GetComponentInParent<RigManager>(); } private void ScheduleDelayedHealthRefresh(RigManager rm) { if (!((Object)(object)rm == (Object)null) && _pendingHealthRefresh.Add(rm)) { MelonCoroutines.Start(DelayedRefreshLimbHealth(rm)); } } private IEnumerator DelayedRefreshLimbHealth(RigManager rm) { yield return null; yield return null; _pendingHealthRefresh.Remove(rm); if (!((Object)(object)rm == (Object)null)) { InvalidateAvatarHealthCache(rm); if (!IsRigLimbDamageBlocked(rm)) { RefreshLimbMaxHealth(rm); } } } public void EnsureRigInitialized(RigManager rm) { RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); if (orCreateRigCache.Initialized && _playersHealth.ContainsKey(rm) && _colliderBoneMap.ContainsKey(rm)) { TrackRig(rm); return; } if (!_playersHealth.ContainsKey(rm)) { ResetLimbStats(rm, restoreBody: false); } if (!_colliderBoneMap.ContainsKey(rm)) { BuildColliderBoneMap(rm); } RebuildBoneCache(rm); orCreateRigCache.Initialized = true; TrackRig(rm); } private void ResetLimbStats(RigManager rm, bool restoreBody) { //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: 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_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return; } if (restoreBody && (Object)(object)rm == (Object)(object)Player.RigManager && _managedFatalOutcome != ManagedFatalOutcome.None) { CancelManagedFatalOutcome((Object)(object)_managedFatalHealth != (Object)null && _managedFatalHealth.alive); } InvalidateAvatarHealthCache(rm); uint stateMask = GetStateMask(rm); _lastLimbDamageTimes.Remove(rm); bool flag = IsArmGoneInMask(stateMask, left: true); bool flag2 = IsArmGoneInMask(stateMask, left: false); bool flag3 = AreBothLegsGoneInMask(stateMask); if (!_playersHealth.ContainsKey(rm)) { _playersHealth[rm] = new Dictionary<HumanBodyBones, float>(); } if (!_originalScales.ContainsKey(rm)) { int hashCode = ((Object)rm.avatar).GetHashCode(); if (_avatarScaleBaselines.TryGetValue(hashCode, out var value)) { _originalScales[rm] = new Dictionary<HumanBodyBones, Vector3>(value); } else { _originalScales[rm] = new Dictionary<HumanBodyBones, Vector3>(); } } HumanBodyBones[] damageBones = DamageBones; RebuildBoneCache(rm); RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); ResetLimbDamageBlockCache(rm); Transform[] boneTransforms = orCreateRigCache.BoneTransforms; HashSet<HumanBodyBones> hashSet = new HashSet<HumanBodyBones>(); for (int i = 0; i < damageBones.Length; i++) { HumanBodyBones val = damageBones[i]; Transform val2 = ((boneTransforms != null && i < boneTransforms.Length) ? boneTransforms[i] : null); if (!((Object)(object)val2 == (Object)null)) { hashSet.Add(val); bool flag4 = restoreBody && (IsBoneInMask(stateMask, val) || ShouldRepairBoneScale(rm, val, val2)); CaptureOriginalBoneScale(rm, val, val2); _playersHealth[rm][val] = GetMaxHealthForBone(rm, val); if (flag4) { val2.localScale = ResolveRestorableBoneScale(rm, val, val2); } } } HumanBodyBones[] array = _playersHealth[rm].Keys.ToArray(); for (int j = 0; j < array.Length; j++) { if (!hashSet.Contains(array[j])) { _playersHealth[rm].Remove(array[j]); } } if (restoreBody) { ClearAppliedLimbState(rm); _hiddenBoneMasks.Remove(rm); } RebuildLimbGoneFlags(rm); if (restoreBody) { ClearStumpBloodState(rm); if ((Object)(object)rm == (Object)(object)Player.RigManager) { ClearVrEyeCameraCache(); _lastAppliedLeftEyeBlind = false; _lastAppliedRightEyeBlind = false; UpdateVrEyeBlindness(rm); RestoreLocomotion(); RestoreOriginalLimits(rm); ResetLegRagdoll(rm); RestoreDeadpieceLegUsage(rm); RestoreNoLegJump(rm); RestoreNoLegFallenState(rm); if (flag3) { ReleaseDeadpieceCrouchState(rm); } if (flag || _leftHandDisabledByDeadPiece) { SetHandUsable(Player.LeftHand, usable: true); } if (flag2 || _rightHandDisabledByDeadPiece) { SetHandUsable(Player.RightHand, usable: true); } _lastLeftArmUsable = true; _lastRightArmUsable = true; } ResetVisualDamage(rm); } if ((Object)(object)rm == (Object)(object)Player.RigManager) { _lastTrackedBodyHealth = -1f; UpdateRigMissingLimbsFlag(rm); SetLocalMetadata(""); } GetAvatarHealthBase(rm); RebuildBoneCache(rm); UpdateRigMissingLimbsFlag(rm); SyncLegColliderState(rm); if (restoreBody && (Object)(object)rm != (Object)(object)Player.RigManager && IsRemotePlayerRig(rm)) { ApplyRemoteLegEffects(rm); } BuildColliderBoneMap(rm); } private void TryCacheFleshSurface() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown if (_fleshCardFound) { return; } try { AssetWarehouse instance = AssetWarehouse.Instance; if (instance == null || !AssetWarehouse.ready) { return; } SurfaceDataCard val = default(SurfaceDataCard); if (instance.TryGetDataCard<SurfaceDataCard>(new Barcode("SLZ.Backlot.SurfaceDataCard.Blood"), ref val) && (Object)(object)val != (Object)null) { _fleshSurfaceCard = new DataCardReference<SurfaceDataCard>(((Scannable)val).Barcode); _fleshCardFound = true; MelonLogger.Msg(ConsoleColor.Gray, "Found vanilla Blood surface card: SLZ.Backlot.SurfaceDataCard.Blood"); return; } SurfaceDataC