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(); 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 _contacts; [ThreadStatic] private static float _updateLastTickTime; private static readonly Dictionary> TrackedColliders = new Dictionary>(); 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(); _updateLastTickTime = (((Object)(object)volume != (Object)null) ? volume._lastTickTime : 0f); } internal static void EndUpdate(DamageVolume volume) { if (!((Object)(object)_updateVolume != (Object)(object)volume)) { List 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 value2; if (entered) { if (!collider.isTrigger) { if (!TrackedColliders.TryGetValue(volume, out var value)) { value = new HashSet(); 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 { 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(); if ((Object)(object)val2 == (Object)(object)rb) { activeCollider = val; return true; } } return false; } private static RigManager ResolveRigManager(Rigidbody rb) { RigManager componentInParent = ((Component)rb).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } PlayerDamageReceiver componentInChildren = ((Component)rb).GetComponentInChildren(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 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(); 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 contacts) { if (contacts == null || contacts.Count == 0 || DeadPieceMod.Instance == null) { return; } Dictionary> dictionary = new Dictionary>(); foreach (Contact contact in contacts) { if (!((Object)(object)contact?.Rig == (Object)null)) { if (!dictionary.TryGetValue(contact.Rig, out var value)) { value = new List(); dictionary[contact.Rig] = value; } value.Add(contact); } } foreach (KeyValuePair> item in dictionary) { bool flag = false; foreach (Contact item2 in item.Value) { flag |= item2.AttackHandled; } bool flag2 = flag; HashSet damagedBones = new HashSet(); 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 Bones = new Dictionary(); public readonly Dictionary OriginalScales = new Dictionary(); public readonly Dictionary> VisualBones = new Dictionary>(); public readonly Dictionary VisualScales = new Dictionary(); public readonly HashSet HiddenVisualBones = new HashSet(); public readonly Dictionary> VisualRenderers = new Dictionary>(); public readonly Dictionary RendererForceOffStates = new Dictionary(); public readonly Dictionary PendingRendererForceOffStates = new Dictionary(); public readonly List VisualMeshes = new List(); public readonly Dictionary VisualMeshRetryTimes = new Dictionary(); public readonly Dictionary VisualMeshFailureCounts = new Dictionary(); public readonly Dictionary NpcRendererUpdateStates = new Dictionary(); public readonly HashSet NpcClothUpdateRenderers = new HashSet(); public readonly Dictionary NpcAnimatorCullingStates = new Dictionary(); 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 LimbHealth = new Dictionary(); public readonly Dictionary LastDamageTimes = new Dictionary(); public readonly Dictionary ColliderStates = new Dictionary(); public uint ColliderMaskApplied; public readonly List BloodEffects = new List(); 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[] 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 MaxLimbHealth; public static MelonPreferences_Entry DamageMultiplier; public static MelonPreferences_Entry EnableSoundEffects; public static MelonPreferences_Entry EnableDualStickDeathReset; public static MelonPreferences_Entry SeveredLimbBleedDamagePerSecond; public static MelonPreferences_Entry EnableVrEyeBlindness; public static MelonPreferences_Entry EnableHeadSever; public static MelonPreferences_Entry EnableVisualCuts; public static MelonPreferences_Entry EnableAttackTypeBalancing; public static MelonPreferences_Entry PiercingDamageMultiplier; public static MelonPreferences_Entry BluntDamageMultiplier; public static MelonPreferences_Entry SlashDamageMultiplier; public static MelonPreferences_Entry StabDamageMultiplier; public static MelonPreferences_Entry FireDamageMultiplier; public static MelonPreferences_Entry ExplosionRadius; public static MelonPreferences_Entry EnableBlastLimbDamage; public static MelonPreferences_Entry EnableImpactBlood; public static MelonPreferences_Entry EnableBloodEffects; public static MelonPreferences_Entry EnableGameBloodEffects; public static MelonPreferences_Entry EnableFallbackBloodEffects; public static MelonPreferences_Entry BloodColorOverride; public static MelonPreferences_Entry EnableMovementPenalty; public static MelonPreferences_Entry EnableSecondLegRagdoll; public static MelonPreferences_Entry HostEnabled; public static MelonPreferences_Entry LimbsEnabled; public static MelonPreferences_Entry OneHpMode; public static DeadPieceMod Instance; private DataCardReference _fleshSurfaceCard; private bool _fleshCardFound; private readonly List _gameBloodSpawnableBarcodes = new List(); 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> _playersHealth = new Dictionary>(); private readonly Dictionary> _colliderBoneMap = new Dictionary>(); private readonly Dictionary> _colliderBoneDistanceMap = new Dictionary>(); private readonly Dictionary> _originalScales = new Dictionary>(); private readonly Dictionary> _avatarScaleBaselines = new Dictionary>(); private readonly Dictionary _hiddenBoneMasks = new Dictionary(); private readonly Dictionary> _lastLimbDamageTimes = new Dictionary>(); private readonly Dictionary> _legColliderOriginalStates = new Dictionary>(); private readonly Dictionary> _lastHitEffectTimes = new Dictionary>(); private readonly Dictionary> _lastStumpBloodEffectTimes = new Dictionary>(); private readonly Dictionary> _stumpBloodStartTimes = new Dictionary>(); private readonly Dictionary _pendingNetworkStates = new Dictionary(); private readonly Dictionary _appliedStateMasks = new Dictionary(); private readonly HashSet _remoteFallenPlayers = new HashSet(); private bool _lastLeftArmUsable = true; private bool _lastRightArmUsable = true; private readonly Dictionary _lastAppliedNetworkSequence = new Dictionary(); private ushort _localStateSequence; private uint _lastSentStateMask = uint.MaxValue; private float _lastStateSyncTime = -999f; private readonly List _dismemberSounds = new List(); public AudioClip DismemberSound; private string _soundFolder; private readonly Dictionary _lastAvatarHashes = new Dictionary(); private readonly Dictionary _avatarBloodOverrides = new Dictionary(); private readonly Dictionary _bloodColorOverrides = new Dictionary(); private readonly Dictionary _bloodColorIndexOverrides = new Dictionary(); 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 _playerLimbsEnabled = new Dictionary(); private readonly Dictionary _networkHealthBaseOverrides = new Dictionary(); private readonly Dictionary _oneHpHealthSnapshots = new Dictionary(); public static readonly HumanBodyBones[] DamageBones; private static readonly HashSet FatalBones; private static readonly HashSet TorsoBones; private static readonly HashSet 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 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 _rigWasDead = new Dictionary(); private readonly Dictionary _avatarHealthBaseCache = new Dictionary(); private readonly Dictionary _avatarHealthHashCache = new Dictionary(); private readonly HashSet _trackedRigs = new HashSet(); private float _slowUpdateTimer; private float _avatarSwapTimer; private RigManager _vrEyeCacheRig; private bool _vrEyeCamerasCached; private bool _lastAppliedLeftEyeBlind; private bool _lastAppliedRightEyeBlind; private readonly List _vrLeftEyeCameras = new List(); private readonly List _vrRightEyeCameras = new List(); private readonly Dictionary _vrCameraEnabledBackup = new Dictionary(); private readonly Dictionary _vrEyeBlackoutObjects = new Dictionary(); private int _updateFrame; private int _sceneGeneration; private bool _localRigInitialized; private bool _startupScheduled; private bool _wasConnected; private readonly HashSet _pendingHealthRefresh = new HashSet(); private readonly HashSet _pendingRespawnPlayers = new HashSet(); private readonly HashSet _activeRespawnRestoreWorkers = new HashSet(); private readonly HashSet _hardRespawnRecoveryPlayers = new HashSet(); 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 _rigCache = new Dictionary(); 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 EnableLocalHealthHud; public static MelonPreferences_Entry 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 _playerHealthBarViews = new Dictionary(); private readonly HashSet _seenPlayerHealthBars = new HashSet(); private static readonly Color DefaultNpcBloodColor; private Material _npcBloodParticleMaterial; private const float NpcDestroyedBodyDespawnDelay = 1.5f; private const float NpcDestroyedBodyDespawnResolveTimeout = 3.5f; private readonly Dictionary _npcLimbStates = new Dictionary(); private readonly Dictionary _npcHealthOwners = new Dictionary(); private readonly Dictionary _npcEntityLookup = new Dictionary(); private readonly HashSet _npcPendingBodyDespawns = new HashSet(); private readonly HashSet _npcTerminalBodyDespawns = new HashSet(); 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 _pendingNpcNetworkStates = new Dictionary(); 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 _localInteractionCooldowns = new Dictionary(); private readonly Dictionary _hostInteractionCooldowns = new Dictionary(); private readonly Dictionary _localCrushContactTimes = new Dictionary(); private readonly Dictionary _recentGrabEvidence = new Dictionary(); private readonly Dictionary _recentNpcGrabEvidence = new Dictionary(); private readonly Dictionary _recentPlayerCrushEvidence = new Dictionary(); private readonly Dictionary _recentNpcCrushEvidence = new Dictionary(); private readonly Dictionary _pendingPlayerInteractions = new Dictionary(); private readonly Dictionary _pendingNpcInteractions = new Dictionary(); private readonly Dictionary _networkInteractionStats = new Dictionary(); private static readonly Il2CppReferenceArray 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 BuildBoneToIndexMap() { Dictionary dictionary = new Dictionary(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)OnHostSettingChanged); _limbsMenuToggle = val.CreateBool("Limbs On-Off", Color.red, LimbsEnabled?.Value ?? true, (Action)OnLimbsSettingChanged); _oneHpMenuToggle = val.CreateBool("All Players 1 HP", Color.red, IsOneHpModeEnabled(), (Action)OnOneHpSettingChanged); _localHealthHudMenuToggle = val.CreateBool("Health HUD", Color.red, EnableLocalHealthHud?.Value ?? false, (Action)OnLocalHealthHudSettingChanged); _playerHealthBarsMenuToggle = val.CreateBool("Player HP Bars", Color.red, EnablePlayerHealthBars?.Value ?? false, (Action)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 hashSet = new HashSet(_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 hashSet = new HashSet(_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("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("LimbsEnabled", true, "Limbs On-Off", "Allow your limbs to be destroyed", false, false, (ValueValidator)null, (string)null); OneHpMode = Category.CreateEntry("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("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("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("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("DamageMultiplier", 1f, "Damage Multiplier", "Multiplier for damage dealt to limbs", false, false, (ValueValidator)null, (string)null); EnableImpactBlood = Category.CreateEntry("EnableImpactBlood", true, "Severed Limb Bleed", "Tiny damage ticks at severed bone tips (vanilla impact blood)", false, false, (ValueValidator)null, (string)null); EnableBloodEffects = Category.CreateEntry("EnableBloodEffects", true, "Blood Effects", "Enable blood particle effects on dismemberment", false, false, (ValueValidator)null, (string)null); EnableGameBloodEffects = Category.CreateEntry("EnableGameBloodEffects", true, "Game Blood", "Clone already-loaded BONELAB blood VFX instead of shipping custom particles", false, false, (ValueValidator)null, (string)null); EnableFallbackBloodEffects = Category.CreateEntry("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("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("EnableMovementPenalty", true, "Movement Penalty", "Apply movement restrictions and body lowering when legs are lost", false, false, (ValueValidator)null, (string)null); EnableSecondLegRagdoll = Category.CreateEntry("EnableSecondLegRagdoll", false, "Second Leg Ragdoll", "Deprecated; DeadPiece no longer changes player leg physics", false, false, (ValueValidator)null, (string)null); SeveredLimbBleedDamagePerSecond = Category.CreateEntry("SeveredLimbBleedDamagePerSecond", 0.01f, "Bleed DPS", "Damage per second at each severed limb tip", false, false, (ValueValidator)null, (string)null); EnableDualStickDeathReset = Category.CreateEntry("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("EnableSoundEffects", true, "Sound Effects", "Enable sound effects on dismemberment", false, false, (ValueValidator)null, (string)null); EnableVrEyeBlindness = Category.CreateEntry("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("EnableHeadSever", true, "Head Sever", "Make lethal head damage use stronger decapitation effects", false, false, (ValueValidator)null, (string)null); EnableVisualCuts = Category.CreateEntry("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("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("PiercingDamageMultiplier", 1.35f, "Piercing Damage", "Limb damage multiplier for piercing attacks", false, false, (ValueValidator)null, (string)null); BluntDamageMultiplier = Category.CreateEntry("BluntDamageMultiplier", 0.65f, "Blunt Damage", "Limb damage multiplier for blunt attacks", false, false, (ValueValidator)null, (string)null); SlashDamageMultiplier = Category.CreateEntry("SlashDamageMultiplier", 1.55f, "Slash Damage", "Limb damage multiplier for slicing attacks", false, false, (ValueValidator)null, (string)null); StabDamageMultiplier = Category.CreateEntry("StabDamageMultiplier", 1.75f, "Stab Damage", "Limb damage multiplier for stabbing attacks", false, false, (ValueValidator)null, (string)null); FireDamageMultiplier = Category.CreateEntry("FireDamageMultiplier", 0.25f, "Fire Damage", "Limb damage multiplier for fire attacks", false, false, (ValueValidator)null, (string)null); ExplosionRadius = Category.CreateEntry("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("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(); } 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(); } if (!_originalScales.ContainsKey(rm)) { int hashCode = ((Object)rm.avatar).GetHashCode(); if (_avatarScaleBaselines.TryGetValue(hashCode, out var value)) { _originalScales[rm] = new Dictionary(value); } else { _originalScales[rm] = new Dictionary(); } } HumanBodyBones[] damageBones = DamageBones; RebuildBoneCache(rm); RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); ResetLimbDamageBlockCache(rm); Transform[] boneTransforms = orCreateRigCache.BoneTransforms; HashSet hashSet = new HashSet(); 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(new Barcode("SLZ.Backlot.SurfaceDataCard.Blood"), ref val) && (Object)(object)val != (Object)null) { _fleshSurfaceCard = new DataCardReference(((Scannable)val).Barcode); _fleshCardFound = true; MelonLogger.Msg(ConsoleColor.Gray, "Found vanilla Blood surface card: SLZ.Backlot.SurfaceDataCard.Blood"); return; } SurfaceDataCard val2 = default(SurfaceDataCard); if (instance.TryGetDataCard(new Barcode("slz.marrow.surfacedata.Flesh"), ref val2) && (Object)(object)val2 != (Object)null) { _fleshSurfaceCard = new DataCardReference(((Scannable)val2).Barcode); _fleshCardFound = true; MelonLogger.Msg(ConsoleColor.Gray, "Found Flesh surface card by barcode: slz.marrow.surfacedata.Flesh"); return; } List dataCards = instance.GetDataCards(); if (dataCards == null) { return; } Enumerator enumerator = dataCards.GetEnumerator(); while (enumerator.MoveNext()) { DataCard current = enumerator.Current; if ((Object)(object)current == (Object)null) { continue; } SurfaceDataCard val3 = ((Il2CppObjectBase)current).TryCast(); if (!((Object)(object)val3 == (Object)null)) { string text = ((Scannable)val3).Title ?? string.Empty; string text2 = text.ToLowerInvariant(); if (text2.Contains("blood") || text2.Contains("flesh")) { _fleshSurfaceCard = new DataCardReference(((Scannable)val3).Barcode); _fleshCardFound = true; MelonLogger.Msg($"Found Flesh surface card by title: {text} ({((Scannable)val3).Barcode})"); break; } } } } catch (Exception ex) { MelonLogger.Warning("Flesh surface scan failed: " + ex.Message); } } private void SetFleshImpactProperties(RigManager rm, HumanBodyBones bone) { //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (!EnableImpactBlood.Value || !_fleshCardFound || (Object)(object)rm == (Object)null || !_colliderBoneMap.TryGetValue(rm, out var value)) { return; } try { foreach (KeyValuePair item in value) { if (item.Value != bone) { continue; } Collider key = item.Key; if (!((Object)(object)key == (Object)null)) { ImpactProperties val = ((Component)key).GetComponent(); if ((Object)(object)val == (Object)null) { val = ((Component)key).gameObject.AddComponent(); } if ((Object)(object)val != (Object)null) { val.SurfaceDataCard = _fleshSurfaceCard; } } } } catch (Exception ex) { MelonLogger.Warning($"SetFleshImpactProperties failed for {bone}: {ex.Message}"); } } private static bool IsAvatarBodyCollider(Collider collider, Transform avatarRoot) { if ((Object)(object)collider == (Object)null || (Object)(object)avatarRoot == (Object)null) { return false; } Transform val = ((Component)collider).transform; if (!val.IsChildOf(avatarRoot)) { return false; } for (int i = 0; i < 14; i++) { if (!((Object)(object)val != (Object)null)) { break; } if (!((Object)(object)val != (Object)(object)avatarRoot)) { break; } string text = ((Object)val).name.ToLowerInvariant(); if (text.Contains("gun") || text.Contains("pistol") || text.Contains("rifle") || text.Contains("weapon") || text.Contains("magazine") || text.Contains("ammo") || text.Contains("slide") || text.Contains("barrel") || text.Contains("trigger") || text.Contains("holster")) { return false; } Type il2CppType = ((Object)val).GetIl2CppType(); if (il2CppType != (Type)null) { string text2 = il2CppType.FullName ?? string.Empty; if (text2.Contains("Gun") || text2.Contains("Weapon") || text2.Contains("Magazine") || text2.Contains("Ammo") || text2.Contains("Firearm") || text2.Contains("Cartridge") || text2.Contains("Projectile")) { return false; } } val = val.parent; } return true; } private static bool IsUsableBoneScale(Vector3 scale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return IsFiniteBoneScale(scale) && ((Vector3)(ref scale)).sqrMagnitude > 1E-06f; } private static bool IsFiniteBoneScale(Vector3 scale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) return !float.IsNaN(scale.x) && !float.IsNaN(scale.y) && !float.IsNaN(scale.z) && !float.IsInfinity(scale.x) && !float.IsInfinity(scale.y) && !float.IsInfinity(scale.z); } private bool HasBoneRestoreEvidence(RigManager rm, HumanBodyBones bone) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || !BoneToIndexMap.TryGetValue(bone, out var value)) { return false; } uint num = (uint)(1 << value); if ((GetStateMask(rm) & num) != 0) { return true; } if (_playersHealth.TryGetValue(rm, out var value2) && value2.TryGetValue(bone, out var value3) && value3 <= 0f) { return true; } foreach (KeyValuePair appliedStateMask in _appliedStateMasks) { if ((appliedStateMask.Value & num) != 0 && TryResolvePlayerRig(appliedStateMask.Key, out var rigManager) && (Object)(object)rigManager == (Object)(object)rm) { return true; } } foreach (KeyValuePair pendingNetworkState in _pendingNetworkStates) { if ((pendingNetworkState.Value.GoneBoneMask & num) != 0 && TryResolvePlayerRig(pendingNetworkState.Key, out var rigManager2) && (Object)(object)rigManager2 == (Object)(object)rm) { return true; } } return false; } private bool ShouldRepairBoneScale(RigManager rm, HumanBodyBones bone, Transform boneTransform) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boneTransform == (Object)null || IsUsableBoneScale(boneTransform.localScale)) { return false; } if (_originalScales.TryGetValue(rm, out var value) && value.TryGetValue(bone, out var value2) && IsFiniteBoneScale(value2)) { return IsUsableBoneScale(value2); } return HasBoneRestoreEvidence(rm, bone); } private Vector3 ResolveRestorableBoneScale(RigManager rm, HumanBodyBones bone, Transform boneTransform) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!_originalScales.TryGetValue(rm, out var value)) { value = new Dictionary(); _originalScales[rm] = value; } if (value.TryGetValue(bone, out var value2) && IsFiniteBoneScale(value2)) { return value2; } Vector3 val = (((Object)(object)boneTransform != (Object)null && IsUsableBoneScale(boneTransform.localScale)) ? boneTransform.localScale : Vector3.one); return value[bone] = val; } private void CaptureOriginalBoneScale(RigManager rm, HumanBodyBones bone, Transform boneTransform) { //IL_004a: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)boneTransform == (Object)null) { return; } if (!_originalScales.TryGetValue(rm, out var value)) { value = new Dictionary(); _originalScales[rm] = value; } if (value.ContainsKey(bone)) { return; } Vector3 localScale = boneTransform.localScale; if (!IsFiniteBoneScale(localScale) || (!IsUsableBoneScale(localScale) && HasBoneRestoreEvidence(rm, bone))) { return; } value[bone] = localScale; if ((Object)(object)rm.avatar != (Object)null) { int hashCode = ((Object)rm.avatar).GetHashCode(); if (!_avatarScaleBaselines.TryGetValue(hashCode, out var value2)) { value2 = new Dictionary(); _avatarScaleBaselines[hashCode] = value2; } if (!value2.ContainsKey(bone)) { value2[bone] = localScale; } } } private void LoadAvatarScaleBaseline(RigManager rm) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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; } int hashCode = ((Object)rm.avatar).GetHashCode(); if (!_avatarScaleBaselines.TryGetValue(hashCode, out var value)) { value = new Dictionary(); _avatarScaleBaselines[hashCode] = value; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (!value.ContainsKey(val)) { Transform cachedBoneTransform = GetCachedBoneTransform(rm, val); if ((Object)(object)cachedBoneTransform != (Object)null && IsFiniteBoneScale(cachedBoneTransform.localScale)) { value[val] = cachedBoneTransform.localScale; } } } _originalScales[rm] = new Dictionary(value); } private void RestoreOutgoingAvatarScales(RigManager rm) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; Transform boneTransform = rm.avatar.animator.GetBoneTransform(val); if ((Object)(object)boneTransform != (Object)null && (IsBoneGone(rm, val) || ShouldRepairBoneScale(rm, val, boneTransform))) { boneTransform.localScale = ResolveRestorableBoneScale(rm, val, boneTransform); } } } private void RegrowLimb(RigManager rm, HumanBodyBones bone) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return; } Transform cachedBoneTransform = GetCachedBoneTransform(rm, bone); if (!((Object)(object)cachedBoneTransform == (Object)null)) { Vector3 localScale = ResolveRestorableBoneScale(rm, bone, cachedBoneTransform); cachedBoneTransform.localScale = localScale; SetBoneHiddenState(rm, bone, hidden: false); if (_playersHealth.TryGetValue(rm, out var value)) { value[bone] = GetMaxHealthForBone(rm, bone); } ClearStumpBloodState(rm, bone); } } private void MarkLimbDamaged(RigManager rm, HumanBodyBones bone) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rm == (Object)null)) { if (!_lastLimbDamageTimes.TryGetValue(rm, out var value)) { value = new Dictionary(); _lastLimbDamageTimes[rm] = value; } value[bone] = Time.time; } } private void ProcessLimbHealthRegeneration(float deltaTime) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) if (deltaTime <= 0f || !IsSessionEnabled() || _playersHealth.Count == 0) { return; } KeyValuePair>[] array = _playersHealth.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair> keyValuePair = array[i]; RigManager key = keyValuePair.Key; if ((Object)(object)key == (Object)null || (Object)(object)key.health == (Object)null || !key.health.alive || ((Object)(object)key != (Object)(object)Player.RigManager && (!NetworkInfo.IsHost || !IsRemotePlayerRig(key))) || !_lastLimbDamageTimes.TryGetValue(key, out var value)) { continue; } Dictionary value2 = keyValuePair.Value; for (int j = 0; j < DamageBones.Length; j++) { HumanBodyBones val = DamageBones[j]; if (IsBoneGone(key, val)) { continue; } float maxHealthForBone = GetMaxHealthForBone(key, val); if (value2.TryGetValue(val, out var value3) && !(value3 <= 0f)) { float value4; if (value3 >= maxHealthForBone) { value2[val] = maxHealthForBone; value.Remove(val); } else if (!value.TryGetValue(val, out value4)) { value[val] = Time.time; } else if (!(Time.time - value4 < 3f)) { value2[val] = Mathf.Min(maxHealthForBone, value3 + maxHealthForBone * 0.1f * deltaTime); } } } if (value.Count == 0) { _lastLimbDamageTimes.Remove(key); } } } private void ProcessPlayerHealing(RigManager rm) { if ((Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)((rm != null) ? rm.health : null) == (Object)null || !rm.health.alive) { return; } if (IsRigLimbDamageBlocked(rm) || !_playersHealth.ContainsKey(rm)) { _lastTrackedBodyHealth = rm.health.curr_Health; return; } float curr_Health = rm.health.curr_Health; if (_lastTrackedBodyHealth < 0f) { _lastTrackedBodyHealth = curr_Health; return; } if (curr_Health <= _lastTrackedBodyHealth) { _lastTrackedBodyHealth = curr_Health; return; } _lastTrackedBodyHealth = curr_Health; if (IsAutoInjectorUseActiveOrRecent()) { RestoreMissingLimbsFromHealing(rm, forceRefresh: true); } } public void OnHealthSetFullHealth(Health health, float previousHealth) { RigManager rigFromHealth = GetRigFromHealth(health); if ((Object)(object)rigFromHealth == (Object)null) { return; } if ((Object)(object)rigFromHealth == (Object)(object)Player.RigManager) { if (health.alive) { RestoreMissingLimbsFromHealing(rigFromHealth, forceRefresh: true); } } else if (IsRemotePlayerRig(rigFromHealth) && health.curr_Health > previousHealth) { RestoreMissingLimbsFromHealing(rigFromHealth, forceRefresh: true); } } public void OnHealthRespawn(Health health) { RigManager rigFromHealth = GetRigFromHealth(health); if (!((Object)(object)rigFromHealth == (Object)null) && !((Object)(object)rigFromHealth != (Object)(object)Player.RigManager)) { CancelManagedFatalOutcome(resetPresentation: false); MaintainOneHpHealth(rigFromHealth, refill: true); RequestLocalRespawnReset(rigFromHealth); } } private void RequestLocalRespawnReset(RigManager rm, bool hardLocomotionRecovery = true) { byte b = ((PlayerIDManager.LocalID != null) ? PlayerIDManager.LocalSmallID : byte.MaxValue); bool flag = b != byte.MaxValue && _pendingRespawnPlayers.Contains(b); if (NetworkInfo.HasServer && b != byte.MaxValue && !flag && Time.unscaledTime - _lastLocalRespawnRequestTime > 0.5f) { _lastLocalRespawnRequestTime = Time.unscaledTime; NetworkSync.SendRespawn(b); } QueueRespawnRestore(b, rm, hardLocomotionRecovery); } private void QueueRespawnRestore(byte playerId, RigManager expectedRig = null, bool hardLocomotionRecovery = false) { if (playerId != byte.MaxValue) { if (hardLocomotionRecovery) { _hardRespawnRecoveryPlayers.Add(playerId); } _pendingNetworkStates.Remove(playerId); _appliedStateMasks.Remove(playerId); _remoteFallenPlayers.Remove(playerId); _pendingRespawnPlayers.Add(playerId); if (!_activeRespawnRestoreWorkers.Add(playerId)) { return; } } else { if (hardLocomotionRecovery) { _hardLocalRespawnRecovery = true; } if (_localRespawnRestoreWorkerActive) { return; } _localRespawnRestoreWorkerActive = true; } MelonCoroutines.Start(DelayedRespawnRestore(playerId, expectedRig, _sceneGeneration)); } private IEnumerator DelayedRespawnRestore(byte playerId, RigManager expectedRig, int generation) { try { while (generation == _sceneGeneration && ((playerId == byte.MaxValue) ? _localRespawnRestoreWorkerActive : _pendingRespawnPlayers.Contains(playerId))) { RigManager rm = null; bool restored = false; try { if (playerId != byte.MaxValue) { TryResolvePlayerRig(playerId, out rm); } else { rm = (((Object)(object)Player.RigManager != (Object)null) ? Player.RigManager : expectedRig); } restored = TryRestoreRigAfterRespawn(rm, playerId); } catch { } if (restored) { if (playerId != byte.MaxValue) { _pendingRespawnPlayers.Remove(playerId); _hardRespawnRecoveryPlayers.Remove(playerId); } else { _hardLocalRespawnRecovery = false; } try { if ((Object)(object)rm == (Object)(object)Player.RigManager && NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { SyncLocalState(0u); } else if (NetworkInfo.IsHost && playerId != byte.MaxValue) { NetworkSync.SendFullState(playerId, 0u, GetBloodColorIndexForRig(rm), 0); } break; } catch { break; } } yield return null; } } finally { if (playerId == byte.MaxValue) { _localRespawnRestoreWorkerActive = false; _hardLocalRespawnRecovery = false; } else { _activeRespawnRestoreWorkers.Remove(playerId); if (!_pendingRespawnPlayers.Contains(playerId)) { _hardRespawnRecoveryPlayers.Remove(playerId); } } } } private bool TryRestoreRigAfterRespawn(RigManager rm, byte playerId) { //IL_013a: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)rm.health == (Object)null || !rm.health.alive || !IsRigAvatarReadyForLimbRestore(rm)) { return false; } HandleAvatarSwap(rm); if (!IsRigAvatarReadyForLimbRestore(rm)) { return false; } if (playerId != byte.MaxValue) { _pendingNetworkStates.Remove(playerId); _appliedStateMasks.Remove(playerId); _remoteFallenPlayers.Remove(playerId); } bool flag = (Object)(object)rm == (Object)(object)Player.RigManager && ((playerId == byte.MaxValue) ? _hardLocalRespawnRecovery : _hardRespawnRecoveryPlayers.Contains(playerId)); if ((Object)(object)rm == (Object)(object)Player.RigManager) { SuppressNoLegRagdollForRespawn(); ResetLocalNoLegRagdollPermission(); } ResetLimbStats(rm, restoreBody: true); if (GetStateMask(rm) != 0) { return false; } RebuildBoneCache(rm); if (!_playersHealth.TryGetValue(rm, out var value)) { return false; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; Transform cachedBoneTransform = GetCachedBoneTransform(rm, val); if ((Object)(object)cachedBoneTransform != (Object)null && (ShouldRepairBoneScale(rm, val, cachedBoneTransform) || !value.TryGetValue(val, out var value2) || value2 <= 0f)) { return false; } } if ((Object)(object)rm == (Object)(object)Player.RigManager) { _lastTrackedBodyHealth = -1f; UpdateLimbPenaltyFlag(rm); if (flag) { ScheduleLocalLocomotionRecovery(rm); if (!IsLocalLocomotionRecovered(rm)) { return false; } } } else if (IsRemotePlayerRig(rm)) { ApplyRemoteLegEffects(rm); } _rigWasDead[rm] = false; TrackRig(rm); return true; } private static bool IsRigAvatarReadyForLimbRestore(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return false; } Animator animator = rm.avatar.animator; if (!animator.isInitialized || !animator.isHuman) { return false; } try { return (Object)(object)animator.GetBoneTransform((HumanBodyBones)0) != (Object)null && (Object)(object)animator.GetBoneTransform((HumanBodyBones)7) != (Object)null && (Object)(object)animator.GetBoneTransform((HumanBodyBones)10) != (Object)null; } catch { return false; } } private void UpdateAutoInjectorUseWindow() { try { if (IsAutoInjectorUsePressed(Player.LeftHand, Player.LeftController) || IsAutoInjectorUsePressed(Player.RightHand, Player.RightController)) { _lastAutoInjectorUseTime = Time.unscaledTime; } } catch { } } public bool IsAutoInjectorUseActiveOrRecent() { if (Time.unscaledTime - _lastAutoInjectorUseTime <= 0.8f) { return true; } return IsAutoInjectorUsePressed(Player.LeftHand, Player.LeftController) || IsAutoInjectorUsePressed(Player.RightHand, Player.RightController); } private void UpdateExplosiveUseWindow() { try { if ((IsExplosiveHeld(Player.LeftHand) || IsExplosiveHeld(Player.RightHand)) && (IsExplosiveDetonatePressed(Player.LeftHand, Player.LeftController) || IsExplosiveDetonatePressed(Player.RightHand, Player.RightController))) { _lastExplosiveUseTime = Time.unscaledTime; TriggerSelfExplosion(); } } catch { } } public bool IsExplosiveUseActiveOrRecent() { if (Time.unscaledTime - _lastExplosiveUseTime <= 1.5f) { return true; } return false; } private bool IsExplosiveHeld(Hand hand) { if ((Object)(object)hand == (Object)null) { return false; } try { HandReciever attachedReceiver = hand.AttachedReceiver; if ((Object)(object)attachedReceiver == (Object)null) { return false; } if (IsExplosiveObject(((Component)attachedReceiver).gameObject)) { return true; } IGrippable host = attachedReceiver.Host; GameObject gameObject = ((host != null) ? host.GetHostGameObject() : null); return IsExplosiveObject(gameObject); } catch { } return false; } private bool IsExplosiveObject(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return false; } Transform val = gameObject.transform; for (int i = 0; i < 8; i++) { if (!((Object)(object)val != (Object)null)) { break; } if (LooksLikeExplosiveName(((Object)val).name)) { return true; } val = val.parent; } return false; } private bool LooksLikeExplosiveName(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } string text = objectName.ToLowerInvariant(); return text.Contains("explosive") || text.Contains("micro") || text.Contains("nuke") || text.Contains("dynamite") || text.Contains("c4") || text.Contains("grenade") || text.Contains("prox") || text.Contains("ied") || text.Contains("mine") || (text.Contains("timed") && (text.Contains("explos") || text.Contains("nuke"))); } private bool IsExplosiveDetonatePressed(Hand hand, BaseController controller) { if ((Object)(object)hand == (Object)null || (Object)(object)controller == (Object)null) { return false; } bool primaryInteractionButtonDown = controller.GetPrimaryInteractionButtonDown(); bool secondaryInteractionButtonDown = controller.GetSecondaryInteractionButtonDown(); return primaryInteractionButtonDown && secondaryInteractionButtonDown; } private void TriggerSelfExplosion() { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null) { return; } string[] array = new string[41] { "BaBaCorp.MiscExplosiveDevices.Spawnable.MicroNukeGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.TimedNuke", "BaBaCorp.MiscExplosiveDevices.Spawnable.KCB4VoidTunnelingDevice", "BaBaCorp.MiscExplosiveDevices.Spawnable.IncinMissile", "BaBaCorp.MiscExplosiveDevices.Spawnable.Missile", "BaBaCorp.MiscExplosiveDevices.Spawnable.MiniMissile", "BaBaCorp.MiscExplosiveDevices.Spawnable.TimedC4", "BaBaCorp.MiscExplosiveDevices.Spawnable.CelebratoryC4", "BaBaCorp.MiscExplosiveDevices.Spawnable.RemoteIED", "BaBaCorp.MiscExplosiveDevices.Spawnable.TriggeredExplosive", "BaBaCorp.MiscExplosiveDevices.Spawnable.ImpactExplosive", "BaBaCorp.MiscExplosiveDevices.Spawnable.TimedExplosive6sec", "BaBaCorp.MiscExplosiveDevices.Spawnable.M72LAW", "BaBaCorp.MiscExplosiveDevices.Spawnable.M72LawINF", "BaBaCorp.MiscExplosiveDevices.Spawnable.ClassicBomb", "BaBaCorp.MiscExplosiveDevices.Spawnable.Dynamite", "BaBaCorp.MiscExplosiveDevices.Spawnable.ProxMine", "BaBaCorp.MiscExplosiveDevices.Spawnable.GiftMine", "BaBaCorp.MiscExplosiveDevices.Spawnable.FragmentationGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.IncendiaryGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.DivinationGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.GasGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.JoyousGreenGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.Stielhandgranate", "BaBaCorp.MiscExplosiveDevices.Spawnable.SmallRocket", "BaBaCorp.MiscExplosiveDevices.Spawnable.PurpleFireworkRocket", "BaBaCorp.MiscExplosiveDevices.Spawnable.GreenFireworkRocket", "BaBaCorp.MiscExplosiveDevices.Spawnable.BlueFireworkRocket", "BaBaCorp.MiscExplosiveDevices.Spawnable.RedFireworkRocket", "BaBaCorp.MiscExplosiveDevices.Spawnable.BirthdayCake", "BaBaCorp.MiscExplosiveDevices.Spawnable.Frank", "BaBaCorp.MiscExplosiveDevices.Spawnable.BatteryAcidGlass", "BaBaCorp.MiscExplosiveDevices.Spawnable.CrateWithLid", "BaBaCorp.MiscExplosiveDevices.Spawnable.PropaneTank", "BaBaCorp.MiscExplosiveDevices.Spawnable.FuelTank", "BaBaCorp.MiscExplosiveDevices.Spawnable.SmokeGrenade", "BaBaCorp.MiscExplosiveDevices.Spawnable.Flare", "BaBaCorp.MiscExplosiveDevices.Spawnable.Jarate", "BaBaCorp.MiscExplosiveDevices.Spawnable.Lighter", "BaBaCorp.MiscExplosiveDevices.Spawnable.Pliers", "BaBaCorp.MiscExplosiveDevices.Spawnable.ExplosionSmallBigDamage" }; string[] array2 = array; foreach (string text in array2) { try { TriggerExplosion(rigManager, text); MelonLogger.Msg(ConsoleColor.Gray, "Self explosion triggered with: " + text); break; } catch (Exception ex) { MelonLogger.Warning("Explosion failed for " + text + ": " + ex.Message); } } } private void TriggerExplosion(RigManager rm, string explosiveBarcode) { //IL_0031: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) MelonLogger.Msg(ConsoleColor.Gray, "TriggerExplosion: attempting " + explosiveBarcode); if ((Object)(object)rm == (Object)null) { MelonLogger.Error("RigManager is null!"); return; } try { Spawnable val = new Spawnable { crateRef = new SpawnableCrateReference(explosiveBarcode), policyData = null }; if (!val.IsValid()) { MelonLogger.Error("Spawnable is not valid for " + explosiveBarcode); return; } MelonLogger.Msg(ConsoleColor.Gray, "Spawnable valid, spawning at position..."); Vector3 val2 = ((Component)rm).transform.position + ((Component)rm).transform.forward * 0.5f + ((Component)rm).transform.up * 0.5f; Action action = OnExplosiveSpawned; AssetSpawner.Spawn(val, val2, Quaternion.identity, new Nullable(Vector3.one), (Transform)null, false, (Nullable)null, Action.op_Implicit(action), (Action)null); MelonLogger.Msg(ConsoleColor.Gray, "AssetSpawner.Spawn called for " + explosiveBarcode); } catch (Exception value) { MelonLogger.Error($"TriggerExplosion exception for {explosiveBarcode}: {value}"); } } private void OnExplosiveSpawned(GameObject spawned) { MelonLogger.Msg(ConsoleColor.Gray, $"OnExplosiveSpawned called, spawned: {(Object)(object)spawned != (Object)null}"); if ((Object)(object)spawned != (Object)null) { MelonLogger.Msg(ConsoleColor.Gray, $"Spawned object name: {((Object)spawned).name}, active: {spawned.activeInHierarchy}"); Il2CppArrayBase componentsInChildren = spawned.GetComponentsInChildren(true); MelonLogger.Msg(ConsoleColor.Gray, $"Found {componentsInChildren.Length} components"); foreach (MonoBehaviour item in componentsInChildren) { if ((Object)(object)item != (Object)null) { MelonLogger.Msg(ConsoleColor.Gray, "Component: " + ((object)item).GetType().Name); } } ForceDetonate(spawned); } else { MelonLogger.Error("Spawned object is null!"); } } private void ForceDetonate(GameObject spawned) { MelonLogger.Msg(ConsoleColor.Gray, "ForceDetonate called for " + ((Object)spawned).name); try { Il2CppArrayBase componentsInChildren = spawned.GetComponentsInChildren(true); MelonLogger.Msg(ConsoleColor.Gray, $"Checking {componentsInChildren.Length} components for Detonate/Explode methods"); foreach (MonoBehaviour item in componentsInChildren) { if (!((Object)(object)item == (Object)null)) { MethodInfo method = ((object)item).GetType().GetMethod("Detonate", BindingFlags.Instance | BindingFlags.Public); if (method != null) { MelonLogger.Msg(ConsoleColor.Gray, "Found Detonate() on " + ((object)item).GetType().Name + ", invoking..."); method.Invoke(item, null); MelonLogger.Msg(ConsoleColor.Gray, "Detonated via " + ((object)item).GetType().Name + ".Detonate()"); return; } } } Rigidbody component = spawned.GetComponent(); if ((Object)(object)component != (Object)null) { component.useGravity = true; component.isKinematic = false; MelonLogger.Msg(ConsoleColor.Gray, "Set rigidbody for gravity detonation"); } else { MelonLogger.Warning("No Rigidbody found on spawned object"); } foreach (MonoBehaviour item2 in componentsInChildren) { if (!((Object)(object)item2 == (Object)null)) { MethodInfo method2 = ((object)item2).GetType().GetMethod("Explode", BindingFlags.Instance | BindingFlags.Public); if (method2 != null) { MelonLogger.Msg(ConsoleColor.Gray, "Found Explode() on " + ((object)item2).GetType().Name + ", invoking..."); method2.Invoke(item2, null); MelonLogger.Msg(ConsoleColor.Gray, "Detonated via " + ((object)item2).GetType().Name + ".Explode()"); return; } } } MelonLogger.Warning("No detonation method found, object spawned but may not explode automatically"); } catch (Exception value) { MelonLogger.Error($"ForceDetonate exception: {value}"); } } public bool IsHoldingNimbusGun(RigManager rm) { return IsNimbusGunHand(Player.LeftHand) || IsNimbusGunHand(Player.RightHand); } private bool IsNimbusGunHand(Hand hand) { if ((Object)(object)hand == (Object)null) { return false; } try { HandReciever attachedReceiver = hand.AttachedReceiver; if ((Object)(object)attachedReceiver == (Object)null) { return false; } IGrippable host = attachedReceiver.Host; GameObject val = ((host != null) ? host.GetHostGameObject() : null); if ((Object)(object)val == (Object)null) { return false; } SpawnableCrate componentInChildren = val.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && ((Scannable)componentInChildren).Barcode != (Barcode)null && ((Object)((Scannable)componentInChildren).Barcode).ToString().Contains("Nimbus")) { return true; } Transform val2 = val.transform; while ((Object)(object)val2 != (Object)null) { if (((Object)val2).name.Contains("Nimbus")) { return true; } val2 = val2.parent; } } catch { } return false; } private bool IsAutoInjectorUsePressed(Hand hand, BaseController controller) { if (!IsAutoInjectorHeldByHand(hand)) { return false; } bool flag = false; try { flag |= (Object)(object)hand != (Object)null && (hand.GetIndexButtonDown() || hand.GetIndexButton()); } catch { } try { flag |= (Object)(object)controller != (Object)null && (controller.GetPrimaryInteractionButtonDown() || controller.GetPrimaryInteractionButton()); flag |= (Object)(object)controller != (Object)null && (controller.GetSecondaryInteractionButtonDown() || controller.GetSecondaryInteractionButton()); flag |= (Object)(object)controller != (Object)null && (controller.GetAButtonDown() || controller.GetAButton()); flag |= (Object)(object)controller != (Object)null && (controller.GetBButtonDown() || controller.GetBButton()); } catch { } return flag; } private bool IsAutoInjectorHeldByHand(Hand hand) { if ((Object)(object)hand == (Object)null) { return false; } try { HandReciever attachedReceiver = hand.AttachedReceiver; if ((Object)(object)attachedReceiver == (Object)null) { return false; } if (IsAutoInjectorObject(((Component)attachedReceiver).gameObject)) { return true; } IGrippable host = attachedReceiver.Host; GameObject gameObject = ((host != null) ? host.GetHostGameObject() : null); return IsAutoInjectorObject(gameObject); } catch { return false; } } private bool IsAutoInjectorObject(GameObject gameObject) { Transform val = (((Object)(object)gameObject != (Object)null) ? gameObject.transform : null); for (int i = 0; i < 8; i++) { if (!((Object)(object)val != (Object)null)) { break; } if (LooksLikeAutoInjectorName(((Object)val).name)) { return true; } val = val.parent; } return false; } private bool LooksLikeAutoInjectorName(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } string text = objectName.ToLowerInvariant(); string text2 = text.Replace(" ", string.Empty).Replace("_", string.Empty).Replace("-", string.Empty); return text2.Contains("autoinjector") || (text2.Contains("auto") && text2.Contains("inject")) || text2.Contains("signalisautoinjector"); } internal void HandleDamageVolumeHealing(RigManager rm) { if (!((Object)(object)rm == (Object)null) && (!((Object)(object)rm != (Object)(object)Player.RigManager) || NetworkInfo.IsHost)) { RestoreMissingLimbsFromHealing(rm); } } internal bool HandleDamageVolumeContact(DamageVolume volume, RigManager rm, Rigidbody rb, Collider volumeCollider, float signedDamage, bool applyBodyDamage, bool applyLimbDamage, HashSet damagedBones) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_01e6: 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_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Invalid comparison between Unknown and I4 //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Invalid comparison between Unknown and I4 //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Invalid comparison between Unknown and I4 //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Expected O, but got Unknown //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)volume == (Object)null || (Object)(object)rm == (Object)null || (Object)(object)rb == (Object)null || signedDamage == 0f || float.IsNaN(signedDamage) || float.IsInfinity(signedDamage) || !IsSessionEnabled()) { return false; } PlayerDamageReceiver val = FindDamageVolumeReceiver(rm, rb, volumeCollider); Collider val2 = volumeCollider ?? ((val != null) ? ((Component)val).GetComponent() : null) ?? ((Component)rb).GetComponentInChildren(true); Vector3 val3 = (((Object)(object)val2 != (Object)null) ? val2.ClosestPoint(rb.worldCenterOfMass) : rb.worldCenterOfMass); Vector3 val4 = (((Object)(object)volume._damageSourceTransform != (Object)null) ? volume._damageSourceTransform.position : ((Component)volume).transform.position); Vector3 val5 = val3 - val4; if (((Vector3)(ref val5)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val5)).Normalize(); } bool result = false; if (applyBodyDamage && (Object)(object)val != (Object)null && !IsRemotePlayerRig(rm)) { Attack val6 = new Attack { damage = signedDamage, origin = val4, direction = val5, normal = -val5, collider = val2, attackType = volume._damageType }; DamageVolumeContextPatch.EnterFallbackBody(); try { val.ReceiveAttack(val6); result = true; } finally { DamageVolumeContextPatch.ExitFallbackBody(); } } if (signedDamage < 0f) { if (damagedBones == null || damagedBones.Add((HumanBodyBones)55)) { HandleDamageVolumeHealing(rm); } return result; } if (!applyLimbDamage) { return result; } if (!IsLimbDestructionAllowed(rm)) { return result; } HumanBodyBones bone = (HumanBodyBones)((!((Object)(object)val != (Object)null)) ? 55 : ((int)BodyPartToBone(val.bodyPart))); if ((int)bone == 55 && (Object)(object)val2 != (Object)null) { TryGetBoneFromCollider(rm, val2, val3, out bone); } if ((int)bone == 55 && !TryGetNearestExtremityBone(rm, val3, out bone)) { TryGetNearestBone(rm, val3, out bone); } if ((int)bone == 55 || (damagedBones != null && !damagedBones.Add(bone))) { return result; } Attack attack = new Attack { damage = signedDamage, origin = val4, direction = val5, normal = -val5, collider = val2, attackType = volume._damageType }; float damage = CalculateAttackDamage(attack, rm, bone); if (IsRemotePlayerRig(rm)) { if (NetworkInfo.IsHost) { ProcessRemoteLimbHit(rm, bone, damage, val3); } } else { OnBoneHit(rm, bone, damage, val3); } return result; } private PlayerDamageReceiver FindDamageVolumeReceiver(RigManager rm, Rigidbody rb, Collider volumeCollider) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) PlayerDamageReceiver val = null; float num = float.MaxValue; if ((Object)(object)volumeCollider != (Object)null) { PlayerDamageReceiver val2 = ((Component)volumeCollider).GetComponentInParent() ?? ((Component)volumeCollider).GetComponentInChildren(true); if ((Object)(object)val2 != (Object)null) { Health health = val2.health; if ((Object)(object)((health != null) ? health._rigManager : null) == (Object)(object)rm) { return val2; } } } Il2CppArrayBase componentsInChildren = ((Component)rb).GetComponentsInChildren(true); Vector3 val3; foreach (PlayerDamageReceiver item in componentsInChildren) { if ((Object)(object)item == (Object)null) { continue; } Health health2 = item.health; if (!((Object)(object)((health2 != null) ? health2._rigManager : null) != (Object)(object)rm)) { val3 = ((Component)item).transform.position - rb.worldCenterOfMass; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = item; } } } PlayerDamageReceiver componentInParent = ((Component)rb).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { Health health3 = componentInParent.health; if ((Object)(object)((health3 != null) ? health3._rigManager : null) == (Object)(object)rm) { val3 = ((Component)componentInParent).transform.position - rb.worldCenterOfMass; float sqrMagnitude2 = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude2 < num) { num = sqrMagnitude2; val = componentInParent; } } } if ((Object)(object)val != (Object)null) { return val; } componentsInChildren = ((Component)rm).GetComponentsInChildren(true); foreach (PlayerDamageReceiver item2 in componentsInChildren) { if ((Object)(object)item2 == (Object)null) { continue; } Health health4 = item2.health; if (!((Object)(object)((health4 != null) ? health4._rigManager : null) != (Object)(object)rm)) { val3 = ((Component)item2).transform.position - rb.worldCenterOfMass; float sqrMagnitude3 = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude3 < num) { num = sqrMagnitude3; val = item2; } } } return val; } private bool NeedsLimbRestore(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return false; } if (GetStateMask(rm) != 0) { return true; } RebuildBoneCache(rm); for (int i = 0; i < DamageBones.Length; i++) { Transform cachedBoneTransform = GetCachedBoneTransform(rm, DamageBones[i]); if ((Object)(object)cachedBoneTransform != (Object)null && ShouldRepairBoneScale(rm, DamageBones[i], cachedBoneTransform)) { return true; } } if (_playersHealth.TryGetValue(rm, out var value)) { for (int j = 0; j < DamageBones.Length; j++) { if (value.TryGetValue(DamageBones[j], out var value2) && value2 <= 0f) { return true; } } } return false; } private bool RestoreMissingLimbsFromHealing(RigManager rm, bool forceRefresh = false) { if ((Object)(object)rm == (Object)null) { return false; } if (!IsRigAvatarReadyForLimbRestore(rm)) { QueueHealingRestore(rm); return false; } _healingRestoreInProgress = true; try { HandleAvatarSwap(rm); if (!IsRigAvatarReadyForLimbRestore(rm)) { QueueHealingRestore(rm); return false; } EnsureRigInitialized(rm); bool flag = NeedsLimbRestore(rm); if (!flag && !forceRefresh) { return false; } ResetLimbStats(rm, restoreBody: true); if (flag && NetworkInfo.HasServer) { byte playerId; if ((Object)(object)rm == (Object)(object)Player.RigManager) { RequestLocalRespawnReset(rm, hardLocomotionRecovery: false); } else if (NetworkInfo.IsHost && TryGetPlayerIdForRig(rm, out playerId)) { NetworkSync.SendFullState(playerId, 0u, 0, 0); } } return true; } finally { _healingRestoreInProgress = false; } } private void QueueHealingRestore(RigManager rm) { if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm.health == (Object)null) && rm.health.alive) { byte playerId; if ((Object)(object)rm == (Object)(object)Player.RigManager) { RequestLocalRespawnReset(rm, hardLocomotionRecovery: false); } else if (NetworkInfo.IsHost && TryGetPlayerIdForRig(rm, out playerId)) { QueueRespawnRestore(playerId, rm); } } } private void ProcessSeveredLimbBleed(RigManager rm, float deltaTime) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (!EnableImpactBlood.Value || (Object)(object)rm == (Object)null || deltaTime <= 0f || !_playersHealth.ContainsKey(rm)) { return; } float num = Mathf.Max(0f, SeveredLimbBleedDamagePerSecond.Value) * deltaTime; if (num <= 0f && !EnableBloodEffects.Value) { return; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones bone = DamageBones[i]; if (!IsBoneGone(rm, bone)) { continue; } float remainingStumpBloodLifetime = GetRemainingStumpBloodLifetime(rm, bone, startIfMissing: true); if (!(remainingStumpBloodLifetime <= 0.05f)) { if (num > 0f) { TryApplyBleedAtBone(rm, bone, num); } TryPlayStumpBloodEffect(rm, bone, remainingStumpBloodLifetime); } } } private void ProcessRemoteRigsStumpBlood(float deltaTime) { if (!EnableImpactBlood.Value || _trackedRigs.Count == 0 || deltaTime <= 0f) { return; } RigManager[] array = _trackedRigs.ToArray(); foreach (RigManager val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)Player.RigManager) { ProcessSeveredLimbBleed(val, deltaTime); } } } private void TryPlayStumpBloodEffect(RigManager rm, HumanBodyBones bone, float remainingBloodLifetime) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!EnableBloodEffects.Value || !EnableGameBloodEffects.Value || (Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null || remainingBloodLifetime <= 0.05f || !ShouldPlayStumpBloodEffect(rm, bone)) { return; } Transform cachedBoneTransform = GetCachedBoneTransform(rm, bone); if (!((Object)(object)cachedBoneTransform == (Object)null)) { Vector3 val = GetBoneStreamDirection(rm, bone, cachedBoneTransform); if (val == Vector3.zero) { val = cachedBoneTransform.up; } val = ((Vector3)(ref val)).normalized; Vector3 val2 = cachedBoneTransform.position + val * 0.04f; Color bloodColor = GetBloodColor(rm); TryApplyBloodImpactAtBone(rm, bone, val2, 3f, bloodColor); if (!TrySpawnVanillaBloodSpawnable(val2, 0.72f, stream: true, Quaternion.LookRotation(val), bloodColor, remainingBloodLifetime)) { TrySpawnGameBlood(val2, 0.55f, bloodColor, remainingBloodLifetime); } } } private bool ShouldPlayStumpBloodEffect(RigManager rm, HumanBodyBones bone) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!_lastStumpBloodEffectTimes.TryGetValue(rm, out var value)) { value = new Dictionary(); _lastStumpBloodEffectTimes[rm] = value; } if (value.TryGetValue(bone, out var value2) && Time.time - value2 < 0.45f) { return false; } value[bone] = Time.time; return true; } private void MarkStumpBloodStarted(RigManager rm, HumanBodyBones bone) { //IL_003b: 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) if (!((Object)(object)rm == (Object)null)) { if (!_stumpBloodStartTimes.TryGetValue(rm, out var value)) { value = new Dictionary(); _stumpBloodStartTimes[rm] = value; } value[bone] = Time.time; if (_lastStumpBloodEffectTimes.TryGetValue(rm, out var value2)) { value2.Remove(bone); } } } private bool HasStumpBloodStart(RigManager rm, HumanBodyBones bone) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) Dictionary value; return (Object)(object)rm != (Object)null && _stumpBloodStartTimes.TryGetValue(rm, out value) && value.ContainsKey(bone); } private float GetRemainingStumpBloodLifetime(RigManager rm, HumanBodyBones bone, bool startIfMissing) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null) { return 0f; } if (!_stumpBloodStartTimes.TryGetValue(rm, out var value) || !value.TryGetValue(bone, out var value2)) { if (!startIfMissing) { return 0f; } MarkStumpBloodStarted(rm, bone); value2 = Time.time; } return Mathf.Max(0f, 10f - (Time.time - value2)); } private void ClearStumpBloodState(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { _stumpBloodStartTimes.Remove(rm); _lastStumpBloodEffectTimes.Remove(rm); } } private void ClearStumpBloodState(RigManager rm, HumanBodyBones bone) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null) { return; } if (_stumpBloodStartTimes.TryGetValue(rm, out var value)) { value.Remove(bone); if (value.Count == 0) { _stumpBloodStartTimes.Remove(rm); } } if (_lastStumpBloodEffectTimes.TryGetValue(rm, out var value2)) { value2.Remove(bone); if (value2.Count == 0) { _lastStumpBloodEffectTimes.Remove(rm); } } } private void TryApplyBleedAtBone(RigManager rm, HumanBodyBones bone, float damage) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) TryApplyBloodImpactAtBone(rm, bone, Vector3.zero, damage); } private bool TryApplyBloodImpactAtBone(RigManager rm, HumanBodyBones bone, Vector3 origin, float damage) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return TryApplyBloodImpactAtBone(rm, bone, origin, damage, Color.white); } private bool TryApplyBloodImpactAtBone(RigManager rm, HumanBodyBones bone, Vector3 origin, float damage, Color color) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //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_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((rm != null) ? rm.avatar : null) == (Object)null || damage <= 0f || !_colliderBoneMap.TryGetValue(rm, out var value)) { return false; } Collider val = null; foreach (KeyValuePair item in value) { if (item.Value == bone) { val = item.Key; break; } } if ((Object)(object)val == (Object)null) { return false; } try { ImpactProperties val2 = ((Component)val).GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).gameObject.AddComponent(); } if ((Object)(object)val2 == (Object)null) { return false; } if (_fleshCardFound) { val2.SurfaceDataCard = _fleshSurfaceCard; } Vector3 val3; Bounds bounds; if (!(origin == Vector3.zero)) { val3 = origin; } else { bounds = val.bounds; val3 = ((Bounds)(ref bounds)).center; } Vector3 val4 = val3; bounds = val.bounds; Vector3 val5 = ((Bounds)(ref bounds)).center - val4; if (val5 == Vector3.zero) { val5 = Vector3.down; } ((Vector3)(ref val5)).Normalize(); Attack val6 = new Attack { damage = damage, normal = -val5, origin = val4, direction = val5, backFacing = false, OrderInPool = 0, collider = val, attackType = (AttackType)1, proxy = null }; val2.ReceiveAttack(val6); return true; } catch { } return false; } private void SpawnBloodPoolDecal(Vector3 origin, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) try { Vector3 val = origin; val.y += 2.5f; RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, Vector3.down, ref val2, 5f, -1, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val2)).collider != (Object)null) { GameObject val3 = new GameObject("DeadPiece_BloodPool"); val3.transform.position = ((RaycastHit)(ref val2)).point + ((RaycastHit)(ref val2)).normal * 0.005f; val3.transform.rotation = Quaternion.LookRotation(((RaycastHit)(ref val2)).normal); val3.transform.localScale = Vector3.one * Mathf.Lerp(0.08f, 0.35f, Random.value); val3.transform.Rotate(0f, 0f, Random.Range(0f, 360f)); MeshFilter val4 = val3.AddComponent(); val4.sharedMesh = BuildBloodQuadMesh(); MeshRenderer val5 = val3.AddComponent(); ((Renderer)val5).material = new Material(Shader.Find("Sprites/Default")); ((Renderer)val5).material.color = color; ((Renderer)val5).material.mainTexture = null; Object.Destroy((Object)(object)val3, 10f); } } catch { } } private IEnumerator DelayedPoolClear(Poolee poolee, float delay) { yield return (object)new WaitForSeconds(delay); if ((Object)(object)poolee != (Object)null && (Object)(object)((Component)poolee).gameObject != (Object)null) { StopBloodEffectObject(((Component)poolee).gameObject); HideRenderers(((Component)poolee).gameObject); try { AssetSpawner.Clear(poolee); } catch { } if ((Object)(object)((Component)poolee).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)poolee).gameObject); } } } private IEnumerator RunAsyncSpawnBlood(Spawnable spawnable, Vector3 position, Quaternion rotation, Nullable scale, Color color, float clearDelay) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Poolee result = null; bool done = false; UniTask task = AssetSpawner.SpawnAsync(spawnable, position, rotation, scale, (Transform)null, false, (Nullable)null, (Action)null, (Action)null, (Action)null); Awaiter awaiter = task.GetAwaiter(); for (int i = 0; i < 60; i++) { if (done) { break; } yield return null; try { result = awaiter.GetResult(); done = true; } catch { } } if (!((Object)(object)result != (Object)null) || !((Object)(object)((Component)result).gameObject != (Object)null)) { yield break; } if (color != Color.white) { Renderer[] renderers = Il2CppArrayBase.op_Implicit(((Component)result).GetComponentsInChildren(true)); Renderer[] array = renderers; foreach (Renderer r in array) { Material mat = r.material; string[] colorProps = new string[5] { "_Color", "_BaseColor", "_TintColor", "_EmissiveColor", "_MainColor" }; string[] array2 = colorProps; foreach (string prop in array2) { if (mat.HasProperty(prop)) { mat.SetColor(prop, color); break; } } } ParticleSystem[] particles = Il2CppArrayBase.op_Implicit(((Component)result).GetComponentsInChildren(true)); ParticleSystem[] array3 = particles; foreach (ParticleSystem ps in array3) { MainModule main = ps.main; main.startColor = MinMaxGradient.op_Implicit(color); } } MelonCoroutines.Start(DelayedPoolClear(result, clearDelay)); } private IEnumerator RunAsyncSpawnVanillaBlood(Spawnable spawnable, Vector3 position, Quaternion rotation, Nullable scale, Nullable groupId, Color color, float clearDelay) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Poolee result = null; bool done = false; UniTask spawnTask = AssetSpawner.SpawnAsync(spawnable, position, rotation, scale, (Transform)null, false, groupId, (Action)null, (Action)null, (Action)null); Awaiter awaiter = spawnTask.GetAwaiter(); for (int i = 0; i < 60; i++) { if (done) { break; } yield return null; try { result = awaiter.GetResult(); done = true; } catch { } } if ((Object)(object)result == (Object)null) { if (!_loggedVanillaBloodSpawnableFailure) { _loggedVanillaBloodSpawnableFailure = true; MelonLogger.Warning("Vanilla BONELAB blood spawnable returned null."); } } else { if (!((Object)(object)((Component)result).gameObject != (Object)null)) { yield break; } Renderer[] allRenderers = Il2CppArrayBase.op_Implicit(((Component)result).GetComponentsInChildren(true)); Renderer[] array = allRenderers; foreach (Renderer r in array) { Material mat = r.material; string[] colorProps = new string[5] { "_Color", "_BaseColor", "_TintColor", "_EmissiveColor", "_MainColor" }; string[] array2 = colorProps; foreach (string prop in array2) { if (mat.HasProperty(prop)) { mat.SetColor(prop, color); break; } } } ParticleSystem[] particles = Il2CppArrayBase.op_Implicit(((Component)result).GetComponentsInChildren(true)); ParticleSystem[] array3 = particles; foreach (ParticleSystem ps in array3) { MainModule m = ps.main; m.startColor = MinMaxGradient.op_Implicit(color); } MelonCoroutines.Start(DelayedPoolClear(result, clearDelay)); } } private void StopBloodEffectObject(GameObject root) { if ((Object)(object)root == (Object)null) { return; } try { ParticleSystem[] array = Il2CppArrayBase.op_Implicit(root.GetComponentsInChildren(true)); ParticleSystem[] array2 = array; foreach (ParticleSystem val in array2) { if ((Object)(object)val != (Object)null) { val.Stop(true, (ParticleSystemStopBehavior)0); } } TrailRenderer[] array3 = Il2CppArrayBase.op_Implicit(root.GetComponentsInChildren(true)); TrailRenderer[] array4 = array3; foreach (TrailRenderer val2 in array4) { if ((Object)(object)val2 != (Object)null) { val2.Clear(); } } } catch { } } private void HideRenderers(GameObject root) { if ((Object)(object)root == (Object)null) { return; } try { Renderer[] array = Il2CppArrayBase.op_Implicit(root.GetComponentsInChildren(true)); Renderer[] array2 = array; foreach (Renderer val in array2) { if ((Object)(object)val != (Object)null) { val.enabled = false; } } } catch { } } private Mesh BuildBloodQuadMesh() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bloodQuadMesh != (Object)null) { return _bloodQuadMesh; } _bloodQuadMesh = new Mesh(); ((Object)_bloodQuadMesh).name = "DeadPiece_BloodQuad"; _bloodQuadMesh.vertices = Il2CppStructArray.op_Implicit((Vector3[])(object)new Vector3[4] { new Vector3(-0.5f, -0.5f, 0f), new Vector3(0.5f, -0.5f, 0f), new Vector3(-0.5f, 0.5f, 0f), new Vector3(0.5f, 0.5f, 0f) }); _bloodQuadMesh.triangles = Il2CppStructArray.op_Implicit(new int[6] { 0, 1, 2, 2, 1, 3 }); _bloodQuadMesh.uv = Il2CppStructArray.op_Implicit((Vector2[])(object)new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0f, 1f), new Vector2(1f, 1f) }); _bloodQuadMesh.RecalculateNormals(); return _bloodQuadMesh; } private void HandleStickInputs(float deltaTime) { if (!EnableDualStickDeathReset.Value || (Object)(object)Player.RigManager == (Object)null) { return; } try { BaseController leftController = Player.LeftController; BaseController rightController = Player.RightController; bool leftStickDown = (Object)(object)leftController != (Object)null && leftController.GetThumbStickDown(); bool rightStickDown = (Object)(object)rightController != (Object)null && rightController.GetThumbStickDown(); TryRegisterDualStickDeathResetTap(leftStickDown, rightStickDown); } catch (Exception ex) { MelonLogger.Warning("Stick input handling failed: " + ex.Message); } } private void TryRegisterDualStickDeathResetTap(bool leftStickDown, bool rightStickDown) { float unscaledTime = Time.unscaledTime; if (leftStickDown) { _lastLeftStickTapTime = unscaledTime; } if (rightStickDown) { _lastRightStickTapTime = unscaledTime; } if ((leftStickDown || rightStickDown) && !(Mathf.Abs(_lastLeftStickTapTime - _lastRightStickTapTime) > 0.25f) && !(unscaledTime - _lastDualStickTapRegisteredTime < 0.08f)) { _lastDualStickTapRegisteredTime = unscaledTime; if (unscaledTime > _dualStickResetTapWindowExpire) { _dualStickResetTapCount = 0; } _dualStickResetTapCount++; _dualStickResetTapWindowExpire = unscaledTime + 1.75f; if (_dualStickResetTapCount >= 2 && unscaledTime - _lastDualStickResetTime >= 0.75f) { _dualStickResetTapCount = 0; _dualStickResetTapWindowExpire = 0f; _lastDualStickResetTime = unscaledTime; PerformDualStickDeathReset(); } } } private void PerformDualStickDeathReset() { RigManager rigManager = Player.RigManager; if (!((Object)(object)rigManager == (Object)null) && !((Object)(object)rigManager.health == (Object)null)) { KillRig(rigManager); } } private void SpawnEyePatch(Vector3 position, Vector3 direction) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_003c: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DeadPiece_EyePatch"); val.transform.position = position + direction * 0.04f; SpriteRenderer val2 = val.AddComponent(); Texture2D val3 = new Texture2D(16, 16, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[256]; Color val4 = default(Color); ((Color)(ref val4))..ctor(0.05f, 0.05f, 0.05f, 1f); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { float num = ((float)i - 7.5f) / 7.5f; float num2 = ((float)j - 7.5f) / 7.5f; array[i * 16 + j] = ((num * num + num2 * num2 < 1f) ? val4 : Color.clear); } } val3.SetPixels(Il2CppStructArray.op_Implicit(array)); val3.Apply(); val2.sprite = Sprite.Create(val3, new Rect(0f, 0f, 16f, 16f), new Vector2(0.5f, 0.5f)); val.transform.localScale = new Vector3(0.08f, 0.08f, 1f); Object.Destroy((Object)(object)val, 6f); } private Vector3 GetBoneStreamDirection(RigManager rm, HumanBodyBones bone, Transform boneTransform) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) HumanBodyBones primaryChildBone = GetPrimaryChildBone(bone); Vector3 val; if ((int)primaryChildBone != 55) { Transform cachedBoneTransform = GetCachedBoneTransform(rm, primaryChildBone); if ((Object)(object)cachedBoneTransform != (Object)null) { val = cachedBoneTransform.position - boneTransform.position; Vector3 normalized = ((Vector3)(ref val)).normalized; if (normalized != Vector3.zero) { return normalized; } } } if ((Object)(object)boneTransform.parent != (Object)null) { val = boneTransform.position - boneTransform.parent.position; return ((Vector3)(ref val)).normalized; } return boneTransform.forward; } private void BuildColliderBoneMap(RigManager rm) { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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; } RebuildBoneCache(rm); Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); Transform[] boneTransforms = orCreateRigCache.BoneTransforms; if (boneTransforms == null) { return; } float num = 0.3025f; float num2 = 0.122499995f; Transform transform = ((Component)rm.avatar).transform; Il2CppArrayBase componentsInChildren = ((Component)rm.avatar).GetComponentsInChildren(true); foreach (Collider item in componentsInChildren) { if ((Object)(object)item == (Object)null || !IsAvatarBodyCollider(item, transform)) { continue; } Transform transform2 = ((Component)item).transform; Bounds bounds = item.bounds; Vector3 center = ((Bounds)(ref bounds)).center; float num3 = float.MaxValue; float value = float.MaxValue; int num4 = -1; for (int i = 0; i < boneTransforms.Length; i++) { Transform val = boneTransforms[i]; if (!((Object)(object)val == (Object)null)) { HumanBodyBones val2 = DamageBones[i]; Vector3 boneSegmentPoint = GetBoneSegmentPoint(rm, val2, val); float num5 = DistanceToSegmentSquared(center, val.position, boneSegmentPoint); if (CoreNearestExcludeBones.Contains(val2)) { num5 += num2; } if (num5 < num3) { num3 = num5; value = GetHierarchyDistance(transform2, val); num4 = i; } } } if (num4 >= 0 && num3 <= num) { dictionary[item] = DamageBones[num4]; dictionary2[item] = value; } } _colliderBoneMap[rm] = dictionary; _colliderBoneDistanceMap[rm] = dictionary2; TrackRig(rm); } public void OnRaycastBoneHit(RigManager rm, RaycastHit hit, float damage) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)((RaycastHit)(ref hit)).collider == (Object)null || damage <= 0f || IsRigLimbDamageBlocked(rm) || !IsLimbDestructionAllowed(rm)) { return; } EnsureRigInitialized(rm); if (TryGetBoneFromHit(rm, hit, out var bone)) { float damage2 = damage * DamageMultiplier.Value; if (IsRemotePlayerRig(rm)) { ProcessRemoteLimbHit(rm, bone, damage2, ((RaycastHit)(ref hit)).point); } else { OnBoneHit(rm, bone, damage2, ((RaycastHit)(ref hit)).point); } } } public void OnAttackReceived(PlayerDamageReceiver receiver, Attack attack) { //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Invalid comparison between Unknown and I4 //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Invalid comparison between Unknown and I4 //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Invalid comparison between Unknown and I4 //IL_015a: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)receiver == (Object)null || attack == null) { return; } Health health = receiver.health; RigManager val = (((Object)(object)health != (Object)null) ? health._rigManager : null); if ((Object)(object)val == (Object)null) { return; } if (DamageVolumeContextPatch.IsActive) { DamageVolumeContextPatch.MarkAttackHandled(val); if (DamageVolumeContextPatch.ShouldDeferLimbDamage) { return; } } if (attack.damage < 0f && DamageVolumeContextPatch.IsActive) { HandleDamageVolumeHealing(val); } else { if (attack.damage <= 0f || IsRigLimbDamageBlocked(val) || !IsLimbDestructionAllowed(val)) { return; } if (IsRemotePlayerRig(val)) { if (DamageVolumeContextPatch.IsActive && NetworkInfo.IsHost) { ProcessRemotePlayerAttack(val, receiver, attack, attack.damage); } return; } EnsureRigInitialized(val); Vector3 attackPoint = GetAttackPoint(receiver, attack); HumanBodyBones bone = BodyPartToBone(receiver.bodyPart); if ((int)bone == 55 && (Object)(object)attack.collider != (Object)null) { TryGetBoneFromCollider(val, attack.collider, attackPoint, out bone); } if ((int)bone == 55 && !TryGetNearestExtremityBone(val, attackPoint, out bone)) { TryGetNearestBone(val, attackPoint, out bone); } if ((int)bone != 55) { OnBoneHit(val, bone, CalculateAttackDamage(attack, val, bone), attackPoint); } } } public bool TryConsumeNonFatalAttack(PlayerDamageReceiver receiver, Attack attack) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: 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_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Invalid comparison between Unknown and I4 //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Invalid comparison between Unknown and I4 //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Invalid comparison between Unknown and I4 //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)receiver == (Object)null || attack == null || attack.damage <= 0f) { return false; } Health health = receiver.health; RigManager val = (((Object)(object)health != (Object)null) ? health._rigManager : null); if ((Object)(object)val == (Object)null) { MelonLogger.Warning($"[DeadPiece] TryConsumeNonFatalAttack: rigManager=null receiver={((receiver != null) ? ((Object)receiver).name : null)} health={(Object)(object)health != (Object)null}"); return false; } if (DamageVolumeContextPatch.IsActive || !IsLimbDestructionAllowed(val)) { return false; } if (IsRemotePlayerRig(val)) { float damage = attack.damage; MelonLogger.Msg(ConsoleColor.DarkYellow, $"[DeadPiece] Remote rig hit: rig={((Object)val).name} damage={damage} bodyPart={receiver.bodyPart}"); ProcessRemotePlayerAttack(val, receiver, attack, damage); attack.damage = 0f; return true; } if (IsRigLimbDamageBlocked(val)) { attack.damage = 0f; return true; } if (IsExplosionLikeAttack(attack)) { bool flag = TryApplyActiveProjectileBlast(val, attack); attack.damage = 0f; if (flag) { SyncFullState(); } return true; } Vector3 attackPoint = GetAttackPoint(receiver, attack); HumanBodyBones bone = BodyPartToBone(receiver.bodyPart); if ((int)bone == 55 && (Object)(object)attack.collider != (Object)null) { TryGetBoneFromCollider(val, attack.collider, attackPoint, out bone); } if ((int)bone == 55 && !TryGetNearestExtremityBone(val, attackPoint, out bone)) { TryGetNearestBone(val, attackPoint, out bone); } EnsureRigInitialized(val); if ((int)bone == 55 || FatalBones.Contains(bone)) { return false; } OnBoneHit(val, bone, CalculateAttackDamage(attack, val, bone), attackPoint); return true; } private float CalculateAttackDamage(Attack attack, RigManager rm, HumanBodyBones bone) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) float num = attack.damage * DamageMultiplier.Value; if (!EnableAttackTypeBalancing.Value) { return NormalizePositiveDamage(num); } num *= GetAttackTypeMultiplier(attack.attackType); return NormalizePositiveDamage(num); } private static float NormalizePositiveDamage(float damage) { if (float.IsNaN(damage) || damage <= 0f) { return 0f; } return float.IsPositiveInfinity(damage) ? float.MaxValue : damage; } private float GetAttackTypeMultiplier(AttackType attackType) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_005b: 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_0060: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Invalid comparison between Unknown and I4 float num = 1f; if ((attackType & 1) > 0) { num = Mathf.Max(num, PiercingDamageMultiplier.Value); } if ((attackType & 2) > 0) { num *= BluntDamageMultiplier.Value; } if ((attackType & 0x10) > 0) { num = Mathf.Max(num, SlashDamageMultiplier.Value); } if ((attackType & 0x20) > 0) { num = Mathf.Max(num, StabDamageMultiplier.Value); } if ((attackType & 8) > 0) { num *= FireDamageMultiplier.Value; } return Mathf.Max(0f, num); } private bool IsExplosionLikeAttack(Attack attack) { return EnableBlastLimbDamage.Value && ExplosivePatches.IsDamagingBlastActive; } private bool TryApplyActiveProjectileBlast(RigManager rigManager, Attack sourceAttack) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rigManager == (Object)null || (NetworkInfo.HasServer && !ExplosivePatches.CanProcessRemotePlayerBlast && (NetworkInfo.IsHost || IsRemotePlayerRig(rigManager))) || !ExplosivePatches.TryConsumeActiveBlast(((Object)rigManager).GetInstanceID(), out var origin, out var radius, out var damage) || damage <= 0f || float.IsNaN(damage) || float.IsInfinity(damage)) { return false; } Attack val = new Attack(); val.damage = damage; val.origin = origin; val.attackType = (AttackType)((sourceAttack == null) ? 2 : ((int)sourceAttack.attackType)); ApplyExplosionDamage(rigManager, val, origin, (radius > 0.1f) ? radius : ExplosionRadius.Value); return true; } public void ApplyRadialBlast(Vector3 origin, float blastRadius, float blastDamage) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) if (!IsSessionEnabled() || !EnableBlastLimbDamage.Value || origin == Vector3.zero || blastDamage <= 0f || float.IsNaN(blastDamage) || float.IsInfinity(blastDamage)) { return; } float num = ((blastRadius > 0.1f) ? blastRadius : ExplosionRadius.Value); float radiusSquared = num * num; Attack val = new Attack(); val.damage = blastDamage; val.origin = origin; val.attackType = (AttackType)2; HashSet hashSet = CollectBlastCandidateRigs(); foreach (RigManager item in hashSet) { if ((Object)(object)item == (Object)null || IsRigLimbDamageBlocked(item) || !IsLimbDestructionAllowed(item) || !IsRigWithinBlastRadius(item, origin, radiusSquared)) { continue; } EnsureRigInitialized(item); ApplyExplosionDamage(item, val, origin, num); if (IsRemotePlayerRig(item)) { if (TryGetPlayerIdForRig(item, out var playerId)) { BroadcastPredictedState(playerId, item); } } else if ((Object)(object)item == (Object)(object)Player.RigManager) { SyncFullState(); } } } private HashSet CollectBlastCandidateRigs() { HashSet hashSet = new HashSet(); if ((Object)(object)Player.RigManager != (Object)null) { hashSet.Add(Player.RigManager); } if (NetworkInfo.HasServer && !NetworkInfo.IsHost) { return hashSet; } foreach (NetworkPlayer player in NetworkPlayer.Players) { object obj; if (player == null) { obj = null; } else { RigRefs rigRefs = player.RigRefs; obj = ((rigRefs != null) ? rigRefs.RigManager : null); } RigManager val = (RigManager)obj; if ((Object)(object)val != (Object)null) { hashSet.Add(val); } } foreach (RigManager trackedRig in _trackedRigs) { if ((Object)(object)trackedRig != (Object)null) { hashSet.Add(trackedRig); } } return hashSet; } private bool IsRigWithinBlastRadius(RigManager rigManager, Vector3 origin, float radiusSquared) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) object obj; if (rigManager == null) { obj = null; } else { Avatar avatar = rigManager.avatar; obj = ((avatar != null) ? avatar.animator : null); } if ((Object)obj == (Object)null) { return false; } Transform boneTransform = rigManager.avatar.animator.GetBoneTransform((HumanBodyBones)0); Vector3 val; if ((Object)(object)boneTransform != (Object)null) { val = boneTransform.position - origin; if (((Vector3)(ref val)).sqrMagnitude <= radiusSquared) { return true; } } Transform boneTransform2 = rigManager.avatar.animator.GetBoneTransform((HumanBodyBones)8); if ((Object)(object)boneTransform2 != (Object)null) { val = boneTransform2.position - origin; if (((Vector3)(ref val)).sqrMagnitude <= radiusSquared) { return true; } } Transform boneTransform3 = rigManager.avatar.animator.GetBoneTransform((HumanBodyBones)10); if ((Object)(object)boneTransform3 != (Object)null) { val = boneTransform3.position - origin; if (((Vector3)(ref val)).sqrMagnitude <= radiusSquared) { return true; } } for (int i = 0; i < DamageBones.Length; i++) { Transform boneTransform4 = rigManager.avatar.animator.GetBoneTransform(DamageBones[i]); if (!((Object)(object)boneTransform4 == (Object)null)) { val = boneTransform4.position - origin; if (((Vector3)(ref val)).sqrMagnitude <= radiusSquared) { return true; } } } return false; } private void ApplyExplosionDamage(RigManager rm, Attack attack, Vector3 origin, float? blastRadiusOverride = null) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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 || IsRigLimbDamageBlocked(rm) || !IsLimbDestructionAllowed(rm)) { return; } float num = Mathf.Max(0.1f, blastRadiusOverride ?? ExplosionRadius.Value); float num2 = num * num; float num3 = attack.damage * DamageMultiplier.Value; bool flag = IsRemotePlayerRig(rm) && !NetworkInfo.IsHost; HumanBodyBones[] damageBones = DamageBones; HumanBodyBones[] array = damageBones; foreach (HumanBodyBones val in array) { Transform boneTransform = rm.avatar.animator.GetBoneTransform(val); if ((Object)(object)boneTransform == (Object)null || boneTransform.localScale == Vector3.zero) { continue; } float num4 = Vector3.SqrMagnitude(boneTransform.position - origin); if (!(num4 > num2)) { float num5 = 1f - Mathf.Clamp01(Mathf.Sqrt(num4) / num); float damage = num3 * Mathf.Lerp(0.35f, 1f, num5); if (flag) { ProcessRemoteLimbHit(rm, val, damage, origin); } else { ApplyBoneHit(rm, val, damage, origin, remapTorsoHit: false, damageNearbyEyes: false); } } } } private Vector3 GetAttackPoint(PlayerDamageReceiver receiver, Attack attack) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)attack.collider != (Object)null) { return attack.collider.ClosestPoint(attack.origin); } Transform transform = ((Component)receiver).transform; if ((Object)(object)transform != (Object)null) { return transform.position; } return attack.origin; } private bool TryGetBoneFromCollider(RigManager rm, Collider collider, Vector3 hitPoint, out HumanBodyBones bone) { //IL_003d: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) bone = (HumanBodyBones)55; if ((Object)(object)collider == (Object)null) { return false; } if (_colliderBoneMap.TryGetValue(rm, out var value) && value.TryGetValue(collider, out bone)) { return ResolveColliderMappedBone(rm, collider, bone, hitPoint, out bone); } if (TryGetBoneFromTransform(rm, ((Component)collider).transform, out bone)) { return ResolveColliderMappedBone(rm, collider, bone, hitPoint, out bone); } return TryGetNearestExtremityBone(rm, hitPoint, out bone) || TryGetNearestBone(rm, hitPoint, out bone); } private HumanBodyBones BodyPartToBone(BodyPart bodyPart) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) switch ((int)bodyPart) { case 0: case 1: return (HumanBodyBones)10; case 2: case 3: return (HumanBodyBones)7; case 4: return (HumanBodyBones)0; case 5: return (HumanBodyBones)13; case 6: return (HumanBodyBones)15; case 7: return (HumanBodyBones)17; case 8: return (HumanBodyBones)14; case 9: return (HumanBodyBones)16; case 10: return (HumanBodyBones)18; case 11: return (HumanBodyBones)1; case 12: return (HumanBodyBones)3; case 13: return (HumanBodyBones)5; case 14: return (HumanBodyBones)2; case 15: return (HumanBodyBones)4; case 16: return (HumanBodyBones)6; default: return (HumanBodyBones)55; } } private bool TryGetBoneFromHit(RigManager rm, RaycastHit hit, out HumanBodyBones bone) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) bone = (HumanBodyBones)55; if (_colliderBoneMap.TryGetValue(rm, out var value) && value.TryGetValue(((RaycastHit)(ref hit)).collider, out bone)) { return ResolveColliderMappedBone(rm, ((RaycastHit)(ref hit)).collider, bone, ((RaycastHit)(ref hit)).point, out bone); } if (TryGetBoneFromTransform(rm, ((Component)((RaycastHit)(ref hit)).collider).transform, out bone)) { return ResolveColliderMappedBone(rm, ((RaycastHit)(ref hit)).collider, bone, ((RaycastHit)(ref hit)).point, out bone); } return TryGetNearestExtremityBone(rm, ((RaycastHit)(ref hit)).point, out bone) || TryGetNearestBone(rm, ((RaycastHit)(ref hit)).point, out bone); } private bool TryGetBoneFromTransform(RigManager rm, Transform source, out HumanBodyBones bone) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected I4, but got Unknown bone = (HumanBodyBones)55; if ((Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null || (Object)(object)source == (Object)null) { return false; } Transform val = source; while ((Object)(object)val != (Object)null) { HumanBodyBones[] damageBones = DamageBones; HumanBodyBones[] array = damageBones; foreach (HumanBodyBones val2 in array) { Transform boneTransform = rm.avatar.animator.GetBoneTransform(val2); if ((Object)(object)boneTransform == (Object)(object)val) { bone = (HumanBodyBones)(int)val2; return true; } } val = val.parent; } return false; } private bool TryGetNearestBone(RigManager rm, Vector3 point, out HumanBodyBones bone) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected I4, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) if (TryGetNearestExtremityBone(rm, point, out bone)) { return true; } bone = (HumanBodyBones)55; if ((Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return false; } float num = float.MaxValue; float num2 = 0.5625f; float num3 = 0.122499995f; HumanBodyBones[] damageBones = DamageBones; HumanBodyBones[] array = damageBones; foreach (HumanBodyBones val in array) { Transform boneTransform = rm.avatar.animator.GetBoneTransform(val); if (!((Object)(object)boneTransform == (Object)null) && !(boneTransform.localScale == Vector3.zero)) { Vector3 boneSegmentPoint = GetBoneSegmentPoint(rm, val, boneTransform); float num4 = DistanceToSegmentSquared(point, boneTransform.position, boneSegmentPoint); if (TorsoBones.Contains(val)) { num4 += num3; } if (num4 < num) { num = num4; bone = (HumanBodyBones)(int)val; } } } if ((int)bone == 55 || num > num2) { bone = (HumanBodyBones)55; return false; } if (CoreNearestExcludeBones.Contains(bone) && point != Vector3.zero && !IsPointNearBone(rm, bone, point, 0.4f)) { return TryGetNearestExtremityBone(rm, point, out bone); } return true; } private bool TryGetNearestExtremityBone(RigManager rm, Vector3 point, out HumanBodyBones bone) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected I4, but got Unknown bone = (HumanBodyBones)55; if ((Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return false; } float num = float.MaxValue; float num2 = 0.5625f; HumanBodyBones[] damageBones = DamageBones; HumanBodyBones[] array = damageBones; foreach (HumanBodyBones val in array) { if (CoreNearestExcludeBones.Contains(val)) { continue; } Transform cachedBoneTransform = GetCachedBoneTransform(rm, val); if (!((Object)(object)cachedBoneTransform == (Object)null) && !(cachedBoneTransform.localScale == Vector3.zero)) { Vector3 boneSegmentPoint = GetBoneSegmentPoint(rm, val, cachedBoneTransform); float num3 = DistanceToSegmentSquared(point, cachedBoneTransform.position, boneSegmentPoint); if (num3 < num) { num = num3; bone = (HumanBodyBones)(int)val; } } } if ((int)bone == 55 || num > num2) { bone = (HumanBodyBones)55; return false; } return true; } private bool IsTorsoBone(HumanBodyBones bone) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)bone == 7 || (int)bone == 0; } private bool IsPointNearBone(RigManager rm, HumanBodyBones bone, Vector3 point, float maxDistance) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Transform cachedBoneTransform = GetCachedBoneTransform(rm, bone); if ((Object)(object)cachedBoneTransform == (Object)null) { return false; } Vector3 boneSegmentPoint = GetBoneSegmentPoint(rm, bone, cachedBoneTransform); float num = maxDistance * maxDistance; return DistanceToSegmentSquared(point, cachedBoneTransform.position, boneSegmentPoint) <= num; } private bool ResolveColliderMappedBone(RigManager rm, Collider collider, HumanBodyBones mappedBone, Vector3 hitPoint, out HumanBodyBones bone) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Expected I4, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) bone = (HumanBodyBones)(int)mappedBone; if (_colliderBoneDistanceMap.TryGetValue(rm, out var value) && value.TryGetValue(collider, out var value2) && value2 > 5f) { return TryGetNearestExtremityBone(rm, hitPoint, out bone) || TryGetNearestBone(rm, hitPoint, out bone); } if (IsTorsoBone(bone) && hitPoint != Vector3.zero && !IsPointNearBone(rm, bone, hitPoint, 0.4f)) { return TryGetNearestExtremityBone(rm, hitPoint, out bone); } return true; } private Vector3 GetBoneSegmentPoint(RigManager rm, HumanBodyBones bone, Transform boneTransform) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) HumanBodyBones primaryChildBone = GetPrimaryChildBone(bone); if ((int)primaryChildBone != 55) { Transform boneTransform2 = rm.avatar.animator.GetBoneTransform(primaryChildBone); if ((Object)(object)boneTransform2 != (Object)null) { return boneTransform2.position; } } if ((Object)(object)boneTransform.parent != (Object)null) { return boneTransform.parent.position; } return boneTransform.position; } private HumanBodyBones GetPrimaryChildBone(HumanBodyBones bone) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) return (HumanBodyBones)((int)bone switch { 13 => 15, 15 => 17, 14 => 16, 16 => 18, 1 => 3, 3 => 5, 2 => 4, 4 => 6, 0 => 7, 7 => 10, _ => 55, }); } private float DistanceToSegmentSquared(Vector3 point, Vector3 start, Vector3 end) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) Vector3 val = end - start; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude <= Mathf.Epsilon) { return Vector3.SqrMagnitude(point - start); } float num = Mathf.Clamp01(Vector3.Dot(point - start, val) / sqrMagnitude); Vector3 val2 = start + val * num; return Vector3.SqrMagnitude(point - val2); } private float GetHierarchyDistance(Transform source, Transform ancestor) { if ((Object)(object)source == (Object)null || (Object)(object)ancestor == (Object)null) { return float.MaxValue; } float num = 0f; Transform val = source; while ((Object)(object)val != (Object)null) { if ((Object)(object)val == (Object)(object)ancestor) { return num; } num += 1f; val = val.parent; } return float.MaxValue; } private float GetMaxHealthForBone(RigManager rm, HumanBodyBones bone) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (IsOneHpModeEnabled()) { return 1f; } float avatarHealthBase = GetAvatarHealthBase(rm); return Mathf.Max(0.0001f, avatarHealthBase * GetBoneHealthScale(bone)); } private void InvalidateAvatarHealthCache(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { _avatarHealthBaseCache.Remove(rm); _avatarHealthHashCache.Remove(rm); } } private float GetAvatarHealthBase(RigManager rm) { if ((Object)(object)rm == (Object)null) { return Mathf.Max(0.0001f, MaxLimbHealth.Value); } int num = (((Object)(object)rm.avatar != (Object)null) ? ((Object)rm.avatar).GetHashCode() : 0); float num2 = ResolveAvatarHealthBase(rm); if (_avatarHealthBaseCache.TryGetValue(rm, out var value) && _avatarHealthHashCache.TryGetValue(rm, out var value2) && value2 == num && value > 0f && !float.IsNaN(value) && !float.IsInfinity(value) && Mathf.Abs(num2 - value) > Mathf.Max(0.0001f, value * 0.0001f)) { RescaleTrackedLimbHealth(rm, value, num2); } _avatarHealthBaseCache[rm] = num2; _avatarHealthHashCache[rm] = num; return num2; } private void RescaleTrackedLimbHealth(RigManager rm, float previousBase, float newBase) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (!_playersHealth.TryGetValue(rm, out var value) || previousBase <= 0f || newBase <= 0f) { return; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (!value.TryGetValue(val, out var value2)) { continue; } if (IsOneHpModeEnabled()) { value[val] = ((value2 > 0f && !IsBoneGone(rm, val)) ? 1f : (-1f)); continue; } float boneHealthScale = GetBoneHealthScale(val); float num = Mathf.Max(0.0001f, previousBase * boneHealthScale); float num2 = Mathf.Max(0.0001f, newBase * boneHealthScale); if (value2 > 0f && !IsBoneGone(rm, val)) { value[val] = num2 * Mathf.Clamp01(value2 / num); } else { value[val] = 0f - num2; } } } private float ResolveAvatarHealthBase(RigManager rm) { if (IsOneHpModeEnabled()) { return 1f; } if (NetworkInfo.HasServer && (Object)(object)rm != (Object)(object)Player.RigManager && IsRemotePlayerRig(rm) && TryGetPlayerIdForRig(rm, out var playerId) && _networkHealthBaseOverrides.TryGetValue(playerId, out var value) && value > 0f && !float.IsNaN(value) && !float.IsInfinity(value)) { return value; } return AvatarHealthResolver.Resolve(rm, MaxLimbHealth.Value); } private void RefreshLimbMaxHealth(RigManager rm) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || !_playersHealth.TryGetValue(rm, out var value)) { return; } HumanBodyBones[] damageBones = DamageBones; HumanBodyBones[] array = damageBones; foreach (HumanBodyBones val in array) { if (value.TryGetValue(val, out var value2) && value2 > 0f && !IsBoneGone(rm, val)) { value[val] = GetMaxHealthForBone(rm, val); } } } private void UpdateLimbPenaltyFlag(RigManager rm) { UpdateRigMissingLimbsFlag(rm); } public void TrackRig(RigManager rm) { if ((Object)(object)rm != (Object)null) { _trackedRigs.Add(rm); MaintainOneHpHealth(rm, refill: false); } } private void PruneTrackedRigs() { if (_trackedRigs.Count == 0) { return; } RigManager[] array = _trackedRigs.ToArray(); foreach (RigManager val in array) { if ((Object)(object)val == (Object)null) { _trackedRigs.Remove(val); _avatarHealthBaseCache.Remove(val); _avatarHealthHashCache.Remove(val); _rigWasDead.Remove(val); _playersHealth.Remove(val); _colliderBoneMap.Remove(val); _colliderBoneDistanceMap.Remove(val); _originalScales.Remove(val); _hiddenBoneMasks.Remove(val); _lastLimbDamageTimes.Remove(val); _legColliderOriginalStates.Remove(val); _lastHitEffectTimes.Remove(val); _lastStumpBloodEffectTimes.Remove(val); _stumpBloodStartTimes.Remove(val); _lastAvatarHashes.Remove(val); _rigCache.Remove(val); } } } private RigRuntimeCache GetOrCreateRigCache(RigManager rm) { if (!_rigCache.TryGetValue(rm, out var value)) { value = new RigRuntimeCache(); _rigCache[rm] = value; } return value; } private void ResetLimbDamageBlockCache(RigManager rm) { if (!((Object)(object)rm == (Object)null) && _rigCache.TryGetValue(rm, out var value)) { value.LimbDamageBlocked = false; value.LimbDamageBlockFrame = -9999; } } private static int GetDamageBoneIndex(HumanBodyBones bone) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (BoneToIndexMap.TryGetValue(bone, out var value)) { return value; } return -1; } private void RebuildLimbGoneFlags(RigManager rm) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected I4, but got Unknown if ((Object)(object)rm == (Object)null) { return; } RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); LimbGoneMask limbGoneMask = LimbGoneMask.None; Transform[] boneTransforms = orCreateRigCache.BoneTransforms; if (boneTransforms == null) { orCreateRigCache.LimbGoneFlags = limbGoneMask; orCreateRigCache.HasMissingLimbs = false; return; } for (int i = 0; i < boneTransforms.Length; i++) { if (!((Object)(object)boneTransforms[i] == (Object)null) && IsBoneGone(rm, DamageBones[i])) { HumanBodyBones val = DamageBones[i]; HumanBodyBones val2 = val; switch ((int)val2) { case 13: case 15: case 17: limbGoneMask |= LimbGoneMask.LeftArm; break; case 14: case 16: case 18: limbGoneMask |= LimbGoneMask.RightArm; break; case 1: case 3: case 5: limbGoneMask |= LimbGoneMask.LeftLeg; break; case 2: case 4: case 6: limbGoneMask |= LimbGoneMask.RightLeg; break; case 7: limbGoneMask |= LimbGoneMask.Spine; break; case 0: limbGoneMask |= LimbGoneMask.Hips; break; } } } orCreateRigCache.LimbGoneFlags = limbGoneMask; orCreateRigCache.HasMissingLimbs = (limbGoneMask & (LimbGoneMask.LeftArm | LimbGoneMask.RightArm | LimbGoneMask.LeftLeg | LimbGoneMask.RightLeg)) != 0; } private HumanBodyBones[] GetAvatarDamageBones(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return DamageBones; } List list = new List(DamageBones.Length); for (int i = 0; i < DamageBones.Length; i++) { Transform boneTransform = rm.avatar.animator.GetBoneTransform(DamageBones[i]); if ((Object)(object)boneTransform != (Object)null) { list.Add(DamageBones[i]); } } if (list.Count == 0) { return DamageBones; } return list.ToArray(); } private void RebuildBoneCache(RigManager rm) { if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm.avatar == (Object)null) && !((Object)(object)rm.avatar.animator == (Object)null)) { RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); orCreateRigCache.AvatarHash = ((Object)rm.avatar).GetHashCode(); if (orCreateRigCache.BoneTransforms == null || orCreateRigCache.BoneTransforms.Length != DamageBones.Length) { orCreateRigCache.BoneTransforms = (Transform[])(object)new Transform[DamageBones.Length]; } for (int i = 0; i < DamageBones.Length; i++) { orCreateRigCache.BoneTransforms[i] = rm.avatar.animator.GetBoneTransform(DamageBones[i]); } RebuildLimbGoneFlags(rm); } } private Transform GetCachedBoneTransform(RigManager rm, HumanBodyBones bone) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null) { return null; } if (_rigCache.TryGetValue(rm, out var value) && value.BoneTransforms != null) { int damageBoneIndex = GetDamageBoneIndex(bone); if (damageBoneIndex >= 0) { Transform val = value.BoneTransforms[damageBoneIndex]; if ((Object)(object)val != (Object)null) { return val; } } } Avatar avatar = rm.avatar; object result; if (avatar == null) { result = null; } else { Animator animator = avatar.animator; result = ((animator != null) ? animator.GetBoneTransform(bone) : null); } return (Transform)result; } public bool IsRigLimbDamageBlocked(RigManager rm) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)rm.health == (Object)null) { return false; } RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); if (Time.frameCount - orCreateRigCache.LimbDamageBlockFrame < 30) { return orCreateRigCache.LimbDamageBlocked; } bool result = (orCreateRigCache.LimbDamageBlocked = (int)rm.health.healthMode == 0 || float.IsPositiveInfinity(rm.health.max_Health)); orCreateRigCache.LimbDamageBlockFrame = Time.frameCount; return result; } private bool RigHasDismemberment(RigManager rm) { if ((Object)(object)rm == (Object)null) { return false; } if (_rigCache.TryGetValue(rm, out var value)) { return value.LimbGoneFlags != LimbGoneMask.None; } return false; } private void EnforceDismemberedBones() { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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) if (!IsSessionEnabled() || _trackedRigs.Count == 0 || _rigCache.Count == 0) { return; } RigManager[] array = _trackedRigs.ToArray(); foreach (RigManager val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.avatar == (Object)null || (Object)(object)val.avatar.animator == (Object)null || !_rigCache.TryGetValue(val, out var value) || GetStateMask(val) == 0) { continue; } Transform[] boneTransforms = value.BoneTransforms; if (boneTransforms == null) { continue; } for (int j = 0; j < boneTransforms.Length && j < DamageBones.Length; j++) { Transform val2 = boneTransforms[j]; if (!((Object)(object)val2 == (Object)null) && !(val2.localScale == Vector3.zero)) { HumanBodyBones bone = DamageBones[j]; if (IsBoneGone(val, bone)) { val2.localScale = Vector3.zero; } } } } } private void EnforceInvincibleRigsForAllTracked() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (_trackedRigs.Count == 0) { return; } RigManager[] array = _trackedRigs.ToArray(); foreach (RigManager val in array) { if ((Object)(object)val == (Object)null || !IsRigLimbDamageBlocked(val) || !RigHasDismemberment(val) || IsRemotePlayerRig(val)) { continue; } if (_rigCache.TryGetValue(val, out var value) && value.BoneTransforms != null) { Transform[] boneTransforms = value.BoneTransforms; for (int j = 0; j < boneTransforms.Length && j < DamageBones.Length; j++) { Transform val2 = boneTransforms[j]; if ((Object)(object)val2 != (Object)null && IsBoneGone(val, DamageBones[j]) && val2.localScale != Vector3.zero) { val2.localScale = Vector3.zero; } } } if ((Object)(object)val == (Object)(object)Player.RigManager) { UpdateLimbPenaltyFlag(val); } } } private void InvalidateRigCache(RigManager rm) { if (!((Object)(object)rm == (Object)null) && _rigCache.TryGetValue(rm, out var value)) { value.Initialized = false; value.LimbDamageBlocked = false; value.LimbDamageBlockFrame = -9999; value.BoneTransforms = null; value.HasMissingLimbs = false; value.LimbGoneFlags = LimbGoneMask.None; value.VisualDamage = null; } } private void UpdateRigMissingLimbsFlag(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { RebuildLimbGoneFlags(rm); } } private VisualDamageController GetVisualDamageController(RigManager rm) { if ((Object)(object)rm == (Object)null) { return null; } RigRuntimeCache orCreateRigCache = GetOrCreateRigCache(rm); if ((Object)(object)orCreateRigCache.VisualDamage != (Object)null) { return orCreateRigCache.VisualDamage; } if ((Object)(object)rm.avatar != (Object)null) { orCreateRigCache.VisualDamage = ((Component)rm.avatar).GetComponentInChildren(true); } return orCreateRigCache.VisualDamage; } private float GetBoneHealthScale(HumanBodyBones bone) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected I4, but got Unknown switch ((int)bone) { case 1: case 2: case 3: case 4: case 5: case 6: return 0.6f; case 10: return 0.5f; case 13: case 14: case 15: case 16: case 17: case 18: return 0.8f; case 21: case 22: return 0.5f; case 0: case 7: return 1f; default: return 1f; } } public void OnBoneHit(RigManager rm, HumanBodyBones bone, float damage, Vector3 hitPoint) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) ApplyBoneHit(rm, bone, damage, hitPoint, remapTorsoHit: true, damageNearbyEyes: true); } private void ApplyBoneHit(RigManager rm, HumanBodyBones bone, float damage, Vector3 hitPoint, bool remapTorsoHit, bool damageNearbyEyes) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) if (damage <= 0f || IsRigLimbDamageBlocked(rm) || !IsLimbDestructionAllowed(rm)) { return; } if (remapTorsoHit && IsTorsoBone(bone) && hitPoint != Vector3.zero && !IsPointNearBone(rm, bone, hitPoint, 0.4f)) { TryGetNearestExtremityBone(rm, hitPoint, out bone); } EnsureRigInitialized(rm); GetAvatarHealthBase(rm); if (_playersHealth.TryGetValue(rm, out var value) && value.ContainsKey(bone) && !IsBoneGone(rm, bone)) { MarkLimbDamaged(rm, bone); value[bone] = Mathf.Max(0f, value[bone] - damage); PlayHitEffects(rm, bone, hitPoint, damage); if (value[bone] <= 0f) { DismemberLimb(rm, bone, hitPoint); } else if (damageNearbyEyes && hitPoint != Vector3.zero) { TryDamageNearbyEyes(rm, hitPoint, damage); } } } private void TryDamageNearbyEyes(RigManager rm, Vector3 hitPoint, float damage) { //IL_0029: 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) if (!((Object)(object)rm == (Object)null) && !(damage <= 0f)) { float radiusSq = 0.0169f; TryDamageEyeIfNear(rm, (HumanBodyBones)21, hitPoint, damage, radiusSq); TryDamageEyeIfNear(rm, (HumanBodyBones)22, hitPoint, damage, radiusSq); } } private void TryDamageEyeIfNear(RigManager rm, HumanBodyBones eyeBone, Vector3 hitPoint, float damage, float radiusSq) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) GetAvatarHealthBase(rm); if (IsBoneGone(rm, eyeBone) || !_playersHealth.TryGetValue(rm, out var value) || !value.ContainsKey(eyeBone)) { return; } Transform cachedBoneTransform = GetCachedBoneTransform(rm, eyeBone); if (!((Object)(object)cachedBoneTransform == (Object)null) && !(Vector3.SqrMagnitude(hitPoint - cachedBoneTransform.position) > radiusSq)) { MarkLimbDamaged(rm, eyeBone); value[eyeBone] = Mathf.Max(0f, value[eyeBone] - damage * 1.25f); if (value[eyeBone] <= 0f) { DismemberLimb(rm, eyeBone, hitPoint); } } } private void DismemberLimb(RigManager rm, HumanBodyBones bone, Vector3 hitPoint) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Invalid comparison between Unknown and I4 //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Invalid comparison between Unknown and I4 //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Invalid comparison between Unknown and I4 //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: 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_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Invalid comparison between Unknown and I4 //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Invalid comparison between Unknown and I4 //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_04de: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Invalid comparison between Unknown and I4 //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Invalid comparison between Unknown and I4 //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Invalid comparison between Unknown and I4 //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Invalid comparison between Unknown and I4 //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Invalid comparison between Unknown and I4 if ((Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null || !IsLimbDestructionAllowed(rm)) { return; } bool wasLeftLegGone = IsLeftLegGone(rm); bool wasRightLegGone = IsRightLegGone(rm); Transform cachedBoneTransform = GetCachedBoneTransform(rm, bone); if ((Object)(object)cachedBoneTransform == (Object)null || IsBoneGone(rm, bone)) { return; } Transform val = null; Transform val2 = null; Vector3 localScale = Vector3.one; Vector3 localScale2 = Vector3.one; if ((int)bone == 10) { val = rm.avatar.animator.GetBoneTransform((HumanBodyBones)21); val2 = rm.avatar.animator.GetBoneTransform((HumanBodyBones)22); if ((Object)(object)val != (Object)null) { localScale = val.localScale; } if ((Object)(object)val2 != (Object)null) { localScale2 = val2.localScale; } } CaptureOriginalBoneScale(rm, bone, cachedBoneTransform); SetBoneHiddenState(rm, bone, hidden: true); cachedBoneTransform.localScale = Vector3.zero; if ((Object)(object)val != (Object)null) { val.localScale = localScale; } if ((Object)(object)val2 != (Object)null) { val2.localScale = localScale2; } if ((int)bone == 21 || (int)bone == 22) { SpawnEyePatch(cachedBoneTransform.position, cachedBoneTransform.forward); } if ((int)bone == 10 && hitPoint != Vector3.zero) { Transform boneTransform = rm.avatar.animator.GetBoneTransform((HumanBodyBones)21); Transform boneTransform2 = rm.avatar.animator.GetBoneTransform((HumanBodyBones)22); if ((Object)(object)boneTransform != (Object)null && boneTransform.localScale != Vector3.zero && Vector3.Distance(hitPoint, boneTransform.position) < 0.15f) { CaptureOriginalBoneScale(rm, (HumanBodyBones)21, boneTransform); SetBoneHiddenState(rm, (HumanBodyBones)21, hidden: true); if (_playersHealth.TryGetValue(rm, out var value)) { value[(HumanBodyBones)21] = 0f - GetMaxHealthForBone(rm, (HumanBodyBones)21); } boneTransform.localScale = Vector3.zero; SpawnEyePatch(boneTransform.position, boneTransform.forward); } if ((Object)(object)boneTransform2 != (Object)null && boneTransform2.localScale != Vector3.zero && Vector3.Distance(hitPoint, boneTransform2.position) < 0.15f) { CaptureOriginalBoneScale(rm, (HumanBodyBones)22, boneTransform2); SetBoneHiddenState(rm, (HumanBodyBones)22, hidden: true); if (_playersHealth.TryGetValue(rm, out var value2)) { value2[(HumanBodyBones)22] = 0f - GetMaxHealthForBone(rm, (HumanBodyBones)22); } boneTransform2.localScale = Vector3.zero; SpawnEyePatch(boneTransform2.position, boneTransform2.forward); } } MarkStumpBloodStarted(rm, bone); SpawnDamageVolume(rm, bone, (hitPoint == Vector3.zero) ? cachedBoneTransform.position : hitPoint); TryAddVisualCut(rm, (hitPoint == Vector3.zero) ? cachedBoneTransform.position : hitPoint); TryApplyBloodImpactAtBone(rm, bone, (hitPoint == Vector3.zero) ? cachedBoneTransform.position : hitPoint, Mathf.Max(5f, GetMaxHealthForBone(rm, bone) * 0.25f), GetBloodColor(rm)); PlayDismemberEffects((hitPoint == Vector3.zero) ? cachedBoneTransform.position : hitPoint, GetBloodColor(rm)); if (FatalBones.Contains(bone)) { SpawnBloodStream(rm, bone, (hitPoint == Vector3.zero) ? cachedBoneTransform.position : hitPoint); } else { SpawnBloodStream(rm, bone, cachedBoneTransform.position); } ApplySecondLegRagdoll(rm, bone, wasLeftLegGone, wasRightLegGone); RebuildLimbGoneFlags(rm); SyncLegColliderState(rm); if ((Object)(object)rm == (Object)(object)Player.RigManager && (IsLeftLegBone(bone) || IsRightLegBone(bone)) && IsBothLegsGone(rm)) { AllowLocalNoLegRagdollFromCurrentSever(); } if (FatalBones.Contains(bone)) { if ((int)bone == 10) { ApplyHeadSeverEffects(rm, (hitPoint == Vector3.zero) ? cachedBoneTransform.position : hitPoint); SpawnHeadProp(cachedBoneTransform, hitPoint, GetBloodColor(rm)); } if ((Object)(object)rm == (Object)(object)Player.RigManager) { SyncFullState(); } if ((Object)(object)rm == (Object)(object)Player.RigManager) { BeginFatalOutcome(rm, bone); } } else if ((Object)(object)rm == (Object)(object)Player.RigManager) { if (_playersHealth.TryGetValue(rm, out var value3)) { value3[bone] = 0f - GetMaxHealthForBone(rm, bone); } UpdateLimbPenaltyFlag(rm); if ((int)bone == 13 || (int)bone == 15 || (int)bone == 17) { SetHandUsable(Player.LeftHand, usable: false); } else if ((int)bone == 14 || (int)bone == 16 || (int)bone == 18) { SetHandUsable(Player.RightHand, usable: false); } SyncFullState(); } if ((Object)(object)rm == (Object)(object)Player.RigManager && AreAllLimbsGone(rm) && !HasFatalBoneInMask(GetStateMask(rm))) { KillRig(rm); } if ((Object)(object)rm == (Object)(object)Player.RigManager && EnableVrEyeBlindness.Value) { UpdateVrEyeBlindness(rm); } } private bool IsRemotePlayerRig(RigManager rm) { if (!NetworkInfo.HasServer || (Object)(object)rm == (Object)null) { return false; } NetworkPlayer val = default(NetworkPlayer); if (NetworkPlayerManager.TryGetPlayer(rm, ref val)) { return !val.NetworkEntity.IsOwner; } try { RigRefs val2 = default(RigRefs); foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID == null || playerID.IsMe || !PlayerRepUtilities.TryGetReferences(playerID.SmallID, ref val2) || !((Object)(object)((val2 != null) ? val2.RigManager : null) == (Object)(object)rm)) { continue; } return true; } } catch { } return false; } public bool TryGetPlayerIdForRig(RigManager rm, out byte playerId) { playerId = 0; if ((Object)(object)rm == (Object)null) { return false; } if ((Object)(object)rm == (Object)(object)Player.RigManager && PlayerIDManager.LocalID != null) { playerId = PlayerIDManager.LocalSmallID; return true; } NetworkPlayer val = default(NetworkPlayer); if (NetworkPlayerManager.TryGetPlayer(rm, ref val) && ((val != null) ? val.PlayerID : null) != null) { playerId = val.PlayerID.SmallID; return true; } if (NetworkInfo.HasServer) { RigRefs val2 = default(RigRefs); foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null) { if (playerID.IsMe && (Object)(object)rm == (Object)(object)Player.RigManager) { playerId = playerID.SmallID; return true; } if (PlayerRepUtilities.TryGetReferences(playerID.SmallID, ref val2) && (Object)(object)((val2 != null) ? val2.RigManager : null) != (Object)null && (Object)(object)val2.RigManager == (Object)(object)rm) { playerId = playerID.SmallID; return true; } } } } MelonLogger.Warning("[DeadPiece] TryGetPlayerIdForRig FAILED for rig " + ((rm != null) ? ((Object)rm).name : null) + " — no matching player found"); return false; } public bool TrySendLimbHitForLocalAttack(PlayerDamageReceiver receiver, Attack attack) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || !IsSessionEnabled() || (Object)(object)receiver == (Object)null || attack == null || attack.damage <= 0f) { return false; } Health health = receiver.health; RigManager val = ((health != null) ? health._rigManager : null); if ((Object)(object)val == (Object)null) { return false; } if (!IsLimbDestructionAllowed(val)) { return false; } NetworkPlayer val2 = default(NetworkPlayer); if (NetworkPlayerManager.TryGetPlayer(val, ref val2) && val2.NetworkEntity.IsOwner) { return false; } if (!TryResolveAttackBone(val, receiver, attack, GetAttackPoint(receiver, attack), out var bone)) { return false; } float num = CalculateAttackDamage(attack, val, bone); if (num <= 0f) { num = attack.damage; } if (num <= 0f) { return false; } if (!BoneToIndexMap.TryGetValue(bone, out var value)) { return false; } if (!TryGetPlayerIdForRig(val, out var playerId)) { return false; } NetworkSync.SendLimbHit(playerId, (byte)value, num, GetAttackPoint(receiver, attack)); return true; } private void ProcessRemotePlayerAttack(RigManager rigManager, PlayerDamageReceiver receiver, Attack attack, float originalDamage) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_015e: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rigManager == (Object)null || attack == null || !IsLimbDestructionAllowed(rigManager)) { MelonLogger.Warning($"[DeadPiece] ProcessRemotePlayerAttack: null rig={(Object)(object)rigManager == (Object)null} attack={attack == null}"); return; } EnsureRigInitialized(rigManager); Vector3 attackPoint = GetAttackPoint(receiver, attack); HumanBodyBones bone; if (IsExplosionLikeAttack(attack)) { if (TryApplyActiveProjectileBlast(rigManager, attack) && TryGetPlayerIdForRig(rigManager, out var playerId)) { BroadcastPredictedState(playerId, rigManager); } } else if (!TryResolveAttackBone(rigManager, receiver, attack, attackPoint, out bone)) { MelonLogger.Warning($"[DeadPiece] ProcessRemotePlayerAttack: TryResolveAttackBone FAILED rig={((Object)rigManager).name} bodyPart={receiver.bodyPart} collider={(Object)(object)attack.collider != (Object)null} attackPoint={attackPoint}"); } else { float num = CalculateAttackDamage(attack, rigManager, bone); if (num <= 0f) { num = originalDamage; } if (num <= 0f) { MelonLogger.Warning($"[DeadPiece] ProcessRemotePlayerAttack: damage=0 after fallback originalDamage={originalDamage}"); } else { ProcessRemoteLimbHit(rigManager, bone, num, attackPoint); } } } private bool TryResolveAttackBone(RigManager rigManager, PlayerDamageReceiver receiver, Attack attack, Vector3 attackPoint, out HumanBodyBones bone) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected I4, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) bone = (HumanBodyBones)(int)BodyPartToBone(receiver.bodyPart); if ((int)bone == 55 && (Object)(object)attack.collider != (Object)null) { TryGetBoneFromCollider(rigManager, attack.collider, attackPoint, out bone); } if ((int)bone == 55 && !TryGetNearestExtremityBone(rigManager, attackPoint, out bone)) { TryGetNearestBone(rigManager, attackPoint, out bone); } return (int)bone != 55; } private void ProcessRemoteLimbHit(RigManager rigManager, HumanBodyBones bone, float damage, Vector3 hitPoint) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) int value; if (!TryGetPlayerIdForRig(rigManager, out var playerId)) { MelonLogger.Warning("[DeadPiece] ProcessRemoteLimbHit: TryGetPlayerIdForRig FAILED for rig " + ((rigManager != null) ? ((Object)rigManager).name : null)); } else if (!BoneToIndexMap.TryGetValue(bone, out value)) { MelonLogger.Warning($"[DeadPiece] ProcessRemoteLimbHit: BoneToIndexMap FAILED bone={bone}"); } else { NetworkSync.SendLimbHit(playerId, (byte)value, damage, hitPoint); } } private void BroadcastPredictedState(byte targetPlayerId, RigManager rigManager) { if (!((Object)(object)rigManager == (Object)null) && NetworkInfo.IsHost) { uint stateMask = GetStateMask(rigManager); byte bloodColorIndexForRig = GetBloodColorIndexForRig(rigManager); NetworkSync.SendFullState(targetPlayerId, stateMask, bloodColorIndexForRig, 0); } } public uint GetStateMask(RigManager rm) { if ((Object)(object)rm == (Object)null) { return 0u; } uint value; return _hiddenBoneMasks.TryGetValue(rm, out value) ? (value & (uint)((1 << DamageBones.Length) - 1)) : 0u; } private static uint ParseGoneMaskFromString(string value) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) uint num = 0u; if (string.IsNullOrEmpty(value)) { return num; } string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { if (Enum.TryParse(array[i], out HumanBodyBones result) && BoneToIndexMap.TryGetValue(result, out var value2)) { num |= (uint)(1 << value2); } } return num; } private bool ShouldApplyNetworkSequence(byte playerId, ushort sequence) { if (sequence == 0) { return true; } if (!_lastAppliedNetworkSequence.TryGetValue(playerId, out var value)) { return true; } if (sequence == value) { return false; } return (ushort)(sequence - value) < 32768; } private bool ShouldReplacePendingNetworkState(byte playerId, ushort sequence) { if (!_pendingNetworkStates.TryGetValue(playerId, out var value)) { return true; } if (sequence == 0) { return value.Sequence == 0; } if (value.Sequence == 0) { return true; } if (sequence == value.Sequence) { return false; } return (ushort)(sequence - value.Sequence) < 32768; } private void QueuePendingNetworkState(byte playerId, ushort sequence, uint goneBoneMask, bool isFallen) { if (ShouldReplacePendingNetworkState(playerId, sequence)) { _pendingNetworkStates[playerId] = new PendingNetworkState { Sequence = sequence, GoneBoneMask = goneBoneMask, IsFallen = isFallen }; } } private void RemoveRigFromCaches(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { if ((Object)(object)_managedFatalRig == (Object)(object)rm) { CancelManagedFatalOutcome((Object)(object)_managedFatalHealth != (Object)null && _managedFatalHealth.alive); } RestoreOneHpHealth(rm); if (_deadpieceNoLegUsageApplied && (Object)(object)_deadpieceUsageRig == (Object)(object)rm) { RestoreDeadpieceLegUsage(rm); } if (_deadpieceJumpBlocked && (Object)(object)_deadpieceJumpOwnerRig == (Object)(object)rm) { RestoreNoLegJump(rm); } RestoreOutgoingAvatarScales(rm); RestoreLegColliderState(rm); _trackedRigs.Remove(rm); _avatarHealthBaseCache.Remove(rm); _avatarHealthHashCache.Remove(rm); _rigWasDead.Remove(rm); _playersHealth.Remove(rm); _colliderBoneMap.Remove(rm); _colliderBoneDistanceMap.Remove(rm); _originalScales.Remove(rm); _hiddenBoneMasks.Remove(rm); _lastLimbDamageTimes.Remove(rm); _lastHitEffectTimes.Remove(rm); _lastStumpBloodEffectTimes.Remove(rm); _stumpBloodStartTimes.Remove(rm); _lastAvatarHashes.Remove(rm); _rigCache.Remove(rm); _bloodColorOverrides.Remove(rm); if (TryGetPlayerIdForRig(rm, out var playerId)) { _appliedStateMasks.Remove(playerId); } _bloodColorIndexOverrides.Remove(rm); } } private void LoadBloodColorOverrides() { //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) try { PropertyInfo property = typeof(MelonUtils).GetProperty("UserDataDirectory", BindingFlags.Static | BindingFlags.Public); string path = Path.Combine((string)property.GetValue(null), "DeadPiece", "BloodColors.txt"); if (!File.Exists(path)) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# DeadPiece Blood Color Overrides"); stringBuilder.AppendLine("# Format: AvatarName=color"); stringBuilder.AppendLine("# Colors: red, black, orange, purple, green, blue, pink, yellow, or R,G,B,A"); stringBuilder.AppendLine("# Examples:"); stringBuilder.AppendLine("# NullBody_Red=red"); stringBuilder.AppendLine("# MyRobotMod=black"); stringBuilder.AppendLine("# MyCustomAvatar=0.3,0.1,0.6,0.9"); stringBuilder.AppendLine("# Wildcards:"); stringBuilder.AppendLine("# *NullBody*=orange (contains \"NullBody\")"); stringBuilder.AppendLine("# MyMod_*=red (starts with \"MyMod_\")"); stringBuilder.AppendLine("# *Robot*=black (contains \"Robot\")"); File.WriteAllText(path, stringBuilder.ToString()); MelonLogger.Msg(ConsoleColor.Gray, "Created BloodColors.txt template"); return; } string[] array = File.ReadAllLines(path); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (string.IsNullOrEmpty(text2) || text2.StartsWith("#")) { continue; } int num = text2.IndexOf('='); if (num < 0) { continue; } string text3 = text2.Substring(0, num).Trim().ToLowerInvariant(); string text4 = text2.Substring(num + 1).Trim().ToLowerInvariant(); if (!string.IsNullOrEmpty(text3) && !string.IsNullOrEmpty(text4)) { Color val = ParseBloodColorString(text4); if (val.a >= 0f) { _avatarBloodOverrides[text3] = val; } } } if (_avatarBloodOverrides.Count > 0) { MelonLogger.Msg($"Loaded {_avatarBloodOverrides.Count} blood color overrides"); } } catch (Exception ex) { MelonLogger.Warning("Blood color override loading failed: " + ex.Message); } } private Color ParseBloodColorString(string s) { //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) switch (s) { case "red": return new Color(0.7f, 0.02f, 0.02f, 0.9f); case "black": return new Color(0.05f, 0.05f, 0.05f, 0.9f); case "orange": return new Color(1f, 0.45f, 0.02f, 0.9f); case "purple": return new Color(0.5f, 0.02f, 0.6f, 0.9f); case "green": return new Color(0.02f, 0.55f, 0.12f, 0.9f); case "blue": return new Color(0.05f, 0.08f, 0.7f, 0.9f); case "pink": return new Color(0.95f, 0.08f, 0.55f, 0.9f); case "yellow": return new Color(0.9f, 0.85f, 0.05f, 0.9f); case "white": return Color.white; default: { string[] array = s.Split(','); if (array.Length >= 3) { float result = 0.9f; if (float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { if (array.Length >= 4) { float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result); } return new Color(result2, result3, result4, result); } } return new Color(-1f, -1f, -1f, -1f); } } } private byte BloodColorToIndex(string colorName) { return colorName.ToLowerInvariant() switch { "red" => 1, "black" => 2, "white" => 3, "orange" => 4, "green" => 5, "blue" => 6, "pink" => 7, "purple" => 8, "yellow" => 9, _ => 0, }; } private Color IndexToBloodColor(byte index) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) return (Color)(index switch { 0 => new Color(-1f, -1f, -1f, -1f), 1 => new Color(0.7f, 0.02f, 0.02f, 0.9f), 2 => new Color(0.05f, 0.05f, 0.05f, 0.9f), 3 => Color.white, 4 => new Color(1f, 0.45f, 0.02f, 0.9f), 5 => new Color(0.02f, 0.55f, 0.12f, 0.9f), 6 => new Color(0.05f, 0.08f, 0.7f, 0.9f), 7 => new Color(0.95f, 0.08f, 0.55f, 0.9f), 8 => new Color(0.5f, 0.02f, 0.6f, 0.9f), 9 => new Color(0.9f, 0.85f, 0.05f, 0.9f), _ => new Color(-1f, -1f, -1f, -1f), }); } private Color GetBloodColor(RigManager rm) { //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)rm != (Object)null && _bloodColorOverrides.TryGetValue(rm, out var value) && value.a >= 0f) { return value; } string text = BloodColorOverride?.Value; if (!string.IsNullOrEmpty(text) && !text.Equals("Auto", StringComparison.OrdinalIgnoreCase)) { Color val = ParseBloodColorString(text.ToLowerInvariant()); if (val.a >= 0f) { return val; } } } catch { } if ((Object)(object)rm != (Object)null && (Object)(object)rm.avatar != (Object)null) { try { string text2 = ((Object)rm.avatar).name?.ToLowerInvariant() ?? string.Empty; foreach (KeyValuePair avatarBloodOverride in _avatarBloodOverrides) { string key = avatarBloodOverride.Key; bool flag = false; if (key.StartsWith("*") && key.EndsWith("*") && key.Length > 2) { flag = text2.Contains(key.Substring(1, key.Length - 2)); } else if (key.EndsWith("*") && key.Length > 1) { flag = text2.StartsWith(key.Substring(0, key.Length - 1)); } else if (key.StartsWith("*") && key.Length > 1) { flag = text2.EndsWith(key.Substring(1)); } else if (text2 == key) { flag = true; } if (flag) { return avatarBloodOverride.Value; } } if ((text2.Contains("small") && text2.Contains("fast")) || (text2.Contains("tall") && text2.Contains("fast"))) { return new Color(0.05f, 0.05f, 0.05f, 0.9f); } if (text2.Contains("lightbody") || text2.Contains("heavybody") || text2.Contains("omni") || text2.Contains("proto") || text2.Contains("drone") || text2.Contains("robot") || text2.Contains("bot_")) { return new Color(0.05f, 0.05f, 0.05f, 0.9f); } if (text2.Contains("purple") || text2.Contains("violet")) { return new Color(0.5f, 0.02f, 0.6f, 0.9f); } if (text2.Contains("green")) { return new Color(0.02f, 0.55f, 0.12f, 0.9f); } if (text2.Contains("yellow")) { return new Color(0.9f, 0.85f, 0.05f, 0.9f); } if (text2.Contains("blue")) { return new Color(0.05f, 0.08f, 0.7f, 0.9f); } if (text2.Contains("pink")) { return new Color(0.95f, 0.08f, 0.55f, 0.9f); } if (text2.Contains("orange")) { return new Color(1f, 0.45f, 0.02f, 0.9f); } if (text2.Contains("red")) { return new Color(0.7f, 0.02f, 0.02f, 0.9f); } if (text2.Contains("null")) { return new Color(1f, 0.45f, 0.02f, 0.9f); } } catch { } } return new Color(0.7f, 0.02f, 0.02f, 0.9f); } private Color SampleAvatarColor(RigManager rm) { //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) try { Renderer[] array = Il2CppArrayBase.op_Implicit(((Component)rm).GetComponentsInChildren(true)); if (array == null || array.Length == 0) { return Color.white; } Color val = Color.black; int num = 0; Renderer[] array2 = array; foreach (Renderer val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } Material sharedMaterial = val2.sharedMaterial; if ((Object)(object)sharedMaterial == (Object)null) { continue; } Color val3 = Color.white; string[] array3 = new string[7] { "_Color", "_BaseColor", "_TintColor", "_EmissiveColor", "_MainColor", "_ColorTint", "_AlbedoColor" }; string[] array4 = array3; foreach (string text in array4) { if (sharedMaterial.HasProperty(text)) { val3 = sharedMaterial.GetColor(text); break; } } if (!(val3 == Color.white)) { float num2 = Mathf.Max(val3.r, Mathf.Max(val3.g, val3.b)); float num3 = Mathf.Min(val3.r, Mathf.Min(val3.g, val3.b)); if (!(num2 < 0.02f) && (!(num2 - num3 < 0.01f) || !(num2 > 0.98f))) { val += val3; num++; } } } if (num > 0) { Color val4 = val / (float)num; float num4 = (val4.r + val4.g + val4.b) / 3f; if (num4 > 0.05f) { return val4; } } } catch { } return Color.white; } private void PlayDismemberEffects(Vector3 position, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0125: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) bool flag = TrySpawnGameBlood(position, 1.2f, color); if (EnableBloodEffects.Value && !flag) { if ((Object)(object)BloodPrefab != (Object)null) { ParticleSystem val = Object.Instantiate(BloodPrefab, position, Quaternion.identity); MainModule main = val.main; main.startColor = MinMaxGradient.op_Implicit(color); val.Play(); Object.Destroy((Object)(object)((Component)val).gameObject, 6f); } else { SpawnFallbackBlood(position, 1.5f, color); } } if (!EnableSoundEffects.Value) { return; } try { AudioClip val2 = DismemberSound; if ((Object)(object)val2 == (Object)null && _dismemberSounds != null && _dismemberSounds.Count > 0) { val2 = _dismemberSounds[Random.Range(0, _dismemberSounds.Count)]; } if ((Object)(object)val2 == (Object)null) { val2 = GenerateTestTone(); } if ((Object)(object)val2 != (Object)null) { GameObject val3 = new GameObject("DeadPiece_SoundEffect"); val3.transform.position = position; AudioSource val4 = val3.AddComponent(); val4.clip = val2; val4.spatialBlend = 1f; val4.Play(); Object.Destroy((Object)(object)val3, val2.length + 0.1f); } else { MelonLogger.Warning("Клип оказался null! Проверь целостность файлов в UserData."); } } catch (Exception ex) { MelonLogger.Warning("Sound playback failed: " + ex.Message); } } private void ApplyHeadSeverEffects(RigManager rm, Vector3 position) { //IL_0025: 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) if (!EnableHeadSever.Value || (Object)(object)rm == (Object)null) { return; } try { TryAddVisualCut(rm, position, 0.34f); Transform val = (((Object)(object)rm.avatar != (Object)null && (Object)(object)rm.avatar.animator != (Object)null) ? rm.avatar.animator.GetBoneTransform((HumanBodyBones)9) : null); if ((Object)(object)val != (Object)null) { TryAddVisualCut(rm, val.position, 0.28f); } } catch (Exception ex) { MelonLogger.Warning("Head sever effects failed: " + ex.Message); } } private void SpawnHeadProp(Transform headTransform, Vector3 hitPoint, Color bloodColor) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)val).name = "DeadPiece_SeveredHead"; val.transform.position = headTransform.position; val.transform.localScale = Vector3.one * 0.13f; val.transform.Rotate(0f, 0f, Random.Range(0f, 360f)); Object.Destroy((Object)(object)val.GetComponent()); MeshRenderer component = val.GetComponent(); ((Renderer)component).material = new Material(Shader.Find("Sprites/Default")) { color = bloodColor }; Rigidbody val2 = val.AddComponent(); val2.mass = 0.5f; val2.drag = 0.5f; Vector3 val4; if (!(hitPoint == Vector3.zero)) { Vector3 val3 = hitPoint - headTransform.position; val4 = ((Vector3)(ref val3)).normalized; } else { val4 = Vector3.up; } Vector3 val5 = val4; val2.AddForce(val5 * 7f + Vector3.up * 4f, (ForceMode)1); val2.AddTorque(new Vector3(Random.value - 0.5f, Random.value - 0.5f, Random.value - 0.5f) * 3f, (ForceMode)1); Object.Destroy((Object)(object)val, 10f); } catch { } } private bool IsBoneGone(RigManager rm, HumanBodyBones bone) { //IL_0035: 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 false; } int damageBoneIndex = GetDamageBoneIndex(bone); uint value; return damageBoneIndex >= 0 && _hiddenBoneMasks.TryGetValue(rm, out value) && (value & (uint)(1 << damageBoneIndex)) != 0; } private void HandleRespawnRestore(RigManager rm) { HandleRigRespawnRestore(rm, syncNetwork: true); } private void EnforceLocalFatalState(RigManager rm) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm != (Object)(object)Player.RigManager) && !((Object)(object)rm.health == (Object)null) && rm.health.alive && HasFatalBoneInMask(GetStateMask(rm)) && (PlayerIDManager.LocalID == null || !_pendingRespawnPlayers.Contains(PlayerIDManager.LocalSmallID)) && !_localRespawnRestoreWorkerActive && !_healingRestoreInProgress && (_managedFatalOutcome == ManagedFatalOutcome.None || !((Object)(object)_managedFatalRig == (Object)(object)rm) || !((Object)(object)_managedFatalHealth == (Object)(object)rm.health)) && TryGetFatalBoneFromMask(GetStateMask(rm), out var fatalBone)) { BeginFatalOutcome(rm, fatalBone); } } private void BeginFatalOutcome(RigManager rm, HumanBodyBones fatalBone) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.health == (Object)null || !rm.health.alive || !FatalBones.Contains(fatalBone)) { return; } if (_managedFatalOutcome != ManagedFatalOutcome.None) { if ((Object)(object)_managedFatalRig == (Object)(object)rm && (Object)(object)_managedFatalHealth == (Object)(object)rm.health) { if ((int)_managedFatalBone == 7 || (int)_managedFatalBone == 0 || (int)fatalBone == 10) { return; } CancelManagedFatalOutcome(resetPresentation: true); } else { CancelManagedFatalOutcome((Object)(object)_managedFatalHealth != (Object)null && _managedFatalHealth.alive); } } if ((int)fatalBone == 10 && Random.value < 0.25f) { StartDirectFatalDelay(rm, fatalBone, Random.Range(0.15f, 3f)); } else { StartNativeFatalDying(rm, fatalBone); } } private void StartDirectFatalDelay(RigManager rm, HumanBodyBones fatalBone, float delay) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Player_Health val = ((Il2CppObjectBase)rm.health).TryCast(); if ((Object)(object)val != (Object)null) { _managedFatalSavedHealthMode = ((Health)val).healthMode; _managedFatalSavedDeathTimeAmount = val.deathTimeAmount; _managedFatalSavedDeathTimeReduction = val.deathTimeReduction; _managedFatalSavedCurrDeathTime = val.currDeathTime; _managedFatalSavedSlowMoOnDeath = val.slowMoOnDeath; _managedFatalHasSavedPlayerState = true; ResetPlayerDyingState(val); } _managedFatalOutcome = ManagedFatalOutcome.DirectDelay; _managedFatalRig = rm; _managedFatalHealth = rm.health; _managedFatalPlayerHealth = val; _managedFatalBone = fatalBone; _managedFatalSceneGeneration = _sceneGeneration; _managedFatalToken++; _managedFatalSavedCurrentHealth = rm.health.curr_Health; if ((Object)(object)val != (Object)null) { ((Health)val).healthMode = (HealthMode)1; val.deathTimeReduction = 0f; val.slowMoOnDeath = false; } if (rm.health.curr_Health <= 0f) { rm.health.curr_Health = Mathf.Max(0.0001f, Mathf.Min(rm.health.max_Health, rm.health.max_Health * 0.01f)); } MelonCoroutines.Start(CompleteFatalAfterDelay(_managedFatalToken, Mathf.Clamp(delay, 0.01f, 3f))); } private void StartNativeFatalDying(RigManager rm, HumanBodyBones fatalBone) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Player_Health val = ((Il2CppObjectBase)rm.health).TryCast(); if ((Object)(object)val != (Object)null) { _managedFatalSavedHealthMode = ((Health)val).healthMode; _managedFatalSavedDeathTimeAmount = val.deathTimeAmount; _managedFatalSavedDeathTimeReduction = val.deathTimeReduction; _managedFatalSavedCurrDeathTime = val.currDeathTime; _managedFatalSavedSlowMoOnDeath = val.slowMoOnDeath; _managedFatalHasSavedPlayerState = true; ResetPlayerDyingState(val, restoreAudio: false); } _managedFatalOutcome = ManagedFatalOutcome.NativeDying; _managedFatalRig = rm; _managedFatalHealth = rm.health; _managedFatalPlayerHealth = val; _managedFatalBone = fatalBone; _managedFatalSceneGeneration = _sceneGeneration; _managedFatalToken++; _managedFatalSavedCurrentHealth = rm.health.curr_Health; if ((Object)(object)val != (Object)null) { ((Health)val).healthMode = (HealthMode)1; val.deathTimeAmount = 4f; val.currDeathTime = 4f; val.deathTimeReduction = 0f; val.slowMoOnDeath = false; ((Health)val).curr_Health = 0f; try { _allowManagedDyingEntry = true; ((Health)val).Dying(0f); } catch (Exception ex) { MelonLogger.Warning("Native dying state failed: " + ex.Message); } finally { _allowManagedDyingEntry = false; } val.currDeathTime = 4f; } else { rm.health.curr_Health = 0f; } MelonCoroutines.Start(CompleteFatalAfterDelay(_managedFatalToken, 4f)); } private IEnumerator CompleteFatalAfterDelay(int token, float delay) { float endTime = Time.realtimeSinceStartup + delay; while (Time.realtimeSinceStartup < endTime) { yield return null; } if (token == _managedFatalToken && _managedFatalOutcome != ManagedFatalOutcome.None) { RigManager rm = _managedFatalRig; Health health = _managedFatalHealth; HumanBodyBones fatalBone = _managedFatalBone; if (_managedFatalSceneGeneration != _sceneGeneration || (Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)health == (Object)null || (Object)(object)rm.health != (Object)(object)health || !health.alive || !IsBoneGone(rm, fatalBone)) { CancelManagedFatalOutcome((Object)(object)health != (Object)null && health.alive); yield break; } CancelManagedFatalOutcome(resetPresentation: true); health.Death(); } } private void UpdateManagedFatalOutcome() { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (_managedFatalOutcome != ManagedFatalOutcome.None) { if (_managedFatalSceneGeneration != _sceneGeneration || (Object)(object)_managedFatalRig == (Object)null || (Object)(object)_managedFatalRig != (Object)(object)Player.RigManager || (Object)(object)_managedFatalHealth == (Object)null || (Object)(object)_managedFatalRig.health != (Object)(object)_managedFatalHealth) { CancelManagedFatalOutcome((Object)(object)_managedFatalHealth != (Object)null && _managedFatalHealth.alive); } else if (!_managedFatalHealth.alive) { CancelManagedFatalOutcome(resetPresentation: false); } else if (!IsBoneGone(_managedFatalRig, _managedFatalBone)) { CancelManagedFatalOutcome(resetPresentation: true); } } } private void ResetPlayerDyingState(Player_Health playerHealth, bool restoreAudio = true) { if ((Object)(object)playerHealth == (Object)null) { return; } bool deathIsImminent = ((Health)playerHealth).deathIsImminent; bool flag = deathIsImminent && playerHealth.slowMoOnDeath; try { ((MonoBehaviour)playerHealth).StopAllCoroutines(); } catch { } ((Health)playerHealth)._deathRoutine = null; playerHealth.vignetteRoutine = null; playerHealth.regenRoutine = null; playerHealth.lowPassAudioRoutine = null; ((Health)playerHealth).deathIsImminent = false; playerHealth.isInstaDying = false; playerHealth.regenerating = false; playerHealth.isFadingVignette = false; if (flag) { try { TimeManager.TOGGLE_TIMESCALE(); } catch { } } if (deathIsImminent) { try { PlayerDeathImminent onDeathImminent = Player_Health.OnDeathImminent; if (onDeathImminent != null) { onDeathImminent.Invoke(false); } } catch { } } try { playerHealth.ResetVigMaterial(); } catch { } if (!restoreAudio) { return; } try { playerHealth.lowPassAudioRoutine = ((MonoBehaviour)playerHealth).StartCoroutine(playerHealth.CoLowPassFilter(false)); } catch { } } private void CancelManagedFatalOutcome(bool resetPresentation) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (_managedFatalOutcome != ManagedFatalOutcome.None) { Player_Health managedFatalPlayerHealth = _managedFatalPlayerHealth; Health managedFatalHealth = _managedFatalHealth; float managedFatalSavedCurrentHealth = _managedFatalSavedCurrentHealth; bool managedFatalHasSavedPlayerState = _managedFatalHasSavedPlayerState; HealthMode managedFatalSavedHealthMode = _managedFatalSavedHealthMode; float managedFatalSavedDeathTimeAmount = _managedFatalSavedDeathTimeAmount; float managedFatalSavedDeathTimeReduction = _managedFatalSavedDeathTimeReduction; float managedFatalSavedCurrDeathTime = _managedFatalSavedCurrDeathTime; bool managedFatalSavedSlowMoOnDeath = _managedFatalSavedSlowMoOnDeath; _managedFatalToken++; _managedFatalOutcome = ManagedFatalOutcome.None; _managedFatalRig = null; _managedFatalHealth = null; _managedFatalPlayerHealth = null; _managedFatalBone = (HumanBodyBones)55; _managedFatalSceneGeneration = -1; _managedFatalHasSavedPlayerState = false; _managedFatalSavedCurrentHealth = 0f; _allowManagedDyingEntry = false; if (resetPresentation && (Object)(object)managedFatalPlayerHealth != (Object)null) { ResetPlayerDyingState(managedFatalPlayerHealth); } if (managedFatalHasSavedPlayerState && (Object)(object)managedFatalPlayerHealth != (Object)null) { ((Health)managedFatalPlayerHealth).healthMode = managedFatalSavedHealthMode; managedFatalPlayerHealth.deathTimeAmount = managedFatalSavedDeathTimeAmount; managedFatalPlayerHealth.deathTimeReduction = managedFatalSavedDeathTimeReduction; managedFatalPlayerHealth.currDeathTime = managedFatalSavedCurrDeathTime; managedFatalPlayerHealth.slowMoOnDeath = managedFatalSavedSlowMoOnDeath; } if (resetPresentation && (Object)(object)managedFatalHealth != (Object)null && managedFatalHealth.alive && managedFatalHealth.curr_Health <= 0f) { float num = ((managedFatalHealth.max_Health > 0f && !float.IsNaN(managedFatalHealth.max_Health) && !float.IsInfinity(managedFatalHealth.max_Health)) ? managedFatalHealth.max_Health : 1f); managedFatalHealth.curr_Health = ((managedFatalSavedCurrentHealth > 0f && !float.IsNaN(managedFatalSavedCurrentHealth) && !float.IsInfinity(managedFatalSavedCurrentHealth)) ? Mathf.Min(num, managedFatalSavedCurrentHealth) : Mathf.Max(0.0001f, num * 0.5f)); } } } internal bool AllowPlayerHealthDying(Player_Health playerHealth) { return _allowManagedDyingEntry || _managedFatalOutcome == ManagedFatalOutcome.None || (Object)(object)_managedFatalPlayerHealth != (Object)(object)playerHealth; } internal bool AllowPlayerHealthLifeSave(Player_Health playerHealth) { return _managedFatalOutcome == ManagedFatalOutcome.None || (Object)(object)_managedFatalPlayerHealth != (Object)(object)playerHealth; } private static bool TryGetFatalBoneFromMask(uint mask, out HumanBodyBones fatalBone) { if (IsBoneInMask(mask, (HumanBodyBones)7)) { fatalBone = (HumanBodyBones)7; return true; } if (IsBoneInMask(mask, (HumanBodyBones)0)) { fatalBone = (HumanBodyBones)0; return true; } if (IsBoneInMask(mask, (HumanBodyBones)10)) { fatalBone = (HumanBodyBones)10; return true; } fatalBone = (HumanBodyBones)55; return false; } private void HandleAllRigsRespawnRestore() { if (!NetworkInfo.HasServer || _trackedRigs.Count == 0) { return; } if (_pendingRespawnPlayers.Count > 0) { byte[] array = _pendingRespawnPlayers.ToArray(); for (int i = 0; i < array.Length; i++) { if (!_activeRespawnRestoreWorkers.Contains(array[i])) { QueueRespawnRestore(array[i]); } } } RigManager[] array2 = _trackedRigs.ToArray(); foreach (RigManager val in array2) { if (!((Object)(object)val == (Object)null) && (Object)(object)val != (Object)(object)Player.RigManager) { HandleRigRespawnRestore(val, syncNetwork: false); } } } private void HandleRigRespawnRestore(RigManager rm, bool syncNetwork) { if ((Object)(object)rm == (Object)null || (Object)(object)rm.health == (Object)null) { return; } bool flag = !rm.health.alive; _rigWasDead.TryGetValue(rm, out var value); if (value && !flag) { byte playerId; if ((Object)(object)rm == (Object)(object)Player.RigManager) { RequestLocalRespawnReset(rm); } else if (TryGetPlayerIdForRig(rm, out playerId)) { QueueRespawnRestore(playerId, rm); } else { ClearAppliedLimbState(rm); ResetLimbStats(rm, restoreBody: true); } } _rigWasDead[rm] = flag; } public void SyncFullState() { if (PlayerIDManager.LocalID != null) { RigManager rigManager = Player.RigManager; if (!((Object)(object)rigManager == (Object)null)) { uint stateMask = GetStateMask(rigManager); SyncLocalState(stateMask); } } } private void ResyncLocalStateIfNeeded() { if (PlayerIDManager.LocalID != null && !((Object)(object)Player.RigManager == (Object)null)) { uint stateMask = GetStateMask(Player.RigManager); if (stateMask != _lastSentStateMask || !(Time.time - _lastStateSyncTime < 5f)) { SyncLocalState(stateMask); } } } private ushort NextLocalStateSequence() { _localStateSequence++; if (_localStateSequence == 0) { _localStateSequence = 1; } return _localStateSequence; } private void SyncLocalState(uint goneBoneMask) { if (PlayerIDManager.LocalID != null && !_pendingRespawnPlayers.Contains(PlayerIDManager.LocalSmallID)) { ushort sequence = NextLocalStateSequence(); byte bloodColorIndex = BloodColorToIndex(BloodColorOverride?.Value ?? "Auto"); NetworkSync.SendFullState(PlayerIDManager.LocalSmallID, goneBoneMask, bloodColorIndex, sequence); _lastSentStateMask = goneBoneMask; _lastStateSyncTime = Time.time; } } public void SetPlayerMetadata(byte playerId, string value) { value = value ?? string.Empty; try { foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null && playerID.SmallID == playerId) { PlayerMetadata metadata = playerID.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null) { playerID.Metadata.Metadata.TrySetMetadata("DeadPieceLimbs", value); break; } } } } catch { } } private byte GetBloodColorIndexForRig(RigManager rm) { if ((Object)(object)rm == (Object)null) { return 0; } if (_bloodColorIndexOverrides.TryGetValue(rm, out var value)) { return value; } return 0; } private bool TryResolvePlayerRig(byte playerId, out RigManager rigManager) { rigManager = null; try { if (PlayerIDManager.LocalID != null && playerId == PlayerIDManager.LocalSmallID && (Object)(object)Player.RigManager != (Object)null) { rigManager = Player.RigManager; return true; } RigRefs val = default(RigRefs); if (PlayerRepUtilities.TryGetReferences(playerId, ref val) && (Object)(object)((val != null) ? val.RigManager : null) != (Object)null) { rigManager = val.RigManager; return true; } } catch { } return false; } private void ApplyBloodColorToRig(RigManager rigManager, byte colorIndex) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rigManager == (Object)null) { return; } if (colorIndex == 0) { _bloodColorOverrides.Remove(rigManager); _bloodColorIndexOverrides.Remove(rigManager); return; } Color val = IndexToBloodColor(colorIndex); if (val.a >= 0f) { _bloodColorOverrides[rigManager] = val; _bloodColorIndexOverrides[rigManager] = colorIndex; } } private void OnPluginLimbHit(byte targetPlayerId, byte boneIndex, float damage, Vector3 hitPoint, bool applyDamage) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (boneIndex >= DamageBones.Length || !TryResolvePlayerRig(targetPlayerId, out var rigManager) || !IsSessionEnabled() || !GetPlayerLimbsEnabled(targetPlayerId) || !IsLimbDestructionAllowed(rigManager)) { return; } EnsureRigInitialized(rigManager); GetAvatarHealthBase(rigManager); HumanBodyBones val = DamageBones[boneIndex]; if (applyDamage) { if (_playersHealth.TryGetValue(rigManager, out var value) && value.ContainsKey(val) && !IsBoneGone(rigManager, val)) { MarkLimbDamaged(rigManager, val); value[val] = Mathf.Max(0f, value[val] - damage); PlayHitEffects(rigManager, val, hitPoint, damage); if (value[val] <= 0f) { DismemberLimb(rigManager, val, hitPoint); if ((Object)(object)rigManager != (Object)(object)Player.RigManager && IsRemotePlayerRig(rigManager)) { ApplyRemoteLegEffects(rigManager); } } else if (hitPoint != Vector3.zero) { TryDamageNearbyEyes(rigManager, hitPoint, damage); } } } else { PlayHitEffects(rigManager, val, hitPoint, damage); } TrackRig(rigManager); if (applyDamage && NetworkInfo.IsHost) { NetworkSync.SendFullState(targetPlayerId, GetStateMask(rigManager), GetBloodColorIndexForRig(rigManager), 0); } } private void OnPluginLimbSever(byte targetPlayerId, byte boneIndex, Vector3 hitPoint, Vector3 hitNormal, float damage) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) OnPluginLimbHit(targetPlayerId, boneIndex, NormalizePositiveDamage(damage), hitPoint, NetworkInfo.IsHost); } private void OnPluginRespawn(byte playerId) { ClearPlayerInteractionState(playerId); _pendingNetworkStates.Remove(playerId); _appliedStateMasks.Remove(playerId); _remoteFallenPlayers.Remove(playerId); TryResolvePlayerRig(playerId, out var rigManager); QueueRespawnRestore(playerId, rigManager); } private void OnPluginBloodColor(byte playerId, byte colorIndex) { if (TryResolvePlayerRig(playerId, out var rigManager)) { ApplyBloodColorToRig(rigManager, colorIndex); } } private uint GetPluginStateMask(byte playerId) { RigManager rigManager; return TryResolvePlayerRig(playerId, out rigManager) ? GetStateMask(rigManager) : 0u; } private void OnPluginFullState(byte playerId, uint goneBoneMask, byte bloodColorIndex, ushort sequence) { ApplyNetworkState(playerId, sequence, goneBoneMask); if (TryResolvePlayerRig(playerId, out var rigManager)) { ApplyBloodColorToRig(rigManager, bloodColorIndex); } } private void OnPlayerJoined(PlayerID id) { PublishLocalSettings(force: true); SyncFullState(); if (id == null || id.IsMe) { return; } if (NetworkInfo.IsHost) { SyncNpcStates(); MelonCoroutines.Start(DelayedNpcStateCatchup()); } RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager != (Object)null) { SyncLocalState(GetStateMask(rigManager)); } PlayerMetadata metadata = id.Metadata; string value = default(string); if (((metadata != null) ? metadata.Metadata : null) != null && id.Metadata.Metadata.TryGetMetadata("DeadPieceLimbs", ref value)) { ApplyNetworkState(id.SmallID, value); } PlayerMetadata metadata2 = id.Metadata; string value2 = default(string); if (((metadata2 != null) ? metadata2.Metadata : null) != null && id.Metadata.Metadata.TryGetMetadata("DeadPieceLimbsEnabled", ref value2)) { HandlePlayerLimbsSetting(id.SmallID, ParseEnabledSetting(value2)); } PlayerMetadata metadata3 = id.Metadata; string value3 = default(string); if (((metadata3 != null) ? metadata3.Metadata : null) != null && id.Metadata.Metadata.TryGetMetadata("DeadPieceHealthBase", ref value3)) { HandlePlayerHealthBase(id.SmallID, value3); } PlayerMetadata metadata4 = id.Metadata; string value4 = default(string); if (((metadata4 != null) ? metadata4.Metadata : null) != null && id.Metadata.Metadata.TryGetMetadata("DeadPieceInteractionStats", ref value4)) { HandlePlayerInteractionStats(id.SmallID, value4); } RigRefs val = default(RigRefs); if (PlayerRepUtilities.TryGetReferences(id.SmallID, ref val) && (Object)(object)((val != null) ? val.RigManager : null) != (Object)null) { TrackRig(val.RigManager); } try { BroadcastBloodColor(); } catch { } } private void OnPlayerLeft(PlayerID id) { if (id != null) { byte smallID = id.SmallID; RemovePlayerHealthBar(smallID); _pendingNetworkStates.Remove(smallID); _lastAppliedNetworkSequence.Remove(smallID); _appliedStateMasks.Remove(smallID); _remoteFallenPlayers.Remove(smallID); _playerLimbsEnabled.Remove(smallID); _networkHealthBaseOverrides.Remove(smallID); _networkInteractionStats.Remove(smallID); _pendingRespawnPlayers.Remove(smallID); _hardRespawnRecoveryPlayers.Remove(smallID); ClearPlayerInteractionState(smallID); NetworkSync.ForgetPlayer(smallID); RigRefs val = default(RigRefs); if (PlayerRepUtilities.TryGetReferences(smallID, ref val) && (Object)(object)((val != null) ? val.RigManager : null) != (Object)null) { RemoveRigFromCaches(val.RigManager); } } } private void OnNetworkRigCreated(NetworkPlayer player, RigManager rig) { if (((player != null) ? player.PlayerID : null) == null || (Object)(object)rig == (Object)null) { return; } byte smallID = player.PlayerID.SmallID; if (_pendingRespawnPlayers.Contains(smallID)) { QueueRespawnRestore(smallID, rig); TrackRig(rig); return; } if (_pendingNetworkStates.TryGetValue(smallID, out var value)) { if ((Object)(object)rig.avatar != (Object)null && (Object)(object)rig.avatar.animator != (Object)null && (value.Sequence == 0 || ShouldApplyNetworkSequence(smallID, value.Sequence))) { if (GetPlayerLimbsEnabled(smallID) && IsSessionEnabled()) { ApplyStateToRig(rig, value.GoneBoneMask); } if (value.Sequence > 0) { _lastAppliedNetworkSequence[smallID] = value.Sequence; } _pendingNetworkStates.Remove(smallID); } } else { PlayerMetadata metadata = player.PlayerID.Metadata; string value2 = default(string); if (((metadata != null) ? metadata.Metadata : null) != null && player.PlayerID.Metadata.Metadata.TryGetMetadata("DeadPieceLimbs", ref value2)) { ApplyNetworkState(smallID, value2); } } uint stateMask = GetStateMask(rig); if (stateMask != 0) { _appliedStateMasks[smallID] = stateMask; } else { _appliedStateMasks.Remove(smallID); } PlayerMetadata metadata2 = player.PlayerID.Metadata; string value3 = default(string); if (((metadata2 != null) ? metadata2.Metadata : null) != null && player.PlayerID.Metadata.Metadata.TryGetMetadata("DeadPieceLimbsEnabled", ref value3)) { HandlePlayerLimbsSetting(smallID, ParseEnabledSetting(value3)); } PlayerMetadata metadata3 = player.PlayerID.Metadata; string value4 = default(string); if (((metadata3 != null) ? metadata3.Metadata : null) != null && player.PlayerID.Metadata.Metadata.TryGetMetadata("DeadPieceHealthBase", ref value4)) { HandlePlayerHealthBase(smallID, value4); } PlayerMetadata metadata4 = player.PlayerID.Metadata; string value5 = default(string); if (((metadata4 != null) ? metadata4.Metadata : null) != null && player.PlayerID.Metadata.Metadata.TryGetMetadata("DeadPieceInteractionStats", ref value5)) { HandlePlayerInteractionStats(smallID, value5); } TrackRig(rig); } private void OnMetadataChanged(PlayerID id, string key, string value) { if (id == null) { return; } switch (key) { case "DeadPieceLimbsEnabled": HandlePlayerLimbsSetting(id.SmallID, ParseEnabledSetting(value)); break; case "DeadPieceHostEnabled": try { if (id.SmallID == 0) { SetServerEnabled(ParseEnabledSetting(value)); } break; } catch { break; } case "DeadPieceOneHpMode": try { if (id.SmallID == 0) { SetServerOneHpMode(ParseOneHpSetting(value)); } break; } catch { break; } case "DeadPieceHealthBase": HandlePlayerHealthBase(id.SmallID, value); break; case "DeadPieceInteractionStats": HandlePlayerInteractionStats(id.SmallID, value); break; case "DeadPieceLegState": { if (!id.IsMe && byte.TryParse(value, out var result) && IsSessionEnabled() && GetPlayerLimbsEnabled(id.SmallID)) { ApplyRemoteLegState(id.SmallID, result); } break; } default: if (!(key != "DeadPieceLimbs") && !id.IsMe && !_pluginCallbacksRegistered) { ApplyNetworkState(id.SmallID, value); } break; } } private unsafe string GetStateString(RigManager rm) { if ((Object)(object)rm == (Object)null) { return string.Empty; } IEnumerable values = NetworkBones.Where((HumanBodyBones bone) => IsBoneGone(rm, bone)).Select(delegate(HumanBodyBones bone) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) HumanBodyBones val = bone; return ((object)(*(HumanBodyBones*)(&val))/*cast due to .constrained prefix*/).ToString(); }); return string.Join(",", values); } private void InitializeModules() { } private void RegisterFusionModules() { } public void ApplyNetworkState(byte playerId, ushort sequence, uint goneBoneMask, bool isFallen) { //IL_0118: Unknown result type (might be due to invalid IL or missing references) goneBoneMask &= (uint)((1 << DamageBones.Length) - 1); if ((_pendingRespawnPlayers.Contains(playerId) && goneBoneMask != 0) || (sequence > 0 && !ShouldApplyNetworkSequence(playerId, sequence))) { return; } if (!TryResolvePlayerRig(playerId, out var rigManager)) { QueuePendingNetworkState(playerId, sequence, goneBoneMask, isFallen); return; } if ((Object)(object)rigManager.avatar == (Object)null || (Object)(object)rigManager.avatar.animator == (Object)null) { QueuePendingNetworkState(playerId, sequence, goneBoneMask, isFallen); return; } if (!IsSessionEnabled() || !GetPlayerLimbsEnabled(playerId)) { goneBoneMask = 0u; } if (IsRigStateMaskCurrent(rigManager, goneBoneMask)) { if ((Object)(object)rigManager == (Object)(object)Player.RigManager && (Object)(object)rigManager.health != (Object)null && rigManager.health.alive && TryGetFatalBoneFromMask(goneBoneMask, out var fatalBone)) { BeginFatalOutcome(rigManager, fatalBone); } TrackRig(rigManager); if (goneBoneMask == 0) { _appliedStateMasks.Remove(playerId); } else { _appliedStateMasks[playerId] = goneBoneMask; } if (sequence > 0) { _lastAppliedNetworkSequence[playerId] = sequence; } _pendingNetworkStates.Remove(playerId); } else { ApplyStateToRig(rigManager, goneBoneMask); if ((Object)(object)rigManager == (Object)(object)Player.RigManager && isFallen && IsBothLegsGone(rigManager)) { ApplyNoLegFallenState(rigManager); } else if ((Object)(object)rigManager == (Object)(object)Player.RigManager && !IsBothLegsGone(rigManager) && _deadpieceFallenStateApplied) { RestoreNoLegFallenState(rigManager); } TrackRig(rigManager); if (sequence > 0) { _lastAppliedNetworkSequence[playerId] = sequence; } _pendingNetworkStates.Remove(playerId); } } private bool IsRigStateMaskCurrent(RigManager rm, uint goneBoneMask) { //IL_0091: 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 false; } for (int i = 0; i < DamageBones.Length; i++) { bool flag = (goneBoneMask & (uint)(1 << i)) != 0; Transform cachedBoneTransform = GetCachedBoneTransform(rm, DamageBones[i]); if (!((Object)(object)cachedBoneTransform == (Object)null)) { if (IsBoneGone(rm, DamageBones[i]) != flag) { return false; } if ((flag && IsUsableBoneScale(cachedBoneTransform.localScale)) || (!flag && ShouldRepairBoneScale(rm, DamageBones[i], cachedBoneTransform))) { return false; } } } return true; } public void ApplyNetworkState(byte playerId, ushort sequence, uint goneBoneMask) { ApplyNetworkState(playerId, sequence, goneBoneMask, isFallen: false); } public void ApplyNetworkState(byte playerId, string value) { ApplyNetworkState(playerId, 0, ParseGoneMaskFromString(value)); } public void ApplyNetworkStateFromMask(byte playerId, uint goneBoneMask) { ApplyNetworkState(playerId, 0, goneBoneMask); } public void ApplyNetworkBloodColor(byte playerId, byte colorIndex) { if (TryResolvePlayerRig(playerId, out var rigManager)) { ApplyBloodColorToRig(rigManager, colorIndex); } } public void BroadcastBloodColor() { try { byte colorIndex = BloodColorToIndex(BloodColorOverride?.Value ?? "Auto"); if ((Object)(object)Player.RigManager != (Object)null) { ApplyBloodColorToRig(Player.RigManager, colorIndex); } if (NetworkInfo.HasServer && PlayerIDManager.LocalID != null) { NetworkSync.SendBloodColor(PlayerIDManager.LocalSmallID, colorIndex); } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Blood color update failed: " + ex.Message); } } public static string BuildStateStringFromMask(uint goneBoneMask) { if (goneBoneMask == 0) { return string.Empty; } List list = new List(); for (int i = 0; i < DamageBones.Length; i++) { if ((goneBoneMask & (uint)(1 << i)) != 0) { list.Add(((object)Unsafe.As(ref DamageBones[i])/*cast due to .constrained prefix*/).ToString()); } } return string.Join(",", list); } private void ApplyPendingNetworkStates() { if (_pendingNetworkStates.Count > 0) { KeyValuePair[] array = _pendingNetworkStates.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; ApplyNetworkState(keyValuePair.Key, keyValuePair.Value.Sequence, keyValuePair.Value.GoneBoneMask, keyValuePair.Value.IsFallen); } } } private void ApplyStateToRig(RigManager rm, string value) { ApplyStateToRig(rm, ParseGoneMaskFromString(value)); } private void ApplyStateToRig(RigManager rm, uint goneBoneMask) { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018b: 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_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_037b: 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; } uint stateMask = GetStateMask(rm); bool flag = IsArmGoneInMask(stateMask, left: true); bool flag2 = IsArmGoneInMask(stateMask, left: false); bool flag3 = AreBothLegsGoneInMask(stateMask); if (IsRigLimbDamageBlocked(rm) && !IsRemotePlayerRig(rm)) { ResetLimbStats(rm, restoreBody: true); return; } HashSet hashSet = new HashSet(); for (int i = 0; i < DamageBones.Length; i++) { if ((goneBoneMask & (uint)(1 << i)) != 0) { hashSet.Add(DamageBones[i]); } } if (hashSet.Count == 0) { ResetLimbStats(rm, restoreBody: true); return; } EnsureRigInitialized(rm); RebuildBoneCache(rm); for (int j = 0; j < DamageBones.Length; j++) { HumanBodyBones val = DamageBones[j]; Transform cachedBoneTransform = GetCachedBoneTransform(rm, val); if ((Object)(object)cachedBoneTransform == (Object)null) { continue; } bool flag4 = (stateMask & (uint)(1 << j)) != 0; if ((goneBoneMask & (uint)(1 << j)) != 0) { CaptureOriginalBoneScale(rm, val, cachedBoneTransform); if (!HasStumpBloodStart(rm, val)) { MarkStumpBloodStarted(rm, val); } SetBoneHiddenState(rm, val, hidden: true); cachedBoneTransform.localScale = Vector3.zero; if (_playersHealth.TryGetValue(rm, out var value)) { value[val] = 0f - GetMaxHealthForBone(rm, val); } if (!flag4) { TryAddVisualCut(rm, cachedBoneTransform.position); if (IsRemotePlayerRig(rm)) { Vector3 position = cachedBoneTransform.position; SpawnBloodStream(rm, val, position); PlayDismemberEffects(position, GetBloodColor(rm)); TryApplyBloodImpactAtBone(rm, val, position, Mathf.Max(5f, GetMaxHealthForBone(rm, val) * 0.25f), GetBloodColor(rm)); } } } else if (flag4 || ShouldRepairBoneScale(rm, val, cachedBoneTransform)) { RegrowLimb(rm, val); } } RebuildLimbGoneFlags(rm); SyncLegColliderState(rm); if ((Object)(object)rm == (Object)(object)Player.RigManager) { UpdateLimbPenaltyFlag(rm); bool flag5 = IsLeftArmGone(rm); bool flag6 = IsRightArmGone(rm); if (flag != flag5) { SetHandUsable(Player.LeftHand, !flag5); } if (flag2 != flag6) { SetHandUsable(Player.RightHand, !flag6); } if (flag3 && !IsBothLegsGone(rm)) { ReleaseDeadpieceCrouchState(rm); } if (IsBothLegsGone(rm)) { AllowLocalNoLegRagdollFromCurrentSever(); } uint num = goneBoneMask & ~stateMask; uint mask = (HasFatalBoneInMask(num) ? num : goneBoneMask); if ((Object)(object)rm.health != (Object)null && rm.health.alive && TryGetFatalBoneFromMask(mask, out var fatalBone)) { BeginFatalOutcome(rm, fatalBone); } } if ((Object)(object)rm != (Object)(object)Player.RigManager && IsRemotePlayerRig(rm)) { ApplyRemoteLegEffects(rm); } TrackRig(rm); if (TryGetPlayerIdForRig(rm, out var playerId)) { if (goneBoneMask != 0) { _appliedStateMasks[playerId] = goneBoneMask; } else { _appliedStateMasks.Remove(playerId); } } if ((Object)(object)rm == (Object)(object)Player.RigManager && EnableVrEyeBlindness.Value) { UpdateVrEyeBlindness(rm); } } private static bool IsArmGoneInMask(uint mask, bool left) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) HumanBodyBones bone = (HumanBodyBones)(left ? 13 : 14); HumanBodyBones bone2 = (HumanBodyBones)(left ? 15 : 16); HumanBodyBones bone3 = (HumanBodyBones)(left ? 17 : 18); return IsBoneInMask(mask, bone) || IsBoneInMask(mask, bone2) || IsBoneInMask(mask, bone3); } private static bool AreBothLegsGoneInMask(uint mask) { bool flag = IsBoneInMask(mask, (HumanBodyBones)1) || IsBoneInMask(mask, (HumanBodyBones)3) || IsBoneInMask(mask, (HumanBodyBones)5); bool flag2 = IsBoneInMask(mask, (HumanBodyBones)2) || IsBoneInMask(mask, (HumanBodyBones)4) || IsBoneInMask(mask, (HumanBodyBones)6); return flag && flag2; } private static bool IsBoneInMask(uint mask, HumanBodyBones bone) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) int value; return BoneToIndexMap.TryGetValue(bone, out value) && (mask & (uint)(1 << value)) != 0; } private void SetBoneHiddenState(RigManager rm, HumanBodyBones bone, bool hidden) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rm == (Object)null) && BoneToIndexMap.TryGetValue(bone, out var value)) { _hiddenBoneMasks.TryGetValue(rm, out var value2); uint num = (uint)(1 << value); value2 = (hidden ? (value2 | num) : (value2 & ~num)); if (value2 == 0) { _hiddenBoneMasks.Remove(rm); } else { _hiddenBoneMasks[rm] = value2; } } } private void ClearAppliedLimbState(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { if (TryGetPlayerIdForRig(rm, out var playerId)) { _pendingNetworkStates.Remove(playerId); _appliedStateMasks.Remove(playerId); _remoteFallenPlayers.Remove(playerId); } if ((Object)(object)rm == (Object)(object)Player.RigManager && PlayerIDManager.LocalID != null) { byte localSmallID = PlayerIDManager.LocalSmallID; _pendingNetworkStates.Remove(localSmallID); _appliedStateMasks.Remove(localSmallID); _remoteFallenPlayers.Remove(localSmallID); } } } private static bool HasFatalBoneInMask(uint mask) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) foreach (HumanBodyBones fatalBone in FatalBones) { if (IsBoneInMask(mask, fatalBone)) { return true; } } return false; } private bool IsEyeGone(RigManager rm, HumanBodyBones eyeBone) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 return ((int)eyeBone == 21 || (int)eyeBone == 22) && IsBoneGone(rm, eyeBone); } private void ClearVrEyeCameraCache() { _vrEyeCamerasCached = false; _vrEyeCacheRig = null; _vrLeftEyeCameras.Clear(); _vrRightEyeCameras.Clear(); RestoreAllVrEyeCameras(); } private void RestoreAllVrEyeCameras() { foreach (KeyValuePair item in _vrCameraEnabledBackup) { if ((Object)(object)item.Key != (Object)null) { ((Behaviour)item.Key).enabled = item.Value; } } _vrCameraEnabledBackup.Clear(); foreach (KeyValuePair vrEyeBlackoutObject in _vrEyeBlackoutObjects) { if ((Object)(object)vrEyeBlackoutObject.Value != (Object)null) { Object.Destroy((Object)(object)vrEyeBlackoutObject.Value); } } _vrEyeBlackoutObjects.Clear(); } private void CacheVrEyeCameras(RigManager rm) { if (_vrEyeCamerasCached && (Object)(object)_vrEyeCacheRig == (Object)(object)rm) { return; } _vrLeftEyeCameras.Clear(); _vrRightEyeCameras.Clear(); _vrEyeCacheRig = rm; if ((Object)(object)((rm != null) ? rm.avatar : null) != (Object)null) { Il2CppArrayBase componentsInChildren = ((Component)rm.avatar).GetComponentsInChildren(true); foreach (Camera item in componentsInChildren) { ClassifyVrEyeCamera(item, _vrLeftEyeCameras, _vrRightEyeCameras); } } _vrEyeCamerasCached = true; } private static void ClassifyVrEyeCamera(Camera camera, List leftCameras, List rightCameras) { if ((Object)(object)camera == (Object)null) { return; } string text = ((Object)camera).name.ToLowerInvariant(); if (!text.Contains("center") && !text.Contains("spectator") && !text.Contains("overlay") && !text.Contains("mirror") && !text.Contains("ui")) { bool flag = text.Contains("left") || text.Contains("leye") || text.EndsWith("_l") || text.EndsWith("lf"); bool flag2 = text.Contains("right") || text.Contains("reye") || text.EndsWith("_r") || text.EndsWith("rt"); if (flag && !flag2) { AddUniqueCamera(leftCameras, camera); } else if (flag2 && !flag) { AddUniqueCamera(rightCameras, camera); } } } private static void AddUniqueCamera(List cameras, Camera camera) { if (!cameras.Contains(camera)) { cameras.Add(camera); } } private void UpdateVrEyeBlindness(RigManager rm) { if (EnableVrEyeBlindness.Value && !((Object)(object)rm != (Object)(object)Player.RigManager)) { bool flag = IsEyeGone(rm, (HumanBodyBones)21); bool flag2 = IsEyeGone(rm, (HumanBodyBones)22); CacheVrEyeCameras(rm); ApplyVrBlindnessToCameras(_vrLeftEyeCameras, flag); ApplyVrBlindnessToCameras(_vrRightEyeCameras, flag2); _lastAppliedLeftEyeBlind = flag; _lastAppliedRightEyeBlind = flag2; } } private void ApplyVrBlindnessToCameras(List cameras, bool blind) { for (int i = 0; i < cameras.Count; i++) { Camera val = cameras[i]; if ((Object)(object)val == (Object)null) { continue; } if (blind) { if (!_vrCameraEnabledBackup.ContainsKey(val)) { _vrCameraEnabledBackup[val] = ((Behaviour)val).enabled; } EnsureVrBlackoutOverlay(val); ((Behaviour)val).enabled = false; } else { if (_vrCameraEnabledBackup.TryGetValue(val, out var value)) { ((Behaviour)val).enabled = value; } RemoveVrBlackoutOverlay(val); } } } private void EnsureVrBlackoutOverlay(Camera camera) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Expected O, but got Unknown if (!((Object)(object)camera == (Object)null) && !_vrEyeBlackoutObjects.ContainsKey(camera)) { GameObject val = new GameObject("DeadPiece_VREyeBlackout"); val.layer = LayerMask.NameToLayer("Ignore Raycast"); val.transform.SetParent(((Component)camera).transform, false); float num = Mathf.Max(camera.nearClipPlane + 0.02f, 0.03f); val.transform.localPosition = new Vector3(0f, 0f, num); val.transform.localRotation = Quaternion.identity; float num2 = Mathf.Tan(camera.fieldOfView * 0.5f * ((float)Math.PI / 180f)) * num * 2.2f; float num3 = num2 * Mathf.Max(camera.aspect, 0.5f); val.transform.localScale = new Vector3(num3, num2, 1f); MeshFilter val2 = val.AddComponent(); Mesh val3 = new Mesh(); ((Object)val3).name = "DeadPiece_VRQuad"; val3.vertices = Il2CppStructArray.op_Implicit((Vector3[])(object)new Vector3[4] { new Vector3(-0.5f, -0.5f, 0f), new Vector3(0.5f, -0.5f, 0f), new Vector3(-0.5f, 0.5f, 0f), new Vector3(0.5f, 0.5f, 0f) }); val3.triangles = Il2CppStructArray.op_Implicit(new int[6] { 0, 1, 2, 2, 1, 3 }); val3.uv = Il2CppStructArray.op_Implicit((Vector2[])(object)new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0f, 1f), new Vector2(1f, 1f) }); val2.sharedMesh = val3; MeshRenderer val4 = val.AddComponent(); Shader val5 = Shader.Find("Unlit/Color"); if ((Object)(object)val5 == (Object)null) { val5 = Shader.Find("Sprites/Default"); } if ((Object)(object)val5 != (Object)null) { ((Renderer)val4).material = new Material(val5) { color = Color.black }; } val.layer = ((Component)camera).gameObject.layer; _vrEyeBlackoutObjects[camera] = val; } } private void RemoveVrBlackoutOverlay(Camera camera) { if (!((Object)(object)camera == (Object)null)) { if (_vrEyeBlackoutObjects.TryGetValue(camera, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } _vrEyeBlackoutObjects.Remove(camera); } } private void TryAddVisualCut(RigManager rm, Vector3 position) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) TryAddVisualCut(rm, position, 0.18f); } private void TryAddVisualCut(RigManager rm, Vector3 position, float scale) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (!EnableVisualCuts.Value || (Object)(object)rm == (Object)null) { return; } try { VisualDamageController visualDamageController = GetVisualDamageController(rm); Matrix4x4 val = Matrix4x4.TRS(position, Quaternion.identity, Vector3.one * Mathf.Max(0.01f, scale)); if ((Object)(object)visualDamageController != (Object)null) { visualDamageController.AddToCutArray(val); visualDamageController.UpdateArray(); } else if ((Object)(object)rm.health != (Object)null) { rm.health.AddToCutArray(val); rm.health.UpdateArray(); } } catch (Exception ex) { MelonLogger.Warning("Visual cut failed: " + ex.Message); } } private void ResetVisualDamage(RigManager rm) { if ((Object)(object)rm == (Object)null) { return; } try { VisualDamageController visualDamageController = GetVisualDamageController(rm); if ((Object)(object)visualDamageController != (Object)null) { visualDamageController.ResetHits(); visualDamageController.UpdateArray(); } if ((Object)(object)rm.health != (Object)null) { rm.health.ResetHits(); rm.health.UpdateArray(); } } catch (Exception ex) { MelonLogger.Warning("Visual damage reset failed: " + ex.Message); } } public void SetLocalMetadata(string value) { value = value ?? string.Empty; try { PlayerMetadata metadata = LocalPlayer.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null) { LocalPlayer.Metadata.Metadata.TrySetMetadata("DeadPieceLimbs", 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("DeadPieceLimbs", value); } } private void KillRig(RigManager rm) { if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm.health == (Object)null)) { rm.health.Death(); } } private bool HasLimbGoneFlag(RigManager rm, LimbGoneMask mask) { if ((Object)(object)rm == (Object)null || !_rigCache.TryGetValue(rm, out var value)) { return false; } return (value.LimbGoneFlags & mask) != 0; } private bool IsLeftArmGone(RigManager rm) { return HasLimbGoneFlag(rm, LimbGoneMask.LeftArm); } private bool IsRightArmGone(RigManager rm) { return HasLimbGoneFlag(rm, LimbGoneMask.RightArm); } private bool IsLeftLegGone(RigManager rm) { return HasLimbGoneFlag(rm, LimbGoneMask.LeftLeg); } private bool IsRightLegGone(RigManager rm) { return HasLimbGoneFlag(rm, LimbGoneMask.RightLeg); } public bool IsBothLegsGone(RigManager rm) { if ((Object)(object)rm == (Object)null) { return false; } return IsLeftLegGone(rm) && IsRightLegGone(rm); } public bool ShouldApplySingleLegSpeedPenalty(RigManager rm) { int result; if ((Object)(object)rm != (Object)null && (Object)(object)rm == (Object)(object)Player.RigManager && IsSessionEnabled()) { MelonPreferences_Entry limbsEnabled = LimbsEnabled; if (limbsEnabled == null || limbsEnabled.Value) { MelonPreferences_Entry enableMovementPenalty = EnableMovementPenalty; if (enableMovementPenalty == null || enableMovementPenalty.Value) { result = ((IsLeftLegGone(rm) != IsRightLegGone(rm)) ? 1 : 0); goto IL_005b; } } } result = 0; goto IL_005b; IL_005b: return (byte)result != 0; } public bool AreAllLimbsGone(RigManager rm) { if ((Object)(object)rm == (Object)null) { return false; } return IsLeftArmGone(rm) && IsRightArmGone(rm) && IsLeftLegGone(rm) && IsRightLegGone(rm); } private void PlayHitEffects(RigManager rm, HumanBodyBones bone, Vector3 position, float damage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (position == Vector3.zero || !ShouldPlayHitEffect(rm, bone)) { return; } if (EnableBloodEffects.Value) { float intensity = Mathf.Clamp01(damage / Mathf.Max(1f, GetMaxHealthForBone(rm, bone))); if (!TrySpawnGameBlood(position, intensity, GetBloodColor(rm)) && (Object)(object)BloodPrefab == (Object)null) { SpawnFallbackBlood(position, intensity, GetBloodColor(rm)); } } if (IsBoneGone(rm, bone)) { float num = Mathf.Max(0f, SeveredLimbBleedDamagePerSecond.Value) * Time.deltaTime; if (num > 0f) { TryApplyBleedAtBone(rm, bone, num); } } } private bool ShouldPlayHitEffect(RigManager rm, HumanBodyBones bone) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!_lastHitEffectTimes.TryGetValue(rm, out var value)) { value = new Dictionary(); _lastHitEffectTimes[rm] = value; } if (value.TryGetValue(bone, out var value2) && Time.time - value2 < 0.12f) { return false; } value[bone] = Time.time; return true; } private IEnumerator LoadDismemberSounds() { MelonLogger.Msg(ConsoleColor.Gray, "LoadDismemberSounds started, folder: " + _soundFolder); string[] files; try { if (!Directory.Exists(_soundFolder)) { MelonLogger.Warning("Sound folder does not exist: " + _soundFolder); yield break; } files = Directory.GetFiles(_soundFolder, "*.wav", SearchOption.TopDirectoryOnly); MelonLogger.Msg(ConsoleColor.Gray, "Found " + files.Length + " WAV files in " + _soundFolder); } catch (Exception ex) { Exception ex2 = ex; MelonLogger.Warning("Sound folder scan failed: " + ex2.Message); yield break; } string[] array = files; foreach (string file in array) { MelonLogger.Msg(ConsoleColor.Gray, "Loading sound file: " + file); AudioClip clip = null; try { clip = API.LoadAudioClip(file, true); } catch (Exception ex3) { MelonLogger.Warning("AudioImportLib failed to load " + Path.GetFileName(file) + ": " + ex3.Message); } if ((Object)(object)clip != (Object)null) { MelonLogger.Msg(ConsoleColor.Gray, "Loaded clip: " + ((Object)clip).name + " length=" + clip.length + " freq=" + clip.frequency + " channels=" + clip.channels); _dismemberSounds.Add(clip); } else { MelonLogger.Warning("AudioImportLib returned null for: " + Path.GetFileName(file)); } } MelonLogger.Msg(ConsoleColor.Gray, "Loaded " + _dismemberSounds.Count + " dismemberment sounds from " + _soundFolder); } private AudioClip GenerateTestTone() { int num = 44100; float num2 = 0.3f; int num3 = (int)((float)num * num2); float[] array = new float[num3]; for (int i = 0; i < num3; i++) { float num4 = (float)i / (float)num; array[i] = Mathf.Sin((float)Math.PI * 880f * num4) * 0.5f; } AudioClip val = AudioClip.Create("DeadPiece_TestTone", num3, 1, num, false); val.SetData(Il2CppStructArray.op_Implicit(array), 0); return val; } internal bool IsLocalHandUnavailable(Hand hand) { if ((Object)(object)hand == (Object)null || !IsSessionEnabled() || !(LimbsEnabled?.Value ?? true)) { return false; } RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null) { return false; } if ((Object)(object)hand == (Object)(object)Player.LeftHand) { return _leftHandDisabledByDeadPiece || IsLeftArmGone(rigManager); } if ((Object)(object)hand == (Object)(object)Player.RightHand) { return _rightHandDisabledByDeadPiece || IsRightArmGone(rigManager); } return false; } private static bool HasResidualHandAttachment(Hand hand) { if ((Object)(object)hand == (Object)null) { return false; } try { if ((Object)(object)hand.AttachedReceiver != (Object)null) { return true; } } catch { } try { if ((Object)(object)hand.m_CurrentAttachedGO != (Object)null) { return true; } } catch { } try { if (hand.HasAttachedObject()) { return true; } } catch { } try { return (Object)(object)hand.joint != (Object)null || (Object)(object)hand.tempJoint != (Object)null; } catch { return false; } } private static void ForceReleaseSeveredHand(Hand hand) { if ((Object)(object)hand == (Object)null) { return; } HandReciever val = null; Grip val2 = null; try { val = hand.AttachedReceiver; } catch { } if ((Object)(object)val != (Object)null) { try { val2 = ((Il2CppObjectBase)val).TryCast(); } catch { } } if ((Object)(object)val2 != (Object)null) { try { val2.ForceDetach(hand); } catch { } } if (HasResidualHandAttachment(hand)) { try { hand.DetachObject(); } catch { } } try { hand.DetachIgnoreBodyJoints(); } catch { } try { hand.SetGripStrength(0f); } catch { } } private void SetHandUsable(Hand hand, bool usable) { if ((Object)(object)hand == (Object)null) { return; } bool flag = (Object)(object)hand == (Object)(object)Player.LeftHand; bool flag2 = (flag ? _leftHandDisabledByDeadPiece : _rightHandDisabledByDeadPiece); if (usable) { if (flag2) { hand.EnableCollider(); if (!hand.HasAttachedObject()) { hand.HoverUnlock(); } if (flag) { _leftHandDisabledByDeadPiece = false; } else { _rightHandDisabledByDeadPiece = false; } } return; } ForceReleaseSeveredHand(hand); hand.HoverLock(); hand.DisableCollider(); if (!flag2) { if (flag) { _leftHandDisabledByDeadPiece = true; } else { _rightHandDisabledByDeadPiece = true; } } } private void EnforceLocalHandUsability() { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null || !IsSessionEnabled() || !(LimbsEnabled?.Value ?? true)) { return; } bool flag = !IsLeftArmGone(rigManager); bool flag2 = !IsRightArmGone(rigManager); if ((Object)(object)Player.LeftHand != (Object)null) { if (!flag) { SetHandUsable(Player.LeftHand, usable: false); } else if (flag && !_lastLeftArmUsable) { SetHandUsable(Player.LeftHand, usable: true); } } if ((Object)(object)Player.RightHand != (Object)null) { if (!flag2) { SetHandUsable(Player.RightHand, usable: false); } else if (flag2 && !_lastRightArmUsable) { SetHandUsable(Player.RightHand, usable: true); } } _lastLeftArmUsable = flag; _lastRightArmUsable = flag2; } private void ApplyRemoteLegEffects(RigManager rm) { if ((Object)(object)rm == (Object)null) { return; } SyncLegColliderState(rm); byte playerId2; if (IsBothLegsGone(rm)) { if (TryGetPlayerIdForRig(rm, out var playerId)) { _remoteFallenPlayers.Add(playerId); } } else if (TryGetPlayerIdForRig(rm, out playerId2)) { _remoteFallenPlayers.Remove(playerId2); } } private void EnforceRemoteFallenState() { if (_remoteFallenPlayers.Count == 0) { return; } byte[] array = new byte[_remoteFallenPlayers.Count]; _remoteFallenPlayers.CopyTo(array); foreach (byte b in array) { if (TryResolvePlayerRig(b, out var rigManager) && !((Object)(object)rigManager == (Object)null) && !IsBothLegsGone(rigManager)) { _remoteFallenPlayers.Remove(b); } } } private bool TrySpawnGameBlood(Vector3 position, float intensity) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return TrySpawnGameBlood(position, intensity, Color.white, 10f); } private bool TrySpawnGameBlood(Vector3 position, float intensity, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return TrySpawnGameBlood(position, intensity, color, 10f); } private bool TrySpawnGameBlood(Vector3 position, float intensity, Color color, float lifetimeSeconds) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_012a: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) if (!EnableBloodEffects.Value || !EnableGameBloodEffects.Value || position == Vector3.zero) { return false; } if (lifetimeSeconds <= 0.05f) { return false; } float num = Mathf.Min(10f, Mathf.Max(0.05f, lifetimeSeconds)); if (TrySpawnVanillaBloodSpawnable(position, intensity, stream: false, Random.rotation, color, num)) { return true; } if (TryCloneLoadedGameBlood(position, intensity, color)) { return true; } if (!EnableFallbackBloodEffects.Value) { return false; } TryCacheGameBloodSpawnables(); if (_gameBloodSpawnableBarcodes.Count <= 0) { return false; } try { AssetSpawner instance = AssetSpawner._instance; if ((Object)(object)instance == (Object)null) { return false; } string text = _gameBloodSpawnableBarcodes[Random.Range(0, _gameBloodSpawnableBarcodes.Count)]; Spawnable val = new Spawnable { crateRef = new SpawnableCrateReference(text) }; if (!val.IsValid()) { return false; } float num2 = Mathf.Lerp(0.75f, 1.35f, Mathf.Clamp01(intensity)); Nullable scale = new Nullable(Vector3.one * num2); MelonCoroutines.Start(RunAsyncSpawnBlood(val, position, Random.rotation, scale, color, num)); return true; } catch (Exception ex) { MelonLogger.Warning("Game blood spawn failed: " + ex.Message); return false; } } private bool TrySpawnVanillaBloodSpawnable(Vector3 position, float intensity) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) return TrySpawnVanillaBloodSpawnable(position, intensity, stream: false, Random.rotation, Color.white, 10f); } private bool TrySpawnVanillaBloodSpawnable(Vector3 position, float intensity, bool stream, Quaternion rotation) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return TrySpawnVanillaBloodSpawnable(position, intensity, stream, rotation, Color.white, 10f); } private bool TrySpawnVanillaBloodSpawnable(Vector3 position, float intensity, bool stream, Quaternion rotation, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return TrySpawnVanillaBloodSpawnable(position, intensity, stream, rotation, color, 10f); } private bool TrySpawnVanillaBloodSpawnable(Vector3 position, float intensity, bool stream, Quaternion rotation, Color color, float lifetimeSeconds) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) try { if (lifetimeSeconds <= 0.05f) { return false; } float clearDelay = Mathf.Min(10f, Mathf.Max(0.05f, lifetimeSeconds)); if (!TryRegisterVanillaBloodSpawnables()) { return false; } Spawnable val; string text; if (stream && _bloodBagBlasterSpawnable != null) { val = _bloodBagBlasterSpawnable; text = "c1534c5a-1ea0-4156-920b-f8a8426c6173"; } else { val = ((intensity >= 0.65f) ? _largeBloodSplatterSpawnable : _smallBloodSplatterSpawnable); text = ((intensity >= 0.65f) ? VanillaBloodSpawnableBarcodes[1] : VanillaBloodSpawnableBarcodes[0]); } if (val == null) { return false; } Nullable scale = new Nullable(Vector3.zero) { hasValue = false }; Nullable groupId = new Nullable(0) { hasValue = false }; MelonCoroutines.Start(RunAsyncSpawnVanillaBlood(val, position, rotation, scale, groupId, color, clearDelay)); if (!_loggedVanillaBloodSpawnable) { _loggedVanillaBloodSpawnable = true; MelonLogger.Msg("Using vanilla BONELAB blood spawnable via SpawnAsync: " + text); } return true; } catch (Exception ex) { MelonLogger.Warning("Vanilla blood spawnable failed: " + ex.Message); } return false; } private bool TryRegisterVanillaBloodSpawnables() { if (_vanillaBloodSpawnablesRegistered) { return true; } try { _smallBloodSplatterSpawnable = CreateVanillaBloodSpawnable(VanillaBloodSpawnableBarcodes[0]); _largeBloodSplatterSpawnable = CreateVanillaBloodSpawnable(VanillaBloodSpawnableBarcodes[1]); _bloodBagBlasterSpawnable = CreateVanillaBloodSpawnable("c1534c5a-1ea0-4156-920b-f8a8426c6173"); AssetSpawner.Register(_smallBloodSplatterSpawnable); AssetSpawner.Register(_largeBloodSplatterSpawnable); AssetSpawner.Register(_bloodBagBlasterSpawnable); _vanillaBloodSpawnablesRegistered = true; return true; } catch (Exception ex) { if (!_loggedVanillaBloodSpawnableFailure) { _loggedVanillaBloodSpawnableFailure = true; MelonLogger.Warning("Vanilla blood spawnable registration failed: " + ex.Message); } _smallBloodSplatterSpawnable = null; _largeBloodSplatterSpawnable = null; _bloodBagBlasterSpawnable = null; _vanillaBloodSpawnablesRegistered = false; } return false; } private Spawnable CreateVanillaBloodSpawnable(string barcode) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown return new Spawnable { crateRef = new SpawnableCrateReference(barcode), policyData = null }; } private bool TryCloneLoadedGameBlood(Vector3 position, float intensity) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return TryCloneLoadedGameBlood(position, intensity, Color.white); } private bool TryCloneLoadedGameBlood(Vector3 position, float intensity, Color color) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) ParticleSystem val = FindLoadedGameBloodParticle(); if ((Object)(object)val == (Object)null) { return false; } try { ParticleSystem val2 = Object.Instantiate(val, position, Random.rotation); if ((Object)(object)val2 == (Object)null) { return false; } ((Object)val2).name = "DeadPiece_GameBlood_" + ((Object)val).name; ((Component)val2).gameObject.SetActive(true); ((Component)val2).transform.position = position; ((Component)val2).transform.localScale = Vector3.one * Mathf.Lerp(0.85f, 1.35f, Mathf.Clamp01(intensity)); ParticleSystem[] array = Il2CppArrayBase.op_Implicit(((Component)val2).GetComponentsInChildren(true)); int num = Mathf.RoundToInt(Mathf.Lerp(4f, 18f, Mathf.Clamp01(intensity))); foreach (ParticleSystem val3 in array) { if (!((Object)(object)val3 == (Object)null)) { ((Component)val3).gameObject.SetActive(true); MainModule main = val3.main; main.startColor = MinMaxGradient.op_Implicit(color); main.simulationSpace = (ParticleSystemSimulationSpace)1; val3.Clear(false); val3.Play(false); val3.Emit(num); } } Object.Destroy((Object)(object)((Component)val2).gameObject, GetParticleDestroyDelay(val2)); return true; } catch (Exception ex) { MelonLogger.Warning("Loaded game blood clone failed: " + ex.Message); _gameBloodParticlePrefab = null; return false; } } private ParticleSystem FindLoadedGameBloodParticle() { if ((Object)(object)_gameBloodParticlePrefab != (Object)null) { return _gameBloodParticlePrefab; } if (Time.time - _lastGameBloodParticleSearchTime < 5f) { return null; } _lastGameBloodParticleSearchTime = Time.time; try { ParticleSystem[] array = Il2CppArrayBase.op_Implicit(Resources.FindObjectsOfTypeAll()); ParticleSystem val = null; int num = 0; foreach (ParticleSystem val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null)) { int num2 = ScoreLoadedGameBloodParticle(val2); if (num2 > num) { num = num2; val = val2; } } } if ((Object)(object)val != (Object)null && num >= 70) { _gameBloodParticlePrefab = val; MelonLogger.Msg($"Using loaded BONELAB blood VFX: {((Object)val).name} (score {num})"); return _gameBloodParticlePrefab; } if (!_loggedMissingGameBloodParticles) { _loggedMissingGameBloodParticles = true; MelonLogger.Warning("No loaded BONELAB blood ParticleSystem found yet; will retry later."); } } catch (Exception ex) { MelonLogger.Warning("Loaded game blood scan failed: " + ex.Message); } return null; } private int ScoreLoadedGameBloodParticle(ParticleSystem particle) { string text = BuildParticleSearchText(particle); if (string.IsNullOrEmpty(text)) { return 0; } int num = 0; for (int i = 0; i < GameBloodPositiveKeywords.Length; i++) { if (text.Contains(GameBloodPositiveKeywords[i])) { num += 30; } } if (text.Contains("blood")) { num += 80; } if (text.Contains("bleed") || text.Contains("gore")) { num += 40; } for (int j = 0; j < GameBloodNegativeKeywords.Length; j++) { if (text.Contains(GameBloodNegativeKeywords[j])) { num -= 120; } } try { if (particle.main.maxParticles < 4) { num -= 25; } if (((Component)particle).gameObject.activeInHierarchy) { num += 5; } } catch { } return Mathf.Max(0, num); } private string BuildParticleSearchText(ParticleSystem particle) { string text = string.Empty; try { text = text + " " + ((Object)particle).name; text = text + " " + ((Object)((Component)particle).gameObject).name; if ((Object)(object)((Component)particle).transform != (Object)null && (Object)(object)((Component)particle).transform.root != (Object)null) { text = text + " " + ((Object)((Component)particle).transform.root).name; } ParticleSystemRenderer component = ((Component)particle).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).sharedMaterial != (Object)null) { text = text + " " + ((Object)((Renderer)component).sharedMaterial).name; if ((Object)(object)((Renderer)component).sharedMaterial.shader != (Object)null) { text = text + " " + ((Object)((Renderer)component).sharedMaterial.shader).name; } } } catch { } return text.ToLowerInvariant(); } private float GetParticleDestroyDelay(ParticleSystem particle) { try { float duration = particle.main.duration; return Mathf.Clamp(duration + 1.5f, 2f, 8f); } catch { return 4f; } } private void TryCacheGameBloodSpawnables() { if (_bloodSpawnablesScanned) { return; } try { AssetWarehouse instance = AssetWarehouse.Instance; if (instance == null || !AssetWarehouse.ready) { return; } List crates = instance.GetCrates(); if (crates == null || crates.Count == 0) { return; } string[] array = new string[10] { "blood", "bloody", "gore", "splat", "spray", "burst", "drip", "bleed", "wound", "squirt" }; string[] array2 = new string[6] { "decal", "quad", "poster", "icon", "ui", "marker" }; int num = 0; Enumerator enumerator = crates.GetEnumerator(); while (enumerator.MoveNext()) { Crate current = enumerator.Current; if ((Object)(object)current == (Object)null) { continue; } num++; SpawnableCrate val = ((Il2CppObjectBase)current).TryCast(); if ((Object)(object)val == (Object)null) { continue; } string text = ((((Scannable)val).Barcode != (Barcode)null) ? ((Object)((Scannable)val).Barcode).ToString() : string.Empty); string text2 = ((Scannable)val).Title ?? string.Empty; string text3 = (text + " " + text2).ToLowerInvariant(); bool flag = false; for (int i = 0; i < array2.Length; i++) { if (text3.Contains(array2[i])) { flag = true; break; } } if (flag) { continue; } string[] array3 = array; string[] array4 = array3; foreach (string value in array4) { if (text3.Contains(value)) { if (!string.IsNullOrEmpty(text) && !_gameBloodSpawnableBarcodes.Contains(text)) { _gameBloodSpawnableBarcodes.Add(text); } break; } } } _bloodSpawnablesScanned = _gameBloodSpawnableBarcodes.Count > 0; MelonLogger.Msg($"Scanned {num} crates, cached {_gameBloodSpawnableBarcodes.Count} blood spawnables."); } catch (Exception ex) { MelonLogger.Warning("Game blood scan failed: " + ex.Message); } } private void SpawnFallbackBlood(Vector3 position, float intensity, Color color) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown try { GameObject val = new GameObject("DeadPiece_FallbackBlood"); val.transform.position = position; ParticleSystem val2 = val.AddComponent(); ParticleSystemRenderer component = val.GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).material = new Material(Shader.Find("Sprites/Default")); } MainModule main = val2.main; main.startLifetime = MinMaxCurve.op_Implicit(0.45f); main.startSpeed = MinMaxCurve.op_Implicit(Mathf.Lerp(0.6f, 2.2f, intensity)); main.startSize = MinMaxCurve.op_Implicit(Mathf.Lerp(0.025f, 0.065f, intensity)); main.startColor = MinMaxGradient.op_Implicit(color); main.maxParticles = 28; main.simulationSpace = (ParticleSystemSimulationSpace)1; EmissionModule emission = val2.emission; emission.enabled = false; ShapeModule shape = val2.shape; shape.shapeType = (ParticleSystemShapeType)0; shape.radius = 0.035f; val2.Emit(Mathf.RoundToInt(Mathf.Lerp(8f, 24f, intensity))); Object.Destroy((Object)(object)val, 1.25f); } catch (Exception ex) { MelonLogger.Warning("Fallback blood failed: " + ex.Message); } } private void SpawnBloodStream(RigManager rm, HumanBodyBones bone, Vector3 position) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown if (!EnableBloodEffects.Value || (Object)(object)rm == (Object)null || (Object)(object)rm.avatar == (Object)null || (Object)(object)rm.avatar.animator == (Object)null) { return; } try { Transform boneTransform = rm.avatar.animator.GetBoneTransform(bone); if ((Object)(object)boneTransform == (Object)null) { return; } Vector3 val = GetBoneStreamDirection(rm, bone, boneTransform); if (val == Vector3.zero) { val = boneTransform.up; } if (!TrySpawnGameBlood(position + ((Vector3)(ref val)).normalized * 0.03f, 0.85f, GetBloodColor(rm))) { GameObject val2 = new GameObject("DeadPiece_BloodStream"); val2.transform.position = position; val2.transform.rotation = Quaternion.LookRotation(val); ParticleSystem val3 = val2.AddComponent(); ParticleSystemRenderer component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).material = new Material(Shader.Find("Sprites/Default")); } MainModule main = val3.main; main.startLifetime = MinMaxCurve.op_Implicit(1.2f); main.startSpeed = MinMaxCurve.op_Implicit(3.5f); main.startSize = MinMaxCurve.op_Implicit(0.04f); main.startColor = MinMaxGradient.op_Implicit(GetBloodColor(rm)); main.maxParticles = 120; main.simulationSpace = (ParticleSystemSimulationSpace)1; main.gravityModifier = MinMaxCurve.op_Implicit(0.6f); main.duration = 2.5f; main.loop = false; main.playOnAwake = true; EmissionModule emission = val3.emission; emission.enabled = true; emission.rateOverTime = MinMaxCurve.op_Implicit(35f); emission.SetBursts(Il2CppReferenceArray.op_Implicit((Burst[])(object)new Burst[3] { new Burst(0f, MinMaxCurve.op_Implicit(12f)), new Burst(0.15f, MinMaxCurve.op_Implicit(8f)), new Burst(0.4f, MinMaxCurve.op_Implicit(6f)) })); ShapeModule shape = val3.shape; shape.shapeType = (ParticleSystemShapeType)4; shape.angle = 12f; shape.radius = 0.03f; val3.Play(); Object.Destroy((Object)(object)val2, 4.5f); } } catch (Exception ex) { MelonLogger.Warning("Blood stream failed: " + ex.Message); } } private void SpawnDamageVolume(RigManager rm, HumanBodyBones bone, Vector3 position) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || !EnableImpactBlood.Value) { return; } try { GameObject val = new GameObject("DeadPiece_DamageVolume"); val.transform.position = position; SphereCollider val2 = val.AddComponent(); ((Collider)val2).isTrigger = true; val2.radius = 0.12f; Rigidbody val3 = val.AddComponent(); val3.isKinematic = true; val3.useGravity = false; StumpDamageVolume stumpDamageVolume = val.AddComponent(); stumpDamageVolume.Initialize(2f, 8f); Object.Destroy((Object)(object)val, 8.5f); } catch (Exception ex) { MelonLogger.Warning("SpawnDamageVolume failed: " + ex.Message); } } private static void AddLegCollider(HashSet colliders, Collider collider) { if ((Object)(object)collider != (Object)null) { colliders.Add(collider); } } private static void AddPhysLegColliders(HashSet colliders, PhysLimb limb) { if (!((Object)(object)limb == (Object)null)) { AddLegCollider(colliders, (Collider)(object)limb.cUpper); AddLegCollider(colliders, (Collider)(object)limb.cLower); AddLegCollider(colliders, (Collider)(object)limb.endCol); } } private static HashSet GetLegColliders(RigManager rm) { HashSet hashSet = new HashSet(); PhysicsRig val = ((rm != null) ? rm.physicsRig : null); if ((Object)(object)val == (Object)null) { return hashSet; } AddPhysLegColliders(hashSet, val.legLf); AddPhysLegColliders(hashSet, val.legRt); AddLegCollider(hashSet, (Collider)(object)val._football); AddLegCollider(hashSet, (Collider)(object)val._kneeFender); AddLegCollider(hashSet, (Collider)(object)val.kneePelvisCol); return hashSet; } private void SyncLegColliderState(RigManager rm) { if ((Object)(object)rm == (Object)null) { return; } if (!IsSessionEnabled() || !AreBothLegsGoneInMask(GetStateMask(rm))) { RestoreLegColliderState(rm); return; } if (!_legColliderOriginalStates.TryGetValue(rm, out var value)) { value = new Dictionary(); _legColliderOriginalStates[rm] = value; } foreach (Collider legCollider in GetLegColliders(rm)) { if (!((Object)(object)legCollider == (Object)null)) { if (!value.ContainsKey(legCollider)) { value[legCollider] = legCollider.enabled; } if (legCollider.enabled) { legCollider.enabled = false; } } } } internal void SyncLegColliderState(PhysicsRig physicsRig) { if ((Object)(object)physicsRig == (Object)null) { return; } RigManager val = ((Component)physicsRig).GetComponentInParent(); if ((Object)(object)val == (Object)null && (Object)(object)Player.RigManager != (Object)null && (Object)(object)Player.RigManager.physicsRig == (Object)(object)physicsRig) { val = Player.RigManager; } if ((Object)(object)val == (Object)null) { foreach (RigManager trackedRig in _trackedRigs) { if ((Object)(object)trackedRig != (Object)null && (Object)(object)trackedRig.physicsRig == (Object)(object)physicsRig) { val = trackedRig; break; } } } SyncLegColliderState(val); } private void RestoreLegColliderState(RigManager rm) { if ((Object)(object)rm == (Object)null || !_legColliderOriginalStates.TryGetValue(rm, out var value)) { return; } KeyValuePair[] array = value.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; Collider key = keyValuePair.Key; if ((Object)(object)key != (Object)null) { key.enabled = keyValuePair.Value; } } _legColliderOriginalStates.Remove(rm); } private void RestoreAllLegColliderStates() { RigManager[] array = _legColliderOriginalStates.Keys.ToArray(); foreach (RigManager rm in array) { RestoreLegColliderState(rm); } } private void EnforceLegColliderStates() { if ((Object)(object)Player.RigManager != (Object)null) { SyncLegColliderState(Player.RigManager); } RigManager[] array = _trackedRigs.ToArray(); foreach (RigManager val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)Player.RigManager) { SyncLegColliderState(val); } } } private void CaptureLocomotionState(RigManager rm) { if (_locomotionStateSaved || (Object)(object)rm == (Object)null || (Object)(object)rm.remapHeptaRig == (Object)null) { return; } try { float maxVelocity = rm.remapHeptaRig.maxVelocity; float currentMaxVelocity = rm.remapHeptaRig.currentMaxVelocity; if (maxVelocity > 0.25f) { _savedLocomotionMaxVelocity = maxVelocity; } if (currentMaxVelocity > 0.25f) { _savedLocomotionCurrentMaxVelocity = currentMaxVelocity; } else { _savedLocomotionCurrentMaxVelocity = _savedLocomotionMaxVelocity; } _savedLocomotionJumpEnabled = rm.remapHeptaRig.jumpEnabled; _locomotionStateSaved = true; } catch (Exception ex) { MelonLogger.Warning("CaptureLocomotionState failed: " + ex.Message); } } private float GetBaseMaxVelocity(RigManager rm) { if (_locomotionStateSaved && _savedLocomotionMaxVelocity > 0.25f) { return _savedLocomotionMaxVelocity; } if ((Object)(object)rm != (Object)null && (Object)(object)rm.remapHeptaRig != (Object)null && rm.remapHeptaRig.maxVelocity > 0.25f) { return rm.remapHeptaRig.maxVelocity; } return 4.5f; } private void DisableDoubleJump(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm.remapHeptaRig == (Object)null) { return; } try { rm.remapHeptaRig.doubleJump = false; } catch { } } private void ApplyMovementConstraints(RigManager rm) { if (IsSessionEnabled()) { MelonPreferences_Entry limbsEnabled = LimbsEnabled; if ((limbsEnabled == null || limbsEnabled.Value) && (EnableMovementPenalty?.Value ?? true)) { ApplyDeadpieceLegUsage(rm); ClearStaleNoLegRagdollState(rm); return; } } bool flag = _deadpieceNoLegUsageApplied || _deadpieceJumpBlocked || _deadpieceFallenStateApplied; RestoreDeadpieceLegUsage(rm); RestoreNoLegJump(rm); RestoreNoLegFallenState(rm); if (flag) { RecoverLocalLocomotion(rm); } } private void SuppressNoLegRagdollForRespawn() { _suppressNoLegRagdollUntil = Time.time + 1.25f; } private void ResetLocalNoLegRagdollPermission() { _localNoLegEffectsPermitted = false; } private void AllowLocalNoLegRagdollFromCurrentSever() { _localNoLegEffectsPermitted = true; _suppressNoLegRagdollUntil = -999f; } public bool IsNoLegRagdollSuppressed() { return Time.time < _suppressNoLegRagdollUntil; } private void ReleaseDeadpieceCrouchState(RigManager rm) { if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm != (Object)(object)Player.RigManager)) { _localNoLegEffectsPermitted = false; if (!((Object)(object)rm.remapHeptaRig == (Object)null)) { rm.remapHeptaRig._crouchVelocity = 0f; } } } public bool ShouldApplyLocalNoLegEffects(RigManager rm) { int result; if ((Object)(object)rm != (Object)null && (Object)(object)rm == (Object)(object)Player.RigManager && IsSessionEnabled()) { MelonPreferences_Entry limbsEnabled = LimbsEnabled; if (limbsEnabled == null || limbsEnabled.Value) { MelonPreferences_Entry enableMovementPenalty = EnableMovementPenalty; if ((enableMovementPenalty == null || enableMovementPenalty.Value) && !IsNoLegRagdollSuppressed() && IsBothLegsGone(rm)) { result = (_localNoLegEffectsPermitted ? 1 : 0); goto IL_005f; } } } result = 0; goto IL_005f; IL_005f: return (byte)result != 0; } private void ClearStaleNoLegRagdollState(RigManager rm) { if (!((Object)(object)rm == (Object)null)) { if ((Object)(object)rm == (Object)(object)Player.RigManager && !IsBothLegsGone(rm)) { _localNoLegEffectsPermitted = false; } if (!IsBothLegsGone(rm) && _deadpieceFallenStateApplied) { RestoreNoLegFallenState(rm); } } } private void ApplyDeadpieceLegUsage(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.health == (Object)null) { return; } if (ShouldApplyLocalNoLegEffects(rm)) { try { int num = (((Object)(object)rm.avatar != (Object)null) ? ((Object)rm.avatar).GetHashCode() : 0); if (_deadpieceNoLegUsageApplied && ((Object)(object)_deadpieceUsageRig != (Object)(object)rm || (Object)(object)_deadpieceUsageHealth != (Object)(object)rm.health)) { RestoreDeadpieceLegUsage(_deadpieceUsageRig); } else if (_deadpieceNoLegUsageApplied && _deadpieceUsageAvatarHash != num) { RestoreDeadpieceLegUsage(_deadpieceUsageRig); } if (!_deadpieceNoLegUsageApplied) { _savedUsageHips = NormalizeUsageValue(rm.health.usage_hips); _savedUsageSpine = NormalizeUsageValue(rm.health.usage_spine); _savedUsageLegLf = NormalizeUsageValue(rm.health.usage_leg_lf); _savedUsageLegRt = NormalizeUsageValue(rm.health.usage_leg_rt); _savedUsageArmLf = NormalizeUsageValue(rm.health.usage_arm_lf); _savedUsageArmRt = NormalizeUsageValue(rm.health.usage_arm_rt); _deadpieceUsageRig = rm; _deadpieceUsageHealth = rm.health; _deadpieceUsageAvatarHash = num; _deadpieceNoLegUsageApplied = true; } rm.health.SetUsage(_savedUsageHips, _savedUsageSpine, 0f, 0f, _savedUsageArmLf, _savedUsageArmRt); } catch (Exception ex) { MelonLogger.Warning("Apply no-leg usage failed: " + ex.Message); } if (!_deadpieceJumpBlocked || (Object)(object)_deadpieceJumpRig != (Object)(object)rm.remapHeptaRig) { BlockNoLegJump(rm); } if (!_deadpieceFallenStateApplied) { ApplyNoLegFallenState(rm); } LockNoLegLocomotion(rm); } else if (IsBothLegsGone(rm)) { ForceClearNoLegRagdollState(rm); RestoreNoLegJump(rm); RestoreDeadpieceLegUsage(rm); } else { if (_deadpieceNoLegUsageApplied) { RestoreDeadpieceLegUsage(rm); } if (_deadpieceJumpBlocked) { RestoreNoLegJump(rm); } if (_deadpieceFallenStateApplied) { RestoreNoLegFallenState(rm); } } } private void RestoreDeadpieceLegUsage(RigManager rm) { if (!_deadpieceNoLegUsageApplied) { return; } try { RigManager rigManager = Player.RigManager; int num = (((Object)(object)_deadpieceUsageRig != (Object)null && (Object)(object)_deadpieceUsageRig.avatar != (Object)null) ? ((Object)_deadpieceUsageRig.avatar).GetHashCode() : 0); if ((Object)(object)_deadpieceUsageRig != (Object)null && (Object)(object)_deadpieceUsageHealth != (Object)null && (Object)(object)_deadpieceUsageRig == (Object)(object)rigManager && (Object)(object)_deadpieceUsageRig.health == (Object)(object)_deadpieceUsageHealth && _deadpieceUsageAvatarHash == num && ((Object)(object)rm == (Object)null || (Object)(object)rm == (Object)(object)_deadpieceUsageRig)) { _deadpieceUsageHealth.SetUsage(_savedUsageHips, _savedUsageSpine, _savedUsageLegLf, _savedUsageLegRt, _savedUsageArmLf, _savedUsageArmRt); } } catch (Exception ex) { MelonLogger.Warning("Restore leg usage failed: " + ex.Message); } finally { ClearDeadpieceLegUsageSnapshot(); } } private static float NormalizeUsageValue(float value) { if (float.IsNaN(value) || float.IsInfinity(value) || value <= 0.01f) { return 1f; } return Mathf.Clamp01(value); } private void ClearDeadpieceLegUsageSnapshot() { _deadpieceNoLegUsageApplied = false; _deadpieceUsageRig = null; _deadpieceUsageHealth = null; _deadpieceUsageAvatarHash = 0; } private void BlockNoLegJump(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.remapHeptaRig == (Object)null) { return; } try { if (_deadpieceJumpBlocked && ((Object)(object)_deadpieceJumpOwnerRig != (Object)(object)rm || (Object)(object)_deadpieceJumpRig != (Object)(object)rm.remapHeptaRig)) { RestoreNoLegJump(_deadpieceJumpOwnerRig); } if (!_deadpieceJumpBlocked) { _savedLocomotionJumpEnabled = rm.remapHeptaRig.jumpEnabled; _savedLocomotionDoubleJump = rm.remapHeptaRig.doubleJump; _deadpieceJumpOwnerRig = rm; _deadpieceJumpRig = rm.remapHeptaRig; _deadpieceJumpBlocked = true; } rm.remapHeptaRig.jumpEnabled = false; rm.remapHeptaRig.doubleJump = false; rm.remapHeptaRig._jumping = false; rm.remapHeptaRig._jumpStage = 0; rm.remapHeptaRig._jumpCycle = 0f; } catch (Exception ex) { MelonLogger.Warning("Block no-leg jump failed: " + ex.Message); } } private void RestoreNoLegJump(RigManager rm) { if (!_deadpieceJumpBlocked) { return; } try { RigManager rigManager = Player.RigManager; if ((Object)(object)_deadpieceJumpOwnerRig != (Object)null && (Object)(object)_deadpieceJumpRig != (Object)null && (Object)(object)_deadpieceJumpOwnerRig == (Object)(object)rigManager && (Object)(object)_deadpieceJumpOwnerRig.remapHeptaRig == (Object)(object)_deadpieceJumpRig && ((Object)(object)rm == (Object)null || (Object)(object)rm == (Object)(object)_deadpieceJumpOwnerRig)) { _deadpieceJumpRig.jumpEnabled = _savedLocomotionJumpEnabled; _deadpieceJumpRig.doubleJump = _savedLocomotionDoubleJump; } } catch (Exception ex) { MelonLogger.Warning("Restore no-leg jump failed: " + ex.Message); } finally { _deadpieceJumpBlocked = false; _deadpieceJumpOwnerRig = null; _deadpieceJumpRig = null; } } private void ApplyNoLegFallenState(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.physicsRig == (Object)null) { return; } try { _deadpieceFallenStateApplied = true; } catch (Exception ex) { MelonLogger.Warning("Apply no-leg fallen state failed: " + ex.Message); } } private void RestoreNoLegFallenState(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.physicsRig == (Object)null || !_deadpieceFallenStateApplied) { return; } try { _deadpieceFallenStateApplied = false; } catch (Exception ex) { MelonLogger.Warning("Restore no-leg fallen state failed: " + ex.Message); } } private void ForceClearNoLegRagdollState(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.physicsRig == (Object)null) { return; } try { _deadpieceFallenStateApplied = false; } catch (Exception ex) { MelonLogger.Warning("ForceClearNoLegRagdollState failed: " + ex.Message); } } private void LockNoLegLocomotion(RigManager rm) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.physicsRig == (Object)null) { return; } try { PhysicsRig physicsRig = rm.physicsRig; physicsRig.groundVelocity = Vector3.zero; physicsRig.skidVelocity = Vector3.zero; physicsRig.skidSpeed = 0f; physicsRig.groundAngVelocity = 0f; physicsRig.wholeBodyVelocity = FlattenHorizontalVelocity(physicsRig.wholeBodyVelocity); physicsRig.pelvisVelocity = FlattenHorizontalVelocity(physicsRig.pelvisVelocity); physicsRig._stepDelta = Vector2.zero; physicsRig._stepVel = Vector2.zero; physicsRig._stepDeltaOverTimeBuffer = Vector2.zero; ClampPlanarVelocity(physicsRig.rbFeet); ClampPlanarVelocity(physicsRig.rbKnee); } catch (Exception ex) { MelonLogger.Warning("No-leg locomotion lock failed: " + ex.Message); } } private static Vector3 FlattenHorizontalVelocity(Vector3 velocity) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) velocity.x = 0f; velocity.z = 0f; return velocity; } private static void ClampPlanarVelocity(Rigidbody rb) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rb == (Object)null)) { Vector3 velocity = rb.velocity; velocity.x = 0f; velocity.z = 0f; rb.velocity = velocity; rb.angularVelocity = Vector3.zero; } } private static void ClampFullVelocity(Rigidbody rb) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rb == (Object)null)) { rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } } private void SaveOriginalLimits(RigManager rm) { if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm.physicsRig == (Object)null) && !_limitsSaved) { _limitsSaved = true; } } private void RestoreOriginalLimits(RigManager rm) { _limitsSaved = false; } private void RestoreLocomotion() { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager != (Object)null) { RestoreDeadpieceLegUsage(rigManager); RestoreNoLegJump(rigManager); RestoreNoLegFallenState(rigManager); RestoreLegColliderState(rigManager); } } private void ScheduleLocalLocomotionRecovery(RigManager rm) { if (!((Object)(object)rm == (Object)null) && !((Object)(object)rm != (Object)(object)Player.RigManager)) { _locomotionRecoveryToken++; int locomotionRecoveryToken = _locomotionRecoveryToken; int sceneGeneration = _sceneGeneration; Health health = rm.health; int avatarHash = (((Object)(object)rm.avatar != (Object)null) ? ((Object)rm.avatar).GetHashCode() : 0); RecoverLocalLocomotion(rm); MelonCoroutines.Start(DelayedLocalLocomotionRecovery(rm, health, avatarHash, sceneGeneration, locomotionRecoveryToken)); } } private IEnumerator DelayedLocalLocomotionRecovery(RigManager rm, Health health, int avatarHash, int generation, int token) { float expiration = Time.unscaledTime + 1.25f; while (Time.unscaledTime < expiration) { yield return null; if (token != _locomotionRecoveryToken || generation != _sceneGeneration || (Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.health != (Object)(object)health || (((Object)(object)rm.avatar != (Object)null) ? ((Object)rm.avatar).GetHashCode() : 0) != avatarHash) { break; } if (!IsLocalLocomotionRecovered(rm)) { RecoverLocalLocomotion(rm); } } } private void RecoverLocalLocomotion(RigManager rm) { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Invalid comparison between Unknown and I4 //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Invalid comparison between Unknown and I4 //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Invalid comparison between Unknown and I4 if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.health == (Object)null || !rm.health.alive || IsLeftLegGone(rm) || IsRightLegGone(rm)) { return; } try { RestoreDeadpieceLegUsage(rm); RestoreNoLegJump(rm); RestoreNoLegFallenState(rm); Health health = rm.health; health.SetUsage(1f, 1f, 1f, 1f, 1f, 1f); health.cur_arm_lf = 1f; health.cur_arm_rt = 1f; health.cur_leg_lf = 1f; health.cur_leg_rt = 1f; health.stun_arm_lf = 0f; health.stun_arm_rt = 0f; health.stun_leg_lf = 0f; health.stun_leg_rt = 0f; health.stun_spine = 0f; health.stunActive = false; RemapRig remapHeptaRig = rm.remapHeptaRig; if ((Object)(object)remapHeptaRig != (Object)null) { remapHeptaRig.jumpEnabled = true; remapHeptaRig._jumping = false; remapHeptaRig._jumpStage = 0; remapHeptaRig._jumpCycle = 0f; remapHeptaRig._currentVelocity = Vector2.zero; remapHeptaRig._currentAcceleration = Vector2.zero; remapHeptaRig._effectiveAcceleration = Vector2.zero; remapHeptaRig._locoDebt = Vector2.zero; remapHeptaRig._locoApplied = Vector2.zero; remapHeptaRig._trackedDebt = Vector2.zero; remapHeptaRig._trackedApplied = Vector2.zero; remapHeptaRig._physDebt = Vector2.zero; remapHeptaRig._physApplied = Vector2.zero; remapHeptaRig._artificialDelta = Vector2.zero; remapHeptaRig.travState = (TraversalState)0; } PhysicsRig physicsRig = rm.physicsRig; if ((Object)(object)physicsRig != (Object)null) { physicsRig.manualFallenState = false; physicsRig._stepDelta = Vector2.zero; physicsRig._stepVel = Vector2.zero; physicsRig._stepDeltaOverTimeBuffer = Vector2.zero; physicsRig.groundVelocity = Vector3.zero; physicsRig.skidVelocity = Vector3.zero; physicsRig.skidSpeed = 0f; if ((int)physicsRig.stepState == 3) { physicsRig.SwitchStepState((StepState)0); } } if ((Object)(object)rm.activeSeat == (Object)null && ((int)rm.bodyState == 2 || (int)rm.bodyState == 3)) { rm.SwitchBodyState((BodyState)0); } RestoreLegColliderState(rm); _deadpieceFallenStateApplied = false; } catch (Exception ex) { MelonLogger.Warning("Locomotion recovery failed: " + ex.Message); } } private bool IsLocalLocomotionRecovered(RigManager rm) { //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Invalid comparison between Unknown and I4 //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Invalid comparison between Unknown and I4 //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Invalid comparison between Unknown and I4 if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager || (Object)(object)rm.health == (Object)null) { return false; } Health health = rm.health; if (!IsHealthyUsage(health.usage_hips) || !IsHealthyUsage(health.usage_spine) || !IsHealthyUsage(health.usage_leg_lf) || !IsHealthyUsage(health.usage_leg_rt) || !IsHealthyUsage(health.usage_arm_lf) || !IsHealthyUsage(health.usage_arm_rt) || health.cur_leg_lf <= 0.01f || health.cur_leg_rt <= 0.01f || _deadpieceNoLegUsageApplied || _deadpieceJumpBlocked || _deadpieceFallenStateApplied) { return false; } if ((Object)(object)rm.remapHeptaRig != (Object)null && !rm.remapHeptaRig.jumpEnabled) { return false; } if ((Object)(object)rm.physicsRig != (Object)null && (rm.physicsRig.manualFallenState || (int)rm.physicsRig.stepState == 3)) { return false; } if ((Object)(object)rm.activeSeat == (Object)null && ((int)rm.bodyState == 2 || (int)rm.bodyState == 3)) { return false; } return !_legColliderOriginalStates.ContainsKey(rm); } private static bool IsHealthyUsage(float value) { return !float.IsNaN(value) && !float.IsInfinity(value) && value > 0.01f && value <= 1.001f; } private bool IsLeftLegBone(HumanBodyBones bone) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 return (int)bone == 1 || (int)bone == 3 || (int)bone == 5; } private bool IsRightLegBone(HumanBodyBones bone) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 return (int)bone == 2 || (int)bone == 4 || (int)bone == 6; } private void ApplySecondLegRagdoll(RigManager rm, HumanBodyBones bone, bool wasLeftLegGone, bool wasRightLegGone) { } private void ResetLegRagdoll(RigManager rm) { } public void SyncLegState(RigManager rm, byte legState) { if (PlayerIDManager.LocalID != null && !((Object)(object)rm == (Object)null)) { NetworkSync.SetPlayerMetadata(PlayerIDManager.LocalSmallID, "DeadPieceLegState", legState.ToString()); } } public void ApplyRemoteLegState(byte playerId, byte legState) { RigRefs val = default(RigRefs); if (PlayerRepUtilities.TryGetReferences(playerId, ref val) && !((Object)(object)((val != null) ? val.RigManager : null) == (Object)null)) { RigManager rigManager = val.RigManager; if ((legState & 3) == 3) { _remoteFallenPlayers.Add(playerId); } else { _remoteFallenPlayers.Remove(playerId); } } } private void UpdateHealthDisplays() { float num = Mathf.Max(0f, Time.unscaledDeltaTime); _localHealthHudTimer -= num; if (_localHealthHudTimer <= 0f) { _localHealthHudTimer = 0.1f; try { UpdateLocalHealthHud(); } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Health HUD update failed: " + ex.Message); _nextLocalHealthHudCreateTime = Time.unscaledTime + 5f; DestroyLocalHealthHud(); } } UpdatePlayerHealthBars(num); } private void OnLocalHealthHudSettingChanged(bool enabled) { EnableLocalHealthHud.Value = enabled; _localHealthHudTimer = 0f; _nextLocalHealthHudCreateTime = 0f; if (!enabled) { DestroyLocalHealthHud(); } else { UpdateLocalHealthHud(); } } private void OnPlayerHealthBarsSettingChanged(bool enabled) { EnablePlayerHealthBars.Value = enabled; if (_playerHealthBarsMenuToggle != null && _playerHealthBarsMenuToggle.Value != enabled) { _playerHealthBarsMenuToggle.Value = enabled; } if (!enabled) { ClearPlayerHealthBars(); } else { UpdatePlayerHealthBars(0f); } } private void UpdateLocalHealthHud() { //IL_0279: Unknown result type (might be due to invalid IL or missing references) RigManager rigManager = Player.RigManager; Camera main = Camera.main; Transform val = ((main != null) ? ((Component)main).transform : null); if ((Object)(object)val == (Object)null) { OpenControllerRig controllerRig = Player.ControllerRig; val = ((controllerRig != null) ? ((Rig)controllerRig).m_head : null); } MelonPreferences_Entry enableLocalHealthHud = EnableLocalHealthHud; if (enableLocalHealthHud != null && enableLocalHealthHud.Value && IsSessionEnabled() && !((Object)(object)rigManager == (Object)null) && !((Object)(object)rigManager.health == (Object)null)) { Avatar avatar = rigManager.avatar; if (!((Object)(object)((avatar != null) ? avatar.animator : null) == (Object)null) && !((Object)(object)val == (Object)null)) { if ((Object)(object)_localHealthHudRoot == (Object)null || (Object)(object)_localHealthHudText == (Object)null || (Object)(object)_localHealthHudRig != (Object)(object)rigManager || (Object)(object)_localHealthHudAnchor != (Object)(object)val) { DestroyLocalHealthHud(); if (Time.unscaledTime < _nextLocalHealthHudCreateTime) { return; } CreateLocalHealthHud(rigManager, val); } if (!((Object)(object)_localHealthHudRoot == (Object)null) && !((Object)(object)_localHealthHudText == (Object)null)) { if (!_playersHealth.ContainsKey(rigManager)) { EnsureRigInitialized(rigManager); } float num = GetAvatarHealthBase(rigManager); if (!IsFiniteHealth(num)) { num = (IsFiniteHealth(rigManager.health.max_Health) ? rigManager.health.max_Health : 1f); } float num2 = (rigManager.health.alive ? rigManager.health.curr_Health : 0f); if (!IsFiniteNonNegativeHealth(num2)) { num2 = 0f; } num2 = Mathf.Clamp(num2, 0f, num); float ratio = ((num > 0f) ? Mathf.Clamp01(num2 / num) : 0f); bool destroyed = HasFatalBoneInMask(GetStateMask(rigManager)); HudPartState hudPartState = GetHudPartState(rigManager, HudHeadBones); HudPartState hudPartState2 = GetHudPartState(rigManager, HudBodyBones); HudPartState hudPartState3 = GetHudPartState(rigManager, HudLeftArmBones); HudPartState hudPartState4 = GetHudPartState(rigManager, HudRightArmBones); HudPartState hudPartState5 = GetHudPartState(rigManager, HudLeftLegBones); HudPartState hudPartState6 = GetHudPartState(rigManager, HudRightLegBones); string text = WrapHudColor("HP " + FormatHealthNumber(num2) + " / " + FormatHealthNumber(num), GetHudStatusColor(ratio, destroyed)); _localHealthHudText.text = text + "\n" + FormatHudPart("HEAD", hudPartState) + " " + FormatHudPart("BODY", hudPartState2) + "\n" + FormatHudPart("L ARM", hudPartState3) + " " + FormatHudPart("R ARM", hudPartState4) + "\n" + FormatHudPart("L LEG", hudPartState5) + " " + FormatHudPart("R LEG", hudPartState6); } return; } } DestroyLocalHealthHud(); } private void CreateLocalHealthHud(RigManager rigManager, Transform anchor) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: 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_0220: Unknown result type (might be due to invalid IL or missing references) try { _localHealthHudRoot = new GameObject("DeadPiece_LocalHealthHud", (Type[])(object)new Type[2] { Il2CppType.Of(), Il2CppType.Of() }); RectTransform component = _localHealthHudRoot.GetComponent(); ((Transform)component).SetParent(anchor, false); component.sizeDelta = new Vector2(300f, 150f); ((Transform)component).localPosition = LocalHealthHudOffset; ((Transform)component).localRotation = Quaternion.identity; ((Transform)component).localScale = Vector3.one * 0.0006f; Canvas component2 = _localHealthHudRoot.GetComponent(); component2.renderMode = (RenderMode)2; component2.worldCamera = Camera.main; component2.overrideSorting = true; component2.sortingOrder = 32767; GameObject val = new GameObject("Readout", (Type[])(object)new Type[4] { Il2CppType.Of(), Il2CppType.Of(), Il2CppType.Of(), Il2CppType.Of() }); RectTransform component3 = val.GetComponent(); ((Transform)component3).SetParent((Transform)(object)component, false); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; component3.offsetMin = new Vector2(8f, 6f); component3.offsetMax = new Vector2(-8f, -6f); _localHealthHudText = val.GetComponent(); Font val2 = Resources.GetBuiltinResource("Arial.ttf"); if ((Object)(object)val2 == (Object)null) { val2 = Font.CreateDynamicFontFromOSFont("Arial", 28); } _localHealthHudText.font = val2; _localHealthHudText.fontSize = 27; _localHealthHudText.fontStyle = (FontStyle)1; _localHealthHudText.alignment = (TextAnchor)0; _localHealthHudText.horizontalOverflow = (HorizontalWrapMode)1; _localHealthHudText.verticalOverflow = (VerticalWrapMode)1; _localHealthHudText.supportRichText = true; ((Graphic)_localHealthHudText).raycastTarget = false; ((Graphic)_localHealthHudText).color = Color.white; Outline component4 = val.GetComponent(); ((Shadow)component4).effectColor = new Color(0f, 0f, 0f, 0.9f); ((Shadow)component4).effectDistance = new Vector2(1.5f, -1.5f); ((Shadow)component4).useGraphicAlpha = true; _localHealthHudRig = rigManager; _localHealthHudAnchor = anchor; _nextLocalHealthHudCreateTime = 0f; } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Health HUD creation failed: " + ex.Message); _nextLocalHealthHudCreateTime = Time.unscaledTime + 5f; DestroyLocalHealthHud(); } } private HudPartState GetHudPartState(RigManager rigManager, HumanBodyBones[] bones) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) HudPartState result = new HudPartState { Ratio = 1f }; if (!_playersHealth.TryGetValue(rigManager, out var value)) { return result; } foreach (HumanBodyBones val in bones) { if ((Object)(object)GetCachedBoneTransform(rigManager, val) == (Object)null || !value.TryGetValue(val, out var value2)) { continue; } result.Valid = true; if (IsBoneGone(rigManager, val) || value2 <= 0f) { result.Destroyed = true; result.Ratio = 0f; continue; } float maxHealthForBone = GetMaxHealthForBone(rigManager, val); if (IsFiniteHealth(maxHealthForBone)) { result.Ratio = Mathf.Min(result.Ratio, Mathf.Clamp01(value2 / maxHealthForBone)); } } return result; } private static string FormatHudPart(string label, HudPartState state) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (!state.Valid) { return WrapHudColor(label + " --", HudUnavailable); } string text = (state.Destroyed ? "LOST" : (Mathf.RoundToInt(state.Ratio * 100f) + "%")); return WrapHudColor(label + " " + text, GetHudStatusColor(state.Ratio, state.Destroyed)); } private static Color GetHudStatusColor(float ratio, bool destroyed) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (destroyed) { return HudViolet; } if (ratio >= 0.67f) { return HudGreen; } return (ratio >= 0.34f) ? HudYellow : HudRed; } private static Color GetSmoothHealthColor(float ratio) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) ratio = Mathf.Clamp01(ratio); return (ratio < 0.5f) ? Color.Lerp(HudRed, HudYellow, ratio * 2f) : Color.Lerp(HudYellow, HudGreen, (ratio - 0.5f) * 2f); } private static string WrapHudColor(string text, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Clamp(Mathf.RoundToInt(color.r * 255f), 0, 255); int num2 = Mathf.Clamp(Mathf.RoundToInt(color.g * 255f), 0, 255); int num3 = Mathf.Clamp(Mathf.RoundToInt(color.b * 255f), 0, 255); return "" + text + ""; } private static string FormatHealthNumber(float value) { if (value >= 1000f) { return value.ToString("0"); } if (value >= 10f) { return value.ToString("0.0"); } return value.ToString("0.00"); } private static bool IsFiniteHealth(float value) { return value > 0f && !float.IsNaN(value) && !float.IsInfinity(value); } private static bool IsFiniteNonNegativeHealth(float value) { return value >= 0f && !float.IsNaN(value) && !float.IsInfinity(value); } private void DestroyLocalHealthHud() { if ((Object)(object)_localHealthHudRoot != (Object)null) { Object.Destroy((Object)(object)_localHealthHudRoot); } _localHealthHudRoot = null; _localHealthHudText = null; _localHealthHudRig = null; _localHealthHudAnchor = null; } private void UpdatePlayerHealthBars(float deltaTime) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown MelonPreferences_Entry enablePlayerHealthBars = EnablePlayerHealthBars; if (enablePlayerHealthBars == null || !enablePlayerHealthBars.Value || !IsSessionEnabled() || !NetworkInfo.HasServer) { ClearPlayerHealthBars(); return; } _seenPlayerHealthBars.Clear(); try { foreach (NetworkPlayer player in NetworkPlayer.Players) { if (((player != null) ? player.PlayerID : null) == null || player.PlayerID.IsMe || player.NetworkEntity == null || player.NetworkEntity.IsOwner || player.HeadUI == null) { continue; } byte smallID = player.PlayerID.SmallID; _seenPlayerHealthBars.Add(smallID); if (!_playerHealthBarViews.TryGetValue(smallID, out var value) || value.Player != player) { if (value != null) { RemovePlayerHealthBar(smallID); } RigHealthBar val = new RigHealthBar { Visible = (player.HealthBar == null || !player.HealthBar.Visible) }; value = new PlayerHealthBarView { Player = player, Bar = val }; _playerHealthBarViews[smallID] = value; try { bool spawned = player.HeadUI.Spawned; player.HeadUI.RegisterElement((IPopupLayoutElement)(object)val); value.SpawnRequested = spawned && (Object)(object)val.Transform == (Object)null; } catch { RemovePlayerHealthBar(smallID); throw; } } UpdatePlayerHealthBar(value, deltaTime); } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Player health bar update failed: " + ex.Message); } byte[] array = new byte[_playerHealthBarViews.Count]; _playerHealthBarViews.Keys.CopyTo(array, 0); for (int i = 0; i < array.Length; i++) { if (!_seenPlayerHealthBars.Contains(array[i])) { RemovePlayerHealthBar(array[i]); } } } private void UpdatePlayerHealthBar(PlayerHealthBarView view, float deltaTime) { //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) if (view?.Player == null || view.Bar == null) { return; } bool flag = view.Player.HealthBar != null && view.Player.HealthBar.Visible; if (view.Bar.Visible == flag) { view.Bar.Visible = !flag; } RigRefs rigRefs = view.Player.RigRefs; RigManager val = ((rigRefs != null) ? rigRefs.RigManager : null); float num = view.Player.RigPose?.Health ?? float.NaN; float num2 = view.Player.RigPose?.MaxHealth ?? float.NaN; Health val2 = ((val != null) ? val.health : null); if (!IsFiniteHealth(num2) && (Object)(object)val2 != (Object)null && IsFiniteHealth(val2.max_Health)) { num2 = val2.max_Health; } if (!IsFiniteNonNegativeHealth(num) && (Object)(object)val2 != (Object)null && IsFiniteNonNegativeHealth(val2.curr_Health)) { num = val2.curr_Health; } if (!IsFiniteHealth(num2)) { num2 = 1f; } if (!IsFiniteNonNegativeHealth(num)) { num = 0f; } float num3 = (((Object)(object)val != (Object)null) ? GetAvatarHealthBase(val) : num2); if (!IsFiniteHealth(num3)) { num3 = num2; } float num4 = num3 * Mathf.Clamp01(num / num2); float healthDisplayEpsilon = GetHealthDisplayEpsilon(num3); float healthDisplayEpsilon2 = GetHealthDisplayEpsilon(num4); bool flag2 = !IsFiniteNonNegativeHealth(view.LastMaximum) || Mathf.Abs(view.LastMaximum - num3) >= healthDisplayEpsilon; bool flag3 = !IsFiniteNonNegativeHealth(view.LastHealth) || Mathf.Abs(view.LastHealth - num4) >= healthDisplayEpsilon2; if (flag2) { view.Bar.MaxHealth = num3; view.LastMaximum = num3; } if (flag3) { view.Bar.Health = num4; view.LastHealth = num4; } Transform transform = view.Bar.Transform; if ((Object)(object)view.Root != (Object)(object)transform) { RestorePlayerHealthBarVisuals(view); view.Root = transform; view.Fill = null; view.HasOriginalFillColor = false; view.Text = null; view.HasOriginalTextColor = false; view.LastText = null; } if ((Object)(object)transform == (Object)null && view.Player.HeadUI != null && view.Player.HeadUI.Spawned) { view.SpawnRequested = true; } else if ((Object)(object)transform != (Object)null) { view.SpawnRequested = false; } if ((Object)(object)transform == (Object)null || flag) { if (flag) { view.LastText = null; } return; } if ((Object)(object)view.Fill == (Object)null || !((Component)view.Fill).transform.IsChildOf(transform)) { Slider componentInChildren = ((Component)transform).GetComponentInChildren(true); object fill; if (componentInChildren == null) { fill = null; } else { RectTransform fillRect = componentInChildren.fillRect; fill = ((fillRect != null) ? ((Component)fillRect).GetComponent() : null); } view.Fill = (Image)fill; if ((Object)(object)view.Fill != (Object)null) { view.OriginalFillColor = ((Graphic)view.Fill).color; view.HasOriginalFillColor = true; } } if ((Object)(object)view.Text == (Object)null || !view.Text.transform.IsChildOf(transform)) { view.Text = ((Component)transform).GetComponentInChildren(true); if ((Object)(object)view.Text != (Object)null) { view.OriginalTextColor = ((Graphic)view.Text).color; view.HasOriginalTextColor = true; } } Color smoothHealthColor = GetSmoothHealthColor(num4 / num3); float num5 = ((deltaTime <= 0f) ? 1f : (1f - Mathf.Exp(-8f * deltaTime))); if ((Object)(object)view.Fill != (Object)null) { ((Graphic)view.Fill).color = Color.Lerp(((Graphic)view.Fill).color, smoothHealthColor, num5); } if ((Object)(object)view.Text != (Object)null) { ((Graphic)view.Text).color = Color.Lerp(((Graphic)view.Text).color, smoothHealthColor, num5); if (flag3 || flag2 || string.IsNullOrEmpty(view.LastText)) { view.LastText = FormatHealthNumber(num4) + " / " + FormatHealthNumber(num3); view.Text.text = view.LastText; } } } private void RemovePlayerHealthBar(byte playerId) { if (!_playerHealthBarViews.TryGetValue(playerId, out var value)) { return; } bool flag = false; try { RestorePlayerHealthBarVisuals(value); if (value?.Bar != null) { value.Bar.Visible = false; } int num; if (value?.Bar != null && (Object)(object)value.Bar.Transform == (Object)null) { if (!value.SpawnRequested) { NetworkPlayer player = value.Player; num = ((((player != null) ? player.HeadUI : null) != null && value.Player.HeadUI.Spawned) ? 1 : 0); } else { num = 1; } } else { num = 0; } flag = (byte)num != 0; object obj; if (value == null) { obj = null; } else { NetworkPlayer player2 = value.Player; obj = ((player2 != null) ? player2.HeadUI : null); } if (obj != null && value.Bar != null) { value.Player.HeadUI.UnregisterElement((IPopupLayoutElement)(object)value.Bar); } else if (value != null) { RigHealthBar bar = value.Bar; if (bar != null) { bar.Despawn(); } } } catch { try { if (value != null) { RigHealthBar bar2 = value.Bar; if (bar2 != null) { bar2.Despawn(); } } } catch { } } finally { _playerHealthBarViews.Remove(playerId); } if (flag && value?.Bar != null) { MelonCoroutines.Start(FinishPlayerHealthBarCleanup(value.Bar)); } } private IEnumerator FinishPlayerHealthBarCleanup(RigHealthBar bar) { float deadline = Time.realtimeSinceStartup + 30f; while (bar != null && (Object)(object)bar.Transform == (Object)null && Time.realtimeSinceStartup < deadline) { yield return null; } if (bar != null && (Object)(object)bar.Transform != (Object)null) { bar.Visible = false; bar.Despawn(); } } private static float GetHealthDisplayEpsilon(float value) { if (value >= 1000f) { return 0.5f; } return (value >= 10f) ? 0.05f : 0.005f; } private static void RestorePlayerHealthBarVisuals(PlayerHealthBarView view) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view?.Fill != (Object)null && view.HasOriginalFillColor) { ((Graphic)view.Fill).color = view.OriginalFillColor; } if ((Object)(object)view?.Text != (Object)null) { if (view.HasOriginalTextColor) { ((Graphic)view.Text).color = view.OriginalTextColor; } float num; if (!IsFiniteNonNegativeHealth(view.LastHealth)) { RigHealthBar bar = view.Bar; num = ((bar != null) ? bar.Health : 0f); } else { num = view.LastHealth; } float num2 = num; float num3; if (!IsFiniteHealth(view.LastMaximum)) { RigHealthBar bar2 = view.Bar; num3 = ((bar2 != null) ? bar2.MaxHealth : 1f); } else { num3 = view.LastMaximum; } float num4 = num3; view.Text.text = Mathf.RoundToInt(num2) + "/" + Mathf.RoundToInt(num4); } } private void ClearPlayerHealthBars() { if (_playerHealthBarViews.Count != 0) { byte[] array = new byte[_playerHealthBarViews.Count]; _playerHealthBarViews.Keys.CopyTo(array, 0); for (int i = 0; i < array.Length; i++) { RemovePlayerHealthBar(array[i]); } _seenPlayerHealthBars.Clear(); } } private void ResetHealthDisplaysForScene() { DestroyLocalHealthHud(); ClearPlayerHealthBars(); _localHealthHudTimer = 0f; _nextLocalHealthHudCreateTime = 0f; } public override void OnDeinitializeMelon() { ResetHealthDisplaysForScene(); } private void TryCacheNpcBloodColor(NpcLimbState state, Collider collider, HumanBodyBones bone) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) if (state == null || (state.HasNativeBloodColor && (Object)(object)collider == (Object)null)) { return; } SurfaceData val = ResolveNpcSurfaceData(collider); if ((Object)(object)val == (Object)null) { val = ResolveNpcBoneSurfaceData(state, bone); } if ((Object)(object)val == (Object)null) { Avatar npcAvatar = GetNpcAvatar(state.PuppetMaster); if ((Object)(object)npcAvatar != (Object)null) { val = npcAvatar.surfaceData; } } if ((Object)(object)val == (Object)null) { return; } Color val2 = val.ParicleColorTint; if (IsFiniteNpcColor(val2) && (val2.r != 0f || val2.g != 0f || val2.b != 0f || val2.a != 0f)) { if (val2.r >= 0.96f && val2.g >= 0.96f && val2.b >= 0.96f) { val2 = DefaultNpcBloodColor; } else { val2.a = Mathf.Max(0.85f, val2.a); } state.NativeBloodColor = val2; state.HasNativeBloodColor = true; } } private static SurfaceData ResolveNpcSurfaceData(Collider collider) { if ((Object)(object)collider == (Object)null) { return null; } try { ImpactProperties val = ((Component)collider).GetComponent(); if ((Object)(object)val == (Object)null && (Object)(object)collider.attachedRigidbody != (Object)null) { val = ((Component)collider.attachedRigidbody).GetComponent(); } if ((Object)(object)val == (Object)null) { val = ((Component)collider).GetComponentInParent(); } if ((Object)(object)val != (Object)null) { return ((Object)(object)val._cachedSurfaceData != (Object)null) ? val._cachedSurfaceData : val.surfaceData; } } catch { } return null; } private static SurfaceData ResolveNpcBoneSurfaceData(NpcLimbState state, HumanBodyBones bone) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)state?.PuppetMaster == (Object)null || state.PuppetMaster.muscles == null) { return null; } try { int muscleIndex = state.PuppetMaster.GetMuscleIndex(bone); if (muscleIndex < 0 || muscleIndex >= ((Il2CppArrayBase)(object)state.PuppetMaster.muscles).Length) { return null; } Muscle val = ((Il2CppArrayBase)(object)state.PuppetMaster.muscles)[muscleIndex]; if (((val != null) ? val.colliders : null) == null) { return null; } for (int i = 0; i < ((Il2CppArrayBase)(object)val.colliders).Length; i++) { SurfaceData val2 = ResolveNpcSurfaceData(((Il2CppArrayBase)(object)val.colliders)[i]); if ((Object)(object)val2 != (Object)null) { return val2; } } } catch { } return null; } private void SpawnNpcSeverBlood(NpcLimbState state, HumanBodyBones bone, Vector3 point) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (state != null && EnableBloodEffects != null && EnableBloodEffects.Value && state.Bones.TryGetValue(bone, out var value) && !((Object)(object)value == (Object)null)) { TryCacheNpcBloodColor(state, null, bone); Color color = (state.HasNativeBloodColor ? state.NativeBloodColor : DefaultNpcBloodColor); Vector3 val = ((IsFiniteNpcVector(point) && point != Vector3.zero) ? point : value.position); Vector3 npcBloodDirection = GetNpcBloodDirection(state, bone, value); bool flag = (int)bone == 7 || (int)bone == 0; SpawnNpcBloodBurst(state, val, npcBloodDirection, color, flag); SpawnNpcBloodJet(state, val + npcBloodDirection * 0.025f, npcBloodDirection, color, flag ? 1.5f : 0.8f, flag); } } private void SpawnNpcStateBlood(NpcLimbState state, uint newlyGone) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (state == null || newlyGone == 0 || EnableBloodEffects == null || !EnableBloodEffects.Value) { return; } HashSet hashSet = new HashSet(); for (int i = 0; i < DamageBones.Length; i++) { uint num = (uint)(1 << i); if ((newlyGone & num) != 0) { HumanBodyBones val = DamageBones[i]; if (state.Bones.TryGetValue(val, out var value) && !((Object)(object)value == (Object)null) && !HasNewlyGoneNpcAncestor(state, value, newlyGone) && hashSet.Add(value)) { SpawnNpcSeverBlood(state, val, value.position); } } } } private static bool HasNewlyGoneNpcAncestor(NpcLimbState state, Transform candidate, uint newlyGone) { for (int i = 0; i < DamageBones.Length; i++) { if ((newlyGone & (uint)(1 << i)) != 0 && state.Bones.TryGetValue(DamageBones[i], out var value) && !((Object)(object)value == (Object)null) && !((Object)(object)value == (Object)(object)candidate) && candidate.IsChildOf(value)) { return true; } } return false; } private Vector3 GetNpcBloodDirection(NpcLimbState state, HumanBodyBones bone, Transform boneTransform) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) HumanBodyBones primaryChildBone = GetPrimaryChildBone(bone); if ((int)primaryChildBone != 55 && state.Bones.TryGetValue(primaryChildBone, out var value) && (Object)(object)value != (Object)null) { Vector3 val = value.position - boneTransform.position; if (((Vector3)(ref val)).sqrMagnitude > 1E-06f) { return ((Vector3)(ref val)).normalized; } } if ((Object)(object)boneTransform.parent != (Object)null) { Vector3 val2 = boneTransform.position - boneTransform.parent.position; if (((Vector3)(ref val2)).sqrMagnitude > 1E-06f) { return ((Vector3)(ref val2)).normalized; } } Vector3 forward = boneTransform.forward; return (((Vector3)(ref forward)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref forward)).normalized : Vector3.up; } private void SpawnNpcBloodBurst(NpcLimbState state, Vector3 position, Vector3 direction, Color color, bool heavy) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { val = new GameObject(heavy ? "DeadPiece_NpcBodyBloodBurst" : "DeadPiece_NpcLimbBloodBurst"); val.transform.position = position; val.transform.rotation = Quaternion.LookRotation(direction); ParticleSystem val2 = val.AddComponent(); ParticleSystemRenderer component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Material npcBloodParticleMaterial = GetNpcBloodParticleMaterial(); if ((Object)(object)npcBloodParticleMaterial != (Object)null) { ((Renderer)component).sharedMaterial = npcBloodParticleMaterial; } } MainModule main = val2.main; main.startLifetime = MinMaxCurve.op_Implicit(heavy ? 1.15f : 0.8f); main.startSpeed = (heavy ? new MinMaxCurve(2.2f, 5.8f) : new MinMaxCurve(1.4f, 4.2f)); main.startSize = (heavy ? new MinMaxCurve(0.045f, 0.095f) : new MinMaxCurve(0.028f, 0.065f)); main.startColor = MinMaxGradient.op_Implicit(color); main.maxParticles = (heavy ? 180 : 90); main.simulationSpace = (ParticleSystemSimulationSpace)1; main.gravityModifier = MinMaxCurve.op_Implicit(0.85f); main.playOnAwake = false; EmissionModule emission = val2.emission; emission.enabled = false; ShapeModule shape = val2.shape; shape.shapeType = (ParticleSystemShapeType)4; shape.angle = (heavy ? 38f : 28f); shape.radius = (heavy ? 0.085f : 0.045f); val2.Emit(heavy ? 105 : 52); TrackNpcBloodEffect(state, val, heavy ? 2.8f : 2.1f); } catch (Exception ex) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } MelonLogger.Warning("[DeadPiece] NPC blood burst failed: " + ex.Message); } } private void SpawnNpcBloodJet(NpcLimbState state, Vector3 position, Vector3 direction, Color color, float duration, bool heavy) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown GameObject val = null; try { val = new GameObject(heavy ? "DeadPiece_NpcBodyBloodJet" : "DeadPiece_NpcLimbBloodJet"); val.transform.position = position; val.transform.rotation = Quaternion.LookRotation(direction); ParticleSystem val2 = val.AddComponent(); ParticleSystemRenderer component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Material npcBloodParticleMaterial = GetNpcBloodParticleMaterial(); if ((Object)(object)npcBloodParticleMaterial != (Object)null) { ((Renderer)component).sharedMaterial = npcBloodParticleMaterial; } } MainModule main = val2.main; main.duration = Mathf.Max(0.1f, duration); main.loop = false; main.startLifetime = (heavy ? new MinMaxCurve(0.65f, 1.15f) : new MinMaxCurve(0.45f, 0.8f)); main.startSpeed = (heavy ? new MinMaxCurve(3.2f, 6.4f) : new MinMaxCurve(2.3f, 4.6f)); main.startSize = (heavy ? new MinMaxCurve(0.04f, 0.085f) : new MinMaxCurve(0.025f, 0.055f)); main.startColor = MinMaxGradient.op_Implicit(color); main.maxParticles = (heavy ? 320 : 150); main.simulationSpace = (ParticleSystemSimulationSpace)1; main.gravityModifier = MinMaxCurve.op_Implicit(0.7f); main.playOnAwake = false; EmissionModule emission = val2.emission; emission.enabled = true; emission.rateOverTime = MinMaxCurve.op_Implicit(heavy ? 105f : 48f); emission.SetBursts(Il2CppReferenceArray.op_Implicit((Burst[])(object)new Burst[3] { new Burst(0f, MinMaxCurve.op_Implicit(heavy ? 30f : 16f)), new Burst(Mathf.Min(0.22f, duration * 0.25f), MinMaxCurve.op_Implicit(heavy ? 22f : 10f)), new Burst(Mathf.Min(0.55f, duration * 0.6f), MinMaxCurve.op_Implicit(heavy ? 16f : 7f)) })); ShapeModule shape = val2.shape; shape.shapeType = (ParticleSystemShapeType)4; shape.angle = (heavy ? 18f : 11f); shape.radius = (heavy ? 0.06f : 0.025f); val2.Play(); TrackNpcBloodEffect(state, val, duration + 2f); } catch (Exception ex) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } MelonLogger.Warning("[DeadPiece] NPC blood jet failed: " + ex.Message); } } private static void TrackNpcBloodEffect(NpcLimbState state, GameObject effect, float lifetime) { if (state == null || (Object)(object)effect == (Object)null) { return; } for (int num = state.BloodEffects.Count - 1; num >= 0; num--) { if ((Object)(object)state.BloodEffects[num] == (Object)null) { state.BloodEffects.RemoveAt(num); } } state.BloodEffects.Add(effect); Object.Destroy((Object)(object)effect, Mathf.Max(0.1f, lifetime)); } private static void ClearNpcBloodEffects(NpcLimbState state) { if (state == null) { return; } for (int i = 0; i < state.BloodEffects.Count; i++) { if ((Object)(object)state.BloodEffects[i] != (Object)null) { Object.Destroy((Object)(object)state.BloodEffects[i]); } } state.BloodEffects.Clear(); } private Material GetNpcBloodParticleMaterial() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if ((Object)(object)_npcBloodParticleMaterial == (Object)null) { Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val != (Object)null) { _npcBloodParticleMaterial = new Material(val) { hideFlags = (HideFlags)52 }; } } return _npcBloodParticleMaterial; } private void ReleaseNpcBloodParticleMaterial() { if ((Object)(object)_npcBloodParticleMaterial != (Object)null) { Object.Destroy((Object)(object)_npcBloodParticleMaterial); _npcBloodParticleMaterial = null; } } private static bool IsFiniteNpcVector(Vector3 value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) return !float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z) && !float.IsInfinity(value.z); } private static bool IsFiniteNpcColor(Color value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) return !float.IsNaN(value.r) && !float.IsInfinity(value.r) && !float.IsNaN(value.g) && !float.IsInfinity(value.g) && !float.IsNaN(value.b) && !float.IsInfinity(value.b) && !float.IsNaN(value.a) && !float.IsInfinity(value.a); } internal void ProcessNpcRuntime(float deltaTime) { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) if (!IsSessionEnabled()) { if (_npcLimbStates.Count != 0) { ResetNpcRuntimeForScene(); } return; } if (NetworkInfo.HasServer && NetworkInfo.IsHost && Time.unscaledTime >= _nextNpcStateRepairTime) { _nextNpcStateRepairTime = Time.unscaledTime + 5f; SyncNpcStates(); } if (_npcLimbStates.Count == 0) { return; } bool flag = deltaTime > 0f && (!NetworkInfo.HasServer || NetworkInfo.IsHost); NpcLimbState[] array = _npcLimbStates.Values.ToArray(); foreach (NpcLimbState npcLimbState in array) { if (!IsNpcStateValid(npcLimbState)) { ForgetNpcRuntime(npcLimbState?.PuppetMaster, restore: true); } else { if (!flag || npcLimbState.PuppetMaster.isDead || npcLimbState.Health == null || npcLimbState.Health.cur_hp <= 0f) { continue; } RefreshNpcHealthBase(npcLimbState); for (int j = 0; j < DamageBones.Length; j++) { HumanBodyBones val = DamageBones[j]; if (npcLimbState.Bones.ContainsKey(val) && !IsNpcBoneGone(npcLimbState, val) && npcLimbState.LimbHealth.TryGetValue(val, out var value) && !(value <= 0f)) { float npcMaxHealth = GetNpcMaxHealth(npcLimbState, val); float value2; if (value >= npcMaxHealth) { npcLimbState.LimbHealth[val] = npcMaxHealth; npcLimbState.LastDamageTimes.Remove(val); } else if (!npcLimbState.LastDamageTimes.TryGetValue(val, out value2)) { npcLimbState.LastDamageTimes[val] = Time.time; } else if (Time.time - value2 >= 3f) { npcLimbState.LimbHealth[val] = Mathf.Min(npcMaxHealth, value + npcMaxHealth * 0.1f * deltaTime); } } } } } } internal void EnforceNpcDismemberment() { if (!IsSessionEnabled() || _npcLimbStates.Count == 0) { return; } _npcVisualScanBudget = 1; _npcProxyBuildBudget = 1; _npcProxyRefreshBudget = 1; NpcLimbState[] array = _npcLimbStates.Values.ToArray(); int num = ((array.Length != 0) ? (_npcEnforceCursor % array.Length) : 0); try { for (int i = 0; i < array.Length; i++) { NpcLimbState npcLimbState = array[(num + i) % array.Length]; if (IsNpcStateValid(npcLimbState) && npcLimbState.GoneMask != 0 && !(Time.unscaledTime < npcLimbState.NextEnforceTime)) { try { EnforceNpcState(npcLimbState); npcLimbState.EnforceFailureCount = 0; npcLimbState.NextEnforceTime = 0f; } catch { npcLimbState.EnforceFailureCount = Math.Min(npcLimbState.EnforceFailureCount + 1, 3); float num2 = ((npcLimbState.EnforceFailureCount == 1) ? 0.5f : ((npcLimbState.EnforceFailureCount == 2) ? 2f : 15f)); npcLimbState.NextEnforceTime = Time.unscaledTime + num2; } } } } finally { _npcVisualScanBudget = 0; _npcProxyBuildBudget = 0; _npcProxyRefreshBudget = 0; _npcEnforceCursor = ((array.Length != 0) ? ((num + 1) % array.Length) : 0); } } internal void ResetNpcRuntimeForScene() { NpcLimbState[] array = _npcLimbStates.Values.ToArray(); for (int i = 0; i < array.Length; i++) { ClearNpcBloodEffects(array[i]); RestoreNpcState(array[i]); } ushort[] array2 = _npcEntityLookup.Keys.ToArray(); for (int j = 0; j < array2.Length; j++) { NetworkSync.ForgetNpc(array2[j]); } _npcLimbStates.Clear(); _npcHealthOwners.Clear(); _npcEntityLookup.Clear(); _npcPendingBodyDespawns.Clear(); _npcTerminalBodyDespawns.Clear(); _npcEnforceCursor = 0; _nextNpcStateRepairTime = 0f; ReleaseNpcBloodParticleMaterial(); } internal void SyncNpcStates() { //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) if (!NetworkInfo.HasServer || !NetworkInfo.IsHost || !IsSessionEnabled()) { return; } NpcLimbState[] array = _npcLimbStates.Values.ToArray(); foreach (NpcLimbState npcLimbState in array) { if (IsNpcStateValid(npcLimbState) && npcLimbState.GoneMask != 0 && TryGetNpcEntityId(npcLimbState.PuppetMaster, out var entityId)) { NetworkSync.SendNpcState(entityId, npcLimbState.GoneMask, 3, 0, 0); } } } internal void OnNpcAttack(SubBehaviourHealth health, int muscleIndex, Attack attack) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) if (health == null || attack == null || !IsSessionEnabled() || (attack.damage <= 0f && !ExplosivePatches.IsDamagingBlastActive)) { return; } BehaviourBase behaviour = ((SubBehaviourBase)health).behaviour; PuppetMaster val = ((behaviour != null) ? behaviour.puppetMaster : null); if (!TryGetOrCreateNpcState(val, health, out var state)) { return; } if (EnableBlastLimbDamage.Value && ExplosivePatches.IsDamagingBlastActive) { if (ExplosivePatches.TryConsumeActiveBlast(((Object)val).GetInstanceID(), out var origin, out var radius, out var damage)) { ApplyNpcExplosionDamage(state, attack, origin, radius, damage); } } else { if (!TryResolveNpcAttackBone(state, muscleIndex, attack, out var bone, out var point)) { return; } TryCacheNpcBloodColor(state, attack.collider, bone); if (IsNpcBoneGone(state, bone)) { return; } float num = attack.damage * DamageMultiplier.Value; if (EnableAttackTypeBalancing.Value) { num *= GetAttackTypeMultiplier(attack.attackType); } num = NormalizePositiveDamage(num); if (num <= 0f || !BoneToIndexMap.TryGetValue(bone, out var value)) { return; } if (NetworkInfo.HasServer) { NetworkEntity val2 = default(NetworkEntity); if (PuppetMasterExtender.Cache.TryGet(val, ref val2) && val2 != null && val2.IsRegistered) { if (val2.IsOwner) { _npcEntityLookup[val2.ID] = val; NetworkSync.SendNpcInteraction(0, val2.ID, (byte)value, (byte)(attack.attackType & 0xFF), num, point); } return; } if (!NetworkInfo.IsHost) { return; } } ApplyNpcDamage(state, bone, num, point); } } private void ApplyNpcExplosionDamage(NpcLimbState state, Attack sourceAttack, Vector3 origin, float blastRadius, float blastDamage) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) if (!IsNpcStateValid(state) || blastDamage <= 0f || float.IsNaN(blastDamage) || float.IsInfinity(blastDamage)) { return; } float num = ((blastRadius > 0.1f) ? blastRadius : ExplosionRadius.Value); float num2 = num * num; float damage = blastDamage * DamageMultiplier.Value; damage = NormalizePositiveDamage(damage); if (damage <= 0f) { return; } NetworkEntity val = null; bool flag = PuppetMasterExtender.Cache.TryGet(state.PuppetMaster, ref val) && val != null && val.IsRegistered; if (NetworkInfo.HasServer && ((flag && !val.IsOwner) || (!flag && !NetworkInfo.IsHost))) { return; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val2 = DamageBones[i]; if (!state.Bones.TryGetValue(val2, out var value) || (Object)(object)value == (Object)null || IsNpcBoneGone(state, val2)) { continue; } Vector3 val3 = value.position - origin; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (!(sqrMagnitude > num2)) { float num3 = 1f - Mathf.Clamp01(Mathf.Sqrt(sqrMagnitude) / num); float num4 = damage * Mathf.Lerp(0.35f, 1f, num3); Vector3 position = value.position; TryCacheNpcBloodColor(state, sourceAttack.collider, val2); if (NetworkInfo.HasServer && flag) { _npcEntityLookup[val.ID] = state.PuppetMaster; NetworkSync.SendNpcInteraction(0, val.ID, (byte)i, (byte)(sourceAttack.attackType & 0xFF), num4, position); } else { ApplyNpcDamage(state, val2, num4, position); } } } } internal bool TryResolveGrabbedNpcLimb(Hand hand, out PuppetMaster puppetMaster, out HumanBodyBones bone) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) puppetMaster = null; bone = (HumanBodyBones)55; if ((Object)(object)hand == (Object)null || (Object)(object)hand.AttachedReceiver == (Object)null) { return false; } HandReciever attachedReceiver = hand.AttachedReceiver; Rigidbody val = null; Grip val2 = null; try { IGrippable host = attachedReceiver.Host; val2 = ((Il2CppObjectBase)attachedReceiver).TryCast(); if ((Object)(object)val2 == (Object)null && host != null) { val2 = host.GetGrip(); } val = ((host != null) ? host.Rb : null); } catch { } if (TryResolveNpcComponent((Component)(object)val, out puppetMaster, out var muscleIndex) || TryResolveNpcComponent((Component)(object)val2, out puppetMaster, out muscleIndex) || TryResolveNpcComponent((Component)(object)attachedReceiver, out puppetMaster, out muscleIndex)) { Vector3 point = (((Object)(object)val != (Object)null) ? val.worldCenterOfMass : ((Component)hand).transform.position); if (TryResolveNpcBone(puppetMaster, muscleIndex, point, out bone) && !IsNpcBoneGone(puppetMaster, bone)) { return true; } } puppetMaster = null; bone = (HumanBodyBones)55; return false; } internal bool TryResolveNpcContact(Collider collider, out PuppetMaster puppetMaster, out HumanBodyBones bone) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) puppetMaster = null; bone = (HumanBodyBones)55; if ((Object)(object)collider == (Object)null || !TryResolveNpcComponent((Component)(object)collider, out puppetMaster, out var muscleIndex)) { return false; } Bounds bounds = collider.bounds; Vector3 center = ((Bounds)(ref bounds)).center; if (!TryResolveNpcBone(puppetMaster, muscleIndex, center, out bone) || IsNpcBoneGone(puppetMaster, bone)) { puppetMaster = null; bone = (HumanBodyBones)55; return false; } return true; } internal float GetNpcStrength(PuppetMaster puppetMaster) { Avatar npcAvatar = GetNpcAvatar(puppetMaster); if ((Object)(object)npcAvatar != (Object)null && IsFinitePositive(npcAvatar.strengthUpper)) { return npcAvatar.strengthUpper; } float num = Mathf.Max(0.1f, GetNpcMass(puppetMaster) / 75f); float num2 = Mathf.Max(0.1f, GetNpcHeight(puppetMaster) / 1.75f); return Mathf.Clamp(Mathf.Sqrt(num) * Mathf.Sqrt(num2), 0.1f, 1000f); } internal float GetNpcHeight(PuppetMaster puppetMaster) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) Avatar npcAvatar = GetNpcAvatar(puppetMaster); if ((Object)(object)npcAvatar != (Object)null && IsFinitePositive(npcAvatar.height)) { return npcAvatar.height; } Animator val = ((puppetMaster != null) ? puppetMaster.targetAnimator : null); if ((Object)(object)val == (Object)null || !val.isHuman) { return 1.75f; } Transform boneTransform = val.GetBoneTransform((HumanBodyBones)10); Transform boneTransform2 = val.GetBoneTransform((HumanBodyBones)0); float num = (((Object)(object)boneTransform != (Object)null && (Object)(object)boneTransform2 != (Object)null) ? Vector3.Distance(boneTransform.position, boneTransform2.position) : 0.7f); float npcLegLength = GetNpcLegLength(val, left: true); float npcLegLength2 = GetNpcLegLength(val, left: false); float num2 = ((npcLegLength > 0f && npcLegLength2 > 0f) ? ((npcLegLength + npcLegLength2) * 0.5f) : Mathf.Max(npcLegLength, npcLegLength2)); float num3 = num + ((num2 > 0f) ? num2 : 0.9f) + 0.15f; return IsFinitePositive(num3) ? Mathf.Clamp(num3, 0.25f, 20f) : 1.75f; } internal float GetNpcMass(PuppetMaster puppetMaster) { Avatar npcAvatar = GetNpcAvatar(puppetMaster); if ((Object)(object)npcAvatar != (Object)null && IsFinitePositive(npcAvatar.massTotal)) { return npcAvatar.massTotal; } if ((Object)(object)puppetMaster == (Object)null || puppetMaster.muscles == null) { return 75f; } HashSet hashSet = new HashSet(); float num = 0f; for (int i = 0; i < ((Il2CppArrayBase)(object)puppetMaster.muscles).Length; i++) { Muscle val = ((Il2CppArrayBase)(object)puppetMaster.muscles)[i]; Rigidbody val2 = (((Object)(object)((val != null) ? val.broadcaster : null) != (Object)null) ? ((Component)val.broadcaster).GetComponent() : null); if ((Object)(object)val2 == (Object)null && (Object)(object)((val != null) ? val.transform : null) != (Object)null) { val2 = ((Component)val.transform).GetComponent(); } if ((Object)(object)val2 != (Object)null && hashSet.Add(val2) && IsFinitePositive(val2.mass)) { num += val2.mass; } } return IsFinitePositive(num) ? Mathf.Clamp(num, 1f, 100000f) : 75f; } internal bool IsNpcBoneGone(PuppetMaster puppetMaster, HumanBodyBones bone) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) NpcLimbState value; return _npcLimbStates.TryGetValue(puppetMaster, out value) && IsNpcBoneGone(value, bone); } internal bool ApplyNpcDamage(PuppetMaster puppetMaster, HumanBodyBones bone, float damage, Vector3 point) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) NpcLimbState state; return TryGetOrCreateNpcState(puppetMaster, null, out state) && ApplyNpcDamage(state, bone, NormalizePositiveDamage(damage), point); } internal bool ApplyNpcRip(PuppetMaster puppetMaster, HumanBodyBones bone, Vector3 point) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if ((NetworkInfo.HasServer && !NetworkInfo.IsHost) || !IsSessionEnabled() || !TryGetOrCreateNpcState(puppetMaster, null, out var state) || IsNpcBoneGone(state, bone)) { return false; } return SeverNpcBone(state, bone, point, killFatal: true); } internal bool ApplyNpcCrush(PuppetMaster puppetMaster, Vector3 point) { if ((NetworkInfo.HasServer && !NetworkInfo.IsHost) || !IsSessionEnabled() || !TryGetOrCreateNpcState(puppetMaster, null, out var state)) { return false; } uint num = 0u; for (int i = 0; i < DamageBones.Length; i++) { if (state.Bones.ContainsKey(DamageBones[i])) { num |= (uint)(1 << i); } } return ApplyNpcState(state, num, killFatal: true); } internal bool TryGetNpcEntityId(PuppetMaster puppetMaster, out ushort entityId) { entityId = 0; NetworkEntity val = default(NetworkEntity); if ((Object)(object)puppetMaster == (Object)null || !PuppetMasterExtender.Cache.TryGet(puppetMaster, ref val) || val == null || !val.IsRegistered) { return false; } entityId = val.ID; _npcEntityLookup[entityId] = puppetMaster; if (_npcLimbStates.TryGetValue(puppetMaster, out var value)) { value.CachedEntityId = entityId; value.HasCachedEntityId = true; } return true; } internal bool TryResolveNpcEntity(ushort entityId, out PuppetMaster puppetMaster) { puppetMaster = null; if (_npcEntityLookup.TryGetValue(entityId, out var value) && (Object)(object)value != (Object)null && (Object)(object)value.targetAnimator != (Object)null && value.targetAnimator.isHuman && TryGetNpcEntityId(value, out var entityId2) && entityId2 == entityId) { puppetMaster = value; return true; } _npcEntityLookup.Remove(entityId); NetworkEntityReference val = default(NetworkEntityReference); ((NetworkEntityReference)(ref val))..ctor(entityId); NetworkEntity val2 = default(NetworkEntity); if (((NetworkEntityReference)(ref val)).TryGetEntity(ref val2) && val2 != null && val2.IsRegistered) { PuppetMaster val3 = ((EntityComponentExtender)(object)val2.GetExtender())?.Component; if ((Object)(object)val3 != (Object)null && (Object)(object)val3.targetAnimator != (Object)null && val3.targetAnimator.isHuman) { _npcEntityLookup[entityId] = val3; puppetMaster = val3; return true; } } return false; } internal uint GetNpcStateMask(PuppetMaster puppetMaster) { NpcLimbState value; return _npcLimbStates.TryGetValue(puppetMaster, out value) ? value.GoneMask : 0u; } internal bool ApplyNpcState(PuppetMaster puppetMaster, uint goneMask, bool killFatal) { return ApplyNpcState(puppetMaster, goneMask, killFatal, playBlood: true); } internal bool ApplyNpcState(PuppetMaster puppetMaster, uint goneMask, bool killFatal, bool playBlood) { NpcLimbState state; return TryGetOrCreateNpcState(puppetMaster, null, out state) && ApplyNpcState(state, goneMask, killFatal, playBlood); } internal void RestoreAndForgetNpc(PuppetMaster puppetMaster) { ForgetNpcRuntime(puppetMaster, restore: true); } internal void RestoreAndForgetNpc(SubBehaviourHealth health) { if (health != null) { if (_npcHealthOwners.TryGetValue(health, out var value)) { ForgetNpcRuntime(value, restore: true); return; } BehaviourBase behaviour = ((SubBehaviourBase)health).behaviour; ForgetNpcRuntime((behaviour != null) ? behaviour.puppetMaster : null, restore: true); } } internal void RestoreAndForgetNpc(AIBrain brain) { if ((Object)(object)brain != (Object)null) { object obj = brain.puppetMaster; if (obj == null) { BehaviourBaseNav behaviour = brain.behaviour; obj = ((behaviour != null) ? ((BehaviourBase)behaviour).puppetMaster : null); } ForgetNpcRuntime((PuppetMaster)obj, restore: true); } } internal void RestoreTrackedNpcOnPoolInitialize(AIBrain brain) { object obj; if (!((Object)(object)brain != (Object)null)) { obj = null; } else { obj = brain.puppetMaster; if (obj == null) { BehaviourBaseNav behaviour = brain.behaviour; obj = ((behaviour != null) ? ((BehaviourBase)behaviour).puppetMaster : null); } } PuppetMaster val = (PuppetMaster)obj; if ((Object)(object)val != (Object)null && _npcLimbStates.ContainsKey(val)) { ForgetNpcRuntime(val, restore: true); } } internal void ForgetNpcRuntime(PuppetMaster puppetMaster, bool restore) { //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) if (puppetMaster == null) { return; } _npcPendingBodyDespawns.Remove(puppetMaster); bool flag = _npcTerminalBodyDespawns.Remove(puppetMaster); NpcLimbState value; bool flag2 = _npcLimbStates.TryGetValue(puppetMaster, out value); ushort num = (ushort)((flag2 && value.HasCachedEntityId) ? value.CachedEntityId : 0); bool flag3 = flag2 && value.HasCachedEntityId; ushort entityId = 0; bool flag4 = TryGetNpcEntityId(puppetMaster, out entityId); if (!flag2) { if (flag4) { _npcEntityLookup.Remove(entityId); ForgetPendingNpcState(entityId); NetworkSync.ForgetNpc(entityId); } return; } try { if (restore) { RestoreNpcState(value); } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] NPC restore cleanup failed: " + ex.Message); } finally { _npcLimbStates.Remove(puppetMaster); if (value.Health != null) { _npcHealthOwners.Remove(value.Health); } } if (flag3 && (!flag4 || num != entityId)) { _npcEntityLookup.Remove(num); ForgetPendingNpcState(num); NetworkSync.ForgetNpc(num); } if (flag4) { _npcEntityLookup.Remove(entityId); ForgetPendingNpcState(entityId); if (NetworkInfo.HasServer && NetworkInfo.IsHost && restore && !flag) { NetworkSync.SendNpcState(entityId, 0u, 3, 0, 0); } NetworkSync.ForgetNpc(entityId); } } private bool ApplyNpcDamage(NpcLimbState state, HumanBodyBones bone, float damage, Vector3 point) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) if (!IsNpcStateValid(state) || damage <= 0f || !state.Bones.ContainsKey(bone) || IsNpcBoneGone(state, bone)) { return false; } RefreshNpcHealthBase(state); if (!state.LimbHealth.TryGetValue(bone, out var value)) { value = GetNpcMaxHealth(state, bone); } state.LastDamageTimes[bone] = Time.time; value = Mathf.Max(0f, value - damage); state.LimbHealth[bone] = value; return value <= 0f && SeverNpcBone(state, bone, point, killFatal: true); } private bool SeverNpcBone(NpcLimbState state, HumanBodyBones bone, Vector3 point, bool killFatal) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Invalid comparison between Unknown and I4 //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Invalid comparison between Unknown and I4 if (!BoneToIndexMap.ContainsKey(bone) || !state.Bones.ContainsKey(bone)) { return false; } uint num = ExpandNpcSubtreeMask(state, bone) & ~state.GoneMask; if (num == 0) { return false; } for (int i = 0; i < DamageBones.Length; i++) { if ((num & (uint)(1 << i)) != 0) { HumanBodyBones val = DamageBones[i]; if (state.Bones.TryGetValue(val, out var value) && (Object)(object)value != (Object)null) { state.OriginalScales[val] = value.localScale; } state.LimbHealth[val] = 0f - GetNpcMaxHealth(state, val); state.LastDamageTimes.Remove(val); } } CaptureNpcVisualScales(state, num); state.GoneMask |= num; SpawnNpcSeverBlood(state, bone, point); EnforceNpcState(state); if (killFatal && FatalBones.Contains(bone)) { TryKillNpc(state); } if (killFatal && ((int)bone == 7 || (int)bone == 0)) { ScheduleNpcBodyDespawn(state); } return true; } private bool ApplyNpcState(NpcLimbState state, uint goneMask, bool killFatal, bool playBlood = true) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if (!IsNpcStateValid(state)) { return false; } uint num = 0u; for (int i = 0; i < DamageBones.Length; i++) { if (state.Bones.ContainsKey(DamageBones[i])) { num |= (uint)(1 << i); } } goneMask &= num; if (goneMask == state.GoneMask) { if (killFatal && HasNpcFatalMask(goneMask)) { TryKillNpc(state); } if (killFatal && HasNpcDestroyedBodyMask(goneMask)) { ScheduleNpcBodyDespawn(state); } return true; } uint num2 = goneMask & ~state.GoneMask; uint num3 = state.GoneMask & ~goneMask; if (num3 != 0) { RestoreNpcVisuals(state); } for (int j = 0; j < DamageBones.Length; j++) { uint num4 = (uint)(1 << j); HumanBodyBones val = DamageBones[j]; if ((num2 & num4) != 0 && state.Bones.TryGetValue(val, out var value) && (Object)(object)value != (Object)null) { state.OriginalScales[val] = value.localScale; } if ((goneMask & num4) != 0) { state.LimbHealth[val] = 0f - GetNpcMaxHealth(state, val); state.LastDamageTimes.Remove(val); } else if ((num3 & num4) != 0) { state.LimbHealth[val] = GetNpcMaxHealth(state, val); state.LastDamageTimes.Remove(val); } } CaptureNpcVisualScales(state, num2); state.GoneMask = goneMask; if (goneMask == 0) { ReleaseNpcVisualMeshes(state); } if (playBlood) { SpawnNpcStateBlood(state, num2); } EnforceNpcState(state); if (killFatal && HasNpcFatalMask(num2)) { TryKillNpc(state); } if (killFatal && HasNpcDestroyedBodyMask(num2)) { ScheduleNpcBodyDespawn(state); } return true; } private bool TryGetOrCreateNpcState(PuppetMaster puppetMaster, SubBehaviourHealth suppliedHealth, out NpcLimbState state) { //IL_0155: 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_0179: 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_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) state = null; if ((Object)(object)puppetMaster == (Object)null) { return false; } if (_npcLimbStates.TryGetValue(puppetMaster, out state)) { if (IsNpcStateValid(state)) { if (state.Health == null && suppliedHealth != null) { state.Health = suppliedHealth; _npcHealthOwners[suppliedHealth] = puppetMaster; } return true; } ForgetNpcRuntime(puppetMaster, restore: true); } Animator targetAnimator = puppetMaster.targetAnimator; if ((Object)(object)targetAnimator == (Object)null || !targetAnimator.isHuman) { return false; } Transform boneTransform = targetAnimator.GetBoneTransform((HumanBodyBones)0); Transform boneTransform2 = targetAnimator.GetBoneTransform((HumanBodyBones)7); Transform boneTransform3 = targetAnimator.GetBoneTransform((HumanBodyBones)10); if ((Object)(object)boneTransform == (Object)null || (Object)(object)boneTransform2 == (Object)null || (Object)(object)boneTransform3 == (Object)null) { return false; } AIBrain val = FindNpcBrain(puppetMaster); object obj = suppliedHealth; if (obj == null) { if (val == null) { obj = null; } else { BehaviourBaseNav behaviour = val.behaviour; obj = ((behaviour != null) ? behaviour.health : null); } } SubBehaviourHealth val2 = (SubBehaviourHealth)obj; state = new NpcLimbState { PuppetMaster = puppetMaster, Health = val2, Brain = val, Animator = targetAnimator, HealthBase = ResolveNpcHealthBase(val2) }; for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val3 = DamageBones[i]; Transform boneTransform4 = targetAnimator.GetBoneTransform(val3); if (!((Object)(object)boneTransform4 == (Object)null)) { state.Bones[val3] = boneTransform4; state.OriginalScales[val3] = boneTransform4.localScale; state.LimbHealth[val3] = GetNpcMaxHealth(state, val3); } } _npcLimbStates[puppetMaster] = state; if (val2 != null) { _npcHealthOwners[val2] = puppetMaster; } TryGetNpcEntityId(puppetMaster, out var _); return true; } private static bool IsNpcStateValid(NpcLimbState state) { if (state == null || (Object)(object)state.PuppetMaster == (Object)null || state.PuppetMaster.hasBeenDespawned || (Object)(object)state.Animator == (Object)null || !state.Animator.isHuman || (Object)(object)state.PuppetMaster.targetAnimator != (Object)(object)state.Animator) { return false; } Poolee val = FindNpcPoolee(state); return (Object)(object)val == (Object)null || !val.IsInPool; } private float ResolveNpcHealthBase(SubBehaviourHealth health) { float num = ((health != null) ? health.maxHitPoints : 0f); if (!IsFinitePositive(num)) { num = MaxLimbHealth?.Value ?? 100f; } return Mathf.Max(0.0001f, num); } private void RefreshNpcHealthBase(NpcLimbState state) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) float num = ResolveNpcHealthBase(state.Health); if (Mathf.Abs(num - state.HealthBase) <= Mathf.Max(0.0001f, state.HealthBase * 0.0001f)) { return; } float num2 = Mathf.Max(0.0001f, state.HealthBase); for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (state.LimbHealth.TryGetValue(val, out var value)) { float num3 = num2 * GetBoneHealthScale(val); float num4 = num * GetBoneHealthScale(val); state.LimbHealth[val] = ((value > 0f && !IsNpcBoneGone(state, val)) ? (num4 * Mathf.Clamp01(value / Mathf.Max(0.0001f, num3))) : (0f - num4)); } } state.HealthBase = num; } private float GetNpcMaxHealth(NpcLimbState state, HumanBodyBones bone) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(0.0001f, state.HealthBase * GetBoneHealthScale(bone)); } private bool TryResolveNpcAttackBone(NpcLimbState state, int muscleIndex, Attack attack, out HumanBodyBones bone, out Vector3 point) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) point = attack.origin; if ((Object)(object)attack.collider != (Object)null) { point = attack.collider.ClosestPoint(attack.origin); } if (point == Vector3.zero && state.PuppetMaster.muscles != null && muscleIndex >= 0 && muscleIndex < ((Il2CppArrayBase)(object)state.PuppetMaster.muscles).Length) { Muscle val = ((Il2CppArrayBase)(object)state.PuppetMaster.muscles)[muscleIndex]; if ((Object)(object)((val != null) ? val.target : null) != (Object)null) { point = val.target.position; } } return TryResolveNpcBone(state, muscleIndex, point, out bone); } private bool TryResolveNpcBone(PuppetMaster puppetMaster, int muscleIndex, Vector3 point, out HumanBodyBones bone) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) bone = (HumanBodyBones)55; NpcLimbState state; return TryGetOrCreateNpcState(puppetMaster, null, out state) && TryResolveNpcBone(state, muscleIndex, point, out bone); } private bool TryResolveNpcBone(NpcLimbState state, int muscleIndex, Vector3 point, out HumanBodyBones bone) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected I4, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected I4, but got Unknown //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Expected I4, but got Unknown bone = (HumanBodyBones)55; float num = float.MaxValue; for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (!state.Bones.TryGetValue(val, out var value) || (Object)(object)value == (Object)null) { continue; } int num2 = -1; try { num2 = state.PuppetMaster.GetMuscleIndex(val); } catch { } if (num2 == muscleIndex && muscleIndex >= 0) { float num3 = ((point == Vector3.zero) ? 0f : Vector3.SqrMagnitude(value.position - point)); if (num3 < num) { num = num3; bone = (HumanBodyBones)(int)val; } } } if ((int)bone != 55) { return true; } Transform val2 = null; if (state.PuppetMaster.muscles != null && muscleIndex >= 0 && muscleIndex < ((Il2CppArrayBase)(object)state.PuppetMaster.muscles).Length) { Muscle obj2 = ((Il2CppArrayBase)(object)state.PuppetMaster.muscles)[muscleIndex]; val2 = ((obj2 != null) ? obj2.target : null); } int num4 = int.MaxValue; if ((Object)(object)val2 != (Object)null) { for (int j = 0; j < DamageBones.Length; j++) { HumanBodyBones val3 = DamageBones[j]; if (state.Bones.TryGetValue(val3, out var value2) && !((Object)(object)value2 == (Object)null)) { int npcHierarchyDistance = GetNpcHierarchyDistance(val2, value2); if (npcHierarchyDistance < num4) { num4 = npcHierarchyDistance; bone = (HumanBodyBones)(int)val3; } } } if ((int)bone != 55) { return true; } } if (point == Vector3.zero) { return false; } num = 0.5625f; for (int k = 0; k < DamageBones.Length; k++) { HumanBodyBones val4 = DamageBones[k]; if (state.Bones.TryGetValue(val4, out var value3) && !((Object)(object)value3 == (Object)null)) { float num5 = Vector3.SqrMagnitude(value3.position - point); if (num5 < num) { num = num5; bone = (HumanBodyBones)(int)val4; } } } return (int)bone != 55; } private bool TryResolveNpcComponent(Component component, out PuppetMaster puppetMaster, out int muscleIndex) { puppetMaster = null; muscleIndex = -1; if ((Object)(object)component == (Object)null) { return false; } Collider val = (Collider)(object)((component is Collider) ? component : null); Rigidbody val2 = (Rigidbody)(((object)((component is Rigidbody) ? component : null)) ?? ((object)(((val != null) ? val.attachedRigidbody : null) ?? component.GetComponent() ?? component.GetComponentInParent()))); MuscleCollisionBroadcaster val3 = component.GetComponent() ?? component.GetComponentInParent(); NpcLimbState state; if ((Object)(object)val3 != (Object)null && (Object)(object)val3.puppetMaster != (Object)null) { puppetMaster = val3.puppetMaster; try { muscleIndex = (((Object)(object)val2 != (Object)null) ? puppetMaster.GetMuscleIndex(val2) : (-1)); } catch { muscleIndex = -1; } if (muscleIndex != val3.muscleIndex) { puppetMaster = null; muscleIndex = -1; return false; } if (muscleIndex < 0 || puppetMaster.muscles == null || muscleIndex >= ((Il2CppArrayBase)(object)puppetMaster.muscles).Length) { puppetMaster = null; muscleIndex = -1; return false; } return TryGetOrCreateNpcState(puppetMaster, null, out state); } puppetMaster = component.GetComponentInParent(); if ((Object)(object)puppetMaster == (Object)null) { val3 = component.GetComponentInChildren(); puppetMaster = ((val3 != null) ? val3.puppetMaster : null); } if ((Object)(object)puppetMaster == (Object)null) { return false; } if ((Object)(object)val2 != (Object)null) { try { muscleIndex = puppetMaster.GetMuscleIndex(val2); } catch { muscleIndex = -1; } } if (muscleIndex < 0 || puppetMaster.muscles == null || muscleIndex >= ((Il2CppArrayBase)(object)puppetMaster.muscles).Length) { puppetMaster = null; muscleIndex = -1; return false; } return TryGetOrCreateNpcState(puppetMaster, null, out state); } private uint ExpandNpcSubtreeMask(NpcLimbState state, HumanBodyBones rootBone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!state.Bones.TryGetValue(rootBone, out var value) || (Object)(object)value == (Object)null) { return 0u; } uint num = 0u; for (int i = 0; i < DamageBones.Length; i++) { if (state.Bones.TryGetValue(DamageBones[i], out var value2) && (Object)(object)value2 != (Object)null && IsSameOrDescendant(value2, value)) { num |= (uint)(1 << i); } } return num; } private void EnforceNpcState(NpcLimbState state) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < DamageBones.Length; i++) { if ((state.GoneMask & (uint)(1 << i)) == 0) { continue; } HumanBodyBones val = DamageBones[i]; Transform value2; if (state.VisualBones.TryGetValue(val, out var value)) { for (int j = 0; j < value.Count; j++) { Transform val2 = value[j]; if ((Object)(object)val2 != (Object)null) { state.HiddenVisualBones.Add(val2); if (val2.localScale != Vector3.zero) { val2.localScale = Vector3.zero; } } } } else if (state.Bones.TryGetValue(val, out value2) && (Object)(object)value2 != (Object)null) { if (!state.VisualScales.ContainsKey(value2) && state.OriginalScales.TryGetValue(val, out var value3)) { state.VisualScales[value2] = value3; } state.HiddenVisualBones.Add(value2); if (value2.localScale != Vector3.zero) { value2.localScale = Vector3.zero; } } ForceNpcRenderersOff(state, val); } ApplyNpcVisualMeshMask(state, state.GoneMask); if (state.ColliderMaskApplied != state.GoneMask) { DisableNpcGoneColliders(state); state.ColliderMaskApplied = state.GoneMask; } else { EnforceCachedNpcColliders(state); } } private static void CacheNpcVisualBones(NpcLimbState state, Renderer[] renderers) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) Animator[] array = CollectNpcAnimators(state); for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (!state.Bones.TryGetValue(val, out var value) || (Object)(object)value == (Object)null) { continue; } List list = new List(); if (!state.VisualScales.ContainsKey(value) && state.OriginalScales.TryGetValue(val, out var value2)) { state.VisualScales[value] = value2; } AddNpcVisualBone(state, list, value); foreach (Animator val2 in array) { if ((Object)(object)val2 != (Object)null && val2.isHuman) { AddNpcVisualBone(state, list, val2.GetBoneTransform(val)); } } string name = ((Object)value).name; for (int k = 0; k < renderers.Length; k++) { SkinnedMeshRenderer val3 = ((Il2CppObjectBase)renderers[k]).TryCast(); if ((Object)(object)val3 == (Object)null || val3.bones == null) { continue; } for (int l = 0; l < ((Il2CppArrayBase)(object)val3.bones).Length; l++) { Transform val4 = ((Il2CppArrayBase)(object)val3.bones)[l]; if ((Object)(object)val4 != (Object)null && string.Equals(((Object)val4).name, name, StringComparison.OrdinalIgnoreCase)) { AddNpcVisualBone(state, list, val4); } } } state.VisualBones[val] = list; List list2 = new List(); foreach (Renderer val5 in renderers) { if (IsNpcRendererWhollyUnderBone(val5, list) && !list2.Contains(val5)) { list2.Add(val5); } } state.VisualRenderers[val] = list2; } KeyValuePair[] array2 = state.RendererForceOffStates.ToArray(); for (int n = 0; n < array2.Length; n++) { KeyValuePair keyValuePair = array2[n]; if (!((Object)(object)keyValuePair.Key == (Object)null) && !IsNpcRendererWhollyGone(state, keyValuePair.Key)) { keyValuePair.Key.forceRenderingOff = keyValuePair.Value; state.RendererForceOffStates.Remove(keyValuePair.Key); } } } private static void AddNpcVisualBone(NpcLimbState state, List visualBones, Transform transform) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)transform == (Object)null) && !visualBones.Contains(transform)) { visualBones.Add(transform); if (!state.VisualScales.ContainsKey(transform)) { state.VisualScales[transform] = transform.localScale; } } } private void DisableNpcGoneColliders(NpcLimbState state) { if (state.PuppetMaster.muscles == null) { return; } for (int i = 0; i < ((Il2CppArrayBase)(object)state.PuppetMaster.muscles).Length; i++) { Muscle val = ((Il2CppArrayBase)(object)state.PuppetMaster.muscles)[i]; if (val == null || (Object)(object)val.target == (Object)null || !IsNpcMuscleGone(state, val.target) || val.colliders == null) { continue; } for (int j = 0; j < ((Il2CppArrayBase)(object)val.colliders).Length; j++) { Collider val2 = ((Il2CppArrayBase)(object)val.colliders)[j]; if (!((Object)(object)val2 == (Object)null)) { if (!state.ColliderStates.ContainsKey(val2)) { state.ColliderStates[val2] = val2.enabled; } if (val2.enabled) { val2.enabled = false; } } } } } private static void EnforceCachedNpcColliders(NpcLimbState state) { foreach (KeyValuePair colliderState in state.ColliderStates) { if ((Object)(object)colliderState.Key != (Object)null && colliderState.Key.enabled) { colliderState.Key.enabled = false; } } } private bool IsNpcMuscleGone(NpcLimbState state, Transform muscleTarget) { for (int i = 0; i < DamageBones.Length; i++) { if ((state.GoneMask & (uint)(1 << i)) != 0 && state.Bones.TryGetValue(DamageBones[i], out var value) && (Object)(object)value != (Object)null && IsSameOrDescendant(muscleTarget, value)) { return true; } } return false; } private void RestoreNpcVisuals(NpcLimbState state) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) Transform[] array = state.HiddenVisualBones.ToArray(); foreach (Transform val in array) { if ((Object)(object)val != (Object)null && state.VisualScales.TryGetValue(val, out var value)) { try { val.localScale = value; } catch { } } } state.HiddenVisualBones.Clear(); for (int j = 0; j < DamageBones.Length; j++) { if ((state.GoneMask & (uint)(1 << j)) == 0 || !state.VisualBones.TryGetValue(DamageBones[j], out var value2)) { continue; } for (int k = 0; k < value2.Count; k++) { Transform val2 = value2[k]; if ((Object)(object)val2 != (Object)null && state.VisualScales.TryGetValue(val2, out var value3)) { try { val2.localScale = value3; } catch { } } } } KeyValuePair[] array2 = state.ColliderStates.ToArray(); for (int l = 0; l < array2.Length; l++) { KeyValuePair keyValuePair = array2[l]; if ((Object)(object)keyValuePair.Key != (Object)null) { try { keyValuePair.Key.enabled = keyValuePair.Value; } catch { } } } state.ColliderStates.Clear(); state.ColliderMaskApplied = 0u; RestoreNpcRendererStates(state); try { ApplyNpcVisualMeshMask(state, 0u); } catch { } } private void RestoreNpcState(NpcLimbState state) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if (state == null) { return; } if (!HasNpcDestroyedBodyMask(state.GoneMask)) { try { ClearNpcBloodEffects(state); } catch { } } try { RestoreNpcVisuals(state); } catch { } try { ReleaseNpcVisualMeshes(state); } catch { } state.GoneMask = 0u; state.LastDamageTimes.Clear(); for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val = DamageBones[i]; if (state.Bones.ContainsKey(val)) { state.LimbHealth[val] = GetNpcMaxHealth(state, val); } } } private bool IsNpcBoneGone(NpcLimbState state, HumanBodyBones bone) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) int value; return BoneToIndexMap.TryGetValue(bone, out value) && (state.GoneMask & (uint)(1 << value)) != 0; } private bool HasNpcFatalMask(uint mask) { int value; int value2; int value3; return (BoneToIndexMap.TryGetValue((HumanBodyBones)10, out value) && (mask & (uint)(1 << value)) != 0) || (BoneToIndexMap.TryGetValue((HumanBodyBones)7, out value2) && (mask & (uint)(1 << value2)) != 0) || (BoneToIndexMap.TryGetValue((HumanBodyBones)0, out value3) && (mask & (uint)(1 << value3)) != 0); } private static bool HasNpcDestroyedBodyMask(uint mask) { int value; int value2; return (BoneToIndexMap.TryGetValue((HumanBodyBones)7, out value) && (mask & (uint)(1 << value)) != 0) || (BoneToIndexMap.TryGetValue((HumanBodyBones)0, out value2) && (mask & (uint)(1 << value2)) != 0); } private void ScheduleNpcBodyDespawn(NpcLimbState state) { if (IsNpcStateValid(state) && HasNpcDestroyedBodyMask(state.GoneMask) && (!NetworkInfo.HasServer || NetworkInfo.IsHost) && _npcPendingBodyDespawns.Add(state.PuppetMaster)) { MelonCoroutines.Start(DelayedNpcBodyDespawn(state.PuppetMaster)); } } private IEnumerator DelayedNpcBodyDespawn(PuppetMaster puppetMaster) { float startedAt = Time.time; float sprayDeadline = startedAt + 1.5f; float resolveDeadline = startedAt + 3.5f; float nextDespawnAttempt = 0f; bool despawnWarningLogged = false; Poolee poolee = null; while (Time.time < sprayDeadline) { if (!_npcPendingBodyDespawns.Contains(puppetMaster)) { yield break; } if ((Object)(object)poolee == (Object)null && _npcLimbStates.TryGetValue(puppetMaster, out var pendingState)) { poolee = FindNpcPoolee(pendingState); } yield return null; pendingState = null; } if (!_npcPendingBodyDespawns.Contains(puppetMaster) || (Object)(object)puppetMaster == (Object)null || puppetMaster.hasBeenDespawned || !_npcLimbStates.TryGetValue(puppetMaster, out var state) || !IsNpcStateValid(state) || !HasNpcDestroyedBodyMask(state.GoneMask)) { _npcPendingBodyDespawns.Remove(puppetMaster); yield break; } if (state.Health != null) { try { state.Health.cur_hp = 0f; } catch { } } while (_npcPendingBodyDespawns.Contains(puppetMaster)) { if ((Object)(object)puppetMaster == (Object)null || puppetMaster.hasBeenDespawned || !_npcLimbStates.TryGetValue(puppetMaster, out state) || !IsNpcStateValid(state) || !HasNpcDestroyedBodyMask(state.GoneMask)) { _npcPendingBodyDespawns.Remove(puppetMaster); break; } if ((Object)(object)poolee == (Object)null) { poolee = FindNpcPoolee(state); } if ((Object)(object)poolee != (Object)null && poolee.IsInPool) { _npcPendingBodyDespawns.Remove(puppetMaster); break; } if ((Object)(object)poolee != (Object)null && CanDespawnNpcLocally(poolee) && Time.time >= nextDespawnAttempt) { nextDespawnAttempt = Time.time + 0.25f; _npcTerminalBodyDespawns.Add(puppetMaster); bool despawnReturned = false; try { poolee.Despawn(); despawnReturned = true; } catch (Exception ex) { Exception ex2 = ex; nextDespawnAttempt = Time.time + 1f; _npcTerminalBodyDespawns.Remove(puppetMaster); if (!despawnWarningLogged) { despawnWarningLogged = true; MelonLogger.Warning("[DeadPiece] NPC despawn failed: " + ex2.Message); } } if (despawnReturned) { yield return null; continue; } } if (Time.time >= resolveDeadline) { if (!((Object)(object)poolee != (Object)null) && !IsNpcNetworkEntityRegistered(puppetMaster, poolee)) { _npcPendingBodyDespawns.Remove(puppetMaster); GameObject destroyTarget = GetNpcDestroyTarget(state); _npcTerminalBodyDespawns.Add(puppetMaster); ForgetNpcRuntime(puppetMaster, restore: true); if ((Object)(object)destroyTarget != (Object)null) { Object.Destroy((Object)(object)destroyTarget); } break; } resolveDeadline = Time.time + 1f; yield return null; } else { yield return null; } } } private static GameObject GetNpcDestroyTarget(NpcLimbState state) { if (state == null) { return null; } object obj; if (!((Object)(object)state.Brain != (Object)null)) { if (!((Object)(object)state.PuppetMaster != (Object)null)) { Animator animator = state.Animator; obj = ((animator != null) ? ((Component)animator).transform : null); } else { obj = ((Component)state.PuppetMaster).transform; } } else { obj = ((Component)state.Brain).transform; } Transform val = (Transform)obj; while ((Object)(object)val != (Object)null) { bool flag = (Object)(object)state.PuppetMaster == (Object)null || IsSameOrDescendant(((Component)state.PuppetMaster).transform, val); bool flag2 = (Object)(object)state.Animator == (Object)null || IsSameOrDescendant(((Component)state.Animator).transform, val); bool flag3 = (Object)(object)state.Brain == (Object)null || IsSameOrDescendant(((Component)state.Brain).transform, val); if (flag && flag2 && flag3) { AIBrain[] array = Il2CppArrayBase.op_Implicit(((Component)val).GetComponentsInChildren(true)); if (array.Length <= 1) { return ((Component)val).gameObject; } break; } val = val.parent; } if ((Object)(object)state.Brain != (Object)null) { return ((Component)state.Brain).gameObject; } object result; if (!((Object)(object)state.PuppetMaster != (Object)null)) { Animator animator2 = state.Animator; result = ((animator2 != null) ? ((Component)animator2).gameObject : null); } else { result = ((Component)state.PuppetMaster).gameObject; } return (GameObject)result; } private static Poolee FindNpcPoolee(NpcLimbState state) { if (state == null) { return null; } if ((Object)(object)state.CachedPoolee != (Object)null) { return state.CachedPoolee; } if (Time.unscaledTime < state.NextPooleeResolveTime) { return null; } state.NextPooleeResolveTime = Time.unscaledTime + 0.5f; Poolee val = null; NetworkEntity val2 = default(NetworkEntity); if ((Object)(object)state.PuppetMaster != (Object)null && PuppetMasterExtender.Cache.TryGet(state.PuppetMaster, ref val2) && val2 != null) { val = ((EntityComponentExtender)(object)val2.GetExtender())?.Component; } if ((Object)(object)val == (Object)null && (Object)(object)state.Brain != (Object)null) { val = ((SpawnEvents)state.Brain)._poolee; } if ((Object)(object)val == (Object)null && (Object)(object)state.PuppetMaster != (Object)null) { val = state.PuppetMaster._poolee; } if ((Object)(object)val == (Object)null) { SubBehaviourHealth health = state.Health; if ((Object)(object)((health != null) ? ((SubBehaviourBase)health).behaviour : null) != (Object)null) { val = ((SubBehaviourBase)state.Health).behaviour._poolee; } } if ((Object)(object)val == (Object)null && (Object)(object)state.Brain != (Object)null) { val = ((Component)state.Brain).GetComponentInParent(); } if ((Object)(object)val == (Object)null && (Object)(object)state.PuppetMaster != (Object)null) { val = ((Component)state.PuppetMaster).GetComponentInParent(); } if ((Object)(object)val == (Object)null && (Object)(object)state.Animator != (Object)null) { val = ((Component)state.Animator).GetComponentInParent(); } object obj; if (!((Object)(object)state.PuppetMaster != (Object)null)) { obj = null; } else { Transform transform = ((Component)state.PuppetMaster).transform; obj = ((transform != null) ? transform.root : null); } Transform val3 = (Transform)obj; if (val == null) { val = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent() : null); } if ((Object)(object)val != (Object)null) { state.CachedPoolee = val; } return val; } private static bool CanDespawnNpcLocally(Poolee poolee) { if (!NetworkInfo.HasServer) { return true; } NetworkEntity val = default(NetworkEntity); if (PooleeExtender.Cache.TryGet(poolee, ref val) && val != null && val.IsRegistered) { return NetworkInfo.IsHost; } return NetworkInfo.IsHost; } private static bool IsNpcNetworkEntityRegistered(PuppetMaster puppetMaster, Poolee poolee) { NetworkEntity val = default(NetworkEntity); if ((Object)(object)poolee != (Object)null && PooleeExtender.Cache.TryGet(poolee, ref val) && val != null && val.IsRegistered) { return true; } NetworkEntity val2 = default(NetworkEntity); return (Object)(object)puppetMaster != (Object)null && PuppetMasterExtender.Cache.TryGet(puppetMaster, ref val2) && val2 != null && val2.IsRegistered; } private void TryKillNpc(NpcLimbState state) { if (state == null || (Object)(object)state.PuppetMaster == (Object)null || !CanKillNpcLocally(state.PuppetMaster)) { return; } bool flag = state.PuppetMaster.isDead || ((Object)(object)state.Brain != (Object)null && state.Brain.isDead); if (state.Health != null) { try { state.Health.cur_hp = 0f; if (!flag) { state.Health.Kill(); } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] NPC health kill failed: " + ex.Message); } } try { if (!state.PuppetMaster.isDead) { state.PuppetMaster.Kill(); } } catch (Exception ex2) { MelonLogger.Warning("[DeadPiece] NPC puppet kill failed: " + ex2.Message); } if (!((Object)(object)state.Brain != (Object)null)) { return; } try { if (!state.Brain.isDead) { state.Brain.OnDeath(); } } catch (Exception ex3) { MelonLogger.Warning("[DeadPiece] NPC brain kill failed: " + ex3.Message); } } private bool CanKillNpcLocally(PuppetMaster puppetMaster) { if (!NetworkInfo.HasServer) { return true; } NetworkEntity val = default(NetworkEntity); if (PuppetMasterExtender.Cache.TryGet(puppetMaster, ref val) && val != null && val.IsRegistered) { return NetworkInfo.IsHost || val.IsOwner; } return NetworkInfo.IsHost; } private static AIBrain FindNpcBrain(PuppetMaster puppetMaster) { if ((Object)(object)puppetMaster == (Object)null) { return null; } AIBrain componentInParent = ((Component)puppetMaster).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Transform transform = ((Component)puppetMaster).transform; Transform val = ((transform != null) ? transform.root : null); return ((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren(true) : null; } private static Avatar GetNpcAvatar(PuppetMaster puppetMaster) { Animator val = ((puppetMaster != null) ? puppetMaster.targetAnimator : null); if ((Object)(object)val == (Object)null) { return null; } Avatar val2 = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInParent(); return val2 ?? ((Component)val).GetComponentInChildren(true); } private static float GetNpcLegLength(Animator animator, bool left) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) Transform boneTransform = animator.GetBoneTransform((HumanBodyBones)(left ? 1 : 2)); Transform boneTransform2 = animator.GetBoneTransform((HumanBodyBones)(left ? 3 : 4)); Transform boneTransform3 = animator.GetBoneTransform((HumanBodyBones)(left ? 5 : 6)); if ((Object)(object)boneTransform == (Object)null || (Object)(object)boneTransform2 == (Object)null || (Object)(object)boneTransform3 == (Object)null) { return 0f; } return Vector3.Distance(boneTransform.position, boneTransform2.position) + Vector3.Distance(boneTransform2.position, boneTransform3.position); } private static int GetNpcHierarchyDistance(Transform source, Transform ancestor) { int num = 0; Transform val = source; while ((Object)(object)val != (Object)null) { if ((Object)(object)val == (Object)(object)ancestor) { return num; } val = val.parent; num++; } return int.MaxValue; } private static bool IsSameOrDescendant(Transform candidate, Transform root) { return (Object)(object)candidate == (Object)(object)root || candidate.IsChildOf(root); } private uint OnPluginNpcInteractionRequest(byte sourcePlayerId, ushort entityId, byte kind, byte boneIndex, byte detail, float value, Vector3 point) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.IsHost || !IsSessionEnabled() || kind > 2 || boneIndex >= DamageBones.Length || !TryResolveNpcEntity(entityId, out var puppetMaster)) { return uint.MaxValue; } HumanBodyBones bone = DamageBones[boneIndex]; if (kind == 0) { float num = NormalizePositiveDamage(value); if (num <= 0f || !IsNpcHitSenderOwner(puppetMaster, sourcePlayerId)) { return uint.MaxValue; } uint npcStateMask = GetNpcStateMask(puppetMaster); ApplyNpcDamage(puppetMaster, bone, num, point); uint npcStateMask2 = GetNpcStateMask(puppetMaster); return (npcStateMask2 != npcStateMask) ? npcStateMask2 : uint.MaxValue; } if (!TryResolvePlayerRig(sourcePlayerId, out var rigManager) || (Object)(object)rigManager == (Object)null || (Object)(object)rigManager.avatar == (Object)null || (Object)(object)rigManager.health == (Object)null || !rigManager.health.alive) { return uint.MaxValue; } switch (kind) { case 1: { if ((detail & 2) == 0 || (detail & -4) != 0 || IsNpcBoneGone(puppetMaster, bone)) { return uint.MaxValue; } float dominance = GetDominance(GetInteractionStrength(rigManager), GetNpcStrength(puppetMaster)); Vector3 npcBonePoint = GetNpcBonePoint(puppetMaster, bone, point); if (dominance <= 0f) { return uint.MaxValue; } if (!ValidateNpcRipProximity(sourcePlayerId, rigManager, puppetMaster, bone, detail, out var consumed)) { if (!consumed) { QueuePendingNpcInteraction(sourcePlayerId, entityId, kind, boneIndex, detail, npcBonePoint); } return uint.MaxValue; } ulong key2 = ComposeNpcInteractionKey(kind, sourcePlayerId, entityId, boneIndex); if (!TryUseInteractionCooldown(_hostInteractionCooldowns, key2, 1f) || !ResolveDominance(dominance)) { return uint.MaxValue; } ApplyNpcRip(puppetMaster, bone, npcBonePoint); return GetNpcStateMask(puppetMaster); } case 2: { if (boneIndex != 0 || detail > 2 || !CanCrushNpc(rigManager, puppetMaster, detail) || !ValidateNpcCrushProximity(rigManager, puppetMaster, detail, point)) { if (detail <= 2 && CanCrushNpc(rigManager, puppetMaster, detail)) { QueuePendingNpcInteraction(sourcePlayerId, entityId, kind, boneIndex, detail, point); } return uint.MaxValue; } ulong key = ComposeNpcInteractionKey(kind, sourcePlayerId, entityId, byte.MaxValue); if (!TryUseInteractionCooldown(_hostInteractionCooldowns, key, 1f) || !ResolveDominance(GetNpcCrushDominance(rigManager, puppetMaster))) { return uint.MaxValue; } ApplyNpcCrush(puppetMaster, point); return GetNpcStateMask(puppetMaster); } default: return uint.MaxValue; } } private static bool IsNpcHitSenderOwner(PuppetMaster target, byte sourcePlayerId) { NetworkEntity val = default(NetworkEntity); if ((Object)(object)target == (Object)null || !PuppetMasterExtender.Cache.TryGet(target, ref val) || val == null || !val.IsRegistered) { return false; } if (val.HasOwner && val.OwnerID != null) { return val.OwnerID.SmallID == sourcePlayerId; } return val.IsOwner && PlayerIDManager.LocalID != null && sourcePlayerId == 0; } private void OnPluginNpcInteractionAuthoritative(ushort entityId, uint goneBoneMask, ushort sequence, byte kind, byte boneIndex, byte detail, Vector3 point) { bool playBlood = kind != 3; if (TryResolveNpcEntity(entityId, out var puppetMaster)) { ApplyNpcState(puppetMaster, IsSessionEnabled() ? goneBoneMask : 0u, killFatal: true, playBlood); _pendingNpcNetworkStates.Remove(entityId); return; } if (goneBoneMask == 0) { _pendingNpcNetworkStates.Remove(entityId); return; } if (_pendingNpcNetworkStates.Count >= 128 && !_pendingNpcNetworkStates.ContainsKey(entityId)) { ushort key = 0; float num = float.PositiveInfinity; foreach (KeyValuePair pendingNpcNetworkState in _pendingNpcNetworkStates) { if (pendingNpcNetworkState.Value.ExpiresAt < num) { key = pendingNpcNetworkState.Key; num = pendingNpcNetworkState.Value.ExpiresAt; } } _pendingNpcNetworkStates.Remove(key); } _pendingNpcNetworkStates[entityId] = new PendingNpcNetworkState { Mask = goneBoneMask, PlayBlood = playBlood, ExpiresAt = Time.unscaledTime + 5f }; } private void ProcessPendingNpcNetworkStates() { if (_pendingNpcNetworkStates.Count == 0) { return; } if (!IsSessionEnabled()) { _pendingNpcNetworkStates.Clear(); return; } float unscaledTime = Time.unscaledTime; if (unscaledTime - _lastPendingNpcResolveTime < 0.5f) { return; } _lastPendingNpcResolveTime = unscaledTime; List list = new List(); foreach (KeyValuePair pendingNpcNetworkState in _pendingNpcNetworkStates) { PuppetMaster puppetMaster; if (unscaledTime >= pendingNpcNetworkState.Value.ExpiresAt) { list.Add(pendingNpcNetworkState.Key); } else if (TryResolveNpcEntity(pendingNpcNetworkState.Key, out puppetMaster)) { ApplyNpcState(puppetMaster, pendingNpcNetworkState.Value.Mask, killFatal: true, pendingNpcNetworkState.Value.PlayBlood); list.Add(pendingNpcNetworkState.Key); } } for (int i = 0; i < list.Count; i++) { _pendingNpcNetworkStates.Remove(list[i]); } } private IEnumerator DelayedNpcStateCatchup() { float first = Time.unscaledTime + 2f; while (Time.unscaledTime < first) { yield return null; } SyncNpcStates(); float second = Time.unscaledTime + 4f; while (Time.unscaledTime < second) { yield return null; } SyncNpcStates(); } private bool ValidateNpcRipProximity(byte sourcePlayerId, RigManager source, PuppetMaster target, HumanBodyBones bone, byte detail, out bool consumed) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) consumed = false; if ((Object)(object)((source != null) ? source.physicsRig : null) == (Object)null || (Object)(object)((target != null) ? target.targetAnimator : null) == (Object)null) { return false; } bool flag = (detail & 1) != 0; Hand val = (flag ? source.physicsRig.rightHand : source.physicsRig.leftHand); if ((Object)(object)val == (Object)null) { return false; } RecordObservedPlayerGrab(sourcePlayerId, val, flag); if (!TryGetNpcEntityId(target, out var entityId)) { return false; } ushort key = ComposeGrabEvidenceKey(sourcePlayerId, flag); if (!_recentNpcGrabEvidence.TryGetValue(key, out var value) || Time.unscaledTime - value.Time > 1.5f || value.EntityId != entityId || value.Bone != bone) { if ((_recentNpcGrabEvidence.TryGetValue(key, out value) && value.Active) || (_recentGrabEvidence.TryGetValue(key, out var value2) && value2.Active)) { consumed = true; } return false; } if (value.Consumed) { consumed = true; return false; } value.Consumed = true; _recentNpcGrabEvidence[key] = value; return true; } private bool CanCrushNpc(RigManager attacker, PuppetMaster target, byte detail) { if ((Object)(object)attacker == (Object)null || (Object)(object)attacker.avatar == (Object)null || (Object)(object)target == (Object)null || (Object)(object)target.targetAnimator == (Object)null || (detail == 1 && IsLeftLegGone(attacker)) || (detail == 2 && IsRightLegGone(attacker)) || (detail == 0 && IsBothLegsGone(attacker))) { return false; } return GetNpcCrushDominance(attacker, target) > 0f; } private float GetNpcCrushDominance(RigManager attacker, PuppetMaster target) { if ((Object)(object)((attacker != null) ? attacker.avatar : null) == (Object)null || (Object)(object)target == (Object)null) { return 0f; } return GetCrushDominance(GetInteractionHeight(attacker), GetNpcHeight(target), GetInteractionMass(attacker), GetNpcMass(target)); } private bool ValidateNpcCrushProximity(RigManager source, PuppetMaster target, byte detail, Vector3 point) { if (TryFindObservedNpcCrushContact(source, target, detail, out var _)) { return true; } if (!TryGetPlayerIdForRig(source, out var playerId) || !TryGetNpcEntityId(target, out var entityId)) { return false; } ulong key = ComposeNpcInteractionKey(2, playerId, entityId, detail); RecentCrushEvidence value; return _recentNpcCrushEvidence.TryGetValue(key, out value) && Time.unscaledTime - value.Time <= 1.5f; } private bool TryFindObservedNpcCrushContact(RigManager source, PuppetMaster target, byte detail, out Vector3 point) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; if (!TryGetCrushFootCollider(source, detail, out var collider)) { return false; } Bounds bounds = collider.bounds; float avatarHeight = GetAvatarHeight(source); float num = Mathf.Clamp(avatarHeight * 0.06f, 0.08f, 0.35f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y - num * 0.5f + 0.01f, ((Bounds)(ref bounds)).center.z); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.x * 1.15f), num * 0.5f + 0.02f, Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.z * 1.15f)); int num2; try { num2 = Physics.OverlapBoxNonAlloc(val, val2, CrushOverlapBuffer, Quaternion.identity, -1, (QueryTriggerInteraction)1); } catch { return false; } for (int i = 0; i < num2; i++) { Collider val3 = ((Il2CppArrayBase)(object)CrushOverlapBuffer)[i]; if (!((Object)(object)val3 == (Object)null) && TryResolveNpcContact(val3, out var puppetMaster, out var bone) && !((Object)(object)puppetMaster != (Object)(object)target) && !IsNpcBoneGone(target, bone) && TryGetCrushContactPoint(collider, val3, avatarHeight, out point)) { return true; } } return false; } private bool TryGetClosestNpcBone(PuppetMaster target, Vector3 point, out Vector3 position, out float distance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; distance = float.MaxValue; bool result = false; Animator val = (((Object)(object)target != (Object)null) ? target.targetAnimator : null); if ((Object)(object)val == (Object)null) { return false; } for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones val2 = DamageBones[i]; Transform boneTransform = val.GetBoneTransform(val2); if (!((Object)(object)boneTransform == (Object)null) && !IsNpcBoneGone(target, val2)) { float num = Vector3.Distance(point, boneTransform.position); if (num < distance) { position = boneTransform.position; distance = num; result = true; } } } return result; } private static ulong ComposeNpcInteractionKey(byte kind, byte sourcePlayerId, ushort entityId, byte boneIndex) { return 0x8000000000000000uL | ((ulong)kind << 48) | ((ulong)sourcePlayerId << 40) | ((ulong)entityId << 8) | boneIndex; } private void ForgetPendingNpcState(ushort entityId) { _pendingNpcNetworkStates.Remove(entityId); RemovePendingNpcInteractions(entityId); } private static Vector3 GetNpcBonePoint(PuppetMaster target, HumanBodyBones bone, Vector3 fallback) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)((target != null) ? target.targetAnimator : null) != (Object)null) ? target.targetAnimator.GetBoneTransform(bone) : null); return ((Object)(object)val != (Object)null) ? val.position : fallback; } private void ClearNpcInteractionState() { _pendingNpcNetworkStates.Clear(); _lastPendingNpcResolveTime = -999f; } private static Renderer[] CollectNpcRenderers(NpcLimbState state) { HashSet hashSet = new HashSet(); Transform[] array = CollectNpcVisualRoots(state); for (int i = 0; i < array.Length; i++) { AddNpcComponents(array[i], hashSet); } Renderer[] array2 = (Renderer[])(object)new Renderer[hashSet.Count]; hashSet.CopyTo(array2); return array2; } private static Animator[] CollectNpcAnimators(NpcLimbState state) { HashSet hashSet = new HashSet(); Transform[] array = CollectNpcVisualRoots(state); for (int i = 0; i < array.Length; i++) { AddNpcComponents(array[i], hashSet); } Animator[] array2 = (Animator[])(object)new Animator[hashSet.Count]; hashSet.CopyTo(array2); return array2; } private static Transform[] CollectNpcVisualRoots(NpcLimbState state) { List list = new List(); Poolee obj = FindNpcPoolee(state); AddNpcVisualRoot(list, (obj != null) ? ((Component)obj).transform : null); object candidate; if (state == null) { candidate = null; } else { Animator animator = state.Animator; candidate = ((animator != null) ? ((Component)animator).transform : null); } AddNpcVisualRoot(list, (Transform)candidate); object candidate2; if (state == null) { candidate2 = null; } else { AIBrain brain = state.Brain; candidate2 = ((brain != null) ? ((Component)brain).transform : null); } AddNpcVisualRoot(list, (Transform)candidate2); object candidate3; if (state == null) { candidate3 = null; } else { PuppetMaster puppetMaster = state.PuppetMaster; candidate3 = ((puppetMaster != null) ? ((Component)puppetMaster).transform : null); } AddNpcVisualRoot(list, (Transform)candidate3); return list.ToArray(); } private static void AddNpcVisualRoot(List roots, Transform candidate) { if ((Object)(object)candidate == (Object)null) { return; } for (int num = roots.Count - 1; num >= 0; num--) { Transform val = roots[num]; if ((Object)(object)val == (Object)null) { roots.RemoveAt(num); } else { if (IsSameOrDescendant(candidate, val)) { return; } if (IsSameOrDescendant(val, candidate)) { roots.RemoveAt(num); } } } roots.Add(candidate); } private static void AddNpcComponents(Transform root, HashSet components) where T : Component { if ((Object)(object)root == (Object)null) { return; } T[] array = Il2CppArrayBase.op_Implicit(((Component)root).GetComponentsInChildren(true)); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { components.Add(array[i]); } } } private static bool IsNpcRendererWhollyUnderBone(Renderer renderer, List visualBones) { if ((Object)(object)renderer == (Object)null || visualBones == null || visualBones.Count == 0) { return false; } SkinnedMeshRenderer val = ((Il2CppObjectBase)renderer).TryCast(); if ((Object)(object)val == (Object)null || val.bones == null || ((Il2CppArrayBase)(object)val.bones).Length == 0) { for (int i = 0; i < visualBones.Count; i++) { Transform val2 = visualBones[i]; if ((Object)(object)val2 != (Object)null && IsSameOrDescendant(((Component)renderer).transform, val2)) { return true; } } return false; } bool result = false; for (int j = 0; j < ((Il2CppArrayBase)(object)val.bones).Length; j++) { Transform val3 = ((Il2CppArrayBase)(object)val.bones)[j]; if ((Object)(object)val3 == (Object)null) { continue; } result = true; bool flag = false; for (int k = 0; k < visualBones.Count; k++) { Transform val4 = visualBones[k]; if ((Object)(object)val4 != (Object)null && IsSameOrDescendant(val3, val4)) { flag = true; break; } } if (!flag) { return false; } } return result; } private static bool IsNpcRendererWhollyGone(NpcLimbState state, Renderer renderer) { for (int i = 0; i < DamageBones.Length; i++) { if ((state.GoneMask & (uint)(1 << i)) != 0 && state.VisualRenderers.TryGetValue(DamageBones[i], out var value) && value.Contains(renderer)) { return true; } } return false; } private static void ForceNpcRenderersOff(NpcLimbState state, HumanBodyBones bone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!state.VisualRenderers.TryGetValue(bone, out var value)) { return; } for (int i = 0; i < value.Count; i++) { Renderer val = value[i]; if (!((Object)(object)val == (Object)null)) { ForceNpcRendererOff(state, val); } } } private static void ForceNpcRendererOff(NpcLimbState state, Renderer renderer) { if (state == null || (Object)(object)renderer == (Object)null) { return; } if (!state.RendererForceOffStates.ContainsKey(renderer)) { if (state.PendingRendererForceOffStates.TryGetValue(renderer, out var value)) { state.RendererForceOffStates[renderer] = value; state.PendingRendererForceOffStates.Remove(renderer); } else { state.RendererForceOffStates[renderer] = renderer.forceRenderingOff; } } renderer.forceRenderingOff = true; } private static void ForceNpcPendingRendererOff(NpcLimbState state, Renderer renderer) { if (state != null && !((Object)(object)renderer == (Object)null)) { if (!state.PendingRendererForceOffStates.ContainsKey(renderer)) { state.PendingRendererForceOffStates[renderer] = (state.RendererForceOffStates.TryGetValue(renderer, out var value) ? value : renderer.forceRenderingOff); } renderer.forceRenderingOff = true; } } private static void RestoreNpcPendingRendererState(NpcLimbState state, Renderer renderer) { if (state != null && !((Object)(object)renderer == (Object)null) && state.PendingRendererForceOffStates.TryGetValue(renderer, out var value)) { renderer.forceRenderingOff = value; state.PendingRendererForceOffStates.Remove(renderer); } } private static void RestoreNpcRendererStates(NpcLimbState state) { foreach (KeyValuePair rendererForceOffState in state.RendererForceOffStates) { if ((Object)(object)rendererForceOffState.Key != (Object)null) { try { rendererForceOffState.Key.forceRenderingOff = rendererForceOffState.Value; } catch { } } } state.RendererForceOffStates.Clear(); foreach (KeyValuePair pendingRendererForceOffState in state.PendingRendererForceOffStates) { if ((Object)(object)pendingRendererForceOffState.Key != (Object)null) { try { pendingRendererForceOffState.Key.forceRenderingOff = pendingRendererForceOffState.Value; } catch { } } } state.PendingRendererForceOffStates.Clear(); } private static void CaptureNpcVisualScales(NpcLimbState state, uint mask) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (state == null || mask == 0) { return; } for (int i = 0; i < DamageBones.Length; i++) { if ((mask & (uint)(1 << i)) == 0 || !state.VisualBones.TryGetValue(DamageBones[i], out var value)) { continue; } for (int j = 0; j < value.Count; j++) { Transform val = value[j]; if ((Object)(object)val != (Object)null) { state.VisualScales[val] = val.localScale; } } } } private void ApplyNpcVisualMeshMask(NpcLimbState state, uint mask) { if (state == null) { return; } if (state.VisualMeshesInitialized && state.NextVisualMeshScanTime > 0f && Time.unscaledTime >= state.NextVisualMeshScanTime) { state.VisualMeshesInitialized = false; state.PendingVisualRenderers = null; state.NextVisualRendererIndex = 0; state.PendingVisualBonesRefresh = false; state.NextVisualMeshScanTime = 0f; } if (mask != 0 && state.VisualMeshesInitialized && state.NextVisualMeshScanTime <= 0f && Time.unscaledTime >= state.NextVisualRendererCheckTime && _npcVisualScanBudget > 0) { _npcVisualScanBudget--; try { Renderer[] array = CollectNpcRenderers(state); int npcRendererSignature = GetNpcRendererSignature(array); state.NextVisualRendererCheckTime = Time.unscaledTime + 15f; if (npcRendererSignature != state.VisualRendererSignature) { state.VisualRendererSignature = npcRendererSignature; state.PendingVisualRenderers = array; state.NextVisualRendererIndex = 0; state.PendingVisualBonesRefresh = true; state.VisualMeshesInitialized = false; } } catch { ScheduleNpcVisualScanRetry(state); } } if (!state.VisualMeshesInitialized && mask != 0 && _npcVisualScanBudget > 0) { _npcVisualScanBudget--; CacheNpcVisualMeshes(state); } bool flag = false; for (int num = state.VisualMeshes.Count - 1; num >= 0; num--) { NpcVisualMeshState npcVisualMeshState = state.VisualMeshes[num]; if ((Object)(object)npcVisualMeshState.Renderer == (Object)null || (Object)(object)npcVisualMeshState.RuntimeMesh == (Object)null || (Object)(object)npcVisualMeshState.OriginalMesh == (Object)null) { ReleaseNpcVisualMesh(npcVisualMeshState); state.VisualMeshes.RemoveAt(num); flag = true; continue; } Mesh sharedMesh = npcVisualMeshState.Renderer.sharedMesh; if (mask != 0 && npcVisualMeshState.CreatedFrame == Time.frameCount) { continue; } if (npcVisualMeshState.UsesBakedProxy) { if ((Object)(object)sharedMesh != (Object)(object)npcVisualMeshState.OriginalMesh) { SkinnedMeshRenderer renderer = npcVisualMeshState.Renderer; bool flag2 = IsNpcRendererWhollyGone(state, (Renderer)(object)renderer); ReleaseNpcVisualMesh(npcVisualMeshState); state.VisualMeshes.RemoveAt(num); if (mask != 0 && (Object)(object)renderer != (Object)null) { if (flag2) { ForceNpcRendererOff(state, (Renderer)(object)renderer); } else { ForceNpcPendingRendererOff(state, (Renderer)(object)renderer); } } flag = true; } else { if (mask != 0 && state.VisualMeshRetryTimes.TryGetValue((Renderer)(object)npcVisualMeshState.Renderer, out var value) && Time.unscaledTime < value) { continue; } if (mask != 0 && (npcVisualMeshState.ProxyTriangles == null || npcVisualMeshState.AppliedMask != mask)) { if (_npcProxyBuildBudget <= 0) { continue; } _npcProxyBuildBudget--; } if (!TryApplyNpcBakedProxy(state, npcVisualMeshState, mask)) { ScheduleNpcVisualMeshRetry(state, (Renderer)(object)npcVisualMeshState.Renderer, rescan: false); } else if (npcVisualMeshState.AppliedMask == mask) { state.VisualMeshRetryTimes.Remove((Renderer)(object)npcVisualMeshState.Renderer); state.VisualMeshFailureCounts.Remove((Renderer)(object)npcVisualMeshState.Renderer); } } } else if (npcVisualMeshState.AppliedMask == mask && (Object)(object)sharedMesh == (Object)(object)npcVisualMeshState.RuntimeMesh) { RestoreNpcPendingRendererState(state, (Renderer)(object)npcVisualMeshState.Renderer); } else if (npcVisualMeshState.AppliedMask == mask && (Object)(object)sharedMesh == (Object)(object)npcVisualMeshState.OriginalMesh) { npcVisualMeshState.Renderer.sharedMesh = npcVisualMeshState.RuntimeMesh; RestoreNpcPendingRendererState(state, (Renderer)(object)npcVisualMeshState.Renderer); } else if ((Object)(object)sharedMesh != (Object)(object)npcVisualMeshState.RuntimeMesh && (Object)(object)sharedMesh != (Object)(object)npcVisualMeshState.OriginalMesh) { SkinnedMeshRenderer renderer2 = npcVisualMeshState.Renderer; bool flag3 = IsNpcRendererWhollyGone(state, (Renderer)(object)renderer2); ReleaseNpcVisualMesh(npcVisualMeshState); state.VisualMeshes.RemoveAt(num); if (mask != 0 && (Object)(object)renderer2 != (Object)null) { if (flag3) { ForceNpcRendererOff(state, (Renderer)(object)renderer2); } else { ForceNpcPendingRendererOff(state, (Renderer)(object)renderer2); } } flag = true; } else if (!TryApplyNpcMeshTriangles(npcVisualMeshState, mask)) { ScheduleNpcVisualMeshRetry(state, (Renderer)(object)npcVisualMeshState.Renderer, rescan: true); ReleaseNpcVisualMesh(npcVisualMeshState); state.VisualMeshes.RemoveAt(num); } else { state.VisualMeshRetryTimes.Remove((Renderer)(object)npcVisualMeshState.Renderer); state.VisualMeshFailureCounts.Remove((Renderer)(object)npcVisualMeshState.Renderer); RestoreNpcPendingRendererState(state, (Renderer)(object)npcVisualMeshState.Renderer); } } if (flag) { state.VisualMeshesInitialized = false; state.PendingVisualRenderers = null; state.NextVisualRendererIndex = 0; state.PendingVisualBonesRefresh = false; } } private bool TryApplyNpcBakedProxy(NpcLimbState state, NpcVisualMeshState meshState, uint mask) { try { if (mask == 0) { bool flag = RestoreNpcBakedRenderer(meshState); if (!flag && !TryBakeNpcBakedProxyMesh(meshState, applyMask: false)) { return false; } if ((Object)(object)meshState.ProxyObject != (Object)null) { meshState.ProxyObject.SetActive(!flag); } meshState.AppliedMask = 0u; return true; } bool flag2 = (Object)(object)meshState.ProxyObject == (Object)null && meshState.AppliedMask == uint.MaxValue && !((Renderer)meshState.Renderer).isVisible; bool flag3 = (Object)(object)meshState.ProxyObject != (Object)null && meshState.ProxyLodReplaced && meshState.AppliedMask != mask && !((Renderer)meshState.ProxyRenderer).isVisible; if (flag2 || flag3) { if (state.NextDeferredProxyBakeTime <= 0f) { state.NextDeferredProxyBakeTime = Time.unscaledTime + 0.05f; return true; } if (Time.unscaledTime < state.NextDeferredProxyBakeTime) { return true; } state.NextDeferredProxyBakeTime = Time.unscaledTime + 0.05f; } bool flag4 = meshState.AppliedMask != mask; if ((meshState.ProxyTriangles == null || flag4) && !TryBuildNpcBakedProxyTriangles(state, meshState, mask)) { return false; } bool flag5 = flag4 || meshState.StagingMeshPrepared || (Object)(object)meshState.ProxyObject == (Object)null || !meshState.ProxyObject.activeSelf; if (!flag5 && (Object)(object)meshState.ProxyRenderer != (Object)null && ((Renderer)meshState.ProxyRenderer).isVisible && Time.unscaledTime >= meshState.NextProxyBakeTime && _npcProxyRefreshBudget > 0) { _npcProxyRefreshBudget--; flag5 = true; } if (flag5) { if (!((meshState.StagingMeshPrepared && meshState.StagingMask == mask) ? CommitNpcBakedProxyMesh(meshState) : TryBakeNpcBakedProxyMesh(meshState, applyMask: true))) { return false; } meshState.NextProxyBakeTime = Time.unscaledTime + 0.25f; } if (!EnsureNpcBakedProxy(meshState)) { return false; } if (!meshState.HasRendererForceState) { meshState.RendererForceState = (state.PendingRendererForceOffStates.TryGetValue((Renderer)(object)meshState.Renderer, out var value) ? value : (state.RendererForceOffStates.TryGetValue((Renderer)(object)meshState.Renderer, out var value2) ? value2 : ((Renderer)meshState.Renderer).forceRenderingOff)); meshState.HasRendererForceState = true; } PreserveNpcBakedAnimation(state, meshState.Renderer); if (!meshState.ProxyLodReplaced && Time.unscaledTime >= meshState.NextProxyLodBindTime) { BindNpcBakedProxyLod(meshState); meshState.NextProxyLodBindTime = Time.unscaledTime + 1f; } SyncNpcBakedProxyRenderer(meshState); ((Renderer)meshState.Renderer).forceRenderingOff = true; meshState.ProxyObject.SetActive(true); meshState.AppliedMask = mask; state.PendingRendererForceOffStates.Remove((Renderer)(object)meshState.Renderer); return true; } catch { return false; } } private static bool TryBakeNpcBakedProxyMesh(NpcVisualMeshState meshState, bool applyMask) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown if ((Object)(object)meshState.StagingMesh == (Object)null || (Object)(object)meshState.StagingMesh == (Object)(object)meshState.RuntimeMesh) { meshState.StagingMesh = new Mesh { name = ((Object)meshState.OriginalMesh).name + "_DeadPieceNpcStaging", hideFlags = (HideFlags)52 }; meshState.StagingMesh.MarkDynamic(); } meshState.StagingMeshPrepared = false; meshState.StagingMask = uint.MaxValue; meshState.StagingMesh.Clear(); meshState.Renderer.BakeMesh(meshState.StagingMesh, false); if (applyMask) { if (meshState.ProxyTriangles == null || meshState.StagingMesh.vertexCount != meshState.ProxyVertexCount || meshState.StagingMesh.subMeshCount != meshState.ProxyTriangles.Length) { return false; } for (int i = 0; i < meshState.ProxyTriangles.Length; i++) { meshState.StagingMesh.SetTriangles(meshState.ProxyTriangles[i], i, false); } } return CommitNpcBakedProxyMesh(meshState); } private static bool CommitNpcBakedProxyMesh(NpcVisualMeshState meshState) { if ((Object)(object)meshState.StagingMesh == (Object)null) { return false; } Mesh stagingMesh = meshState.StagingMesh; if ((Object)(object)meshState.ProxyFilter != (Object)null) { meshState.ProxyFilter.sharedMesh = stagingMesh; } meshState.StagingMesh = meshState.RuntimeMesh; meshState.RuntimeMesh = stagingMesh; meshState.StagingMeshPrepared = false; meshState.StagingMask = uint.MaxValue; return true; } private static void PreserveNpcBakedAnimation(NpcLimbState state, SkinnedMeshRenderer renderer) { if (!state.NpcRendererUpdateStates.ContainsKey(renderer)) { state.NpcRendererUpdateStates[renderer] = renderer.updateWhenOffscreen; if ((Object)(object)((Component)renderer).gameObject.GetComponent("Cloth") != (Object)null) { state.NpcClothUpdateRenderers.Add(renderer); } Il2CppArrayBase componentsInParent = ((Component)renderer).GetComponentsInParent(true); for (int i = 0; i < componentsInParent.Length; i++) { PreserveNpcAnimatorCulling(state, componentsInParent[i]); } PreserveNpcAnimatorCulling(state, state.Animator); } if (state.NpcClothUpdateRenderers.Contains(renderer)) { renderer.updateWhenOffscreen = true; } } private static void PreserveNpcAnimatorCulling(NpcLimbState state, Animator animator) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)animator == (Object)null)) { if (!state.NpcAnimatorCullingStates.ContainsKey(animator)) { state.NpcAnimatorCullingStates[animator] = animator.cullingMode; } animator.cullingMode = (AnimatorCullingMode)0; } } private static void RestoreNpcBakedAnimationStates(NpcLimbState state) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair npcRendererUpdateState in state.NpcRendererUpdateStates) { if ((Object)(object)npcRendererUpdateState.Key != (Object)null) { try { npcRendererUpdateState.Key.updateWhenOffscreen = npcRendererUpdateState.Value; } catch { } } } state.NpcRendererUpdateStates.Clear(); state.NpcClothUpdateRenderers.Clear(); foreach (KeyValuePair npcAnimatorCullingState in state.NpcAnimatorCullingStates) { if ((Object)(object)npcAnimatorCullingState.Key != (Object)null) { try { npcAnimatorCullingState.Key.cullingMode = npcAnimatorCullingState.Value; } catch { } } } state.NpcAnimatorCullingStates.Clear(); } private static bool TryBuildNpcBakedProxyTriangles(NpcLimbState state, NpcVisualMeshState meshState, uint mask) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) Mesh val = null; Mesh val2 = null; Dictionary dictionary = new Dictionary(); try { val = new Mesh { name = ((Object)meshState.OriginalMesh).name + "_DeadPieceNpcIntact", hideFlags = (HideFlags)52 }; val2 = new Mesh { name = ((Object)meshState.OriginalMesh).name + "_DeadPieceNpcCollapsed", hideFlags = (HideFlags)52 }; for (int i = 0; i < DamageBones.Length; i++) { if ((mask & (uint)(1 << i)) == 0 || !state.VisualBones.TryGetValue(DamageBones[i], out var value)) { continue; } for (int j = 0; j < value.Count; j++) { Transform val3 = value[j]; if (!((Object)(object)val3 == (Object)null) && !dictionary.ContainsKey(val3)) { dictionary[val3] = val3.localScale; if (state.VisualScales.TryGetValue(val3, out var value2)) { val3.localScale = value2; } } } } meshState.Renderer.BakeMesh(val, false); Vector3[] array = (Vector3[])(object)new Vector3[DamageBones.Length]; bool[] array2 = new bool[DamageBones.Length]; for (int k = 0; k < DamageBones.Length; k++) { if (state.Bones.TryGetValue(DamageBones[k], out var value3) && (Object)(object)value3 != (Object)null) { array[k] = ((Component)meshState.Renderer).transform.InverseTransformPoint(value3.position); array2[k] = true; } } foreach (KeyValuePair item in dictionary) { if ((Object)(object)item.Key != (Object)null) { item.Key.localScale = Vector3.zero; } } dictionary.Clear(); meshState.Renderer.BakeMesh(val2, false); if (val.vertexCount <= 0 || val.vertexCount != val2.vertexCount || val.subMeshCount != val2.subMeshCount) { return false; } Il2CppStructArray vertices = val.vertices; Il2CppStructArray vertices2 = val2.vertices; if (vertices == null || vertices2 == null || ((Il2CppArrayBase)(object)vertices).Length != val.vertexCount || ((Il2CppArrayBase)(object)vertices2).Length != val.vertexCount) { return false; } bool[] array3 = new bool[val.vertexCount]; Bounds bounds = val.bounds; Vector3 val4 = ((Bounds)(ref bounds)).extents; float num = Mathf.Max(0.1f, ((Vector3)(ref val4)).magnitude); float num2 = num * 0.0001f; float num3 = num2 * num2; int num4 = 0; for (int l = 0; l < val.vertexCount; l++) { val4 = ((Il2CppArrayBase)(object)vertices)[l] - ((Il2CppArrayBase)(object)vertices2)[l]; if (array3[l] = ((Vector3)(ref val4)).sqrMagnitude > num3) { num4++; } } if (num4 == 0) { for (int m = 0; m < val.vertexCount; m++) { Vector3 val5 = ((Il2CppArrayBase)(object)vertices)[m]; float num5 = float.PositiveInfinity; float num6 = float.PositiveInfinity; for (int n = 0; n < DamageBones.Length; n++) { if (array2[n]) { val4 = val5 - array[n]; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if ((mask & (uint)(1 << n)) != 0) { num5 = Mathf.Min(num5, sqrMagnitude); } else { num6 = Mathf.Min(num6, sqrMagnitude); } } } if (array3[m] = num5 < float.PositiveInfinity && (num6 == float.PositiveInfinity || num5 < num6 * 0.64f)) { num4++; } } } if (num4 == 0) { return false; } Il2CppStructArray[] array4 = new Il2CppStructArray[val2.subMeshCount]; bool flag = false; for (int num7 = 0; num7 < val2.subMeshCount; num7++) { Il2CppStructArray triangles = val2.GetTriangles(num7); List list = new List(((Il2CppArrayBase)(object)triangles).Length); for (int num8 = 0; num8 + 2 < ((Il2CppArrayBase)(object)triangles).Length; num8 += 3) { int num9 = ((Il2CppArrayBase)(object)triangles)[num8]; int num10 = ((Il2CppArrayBase)(object)triangles)[num8 + 1]; int num11 = ((Il2CppArrayBase)(object)triangles)[num8 + 2]; if (num9 < 0 || num10 < 0 || num11 < 0 || num9 >= array3.Length || num10 >= array3.Length || num11 >= array3.Length) { return false; } if (array3[num9] || array3[num10] || array3[num11]) { flag = true; continue; } list.Add(num9); list.Add(num10); list.Add(num11); } array4[num7] = new Il2CppStructArray(list.ToArray()); } if (!flag) { return false; } for (int num12 = 0; num12 < array4.Length; num12++) { val2.SetTriangles(array4[num12], num12, false); } val2.MarkDynamic(); if ((Object)(object)meshState.StagingMesh != (Object)null && (Object)(object)meshState.StagingMesh != (Object)(object)meshState.RuntimeMesh) { Object.Destroy((Object)(object)meshState.StagingMesh); } meshState.StagingMesh = val2; val2 = null; meshState.StagingMeshPrepared = true; meshState.StagingMask = mask; meshState.ProxyTriangles = array4; meshState.ProxyVertexCount = val.vertexCount; return true; } catch { return false; } finally { foreach (KeyValuePair item2 in dictionary) { if ((Object)(object)item2.Key != (Object)null) { item2.Key.localScale = Vector3.zero; } } if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } } } private static bool EnsureNpcBakedProxy(NpcVisualMeshState meshState) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown if ((Object)(object)meshState.ProxyObject != (Object)null && (Object)(object)meshState.ProxyFilter != (Object)null && (Object)(object)meshState.ProxyRenderer != (Object)null) { if (!meshState.ProxyObject.activeSelf && !meshState.ProxyLodReplaced && Time.unscaledTime >= meshState.NextProxyLodBindTime) { BindNpcBakedProxyLod(meshState); meshState.NextProxyLodBindTime = Time.unscaledTime + 1f; } return true; } GameObject val = null; try { val = new GameObject(((Object)meshState.OriginalMesh).name + "_DeadPieceNpcProxy"); ((Object)val).hideFlags = (HideFlags)52; val.layer = ((Component)meshState.Renderer).gameObject.layer; val.transform.SetParent(((Component)meshState.Renderer).transform, false); MeshFilter val2 = val.AddComponent(); MeshRenderer proxyRenderer = val.AddComponent(); val2.sharedMesh = meshState.RuntimeMesh; meshState.ProxyObject = val; meshState.ProxyFilter = val2; meshState.ProxyRenderer = proxyRenderer; meshState.ProxyPropertyBlock = new MaterialPropertyBlock(); BindNpcBakedProxyLod(meshState); meshState.NextProxyLodBindTime = Time.unscaledTime + 1f; return true; } catch { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } meshState.ProxyObject = null; meshState.ProxyFilter = null; meshState.ProxyRenderer = null; meshState.ProxyPropertyBlock = null; return false; } } private static void BindNpcBakedProxyLod(NpcVisualMeshState meshState) { bool flag = false; bool flag2 = false; try { Il2CppArrayBase componentsInParent = ((Component)meshState.Renderer).GetComponentsInParent(true); for (int i = 0; i < componentsInParent.Length; i++) { LODGroup val = componentsInParent[i]; if ((Object)(object)val == (Object)null) { continue; } flag = true; if (NpcLodContainsRenderer(val, (Renderer)(object)meshState.Renderer)) { flag2 = true; if (ReplaceNpcLodRenderer(val, (Renderer)(object)meshState.Renderer, (Renderer)(object)meshState.ProxyRenderer)) { meshState.ProxyLodGroup = val; meshState.ProxyLodReplaced = true; meshState.ProxyLodBindingRequired = false; return; } } } meshState.ProxyLodBindingRequired = flag2; } catch { meshState.ProxyLodGroup = null; meshState.ProxyLodReplaced = false; meshState.ProxyLodBindingRequired = flag2 || flag; } } private static bool NpcLodContainsRenderer(LODGroup group, Renderer renderer) { if ((Object)(object)group == (Object)null || (Object)(object)renderer == (Object)null) { return false; } Il2CppReferenceArray lODs = group.GetLODs(); if (lODs == null) { return false; } for (int i = 0; i < ((Il2CppArrayBase)(object)lODs).Length; i++) { LOD obj = ((Il2CppArrayBase)(object)lODs)[i]; Il2CppReferenceArray val = ((obj != null) ? obj.renderers : null); if (val == null) { continue; } for (int j = 0; j < ((Il2CppArrayBase)(object)val).Length; j++) { if ((Object)(object)((Il2CppArrayBase)(object)val)[j] == (Object)(object)renderer) { return true; } } } return false; } private static bool ReplaceNpcLodRenderer(LODGroup group, Renderer source, Renderer replacement) { if ((Object)(object)group == (Object)null || (Object)(object)source == (Object)null || (Object)(object)replacement == (Object)null) { return false; } Il2CppReferenceArray lODs = group.GetLODs(); if (lODs == null) { return false; } bool flag = false; for (int i = 0; i < ((Il2CppArrayBase)(object)lODs).Length; i++) { LOD val = ((Il2CppArrayBase)(object)lODs)[i]; Il2CppReferenceArray val2 = ((val != null) ? val.renderers : null); if (val2 == null) { continue; } Il2CppReferenceArray val3 = null; for (int j = 0; j < ((Il2CppArrayBase)(object)val2).Length; j++) { if ((Object)(object)((Il2CppArrayBase)(object)val2)[j] != (Object)(object)source) { continue; } if (val3 == null) { val3 = new Il2CppReferenceArray((long)((Il2CppArrayBase)(object)val2).Length); for (int k = 0; k < ((Il2CppArrayBase)(object)val2).Length; k++) { ((Il2CppArrayBase)(object)val3)[k] = ((Il2CppArrayBase)(object)val2)[k]; } } ((Il2CppArrayBase)(object)val3)[j] = replacement; } if (val3 != null) { val.renderers = val3; ((Il2CppArrayBase)(object)lODs)[i] = val; flag = true; } } if (flag) { group.SetLODs(lODs); } return flag; } private static void SyncNpcBakedProxyRenderer(NpcVisualMeshState meshState) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) SkinnedMeshRenderer renderer = meshState.Renderer; MeshRenderer proxyRenderer = meshState.ProxyRenderer; if (!meshState.ProxyLodReplaced) { ((Renderer)proxyRenderer).enabled = ((Renderer)renderer).enabled; } ((Renderer)proxyRenderer).forceRenderingOff = meshState.RendererForceState; if (Time.unscaledTime >= meshState.NextProxyRendererSyncTime) { meshState.ProxyObject.layer = ((Component)renderer).gameObject.layer; ((Renderer)proxyRenderer).sharedMaterials = ((Renderer)renderer).sharedMaterials; ((Renderer)proxyRenderer).shadowCastingMode = ((Renderer)renderer).shadowCastingMode; ((Renderer)proxyRenderer).receiveShadows = ((Renderer)renderer).receiveShadows; ((Renderer)proxyRenderer).lightProbeUsage = ((Renderer)renderer).lightProbeUsage; ((Renderer)proxyRenderer).reflectionProbeUsage = ((Renderer)renderer).reflectionProbeUsage; ((Renderer)proxyRenderer).probeAnchor = ((Renderer)renderer).probeAnchor; ((Renderer)proxyRenderer).allowOcclusionWhenDynamic = ((Renderer)renderer).allowOcclusionWhenDynamic; ((Renderer)proxyRenderer).motionVectorGenerationMode = ((Renderer)renderer).motionVectorGenerationMode; ((Renderer)proxyRenderer).renderingLayerMask = ((Renderer)renderer).renderingLayerMask; ((Renderer)proxyRenderer).sortingLayerID = ((Renderer)renderer).sortingLayerID; ((Renderer)proxyRenderer).sortingOrder = ((Renderer)renderer).sortingOrder; meshState.ProxyPropertyBlock.Clear(); ((Renderer)renderer).GetPropertyBlock(meshState.ProxyPropertyBlock); ((Renderer)proxyRenderer).SetPropertyBlock(meshState.ProxyPropertyBlock); meshState.NextProxyRendererSyncTime = Time.unscaledTime + 0.25f; } } private static bool RestoreNpcBakedRenderer(NpcVisualMeshState meshState) { bool flag = TryRestoreNpcBakedLod(meshState); if (flag) { meshState.ProxyLodGroup = null; meshState.ProxyLodReplaced = false; meshState.ProxyLodBindingRequired = false; meshState.NextProxyLodBindTime = 0f; } if (flag) { if (meshState.HasRendererForceState && (Object)(object)meshState.Renderer != (Object)null) { ((Renderer)meshState.Renderer).forceRenderingOff = meshState.RendererForceState; } meshState.HasRendererForceState = false; } else { if ((Object)(object)meshState.Renderer != (Object)null) { ((Renderer)meshState.Renderer).forceRenderingOff = true; } if ((Object)(object)meshState.ProxyRenderer != (Object)null) { ((Renderer)meshState.ProxyRenderer).forceRenderingOff = meshState.HasRendererForceState && meshState.RendererForceState; } } return flag; } private static bool TryRestoreNpcBakedLod(NpcVisualMeshState meshState) { if (!meshState.ProxyLodReplaced || (Object)(object)meshState.ProxyRenderer == (Object)null || (Object)(object)meshState.Renderer == (Object)null) { return true; } try { LODGroup proxyLodGroup = meshState.ProxyLodGroup; if ((Object)(object)proxyLodGroup != (Object)null && (ReplaceNpcLodRenderer(proxyLodGroup, (Renderer)(object)meshState.ProxyRenderer, (Renderer)(object)meshState.Renderer) || !NpcLodContainsRenderer(proxyLodGroup, (Renderer)(object)meshState.ProxyRenderer))) { return true; } Il2CppArrayBase componentsInParent = ((Component)meshState.Renderer).GetComponentsInParent(true); bool flag = false; for (int i = 0; i < componentsInParent.Length; i++) { LODGroup val = componentsInParent[i]; if (!((Object)(object)val == (Object)null) && NpcLodContainsRenderer(val, (Renderer)(object)meshState.ProxyRenderer)) { flag = true; if (ReplaceNpcLodRenderer(val, (Renderer)(object)meshState.ProxyRenderer, (Renderer)(object)meshState.Renderer)) { return true; } } } return !flag; } catch { return false; } } private static bool TryApplyNpcMeshTriangles(NpcVisualMeshState meshState, uint mask) { try { meshState.Renderer.sharedMesh = meshState.RuntimeMesh; for (int i = 0; i < meshState.OriginalTriangles.Length; i++) { int[] array = meshState.OriginalTriangles[i]; if (mask == 0) { meshState.RuntimeMesh.SetTriangles(Il2CppStructArray.op_Implicit(array), i, false); continue; } List list = new List(array.Length); for (int j = 0; j + 2 < array.Length; j += 3) { int num = array[j]; int num2 = array[j + 1]; int num3 = array[j + 2]; if (!IsNpcVertexHidden(meshState, num, mask) && !IsNpcVertexHidden(meshState, num2, mask) && !IsNpcVertexHidden(meshState, num3, mask)) { list.Add(num); list.Add(num2); list.Add(num3); } } meshState.RuntimeMesh.SetTriangles(Il2CppStructArray.op_Implicit(list.ToArray()), i, false); } meshState.AppliedMask = mask; return true; } catch { return false; } } private void CacheNpcVisualMeshes(NpcLimbState state) { //IL_031f: Unknown result type (might be due to invalid IL or missing references) if (state.PendingVisualRenderers == null) { try { Renderer[] renderers = (state.PendingVisualRenderers = CollectNpcRenderers(state)); state.NextVisualRendererIndex = 0; state.PendingVisualBonesRefresh = true; state.VisualRendererSignature = GetNpcRendererSignature(renderers); state.NextVisualRendererCheckTime = Time.unscaledTime + 15f; state.VisualMeshesInitialized = false; return; } catch { ScheduleNpcVisualScanRetry(state); return; } } if (state.PendingVisualBonesRefresh) { try { CacheNpcVisualBones(state, state.PendingVisualRenderers ?? Array.Empty()); state.PendingVisualBonesRefresh = false; state.VisualScanFailureCount = 0; return; } catch { ScheduleNpcVisualScanRetry(state); return; } } Renderer[] array = state.PendingVisualRenderers ?? Array.Empty(); bool flag = false; int num = 0; while (state.NextVisualRendererIndex < array.Length && !flag && num < 8) { Renderer val = array[state.NextVisualRendererIndex++]; num++; if ((Object)(object)val == (Object)null) { continue; } SkinnedMeshRenderer val2 = null; Mesh val3 = null; Mesh val4 = null; try { val2 = ((Il2CppObjectBase)val).TryCast(); if ((Object)(object)val2 == (Object)null || (Object)(object)val2.sharedMesh == (Object)null) { continue; } flag = true; val3 = val2.sharedMesh; Transform[] array2 = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)val2.bones); uint[] array3 = ((array2 == null || array2.Length == 0) ? Array.Empty() : BuildNpcRendererBoneMasks(state, array2)); bool flag2 = false; for (int i = 0; i < array3.Length; i++) { if (array3[i] != 0) { flag2 = true; break; } } NpcVisualMeshState npcVisualMeshState = FindNpcVisualMeshState(state, val2); if (IsNpcRendererWhollyGone(state, (Renderer)(object)val2)) { if (npcVisualMeshState != null) { RemoveNpcVisualMeshesForRenderer(state, val2); } ForceNpcRendererOff(state, (Renderer)(object)val2); continue; } if (npcVisualMeshState == null) { goto IL_0278; } bool flag3 = (Object)(object)val3 == (Object)(object)npcVisualMeshState.OriginalMesh || (Object)(object)val3 == (Object)(object)npcVisualMeshState.RuntimeMesh; if (!flag3 || (flag2 && !AreNpcBoneMasksEqual(npcVisualMeshState.RendererBoneMasks, array3) && CountNpcMappedBones(array3) >= CountNpcMappedBones(npcVisualMeshState.RendererBoneMasks))) { Mesh val5 = (flag3 ? npcVisualMeshState.OriginalMesh : val3); RemoveNpcVisualMeshesForRenderer(state, val2); val3 = val5; if (!((Object)(object)val3 == (Object)null)) { goto IL_0278; } } goto end_IL_0102; IL_0278: if (state.VisualMeshRetryTimes.TryGetValue((Renderer)(object)val2, out var value) && Time.unscaledTime < value) { continue; } int[][] triangles = null; bool flag4 = !val3.isReadable || (Object)(object)((Component)val2).gameObject.GetComponent("Cloth") != (Object)null; NpcVertexWeights[] vertexWeights; if (!flag4 && flag2) { if (!TryReadNpcReadableMeshData(val3, array3, out vertexWeights, out triangles)) { flag4 = true; } } else { vertexWeights = null; } if (!flag4 && !flag2) { flag4 = true; } val4 = (Mesh)((!flag4) ? ((object)Object.Instantiate(val3)) : ((object)new Mesh())); ((Object)val4).name = ((Object)val3).name + "_DeadPieceNpc"; ((Object)val4).hideFlags = (HideFlags)52; val4.MarkDynamic(); if (!flag4) { val2.sharedMesh = val4; } state.VisualMeshes.Add(new NpcVisualMeshState { OwnerState = state, Renderer = val2, OriginalMesh = val3, RuntimeMesh = val4, RendererBoneMasks = array3, VertexWeights = vertexWeights, OriginalTriangles = triangles, UsesBakedProxy = flag4, CreatedFrame = Time.frameCount }); end_IL_0102:; } catch { if ((Object)(object)val4 != (Object)null) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh == (Object)(object)val4) { val2.sharedMesh = val3; } Object.Destroy((Object)(object)val4); } ScheduleNpcVisualMeshRetry(state, val, rescan: true); } } if (state.NextVisualRendererIndex >= array.Length) { state.PendingVisualRenderers = null; state.NextVisualRendererIndex = 0; state.VisualMeshesInitialized = true; state.VisualMeshScanPassCount++; if (state.VisualMeshScanPassCount == 1 && state.NextVisualMeshScanTime <= 0f) { state.NextVisualMeshScanTime = Time.unscaledTime + 2f; } } else { state.VisualMeshesInitialized = false; } } private static int GetNpcRendererSignature(Renderer[] renderers) { int num = ((renderers != null) ? renderers.Length : 0); if (renderers == null) { return num; } foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null) { num ^= ((Object)val).GetInstanceID() * 397; } } return num; } private static void ScheduleNpcVisualScanRetry(NpcLimbState state) { state.VisualScanFailureCount = Math.Min(state.VisualScanFailureCount + 1, 3); float num = ((state.VisualScanFailureCount == 1) ? 0.5f : ((state.VisualScanFailureCount == 2) ? 2f : 15f)); state.PendingVisualRenderers = null; state.NextVisualRendererIndex = 0; state.PendingVisualBonesRefresh = false; state.VisualMeshesInitialized = true; state.NextVisualMeshScanTime = Time.unscaledTime + num; } private static void ScheduleNpcVisualMeshRetry(NpcLimbState state, Renderer renderer, bool rescan) { if (state != null && !((Object)(object)renderer == (Object)null)) { int value; int num = ((!state.VisualMeshFailureCounts.TryGetValue(renderer, out value)) ? 1 : Math.Min(value + 1, 3)); state.VisualMeshFailureCounts[renderer] = num; float num2 = Time.unscaledTime + num switch { 2 => 2f, 1 => 0.5f, _ => 15f, }; state.VisualMeshRetryTimes[renderer] = num2; if (num >= 3) { RestoreNpcPendingRendererState(state, renderer); } if (rescan && (state.NextVisualMeshScanTime <= 0f || num2 < state.NextVisualMeshScanTime)) { state.NextVisualMeshScanTime = num2; } } } private static bool TryReadNpcReadableMeshData(Mesh mesh, uint[] rendererBoneMasks, out NpcVertexWeights[] vertexWeights, out int[][] triangles) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) vertexWeights = null; triangles = null; try { Il2CppStructArray boneWeights = mesh.boneWeights; if (boneWeights == null || ((Il2CppArrayBase)(object)boneWeights).Length != mesh.vertexCount) { return false; } vertexWeights = new NpcVertexWeights[((Il2CppArrayBase)(object)boneWeights).Length]; for (int i = 0; i < ((Il2CppArrayBase)(object)boneWeights).Length; i++) { BoneWeight val = ((Il2CppArrayBase)(object)boneWeights)[i]; vertexWeights[i] = new NpcVertexWeights { Bone0 = GetNpcRendererBoneMask(rendererBoneMasks, ((BoneWeight)(ref val)).boneIndex0), Bone1 = GetNpcRendererBoneMask(rendererBoneMasks, ((BoneWeight)(ref val)).boneIndex1), Bone2 = GetNpcRendererBoneMask(rendererBoneMasks, ((BoneWeight)(ref val)).boneIndex2), Bone3 = GetNpcRendererBoneMask(rendererBoneMasks, ((BoneWeight)(ref val)).boneIndex3), Weight0 = ((BoneWeight)(ref val)).weight0, Weight1 = ((BoneWeight)(ref val)).weight1, Weight2 = ((BoneWeight)(ref val)).weight2, Weight3 = ((BoneWeight)(ref val)).weight3 }; } triangles = new int[mesh.subMeshCount][]; for (int j = 0; j < mesh.subMeshCount; j++) { Il2CppStructArray triangles2 = mesh.GetTriangles(j); triangles[j] = new int[((Il2CppArrayBase)(object)triangles2).Length]; for (int k = 0; k < ((Il2CppArrayBase)(object)triangles2).Length; k++) { triangles[j][k] = ((Il2CppArrayBase)(object)triangles2)[k]; } } return true; } catch { vertexWeights = null; triangles = null; return false; } } private static NpcVisualMeshState FindNpcVisualMeshState(NpcLimbState state, SkinnedMeshRenderer renderer) { for (int i = 0; i < state.VisualMeshes.Count; i++) { NpcVisualMeshState npcVisualMeshState = state.VisualMeshes[i]; if ((Object)(object)npcVisualMeshState.Renderer == (Object)(object)renderer) { return npcVisualMeshState; } } return null; } private static void RemoveNpcVisualMeshesForRenderer(NpcLimbState state, SkinnedMeshRenderer renderer) { for (int num = state.VisualMeshes.Count - 1; num >= 0; num--) { if (!((Object)(object)state.VisualMeshes[num].Renderer != (Object)(object)renderer)) { ReleaseNpcVisualMesh(state.VisualMeshes[num]); state.VisualMeshes.RemoveAt(num); } } } private static bool AreNpcBoneMasksEqual(uint[] first, uint[] second) { if (first == null || second == null || first.Length != second.Length) { return false; } for (int i = 0; i < first.Length; i++) { if (first[i] != second[i]) { return false; } } return true; } private static int CountNpcMappedBones(uint[] masks) { if (masks == null) { return 0; } int num = 0; for (int i = 0; i < masks.Length; i++) { if (masks[i] != 0) { num++; } } return num; } private static uint[] BuildNpcRendererBoneMasks(NpcLimbState state, Transform[] rendererBones) { uint[] array = new uint[rendererBones.Length]; for (int i = 0; i < rendererBones.Length; i++) { Transform val = rendererBones[i]; if ((Object)(object)val == (Object)null) { continue; } int num = int.MaxValue; int num2 = -1; for (int j = 0; j < DamageBones.Length; j++) { if (!state.VisualBones.TryGetValue(DamageBones[j], out var value)) { continue; } for (int k = 0; k < value.Count; k++) { Transform val2 = value[k]; if (!((Object)(object)val2 == (Object)null) && IsSameOrDescendant(val, val2)) { int npcHierarchyDistance = GetNpcHierarchyDistance(val, val2); if (npcHierarchyDistance < num) { num = npcHierarchyDistance; num2 = j; } } } } if (num2 >= 0) { array[i] = (uint)(1 << num2); } } return array; } private static uint GetNpcRendererBoneMask(uint[] masks, int index) { return (index >= 0 && index < masks.Length) ? masks[index] : 0u; } private static bool IsNpcVertexHidden(NpcVisualMeshState meshState, int vertex, uint goneMask) { if (vertex < 0 || vertex >= meshState.VertexWeights.Length) { return false; } NpcVertexWeights npcVertexWeights = meshState.VertexWeights[vertex]; float num = 0f; if ((npcVertexWeights.Bone0 & goneMask) != 0) { num += npcVertexWeights.Weight0; } if ((npcVertexWeights.Bone1 & goneMask) != 0) { num += npcVertexWeights.Weight1; } if ((npcVertexWeights.Bone2 & goneMask) != 0) { num += npcVertexWeights.Weight2; } if ((npcVertexWeights.Bone3 & goneMask) != 0) { num += npcVertexWeights.Weight3; } return num > 0.01f; } private static void ReleaseNpcVisualMeshes(NpcLimbState state) { if (state == null) { return; } for (int i = 0; i < state.VisualMeshes.Count; i++) { try { ReleaseNpcVisualMesh(state.VisualMeshes[i]); } catch { } } state.VisualMeshes.Clear(); state.VisualMeshRetryTimes.Clear(); state.VisualMeshFailureCounts.Clear(); state.PendingVisualRenderers = null; state.NextVisualRendererIndex = 0; state.PendingVisualBonesRefresh = false; state.VisualMeshScanPassCount = 0; state.VisualScanFailureCount = 0; state.VisualRendererSignature = 0; state.NextVisualRendererCheckTime = 0f; state.NextDeferredProxyBakeTime = 0f; RestoreNpcBakedAnimationStates(state); state.VisualMeshesInitialized = false; state.NextVisualMeshScanTime = 0f; } private static void ReleaseNpcVisualMesh(NpcVisualMeshState meshState) { if (meshState == null) { return; } bool flag = RestoreNpcBakedRenderer(meshState); if ((Object)(object)meshState.Renderer != (Object)null && (Object)(object)meshState.OriginalMesh != (Object)null && (Object)(object)meshState.Renderer.sharedMesh == (Object)(object)meshState.RuntimeMesh) { meshState.Renderer.sharedMesh = meshState.OriginalMesh; } if (!flag && meshState.UsesBakedProxy && (Object)(object)meshState.ProxyObject != (Object)null) { if (!meshState.ProxyLodRestorePending) { meshState.ProxyLodRestorePending = true; MelonCoroutines.Start(RetryNpcLodRestoreAndRelease(meshState)); } return; } if ((Object)(object)meshState.ProxyObject != (Object)null) { Object.Destroy((Object)(object)meshState.ProxyObject); } if ((Object)(object)meshState.RuntimeMesh != (Object)null) { Object.Destroy((Object)(object)meshState.RuntimeMesh); } if ((Object)(object)meshState.StagingMesh != (Object)null && (Object)(object)meshState.StagingMesh != (Object)(object)meshState.RuntimeMesh) { Object.Destroy((Object)(object)meshState.StagingMesh); } } private static IEnumerator RetryNpcLodRestoreAndRelease(NpcVisualMeshState meshState) { float nextRetryTime = 0f; float retryDelay = 0.25f; float deadline = Time.unscaledTime + 15f; while ((Object)(object)meshState.ProxyObject != (Object)null && (Object)(object)meshState.ProxyRenderer != (Object)null && (Object)(object)meshState.Renderer != (Object)null && meshState.ProxyLodReplaced && Time.unscaledTime < deadline) { yield return null; DeadPieceMod mod = Instance; NpcLimbState owner = meshState.OwnerState; PuppetMaster puppetMaster = owner?.PuppetMaster; if (mod != null && (Object)(object)puppetMaster != (Object)null && mod._npcLimbStates.TryGetValue(puppetMaster, out var current) && current != owner) { deadline = Mathf.Min(deadline, Time.unscaledTime + 1f); } if (!(Time.unscaledTime < nextRetryTime)) { nextRetryTime = Time.unscaledTime + retryDelay; retryDelay = Mathf.Min(retryDelay * 2f, 2f); if (TryRestoreNpcBakedLod(meshState)) { meshState.ProxyLodGroup = null; meshState.ProxyLodReplaced = false; meshState.ProxyLodBindingRequired = false; break; } } } if (meshState.ProxyLodReplaced) { if ((Object)(object)meshState.ProxyObject != (Object)null) { meshState.ProxyObject.SetActive(false); } if ((Object)(object)meshState.ProxyRenderer != (Object)null) { ((Renderer)meshState.ProxyRenderer).enabled = false; } meshState.ProxyLodGroup = null; meshState.ProxyLodReplaced = false; meshState.ProxyLodBindingRequired = false; } bool replacementNeedsRendererHidden = false; DeadPieceMod instance = Instance; NpcLimbState previousOwner = meshState.OwnerState; PuppetMaster previousPuppet = previousOwner?.PuppetMaster; if (instance != null && (Object)(object)previousPuppet != (Object)null && instance._npcLimbStates.TryGetValue(previousPuppet, out var replacement) && replacement != previousOwner && replacement.GoneMask != 0) { replacementNeedsRendererHidden = true; } if (!replacementNeedsRendererHidden && meshState.HasRendererForceState && (Object)(object)meshState.Renderer != (Object)null) { ((Renderer)meshState.Renderer).forceRenderingOff = meshState.RendererForceState; } meshState.HasRendererForceState = false; meshState.ProxyLodRestorePending = false; if ((Object)(object)meshState.ProxyObject != (Object)null) { Object.Destroy((Object)(object)meshState.ProxyObject); } if ((Object)(object)meshState.RuntimeMesh != (Object)null) { Object.Destroy((Object)(object)meshState.RuntimeMesh); } if ((Object)(object)meshState.StagingMesh != (Object)null && (Object)(object)meshState.StagingMesh != (Object)(object)meshState.RuntimeMesh) { Object.Destroy((Object)(object)meshState.StagingMesh); } } private void ProcessLocalRipGrabs() { RigManager rigManager = Player.RigManager; if (NetworkInfo.HasServer && NetworkInfo.IsHost) { if (IsSessionEnabled()) { RecordObservedPlayerGrabs(); RecordObservedCrushContacts(); } ProcessPendingHostInteractions(); } if (IsSessionEnabled()) { PruneInteractionCooldowns(); } if (!IsSessionEnabled() || (Object)(object)rigManager == (Object)null || (Object)(object)rigManager.health == (Object)null || !rigManager.health.alive || (Object)(object)rigManager.avatar == (Object)null) { ResetLocalRipPullState(); return; } ProcessLocalRipHand(rigManager, Player.LeftHand, rightHand: false); ProcessLocalRipHand(rigManager, Player.RightHand, rightHand: true); ProcessLocalCrushOverlaps(rigManager); } internal void OnHandJointBreak(Hand hand) { RigManager rigManager = Player.RigManager; if (!IsSessionEnabled() || (Object)(object)hand == (Object)null || (Object)(object)rigManager == (Object)null || (Object)(object)hand.manager != (Object)(object)rigManager || IsLocalHandUnavailable(hand) || (Object)(object)rigManager.health == (Object)null || !rigManager.health.alive || (Object)(object)rigManager.avatar == (Object)null) { return; } bool flag = (Object)(object)hand == (Object)(object)Player.RightHand; HandReciever attachedReceiver = hand.AttachedReceiver; if (!((Object)(object)attachedReceiver == (Object)null) && !(flag ? _rightRipPullConsumed : _leftRipPullConsumed)) { if ((Object)(object)(flag ? _rightRipPullReceiver : _leftRipPullReceiver) != (Object)(object)attachedReceiver) { SetRipPullState(flag, attachedReceiver, -1f); } SetRipPullConsumed(flag, consumed: true); byte detail = (byte)(2 | (flag ? 1 : 0)); TryRipHeldLimb(rigManager, hand, detail); } } private void ProcessLocalRipHand(RigManager attacker, Hand hand, bool rightHand) { if (IsLocalHandUnavailable(hand)) { SetRipPullState(rightHand, null, -1f); SetRipPullConsumed(rightHand, consumed: false); } else if (HasSustainedRipPull(attacker, hand, rightHand)) { byte detail = (byte)(2 | (rightHand ? 1 : 0)); TryRipHeldLimb(attacker, hand, detail); } } private bool HasSustainedRipPull(RigManager attacker, Hand hand, bool rightHand) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) HandReciever val = ((hand != null) ? hand.AttachedReceiver : null); if ((Object)(object)val == (Object)null) { SetRipPullState(rightHand, null, -1f); return false; } float num; try { Vector3 position = hand.GetControllerWristTransform(true).position; num = Vector3.Distance(position, GetHandPosition(hand)); } catch { SetRipPullState(rightHand, val, -1f); return false; } float num2 = Mathf.Clamp(GetAvatarHeight(attacker) * 0.08f, 0.1f, 0.4f); HandReciever val2 = (rightHand ? _rightRipPullReceiver : _leftRipPullReceiver); float num3 = (rightHand ? _rightRipPullStart : _leftRipPullStart); if ((Object)(object)val2 != (Object)(object)val) { SetRipPullState(rightHand, val, (num >= num2) ? Time.unscaledTime : (-1f)); SetRipPullConsumed(rightHand, consumed: false); return false; } if (num < num2) { SetRipPullState(rightHand, val, -1f); return false; } if (num3 < 0f) { SetRipPullState(rightHand, val, Time.unscaledTime); return false; } if (Time.unscaledTime - num3 < 0.15f) { return false; } return true; } private void SetRipPullState(bool rightHand, HandReciever receiver, float startedAt) { if (rightHand) { _rightRipPullReceiver = receiver; _rightRipPullStart = startedAt; } else { _leftRipPullReceiver = receiver; _leftRipPullStart = startedAt; } } private void ResetLocalRipPullState() { _leftRipPullReceiver = null; _rightRipPullReceiver = null; _leftRipPullStart = -1f; _rightRipPullStart = -1f; _leftRipPullConsumed = false; _rightRipPullConsumed = false; } private void SetRipPullConsumed(bool rightHand, bool consumed) { if (rightHand) { _rightRipPullConsumed = consumed; } else { _leftRipPullConsumed = consumed; } } private void TryRipHeldLimb(RigManager attacker, Hand hand, byte detail) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) if (TryResolveGrabbedPlayerLimb(hand, out var victim, out var bone)) { if (NetworkInfo.HasServer && PlayerIDManager.LocalID != null && CanRipLimb(attacker, victim, bone)) { if (NetworkInfo.IsHost) { RecordObservedPlayerGrab(PlayerIDManager.LocalSmallID, hand, (Object)(object)hand == (Object)(object)Player.RightHand); } TrySendRipInteraction(hand, victim, bone, detail); } } else { if (!TryResolveGrabbedNpcLimb(hand, out var puppetMaster, out bone) || IsNpcBoneGone(puppetMaster, bone)) { return; } float dominance = GetDominance(GetAvatarStrength(attacker), GetNpcStrength(puppetMaster)); if (dominance <= 0f || !BoneToIndexMap.TryGetValue(bone, out var value)) { return; } Transform val = (((Object)(object)puppetMaster.targetAnimator != (Object)null) ? puppetMaster.targetAnimator.GetBoneTransform(bone) : null); Vector3 point = (((Object)(object)val != (Object)null) ? val.position : GetHandPosition(hand)); byte sourcePlayerId = ((PlayerIDManager.LocalID != null) ? PlayerIDManager.LocalSmallID : byte.MaxValue); ushort entityId; bool flag = TryGetNpcEntityId(puppetMaster, out entityId); ulong key = (flag ? ComposeNpcInteractionKey(1, sourcePlayerId, entityId, (byte)value) : (0x2000000000000000L | ((ulong)(byte)value << 32) | (uint)((Object)puppetMaster).GetInstanceID())); if (!TryUseInteractionCooldown(_localInteractionCooldowns, key, 0.8f)) { return; } if (!NetworkInfo.HasServer) { if (ResolveDominance(dominance)) { ApplyNpcRip(puppetMaster, bone, point); } } else if (PlayerIDManager.LocalID != null) { if (flag) { NetworkSync.SendNpcInteraction(1, entityId, (byte)value, detail, 0f, point); } else if (NetworkInfo.IsHost && ResolveDominance(dominance)) { ApplyNpcRip(puppetMaster, bone, point); } } } } private void RecordObservedPlayerGrabs() { List list = CollectKnownPlayerRigs(); for (int i = 0; i < list.Count; i++) { RigManager val = list[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.physicsRig == (Object)null) && TryGetPlayerIdForRig(val, out var playerId)) { RecordObservedPlayerGrab(playerId, IsLeftArmGone(val) ? null : val.physicsRig.leftHand, rightHand: false); RecordObservedPlayerGrab(playerId, IsRightArmGone(val) ? null : val.physicsRig.rightHand, rightHand: true); } } } private void RecordObservedPlayerGrab(byte sourcePlayerId, Hand hand, bool rightHand) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) ushort key = ComposeGrabEvidenceKey(sourcePlayerId, rightHand); HandReciever val = ((hand != null) ? hand.AttachedReceiver : null); int num = (((Object)(object)val != (Object)null) ? ((Object)val).GetInstanceID() : 0); PuppetMaster puppetMaster; ushort entityId; if (TryResolveGrabbedPlayerLimb(hand, out var victim, out var bone)) { if (TryGetPlayerIdForRig(victim, out var playerId)) { _recentGrabEvidence[key] = new RecentGrabEvidence { TargetPlayerId = playerId, Bone = bone, Time = Time.unscaledTime, Active = true, ReceiverId = num }; _recentNpcGrabEvidence.Remove(key); } } else if (TryResolveGrabbedNpcLimb(hand, out puppetMaster, out bone) && TryGetNpcEntityId(puppetMaster, out entityId)) { RecentNpcGrabEvidence value; bool consumed = _recentNpcGrabEvidence.TryGetValue(key, out value) && value.Active && value.ReceiverId == num && value.EntityId == entityId && value.Bone == bone && value.Consumed; _recentGrabEvidence.Remove(key); _recentNpcGrabEvidence[key] = new RecentNpcGrabEvidence { EntityId = entityId, Bone = bone, Time = Time.unscaledTime, Active = true, Consumed = consumed, ReceiverId = num }; } else { if (_recentGrabEvidence.TryGetValue(key, out var value2) && value2.Active) { value2.Active = false; _recentGrabEvidence[key] = value2; } if (_recentNpcGrabEvidence.TryGetValue(key, out var value3) && value3.Active) { value3.Active = false; _recentNpcGrabEvidence[key] = value3; } } } private void RecordObservedCrushContacts() { if (Time.unscaledTime < _nextHostCrushObservationTime) { return; } _nextHostCrushObservationTime = Time.unscaledTime + 0.05f; List list = CollectKnownPlayerRigs(); for (int i = 0; i < list.Count; i++) { RigManager val = list[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.physicsRig == (Object)null) && !((Object)(object)val.health == (Object)null) && val.health.alive && TryGetPlayerIdForRig(val, out var playerId)) { RecordObservedCrushFootContacts(val, playerId, 1); RecordObservedCrushFootContacts(val, playerId, 2); RecordObservedCrushFootContacts(val, playerId, 0); } } } private void RecordObservedCrushFootContacts(RigManager source, byte sourcePlayerId, byte detail) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_020f: 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) if (!TryGetCrushFootCollider(source, detail, out var collider)) { return; } Bounds bounds = collider.bounds; float avatarHeight = GetAvatarHeight(source); float num = Mathf.Clamp(avatarHeight * 0.06f, 0.08f, 0.35f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y - num * 0.5f + 0.01f, ((Bounds)(ref bounds)).center.z); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.x * 1.15f), num * 0.5f + 0.02f, Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.z * 1.15f)); int num2; try { num2 = Physics.OverlapBoxNonAlloc(val, val2, CrushOverlapBuffer, Quaternion.identity, -1, (QueryTriggerInteraction)1); } catch { return; } for (int i = 0; i < num2; i++) { Collider val3 = ((Il2CppArrayBase)(object)CrushOverlapBuffer)[i]; if ((Object)(object)val3 == (Object)null || (Object)(object)val3 == (Object)(object)collider || ((Object)(object)((Component)source).transform != (Object)null && ((Component)val3).transform.IsChildOf(((Component)source).transform)) || ((Object)(object)source.physicsRig != (Object)null && ((Component)val3).transform.IsChildOf(((Component)source.physicsRig).transform)) || !TryGetCrushContactPoint(collider, val3, avatarHeight, out var _)) { continue; } RigManager val4 = ResolvePlayerRigFromCollider(val3); PuppetMaster puppetMaster; HumanBodyBones bone2; ushort entityId; if ((Object)(object)val4 != (Object)null) { if ((Object)(object)val4 != (Object)(object)source && TryGetPlayerIdForRig(val4, out var playerId) && TryResolvePlayerCrushContactBone(val4, val3, out var bone) && !IsBoneEffectivelyGone(val4, bone)) { ulong key = ComposeInteractionKey(1, sourcePlayerId, playerId, detail); _recentPlayerCrushEvidence[key] = new RecentCrushEvidence { Time = Time.unscaledTime }; } } else if (TryResolveNpcContact(val3, out puppetMaster, out bone2) && !IsNpcBoneGone(puppetMaster, bone2) && TryGetNpcEntityId(puppetMaster, out entityId)) { ulong key2 = ComposeNpcInteractionKey(2, sourcePlayerId, entityId, detail); _recentNpcCrushEvidence[key2] = new RecentCrushEvidence { Time = Time.unscaledTime }; } } } private bool CanRipLimb(RigManager attacker, RigManager victim, HumanBodyBones bone) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)attacker == (Object)null || (Object)(object)victim == (Object)null || (Object)(object)attacker == (Object)(object)victim || (Object)(object)victim.health == (Object)null || !victim.health.alive || (Object)(object)attacker.avatar == (Object)null || (Object)(object)victim.avatar == (Object)null || IsBoneEffectivelyGone(victim, bone) || !IsLimbDestructionAllowed(victim) || (IsRigLimbDamageBlocked(victim) && !IsRemotePlayerRig(victim))) { return false; } return GetRipDominance(attacker, victim) > 0f; } private float GetRipDominance(RigManager attacker, RigManager victim) { return GetDominance(GetInteractionStrength(attacker), GetInteractionStrength(victim)); } private static float GetDominance(float attackerValue, float victimValue) { if (!IsFinitePositive(attackerValue) || !IsFinitePositive(victimValue)) { return 0f; } float num = attackerValue / Mathf.Max(0.05f, victimValue); float num2 = Mathf.Clamp01((num - 1f) / 2f); return num2 * num2 * (3f - 2f * num2); } private static bool ResolveDominance(float dominance) { return dominance >= 1f || (dominance > 0f && Random.value <= dominance); } private bool TrySendRipInteraction(Hand hand, RigManager victim, HumanBodyBones bone, byte detail) { //IL_0006: 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_007a: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (!BoneToIndexMap.TryGetValue(bone, out var value) || !TryGetPlayerIdForRig(victim, out var playerId)) { return false; } byte localSmallID = PlayerIDManager.LocalSmallID; ulong key = ComposeInteractionKey(0, localSmallID, playerId, (byte)value); if (!TryUseInteractionCooldown(_localInteractionCooldowns, key, 0.8f)) { return false; } Transform cachedBoneTransform = GetCachedBoneTransform(victim, bone); Vector3 point = (((Object)(object)cachedBoneTransform != (Object)null) ? cachedBoneTransform.position : GetHandPosition(hand)); NetworkSync.SendPlayerInteraction(0, playerId, (byte)value, detail, point); return true; } private bool TryResolveGrabbedPlayerLimb(Hand hand, out RigManager victim, out HumanBodyBones bone) { victim = null; bone = (HumanBodyBones)55; if ((Object)(object)hand == (Object)null || (Object)(object)hand.AttachedReceiver == (Object)null) { return false; } HandReciever attachedReceiver = hand.AttachedReceiver; IGrippable val = null; Grip val2 = null; Rigidbody rigidbody = null; try { val = attachedReceiver.Host; val2 = ((Il2CppObjectBase)attachedReceiver).TryCast(); if ((Object)(object)val2 == (Object)null && val != null) { val2 = val.GetGrip(); } if (val != null) { rigidbody = val.Rb; } } catch { } List list = CollectKnownPlayerRigs(); for (int i = 0; i < list.Count; i++) { RigManager val3 = list[i]; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)hand.manager)) { if (TryMapPlayerLimb(val3, val2, rigidbody, out bone)) { victim = val3; return true; } if (TryMapPlayerLimbByHierarchy(val3, attachedReceiver, val2, rigidbody, out bone)) { victim = val3; return true; } } } return false; } private bool TryMapPlayerLimbByHierarchy(RigManager rig, HandReciever receiver, Grip grip, Rigidbody rigidbody, out HumanBodyBones bone) { bone = (HumanBodyBones)55; Transform val = (((Object)(object)receiver != (Object)null) ? ((Component)receiver).transform : (((Object)(object)grip != (Object)null) ? ((Component)grip).transform : ((rigidbody != null) ? ((Component)rigidbody).transform : null))); if ((Object)(object)rig == (Object)null || (Object)(object)val == (Object)null || (!val.IsChildOf(((Component)rig).transform) && (!((Object)(object)rig.physicsRig != (Object)null) || !val.IsChildOf(((Component)rig.physicsRig).transform)))) { return false; } Transform val2 = val; int num = 0; while ((Object)(object)val2 != (Object)null && num < 16) { try { Grip component = ((Component)val2).GetComponent(); Rigidbody component2 = ((Component)val2).GetComponent(); if (TryMapPlayerLimb(rig, component, component2, out bone)) { return true; } } catch { } if ((Object)(object)val2 == (Object)(object)((Component)rig).transform || ((Object)(object)rig.physicsRig != (Object)null && (Object)(object)val2 == (Object)(object)((Component)rig.physicsRig).transform)) { break; } val2 = val2.parent; num++; } return false; } private List CollectKnownPlayerRigs() { List list = new List(); AddKnownRig(list, Player.RigManager); try { RigRefs val = default(RigRefs); foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null && PlayerRepUtilities.TryGetReferences(playerID.SmallID, ref val)) { AddKnownRig(list, (val != null) ? val.RigManager : null); } } } catch { } return list; } private static void AddKnownRig(List rigs, RigManager rig) { if ((Object)(object)rig == (Object)null) { return; } for (int i = 0; i < rigs.Count; i++) { if ((Object)(object)rigs[i] == (Object)(object)rig) { return; } } rigs.Add(rig); } private static bool TryMapPlayerLimb(RigManager rig, Grip grip, Rigidbody rigidbody, out HumanBodyBones bone) { bone = (HumanBodyBones)55; PhysicsRig val = (((Object)(object)rig != (Object)null) ? rig.physicsRig : null); if ((Object)(object)val == (Object)null) { return false; } PhysTorso torso = val.torso; if ((Object)(object)torso != (Object)null) { if (GripMatches(grip, torso.gHead) || GripMatches(grip, (Grip)(object)torso.gNeck) || RigidbodyMatches(rigidbody, torso.rbHead) || RigidbodyMatches(rigidbody, torso.rbNeck)) { bone = (HumanBodyBones)10; return true; } if (GripMatches(grip, torso.gChest) || GripMatches(grip, torso.gSpine) || RigidbodyMatches(rigidbody, torso.rbChest) || RigidbodyMatches(rigidbody, torso.rbSpine)) { bone = (HumanBodyBones)7; return true; } if (GripMatches(grip, torso.gPelvis) || RigidbodyMatches(rigidbody, torso.rbPelvis)) { bone = (HumanBodyBones)0; return true; } } PhysHand arm = (((Object)(object)val.leftHand != (Object)null) ? val.leftHand.physHand : null); if (TryMapArm(arm, left: true, grip, rigidbody, out bone)) { return true; } PhysHand arm2 = (((Object)(object)val.rightHand != (Object)null) ? val.rightHand.physHand : null); if (TryMapArm(arm2, left: false, grip, rigidbody, out bone)) { return true; } if (TryMapLeg(val.legLf, left: true, rigidbody, out bone)) { return true; } return TryMapLeg(val.legRt, left: false, rigidbody, out bone); } private static bool TryMapArm(PhysHand arm, bool left, Grip grip, Rigidbody rigidbody, out HumanBodyBones bone) { bone = (HumanBodyBones)55; if ((Object)(object)arm == (Object)null) { return false; } if (GripMatches(grip, (Grip)(object)arm.gShoulder) || RigidbodyMatches(rigidbody, arm.rbUpper)) { bone = (HumanBodyBones)(left ? 13 : 14); return true; } if (GripMatches(grip, (Grip)(object)arm.gElbow) || RigidbodyMatches(rigidbody, arm.rbLower)) { bone = (HumanBodyBones)(left ? 15 : 16); return true; } if (RigidbodyMatches(rigidbody, arm.rbHand)) { bone = (HumanBodyBones)(left ? 17 : 18); return true; } return false; } private static bool TryMapLeg(PhysLimb leg, bool left, Rigidbody rigidbody, out HumanBodyBones bone) { bone = (HumanBodyBones)55; if ((Object)(object)leg == (Object)null) { return false; } if (RigidbodyMatches(rigidbody, leg.rbUpper)) { bone = (HumanBodyBones)(left ? 1 : 2); return true; } if (RigidbodyMatches(rigidbody, leg.rbLower)) { bone = (HumanBodyBones)(left ? 3 : 4); return true; } if (RigidbodyMatches(rigidbody, leg.rbEnd)) { bone = (HumanBodyBones)(left ? 5 : 6); return true; } return false; } private static bool GripMatches(Grip value, Grip expected) { return (Object)(object)value != (Object)null && (Object)(object)expected != (Object)null && (Object)(object)value == (Object)(object)expected; } private static bool RigidbodyMatches(Rigidbody value, Rigidbody expected) { return (Object)(object)value != (Object)null && (Object)(object)expected != (Object)null && (Object)(object)value == (Object)(object)expected; } internal void OnGrounderCollision(PhysGrounder grounder, Collision collision) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) RigManager rigManager = Player.RigManager; if (!IsSessionEnabled() || (Object)(object)grounder == (Object)null || collision == null || (Object)(object)rigManager == (Object)null || (Object)(object)rigManager.physicsRig == (Object)null || (Object)(object)grounder.physRig != (Object)(object)rigManager.physicsRig || (Object)(object)rigManager.health == (Object)null || !rigManager.health.alive || (Object)(object)rigManager.avatar == (Object)null) { return; } PhysicsRig physicsRig = rigManager.physicsRig; for (int i = 0; i < collision.contactCount; i++) { ContactPoint contact = collision.GetContact(i); Collider footCollider; Collider val; if (TryGetCrushFoot(physicsRig, ((ContactPoint)(ref contact)).thisCollider, out var detail)) { footCollider = ((ContactPoint)(ref contact)).thisCollider; val = ((ContactPoint)(ref contact)).otherCollider; } else { if (!TryGetCrushFoot(physicsRig, ((ContactPoint)(ref contact)).otherCollider, out detail)) { continue; } footCollider = ((ContactPoint)(ref contact)).otherCollider; val = ((ContactPoint)(ref contact)).thisCollider; } if (!IsStepContact(footCollider, val, contact)) { continue; } RigManager val2 = ResolvePlayerRigFromCollider(val); PuppetMaster puppetMaster; HumanBodyBones bone; if ((Object)(object)val2 != (Object)null) { if (TryProcessPlayerCrush(rigManager, val2, val, detail, ((ContactPoint)(ref contact)).point)) { break; } } else if (TryResolveNpcContact(val, out puppetMaster, out bone) && !IsNpcBoneGone(puppetMaster, bone) && TryProcessNpcCrush(rigManager, puppetMaster, detail, ((ContactPoint)(ref contact)).point)) { break; } } } private void ProcessLocalCrushOverlaps(RigManager attacker) { if (Time.unscaledTime < _nextCrushOverlapTime || (Object)(object)((attacker != null) ? attacker.physicsRig : null) == (Object)null) { return; } _nextCrushOverlapTime = Time.unscaledTime + 0.1f; PhysicsRig physicsRig = attacker.physicsRig; PhysLimb legLf = physicsRig.legLf; if (!TryProcessCrushFootOverlap(attacker, (Collider)(object)((legLf != null) ? legLf.endCol : null), 1)) { PhysLimb legRt = physicsRig.legRt; if (!TryProcessCrushFootOverlap(attacker, (Collider)(object)((legRt != null) ? legRt.endCol : null), 2) && !TryProcessCrushFootOverlap(attacker, (Collider)(object)physicsRig._football, 0) && !TryProcessPlayerCrushGeometry(attacker, 1) && !TryProcessPlayerCrushGeometry(attacker, 2)) { TryProcessPlayerCrushGeometry(attacker, 0); } } } private bool TryProcessCrushFootOverlap(RigManager attacker, Collider footCollider, byte detail) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)footCollider == (Object)null || !footCollider.enabled || (detail == 1 && IsLeftLegGone(attacker)) || (detail == 2 && IsRightLegGone(attacker)) || (detail == 0 && IsBothLegsGone(attacker))) { return false; } Bounds bounds = footCollider.bounds; float num = Mathf.Clamp(GetAvatarHeight(attacker) * 0.06f, 0.08f, 0.35f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y - num * 0.5f + 0.01f, ((Bounds)(ref bounds)).center.z); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.x * 1.15f), num * 0.5f + 0.02f, Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.z * 1.15f)); int num2; try { num2 = Physics.OverlapBoxNonAlloc(val, val2, CrushOverlapBuffer, Quaternion.identity, -1, (QueryTriggerInteraction)1); } catch { return false; } float avatarHeight = GetAvatarHeight(attacker); for (int i = 0; i < num2; i++) { Collider val3 = ((Il2CppArrayBase)(object)CrushOverlapBuffer)[i]; if ((Object)(object)val3 == (Object)null || (Object)(object)val3 == (Object)(object)footCollider || ((Object)(object)((Component)attacker).transform != (Object)null && ((Component)val3).transform.IsChildOf(((Component)attacker).transform)) || ((Object)(object)attacker.physicsRig != (Object)null && ((Component)val3).transform.IsChildOf(((Component)attacker.physicsRig).transform)) || !TryGetCrushContactPoint(footCollider, val3, avatarHeight, out var point)) { continue; } RigManager val4 = ResolvePlayerRigFromCollider(val3); PuppetMaster puppetMaster; HumanBodyBones bone; if ((Object)(object)val4 != (Object)null) { if (TryProcessPlayerCrush(attacker, val4, val3, detail, point)) { return true; } } else if (TryResolveNpcContact(val3, out puppetMaster, out bone) && !IsNpcBoneGone(puppetMaster, bone) && TryProcessNpcCrush(attacker, puppetMaster, detail, point)) { return true; } } return false; } private static bool TryGetCrushContactPoint(Collider footCollider, Collider targetCollider, float attackerHeight, out Vector3 point) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: 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_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; if ((Object)(object)footCollider == (Object)null || (Object)(object)targetCollider == (Object)null) { return false; } Bounds bounds = footCollider.bounds; Bounds bounds2 = targetCollider.bounds; float num = Mathf.Clamp(attackerHeight * 0.01f, 0.01f, 0.06f); if (((Bounds)(ref bounds2)).max.x < ((Bounds)(ref bounds)).min.x - num || ((Bounds)(ref bounds2)).min.x > ((Bounds)(ref bounds)).max.x + num || ((Bounds)(ref bounds2)).max.z < ((Bounds)(ref bounds)).min.z - num || ((Bounds)(ref bounds2)).min.z > ((Bounds)(ref bounds)).max.z + num || ((Bounds)(ref bounds2)).center.y >= ((Bounds)(ref bounds)).center.y) { return false; } float num2 = Mathf.Clamp(attackerHeight * 0.025f, 0.025f, 0.12f); float num3 = Mathf.Clamp(Mathf.Max(((Bounds)(ref bounds)).size.y * 0.75f, attackerHeight * 0.03f), 0.05f, 0.3f); float num4 = ((Bounds)(ref bounds)).min.y - ((Bounds)(ref bounds2)).max.y; if (num4 > num2 || num4 < 0f - num3) { return false; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Clamp(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds2)).min.x, ((Bounds)(ref bounds2)).max.x), ((Bounds)(ref bounds)).min.y, Mathf.Clamp(((Bounds)(ref bounds)).center.z, ((Bounds)(ref bounds2)).min.z, ((Bounds)(ref bounds2)).max.z)); point = targetCollider.ClosestPoint(val); float num5 = ((Bounds)(ref bounds)).min.y - point.y; return num5 <= num2 && num5 >= 0f - num3 && point.x >= ((Bounds)(ref bounds)).min.x - num && point.x <= ((Bounds)(ref bounds)).max.x + num && point.z >= ((Bounds)(ref bounds)).min.z - num && point.z <= ((Bounds)(ref bounds)).max.z + num && point.y <= ((Bounds)(ref bounds)).center.y; } private bool TryProcessPlayerCrush(RigManager attacker, RigManager victim, Collider targetCollider, byte detail, Vector3 point) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)victim == (Object)(object)attacker || !CanCrushPlayer(attacker, victim, detail) || !TryResolvePlayerCrushContactBone(victim, targetCollider, out var bone) || IsBoneEffectivelyGone(victim, bone)) { return false; } return TrySendPlayerCrush(attacker, victim, detail, point); } private bool TryProcessPlayerCrushGeometry(RigManager attacker, byte detail) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if (!TryGetFootPosition(attacker, detail, out var position, out var bottomY, out var horizontalExtents)) { return false; } Vector3 point = default(Vector3); ((Vector3)(ref point))..ctor(position.x, bottomY, position.z); float avatarHeight = GetAvatarHeight(attacker); List list = CollectKnownPlayerRigs(); Vector3 point2 = default(Vector3); for (int i = 0; i < list.Count; i++) { RigManager val = list[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)attacker) && CanCrushPlayer(attacker, val, detail) && TryGetClosestExistingDamageBone(val, point, out var position2, out var distance)) { ((Vector3)(ref point2))..ctor(position2.x, bottomY, position2.z); if (ValidateCrushContactGeometry(position, bottomY, horizontalExtents, position2, distance, avatarHeight, GetAvatarHeight(val), point2) && TrySendPlayerCrush(attacker, val, detail, point2)) { return true; } } } return false; } private bool TrySendPlayerCrush(RigManager attacker, RigManager victim, byte detail, Vector3 point) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || PlayerIDManager.LocalID == null || (Object)(object)victim == (Object)(object)attacker || !CanCrushPlayer(attacker, victim, detail) || !TryGetPlayerIdForRig(victim, out var playerId)) { return false; } byte localSmallID = PlayerIDManager.LocalSmallID; ulong key = ComposeInteractionKey(1, localSmallID, playerId, byte.MaxValue); if (!TryUseInteractionCooldown(_localInteractionCooldowns, key, 0.8f)) { return false; } NetworkSync.SendPlayerInteraction(1, playerId, byte.MaxValue, detail, point); return true; } private bool TryProcessNpcCrush(RigManager attacker, PuppetMaster npc, byte detail, Vector3 point) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (!CanCrushNpc(attacker, npc, detail)) { return false; } ushort entityId; bool flag = TryGetNpcEntityId(npc, out entityId); byte sourcePlayerId = ((PlayerIDManager.LocalID != null) ? PlayerIDManager.LocalSmallID : byte.MaxValue); ulong key = (flag ? ComposeNpcInteractionKey(2, sourcePlayerId, entityId, byte.MaxValue) : (0x4000000000000000uL | (ulong)(uint)((Object)npc).GetInstanceID())); if (!TryBeginCrushContact(key) || !TryUseInteractionCooldown(_localInteractionCooldowns, key, 0.3f)) { return false; } float npcCrushDominance = GetNpcCrushDominance(attacker, npc); if (!NetworkInfo.HasServer) { return ResolveDominance(npcCrushDominance) && ApplyNpcCrush(npc, point); } if (PlayerIDManager.LocalID == null) { return false; } if (flag) { NetworkSync.SendNpcInteraction(2, entityId, 0, detail, 0f, point); return true; } return NetworkInfo.IsHost && ResolveDominance(npcCrushDominance) && ApplyNpcCrush(npc, point); } private static bool TryGetCrushFoot(PhysicsRig physicsRig, Collider collider, out byte detail) { detail = byte.MaxValue; if ((Object)(object)physicsRig == (Object)null || (Object)(object)collider == (Object)null) { return false; } if ((Object)(object)physicsRig._football != (Object)null && (Object)(object)collider == (Object)(object)physicsRig._football) { detail = 0; return true; } if ((Object)(object)physicsRig.legLf != (Object)null && (Object)(object)physicsRig.legLf.endCol != (Object)null && (Object)(object)collider == (Object)(object)physicsRig.legLf.endCol) { detail = 1; return true; } if ((Object)(object)physicsRig.legRt != (Object)null && (Object)(object)physicsRig.legRt.endCol != (Object)null && (Object)(object)collider == (Object)(object)physicsRig.legRt.endCol) { detail = 2; return true; } return false; } private RigManager ResolvePlayerRigFromCollider(Collider collider) { if ((Object)(object)collider == (Object)null) { return null; } RigManager componentInParent = ((Component)collider).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && TryGetPlayerIdForRig(componentInParent, out var _)) { return componentInParent; } List list = CollectKnownPlayerRigs(); for (int i = 0; i < list.Count; i++) { RigManager val = list[i]; if ((Object)(object)val != (Object)null && (((Component)collider).transform.IsChildOf(((Component)val).transform) || ((Object)(object)val.physicsRig != (Object)null && ((Component)collider).transform.IsChildOf(((Component)val.physicsRig).transform)))) { return val; } } return null; } private bool CanCrushPlayer(RigManager attacker, RigManager victim, byte detail) { if ((Object)(object)attacker == (Object)null || (Object)(object)victim == (Object)null || (Object)(object)attacker == (Object)(object)victim || (Object)(object)attacker.avatar == (Object)null || (Object)(object)victim.avatar == (Object)null || (Object)(object)victim.health == (Object)null || !victim.health.alive || !IsLimbDestructionAllowed(victim) || (IsRigLimbDamageBlocked(victim) && !IsRemotePlayerRig(victim))) { return false; } if ((detail == 1 && IsLeftLegGone(attacker)) || (detail == 2 && IsRightLegGone(attacker)) || (detail == 0 && IsBothLegsGone(attacker))) { return false; } return GetCrushDominance(attacker, victim) > 0f; } private float GetCrushDominance(RigManager attacker, RigManager victim) { if ((Object)(object)((attacker != null) ? attacker.avatar : null) == (Object)null || (Object)(object)((victim != null) ? victim.avatar : null) == (Object)null) { return 0f; } return GetCrushDominance(GetInteractionHeight(attacker), GetInteractionHeight(victim), GetInteractionMass(attacker), GetInteractionMass(victim)); } private static float GetCrushDominance(float attackerHeight, float victimHeight, float attackerMass, float victimMass) { if (!IsFinitePositive(attackerHeight) || !IsFinitePositive(victimHeight) || !IsFinitePositive(attackerMass) || !IsFinitePositive(victimMass)) { return 0f; } return GetDominance(attackerHeight, victimHeight) * GetDominance(attackerMass, victimMass); } private bool TryResolvePlayerCrushContactBone(RigManager victim, Collider collider, out HumanBodyBones bone) { bone = (HumanBodyBones)55; if ((Object)(object)victim == (Object)null || (Object)(object)collider == (Object)null) { return false; } EnsureRigInitialized(victim); Rigidbody rigidbody = null; try { rigidbody = collider.attachedRigidbody; } catch { } if (TryMapPlayerLimb(victim, null, rigidbody, out bone)) { return true; } if ((Object)(object)victim.physicsRig != (Object)null && (Object)(object)victim.physicsRig._football != (Object)null && (Object)(object)collider == (Object)(object)victim.physicsRig._football) { bone = (HumanBodyBones)0; return true; } Dictionary value; return _colliderBoneMap.TryGetValue(victim, out value) && value.TryGetValue(collider, out bone) && (int)bone != 55; } private bool IsBoneEffectivelyGone(RigManager rig, HumanBodyBones bone) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected I4, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Invalid comparison between Unknown and I4 //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Invalid comparison between Unknown and I4 //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Invalid comparison between Unknown and I4 //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Invalid comparison between Unknown and I4 //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Invalid comparison between Unknown and I4 //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Invalid comparison between Unknown and I4 if (IsBoneGone(rig, bone) || ((int)bone != 0 && IsBoneGone(rig, (HumanBodyBones)0))) { return true; } switch (bone - 3) { case 7: case 18: case 19: return IsBoneGone(rig, (HumanBodyBones)7) || (((int)bone == 21 || (int)bone == 22) && IsBoneGone(rig, (HumanBodyBones)10)); case 10: case 12: case 14: return IsBoneGone(rig, (HumanBodyBones)7) || ((int)bone != 13 && IsBoneGone(rig, (HumanBodyBones)13)) || ((int)bone == 17 && IsBoneGone(rig, (HumanBodyBones)15)); case 11: case 13: case 15: return IsBoneGone(rig, (HumanBodyBones)7) || ((int)bone != 14 && IsBoneGone(rig, (HumanBodyBones)14)) || ((int)bone == 18 && IsBoneGone(rig, (HumanBodyBones)16)); case 0: case 2: return IsBoneGone(rig, (HumanBodyBones)1) || ((int)bone == 5 && IsBoneGone(rig, (HumanBodyBones)3)); case 1: case 3: return IsBoneGone(rig, (HumanBodyBones)2) || ((int)bone == 6 && IsBoneGone(rig, (HumanBodyBones)4)); default: return false; } } private static bool IsStepContact(Collider footCollider, Collider otherCollider, ContactPoint contact) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)footCollider == (Object)null || (Object)(object)otherCollider == (Object)null) { return false; } Bounds bounds = footCollider.bounds; Bounds bounds2 = otherCollider.bounds; float num = Mathf.Max(0.08f, ((Bounds)(ref bounds)).size.y * 0.35f); bool flag = Mathf.Abs(((ContactPoint)(ref contact)).point.y - ((Bounds)(ref bounds)).min.y) <= num; bool flag2 = ((ContactPoint)(ref contact)).point.y >= ((Bounds)(ref bounds2)).center.y - Mathf.Max(0.04f, ((Bounds)(ref bounds2)).extents.y * 0.15f); return Mathf.Abs(((ContactPoint)(ref contact)).normal.y) >= 0.45f && ((Bounds)(ref bounds)).center.y > ((Bounds)(ref bounds2)).center.y && flag && flag2; } private bool OnPluginInteractionRequest(byte sourcePlayerId, byte targetPlayerId, byte kind, byte boneIndex, byte detail, Vector3 point) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.IsHost || !IsSessionEnabled() || sourcePlayerId == targetPlayerId || !GetPlayerLimbsEnabled(targetPlayerId) || !IsValidPlayerInteractionRequest(kind, boneIndex, detail)) { return false; } if (!TryResolvePlayerRig(sourcePlayerId, out var rigManager) || !TryResolvePlayerRig(targetPlayerId, out var rigManager2)) { QueuePendingPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point); return false; } if ((Object)(object)rigManager == (Object)(object)rigManager2) { return false; } if ((Object)(object)rigManager.health == (Object)null || (Object)(object)rigManager2.health == (Object)null || (Object)(object)rigManager.avatar == (Object)null || (Object)(object)rigManager2.avatar == (Object)null || (Object)(object)rigManager2.avatar.animator == (Object)null || (Object)(object)rigManager.physicsRig == (Object)null) { QueuePendingPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point); return false; } if (!rigManager.health.alive || !rigManager2.health.alive || (IsRigLimbDamageBlocked(rigManager2) && !IsRemotePlayerRig(rigManager2))) { return false; } switch (kind) { case 0: { HumanBodyBones bone = DamageBones[boneIndex]; if (!CanRipLimb(rigManager, rigManager2, bone)) { return false; } if (!ValidateRipProximity(sourcePlayerId, targetPlayerId, rigManager, rigManager2, bone, detail, point)) { QueuePendingPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point); return false; } ulong key2 = ComposeInteractionKey(kind, sourcePlayerId, targetPlayerId, boneIndex); return TryUseInteractionCooldown(_hostInteractionCooldowns, key2, 1f) && ResolveDominance(GetRipDominance(rigManager, rigManager2)) && ApplyPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point, syncState: true); } case 1: { if (boneIndex != byte.MaxValue || detail > 2 || !CanCrushPlayer(rigManager, rigManager2, detail) || !ValidateCrushProximity(rigManager, rigManager2, detail, point)) { if (detail <= 2 && CanCrushPlayer(rigManager, rigManager2, detail)) { QueuePendingPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point); } return false; } ulong key = ComposeInteractionKey(kind, sourcePlayerId, targetPlayerId, byte.MaxValue); return TryUseInteractionCooldown(_hostInteractionCooldowns, key, 1f) && ResolveDominance(GetCrushDominance(rigManager, rigManager2)) && ApplyPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point, syncState: true); } default: return false; } } private static bool IsValidPlayerInteractionRequest(byte kind, byte boneIndex, byte detail) { if (kind == 0) { return boneIndex < DamageBones.Length && (detail & 2) != 0 && (detail & -4) == 0; } return kind == 1 && boneIndex == byte.MaxValue && detail <= 2; } private void OnPluginInteractionAuthoritative(byte sourcePlayerId, byte targetPlayerId, byte kind, byte boneIndex, byte detail, Vector3 point) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) ApplyPlayerInteraction(sourcePlayerId, targetPlayerId, kind, boneIndex, detail, point, syncState: false); } private bool ValidateRipProximity(byte sourcePlayerId, byte targetPlayerId, RigManager source, RigManager target, HumanBodyBones bone, byte detail, Vector3 point) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) Transform cachedBoneTransform = GetCachedBoneTransform(target, bone); if ((Object)(object)cachedBoneTransform == (Object)null) { return false; } bool flag = (detail & 1) != 0; Hand val = ((!((Object)(object)source.physicsRig != (Object)null)) ? null : (flag ? source.physicsRig.rightHand : source.physicsRig.leftHand)); if ((Object)(object)val == (Object)null) { return false; } ushort key = ComposeGrabEvidenceKey(sourcePlayerId, flag); if (_recentGrabEvidence.TryGetValue(key, out var value) && Time.unscaledTime - value.Time <= 1.5f && value.TargetPlayerId == targetPlayerId && value.Bone == bone) { return true; } if ((_recentGrabEvidence.TryGetValue(key, out value) && value.Active && Time.unscaledTime - value.Time <= 1.5f && value.TargetPlayerId != targetPlayerId) || (_recentNpcGrabEvidence.TryGetValue(key, out var value2) && value2.Active && Time.unscaledTime - value2.Time <= 1.5f)) { return false; } return ValidateRipRequestGeometry(source, target, bone, val, point); } private bool ValidateRipRequestGeometry(RigManager source, RigManager target, HumanBodyBones bone, Hand hand, Vector3 point) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) Transform cachedBoneTransform = GetCachedBoneTransform(target, bone); if ((Object)(object)cachedBoneTransform == (Object)null || (Object)(object)hand == (Object)null) { return false; } float avatarHeight = GetAvatarHeight(source); float avatarHeight2 = GetAvatarHeight(target); float num = Mathf.Clamp(avatarHeight2 * 0.22f, 0.18f, 1.25f); float num2 = Mathf.Clamp(Mathf.Max(avatarHeight2 * 0.4f, avatarHeight * 0.25f), 0.45f, 2f); Vector3 handPosition = GetHandPosition(hand); return Vector3.Distance(point, cachedBoneTransform.position) <= num && Vector3.Distance(handPosition, cachedBoneTransform.position) <= num2 && Vector3.Distance(handPosition, point) <= num2 + num * 0.5f; } private bool ValidateCrushProximity(RigManager source, RigManager target, byte detail, Vector3 point) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (TryFindObservedPlayerCrushContact(source, target, detail, out var _)) { return true; } if (!TryGetPlayerIdForRig(source, out var playerId) || !TryGetPlayerIdForRig(target, out var playerId2)) { return false; } ulong key = ComposeInteractionKey(1, playerId, playerId2, detail); if (_recentPlayerCrushEvidence.TryGetValue(key, out var value) && Time.unscaledTime - value.Time <= 1.5f) { return true; } Vector3 position; float bottomY; Vector2 horizontalExtents; Vector3 position2; float distance; return TryGetFootPosition(source, detail, out position, out bottomY, out horizontalExtents) && TryGetClosestExistingDamageBone(target, point, out position2, out distance) && ValidateCrushContactGeometry(position, bottomY, horizontalExtents, position2, distance, GetAvatarHeight(source), GetAvatarHeight(target), point); } private bool TryFindObservedPlayerCrushContact(RigManager source, RigManager target, byte detail, out Vector3 point) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; if (!TryGetCrushFootCollider(source, detail, out var collider)) { return false; } Bounds bounds = collider.bounds; float avatarHeight = GetAvatarHeight(source); float num = Mathf.Clamp(avatarHeight * 0.06f, 0.08f, 0.35f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y - num * 0.5f + 0.01f, ((Bounds)(ref bounds)).center.z); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.x * 1.15f), num * 0.5f + 0.02f, Mathf.Max(0.04f, ((Bounds)(ref bounds)).extents.z * 1.15f)); int num2; try { num2 = Physics.OverlapBoxNonAlloc(val, val2, CrushOverlapBuffer, Quaternion.identity, -1, (QueryTriggerInteraction)1); } catch { return false; } for (int i = 0; i < num2; i++) { Collider val3 = ((Il2CppArrayBase)(object)CrushOverlapBuffer)[i]; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)ResolvePlayerRigFromCollider(val3) != (Object)(object)target) && TryResolvePlayerCrushContactBone(target, val3, out var bone) && !IsBoneEffectivelyGone(target, bone) && TryGetCrushContactPoint(collider, val3, avatarHeight, out point)) { return true; } } return false; } private bool TryGetCrushFootCollider(RigManager rig, byte detail, out Collider collider) { collider = null; PhysicsRig val = (((Object)(object)rig != (Object)null) ? rig.physicsRig : null); if ((Object)(object)val == (Object)null) { return false; } if (detail == 0 && !IsBothLegsGone(rig)) { collider = (Collider)(object)val._football; } else if (detail == 1 && !IsLeftLegGone(rig)) { PhysLimb legLf = val.legLf; collider = (Collider)(object)((legLf != null) ? legLf.endCol : null); } else if (detail == 2 && !IsRightLegGone(rig)) { PhysLimb legRt = val.legRt; collider = (Collider)(object)((legRt != null) ? legRt.endCol : null); } return (Object)(object)collider != (Object)null && collider.enabled; } private static bool ValidateCrushContactGeometry(Vector3 footPosition, float footBottomY, Vector2 horizontalExtents, Vector3 targetBonePosition, float directDistance, float sourceHeight, float targetHeight, Vector3 point) { //IL_0088: 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_00b2: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(Mathf.Max(targetHeight * 0.45f, sourceHeight * 0.08f), 0.35f, 1.25f); float num2 = Mathf.Clamp(targetHeight * 0.03f, 0.025f, 0.12f); float num3 = Mathf.Clamp(targetHeight * 0.3f, 0.12f, 0.6f); float num4 = Mathf.Clamp(sourceHeight * 0.05f, 0.08f, 0.3f); float num5 = Mathf.Clamp(sourceHeight * 0.015f, 0.02f, 0.12f); float num6 = footBottomY - targetBonePosition.y; return directDistance <= num && num6 >= 0f - num2 && num6 <= num3 && Mathf.Abs(point.y - footBottomY) <= num4 && Mathf.Abs(point.x - footPosition.x) <= horizontalExtents.x + num5 && Mathf.Abs(point.z - footPosition.z) <= horizontalExtents.y + num5; } private bool TryGetFootPosition(RigManager rig, byte detail, out Vector3 position, out float bottomY, out Vector2 horizontalExtents) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; bottomY = 0f; horizontalExtents = Vector2.zero; PhysicsRig val = (((Object)(object)rig != (Object)null) ? rig.physicsRig : null); if ((Object)(object)val == (Object)null) { return false; } if (detail == 0 && !IsBothLegsGone(rig)) { if ((Object)(object)val._football != (Object)null && ((Collider)val._football).enabled) { Bounds bounds = ((Collider)val._football).bounds; position = ((Bounds)(ref bounds)).center; bottomY = ((Bounds)(ref bounds)).min.y; horizontalExtents = new Vector2(Mathf.Max(0.03f, ((Bounds)(ref bounds)).extents.x), Mathf.Max(0.03f, ((Bounds)(ref bounds)).extents.z)); return true; } Vector3 position2; float bottomY2; Vector2 horizontalExtents2; bool flag = TryGetFootPosition(rig, 1, out position2, out bottomY2, out horizontalExtents2); Vector3 position3; float bottomY3; Vector2 horizontalExtents3; bool flag2 = TryGetFootPosition(rig, 2, out position3, out bottomY3, out horizontalExtents3); if (!flag && !flag2) { return false; } if (!flag) { position = position3; bottomY = bottomY3; horizontalExtents = horizontalExtents3; return true; } if (!flag2) { position = position2; bottomY = bottomY2; horizontalExtents = horizontalExtents2; return true; } float num = Mathf.Min(position2.x - horizontalExtents2.x, position3.x - horizontalExtents3.x); float num2 = Mathf.Max(position2.x + horizontalExtents2.x, position3.x + horizontalExtents3.x); float num3 = Mathf.Min(position2.z - horizontalExtents2.y, position3.z - horizontalExtents3.y); float num4 = Mathf.Max(position2.z + horizontalExtents2.y, position3.z + horizontalExtents3.y); position = new Vector3((num + num2) * 0.5f, (position2.y + position3.y) * 0.5f, (num3 + num4) * 0.5f); bottomY = Mathf.Min(bottomY2, bottomY3); horizontalExtents = new Vector2(Mathf.Max(0.03f, (num2 - num) * 0.5f), Mathf.Max(0.03f, (num4 - num3) * 0.5f)); return true; } PhysLimb val2 = (PhysLimb)(detail switch { 2 => val.legRt, 1 => val.legLf, _ => null, }); if ((Object)(object)val2 == (Object)null || ((detail == 1) ? IsLeftLegGone(rig) : IsRightLegGone(rig))) { return false; } if ((Object)(object)val2.endCol != (Object)null && ((Collider)val2.endCol).enabled) { Bounds bounds2 = ((Collider)val2.endCol).bounds; position = ((Bounds)(ref bounds2)).center; bottomY = ((Bounds)(ref bounds2)).min.y; horizontalExtents = new Vector2(Mathf.Max(0.03f, ((Bounds)(ref bounds2)).extents.x), Mathf.Max(0.03f, ((Bounds)(ref bounds2)).extents.z)); return true; } if ((Object)(object)val2.rbEnd != (Object)null) { position = val2.rbEnd.worldCenterOfMass; bottomY = position.y - Mathf.Max(0.03f, GetAvatarHeight(rig) * 0.025f); float num5 = Mathf.Clamp(GetAvatarHeight(rig) * 0.035f, 0.04f, 0.35f); horizontalExtents = new Vector2(num5, num5); return true; } return false; } private bool TryGetClosestExistingDamageBone(RigManager rig, Vector3 point, out Vector3 position, out float distance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; distance = float.MaxValue; bool result = false; RebuildBoneCache(rig); for (int i = 0; i < DamageBones.Length; i++) { HumanBodyBones bone = DamageBones[i]; Transform cachedBoneTransform = GetCachedBoneTransform(rig, bone); if ((Object)(object)cachedBoneTransform != (Object)null && !IsBoneEffectivelyGone(rig, bone)) { float num = Vector3.Distance(point, cachedBoneTransform.position); if (num < distance) { distance = num; position = cachedBoneTransform.position; result = true; } } } return result; } private bool ApplyPlayerInteraction(byte sourcePlayerId, byte targetPlayerId, byte kind, byte boneIndex, byte detail, Vector3 point, bool syncState) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (!IsSessionEnabled() || !GetPlayerLimbsEnabled(targetPlayerId) || !TryResolvePlayerRig(targetPlayerId, out var rigManager) || (Object)(object)rigManager == (Object)null || (Object)(object)rigManager.avatar == (Object)null || (Object)(object)rigManager.avatar.animator == (Object)null || (IsRigLimbDamageBlocked(rigManager) && !IsRemotePlayerRig(rigManager))) { return false; } bool flag; uint authoritativeMask; switch (kind) { case 0: { if (boneIndex >= DamageBones.Length) { return false; } HumanBodyBones bone = DamageBones[boneIndex]; uint stateMask = GetStateMask(rigManager); if (!IsBoneGone(rigManager, bone)) { Transform cachedBoneTransform = GetCachedBoneTransform(rigManager, bone); Vector3 hitPoint = (((Object)(object)cachedBoneTransform != (Object)null) ? cachedBoneTransform.position : point); DismemberLimb(rigManager, bone, hitPoint); } flag = GetStateMask(rigManager) != stateMask || IsBoneGone(rigManager, bone); authoritativeMask = GetStateMask(rigManager); break; } case 1: { uint num = (uint)((1 << DamageBones.Length) - 1); ApplyStateToRig(rigManager, num); flag = AreAllExistingDamageBonesGone(rigManager); authoritativeMask = num; break; } default: return false; } if (!flag) { return false; } if ((Object)(object)rigManager != (Object)(object)Player.RigManager && IsRemotePlayerRig(rigManager)) { ApplyRemoteLegEffects(rigManager); } TrackRig(rigManager); if (syncState && NetworkInfo.IsHost) { MelonCoroutines.Start(DelayedInteractionStateSync(targetPlayerId, authoritativeMask)); } return true; } private bool AreAllExistingDamageBonesGone(RigManager rig) { bool result = false; RebuildBoneCache(rig); for (int i = 0; i < DamageBones.Length; i++) { Transform cachedBoneTransform = GetCachedBoneTransform(rig, DamageBones[i]); if (!((Object)(object)cachedBoneTransform == (Object)null)) { result = true; if (!IsBoneGone(rig, DamageBones[i])) { return false; } } } return result; } private IEnumerator DelayedInteractionStateSync(byte targetPlayerId, uint authoritativeMask) { yield return null; if (NetworkInfo.IsHost && TryResolvePlayerRig(targetPlayerId, out var target)) { NetworkSync.SendFullState(targetPlayerId, authoritativeMask, GetBloodColorIndexForRig(target), 0); } } private static float GetAvatarStrength(RigManager rig) { float num = (((Object)(object)((rig != null) ? rig.avatar : null) != (Object)null) ? rig.avatar.strengthUpper : 0f); if (IsFinitePositive(num)) { return num; } float num2 = Mathf.Max(0.1f, GetAvatarMass(rig) / 75f); float num3 = Mathf.Max(0.1f, GetAvatarHeight(rig) / 1.75f); return Mathf.Clamp(Mathf.Sqrt(num2) * Mathf.Sqrt(num3), 0.1f, 1000f); } private static float GetAvatarHeight(RigManager rig) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) float num = (((Object)(object)((rig != null) ? rig.avatar : null) != (Object)null) ? rig.avatar.height : 0f); if (IsFinitePositive(num)) { return num; } object obj; if (rig == null) { obj = null; } else { Avatar avatar = rig.avatar; obj = ((avatar != null) ? avatar.animator : null); } Animator val = (Animator)obj; if ((Object)(object)val == (Object)null || !val.isHuman) { return 1.75f; } Transform boneTransform = val.GetBoneTransform((HumanBodyBones)10); Transform boneTransform2 = val.GetBoneTransform((HumanBodyBones)0); float num2 = (((Object)(object)boneTransform != (Object)null && (Object)(object)boneTransform2 != (Object)null) ? Vector3.Distance(boneTransform.position, boneTransform2.position) : 0.7f); float npcLegLength = GetNpcLegLength(val, left: true); float npcLegLength2 = GetNpcLegLength(val, left: false); float num3 = ((npcLegLength > 0f && npcLegLength2 > 0f) ? ((npcLegLength + npcLegLength2) * 0.5f) : Mathf.Max(npcLegLength, npcLegLength2)); float num4 = num2 + ((num3 > 0f) ? num3 : 0.9f) + 0.15f; return IsFinitePositive(num4) ? Mathf.Clamp(num4, 0.25f, 20f) : 1.75f; } private static float GetAvatarMass(RigManager rig) { float num = (((Object)(object)((rig != null) ? rig.avatar : null) != (Object)null) ? rig.avatar.massTotal : 0f); if (IsFinitePositive(num)) { return num; } PhysicsRig val = ((rig != null) ? rig.physicsRig : null); if ((Object)(object)val == (Object)null) { return 75f; } Rigidbody[] array = Il2CppArrayBase.op_Implicit(((Component)val).GetComponentsInChildren(true)); HashSet hashSet = new HashSet(); float num2 = 0f; foreach (Rigidbody val2 in array) { if ((Object)(object)val2 != (Object)null && hashSet.Add(val2) && IsFinitePositive(val2.mass)) { num2 += val2.mass; } } return IsFinitePositive(num2) ? Mathf.Clamp(num2, 1f, 100000f) : 75f; } private float GetInteractionStrength(RigManager rig) { PlayerInteractionStats stats; return TryGetInteractionStats(rig, out stats) ? stats.Strength : GetAvatarStrength(rig); } private float GetInteractionHeight(RigManager rig) { PlayerInteractionStats stats; return TryGetInteractionStats(rig, out stats) ? stats.Height : GetAvatarHeight(rig); } private float GetInteractionMass(RigManager rig) { PlayerInteractionStats stats; return TryGetInteractionStats(rig, out stats) ? stats.Mass : GetAvatarMass(rig); } private bool TryGetInteractionStats(RigManager rig, out PlayerInteractionStats stats) { stats = default(PlayerInteractionStats); if ((Object)(object)rig == (Object)null) { return false; } if ((Object)(object)rig == (Object)(object)Player.RigManager && PlayerIDManager.LocalID != null) { return _networkInteractionStats.TryGetValue(PlayerIDManager.LocalSmallID, out stats); } byte playerId; return TryGetPlayerIdForRig(rig, out playerId) && _networkInteractionStats.TryGetValue(playerId, out stats); } private void PublishLocalInteractionStats(bool force) { RigManager rigManager = Player.RigManager; if (!((Object)(object)rigManager == (Object)null) && PlayerIDManager.LocalID != null) { PlayerInteractionStats playerInteractionStats = NormalizeInteractionStats(GetAvatarStrength(rigManager), GetAvatarHeight(rigManager), GetAvatarMass(rigManager)); if (force || !_interactionStatsPublished || InteractionStatsChanged(playerInteractionStats, _lastPublishedInteractionStats)) { string value = playerInteractionStats.Strength.ToString("R", CultureInfo.InvariantCulture) + "|" + playerInteractionStats.Height.ToString("R", CultureInfo.InvariantCulture) + "|" + playerInteractionStats.Mass.ToString("R", CultureInfo.InvariantCulture); SetLocalMetadataValue("DeadPieceInteractionStats", value); _lastPublishedInteractionStats = playerInteractionStats; _interactionStatsPublished = true; } _networkInteractionStats[PlayerIDManager.LocalSmallID] = playerInteractionStats; } } private void HandlePlayerInteractionStats(byte playerId, string value) { if (!TryParseInteractionStats(value, out var stats)) { _networkInteractionStats.Remove(playerId); } else { _networkInteractionStats[playerId] = stats; } } private static bool TryParseInteractionStats(string value, out PlayerInteractionStats stats) { stats = default(PlayerInteractionStats); if (string.IsNullOrWhiteSpace(value)) { return false; } string[] array = value.Split('|'); if (array.Length != 3 || !float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !IsFinitePositive(result) || !IsFinitePositive(result2) || !IsFinitePositive(result3)) { return false; } stats = NormalizeInteractionStats(result, result2, result3); return true; } private static PlayerInteractionStats NormalizeInteractionStats(float strength, float height, float mass) { return new PlayerInteractionStats { Strength = Mathf.Clamp(strength, 0.05f, 1000f), Height = Mathf.Clamp(height, 0.25f, 20f), Mass = Mathf.Clamp(mass, 1f, 100000f) }; } private static bool InteractionStatsChanged(PlayerInteractionStats current, PlayerInteractionStats previous) { return Mathf.Abs(current.Strength - previous.Strength) > Mathf.Max(0.0001f, current.Strength * 0.001f) || Mathf.Abs(current.Height - previous.Height) > Mathf.Max(0.0001f, current.Height * 0.001f) || Mathf.Abs(current.Mass - previous.Mass) > Mathf.Max(0.001f, current.Mass * 0.001f); } private static bool IsFinitePositive(float value) { return value > 0f && !float.IsNaN(value) && !float.IsInfinity(value); } private static Vector3 GetHandPosition(Hand hand) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_003b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hand == (Object)null) { return Vector3.zero; } return ((Object)(object)hand.palmPositionTransform != (Object)null) ? hand.palmPositionTransform.position : ((Component)hand).transform.position; } private static ulong ComposeInteractionKey(byte kind, byte sourcePlayerId, byte targetPlayerId, byte boneIndex) { return ((ulong)kind << 24) | ((ulong)sourcePlayerId << 16) | ((ulong)targetPlayerId << 8) | boneIndex; } private static ushort ComposeGrabEvidenceKey(byte sourcePlayerId, bool rightHand) { return (ushort)((sourcePlayerId << 1) | (rightHand ? 1 : 0)); } private static ulong ComposePendingPlayerInteractionKey(byte sourcePlayerId, byte targetPlayerId, byte kind, byte boneIndex, byte detail) { return ((ulong)kind << 32) | ((ulong)sourcePlayerId << 24) | ((ulong)targetPlayerId << 16) | ((ulong)boneIndex << 8) | detail; } private static ulong ComposePendingNpcInteractionKey(byte sourcePlayerId, ushort entityId, byte kind, byte boneIndex, byte detail) { return 0x8000000000000000uL | ((ulong)kind << 48) | ((ulong)sourcePlayerId << 40) | ((ulong)entityId << 16) | ((ulong)boneIndex << 8) | detail; } private void QueuePendingPlayerInteraction(byte sourcePlayerId, byte targetPlayerId, byte kind, byte boneIndex, byte detail, Vector3 point) { //IL_0095: 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) ulong key = ComposePendingPlayerInteractionKey(sourcePlayerId, targetPlayerId, kind, boneIndex, detail); if (!_pendingPlayerInteractions.ContainsKey(key)) { RemovePendingInteractionChannel(sourcePlayerId, kind == 0, detail); if (_pendingPlayerInteractions.Count + _pendingNpcInteractions.Count < 128) { _pendingPlayerInteractions[key] = new PendingPlayerInteraction { SourcePlayerId = sourcePlayerId, TargetPlayerId = targetPlayerId, Kind = kind, BoneIndex = boneIndex, Detail = detail, Point = point, ExpiresAt = Time.unscaledTime + 1.5f }; } } } private void QueuePendingNpcInteraction(byte sourcePlayerId, ushort entityId, byte kind, byte boneIndex, byte detail, Vector3 point) { //IL_0095: 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) ulong key = ComposePendingNpcInteractionKey(sourcePlayerId, entityId, kind, boneIndex, detail); if (!_pendingNpcInteractions.ContainsKey(key)) { RemovePendingInteractionChannel(sourcePlayerId, kind == 1, detail); if (_pendingPlayerInteractions.Count + _pendingNpcInteractions.Count < 128) { _pendingNpcInteractions[key] = new PendingNpcInteraction { SourcePlayerId = sourcePlayerId, EntityId = entityId, Kind = kind, BoneIndex = boneIndex, Detail = detail, Point = point, ExpiresAt = Time.unscaledTime + 1.5f }; } } } private void ProcessPendingHostInteractions() { //IL_0534: Unknown result type (might be due to invalid IL or missing references) //IL_0539: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_05d9: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_06cb: Unknown result type (might be due to invalid IL or missing references) //IL_06d0: Unknown result type (might be due to invalid IL or missing references) //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Unknown result type (might be due to invalid IL or missing references) //IL_070f: Unknown result type (might be due to invalid IL or missing references) //IL_06f2: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) //IL_073a: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.IsHost || !IsSessionEnabled()) { _pendingPlayerInteractions.Clear(); _pendingNpcInteractions.Clear(); return; } float unscaledTime = Time.unscaledTime; if (_pendingPlayerInteractions.Count > 0) { List list = new List(); foreach (KeyValuePair pendingPlayerInteraction in _pendingPlayerInteractions) { PendingPlayerInteraction value = pendingPlayerInteraction.Value; if (unscaledTime >= value.ExpiresAt) { list.Add(pendingPlayerInteraction.Key); } else { if (!TryResolvePlayerRig(value.SourcePlayerId, out var rigManager) || !TryResolvePlayerRig(value.TargetPlayerId, out var rigManager2)) { continue; } if ((Object)(object)rigManager == (Object)(object)rigManager2) { list.Add(pendingPlayerInteraction.Key); } else { if ((Object)(object)rigManager.health == (Object)null || (Object)(object)rigManager2.health == (Object)null || (Object)(object)rigManager.avatar == (Object)null || (Object)(object)rigManager2.avatar == (Object)null || (Object)(object)rigManager2.avatar.animator == (Object)null || (Object)(object)rigManager.physicsRig == (Object)null) { continue; } if (!rigManager.health.alive || !rigManager2.health.alive || !GetPlayerLimbsEnabled(value.TargetPlayerId) || (IsRigLimbDamageBlocked(rigManager2) && !IsRemotePlayerRig(rigManager2))) { list.Add(pendingPlayerInteraction.Key); continue; } bool flag = false; float num = 0f; byte boneIndex = value.BoneIndex; if (value.Kind == 0 && value.BoneIndex < DamageBones.Length && (value.Detail & 2) != 0 && (value.Detail & -4) == 0) { HumanBodyBones bone = DamageBones[value.BoneIndex]; if (!CanRipLimb(rigManager, rigManager2, bone)) { list.Add(pendingPlayerInteraction.Key); continue; } flag = ValidateRipProximity(value.SourcePlayerId, value.TargetPlayerId, rigManager, rigManager2, bone, value.Detail, value.Point); num = GetRipDominance(rigManager, rigManager2); } else { if (value.Kind != 1 || value.BoneIndex != byte.MaxValue || value.Detail > 2 || !CanCrushPlayer(rigManager, rigManager2, value.Detail)) { list.Add(pendingPlayerInteraction.Key); continue; } flag = ValidateCrushProximity(rigManager, rigManager2, value.Detail, value.Point); num = GetCrushDominance(rigManager, rigManager2); boneIndex = byte.MaxValue; } if (flag) { list.Add(pendingPlayerInteraction.Key); ulong key = ComposeInteractionKey(value.Kind, value.SourcePlayerId, value.TargetPlayerId, boneIndex); if (TryUseInteractionCooldown(_hostInteractionCooldowns, key, 1f) && ResolveDominance(num)) { ApplyPlayerInteraction(value.SourcePlayerId, value.TargetPlayerId, value.Kind, value.BoneIndex, value.Detail, value.Point, syncState: true); } } } } } for (int i = 0; i < list.Count; i++) { _pendingPlayerInteractions.Remove(list[i]); } } if (_pendingNpcInteractions.Count <= 0) { return; } List list2 = new List(); foreach (KeyValuePair pendingNpcInteraction in _pendingNpcInteractions) { PendingNpcInteraction value2 = pendingNpcInteraction.Value; if (unscaledTime >= value2.ExpiresAt) { list2.Add(pendingNpcInteraction.Key); } else { if (!TryResolvePlayerRig(value2.SourcePlayerId, out var rigManager3) || !TryResolveNpcEntity(value2.EntityId, out var puppetMaster)) { continue; } if ((Object)(object)rigManager3.health == (Object)null || !rigManager3.health.alive || (Object)(object)rigManager3.avatar == (Object)null) { list2.Add(pendingNpcInteraction.Key); continue; } bool flag2 = false; bool consumed = false; float num2 = 0f; byte boneIndex2 = value2.BoneIndex; if (value2.Kind == 1 && value2.BoneIndex < DamageBones.Length && (value2.Detail & 2) != 0 && (value2.Detail & -4) == 0) { HumanBodyBones bone2 = DamageBones[value2.BoneIndex]; if (IsNpcBoneGone(puppetMaster, bone2)) { list2.Add(pendingNpcInteraction.Key); continue; } flag2 = ValidateNpcRipProximity(value2.SourcePlayerId, rigManager3, puppetMaster, bone2, value2.Detail, out consumed); num2 = GetDominance(GetInteractionStrength(rigManager3), GetNpcStrength(puppetMaster)); } else { if (value2.Kind != 2 || value2.BoneIndex != 0 || value2.Detail > 2 || !CanCrushNpc(rigManager3, puppetMaster, value2.Detail)) { list2.Add(pendingNpcInteraction.Key); continue; } flag2 = ValidateNpcCrushProximity(rigManager3, puppetMaster, value2.Detail, value2.Point); num2 = GetNpcCrushDominance(rigManager3, puppetMaster); boneIndex2 = byte.MaxValue; } if (!flag2) { if (consumed) { list2.Add(pendingNpcInteraction.Key); } continue; } list2.Add(pendingNpcInteraction.Key); ulong key2 = ComposeNpcInteractionKey(value2.Kind, value2.SourcePlayerId, value2.EntityId, boneIndex2); bool flag3 = false; if (TryUseInteractionCooldown(_hostInteractionCooldowns, key2, 1f) && ResolveDominance(num2)) { flag3 = ((value2.Kind == 1) ? ApplyNpcRip(puppetMaster, DamageBones[value2.BoneIndex], GetNpcBonePoint(puppetMaster, DamageBones[value2.BoneIndex], value2.Point)) : ApplyNpcCrush(puppetMaster, value2.Point)); } if (flag3) { Vector3 point = ((value2.Kind == 1) ? GetNpcBonePoint(puppetMaster, DamageBones[value2.BoneIndex], value2.Point) : value2.Point); NetworkSync.SendNpcState(value2.EntityId, GetNpcStateMask(puppetMaster), value2.Kind, value2.BoneIndex, value2.Detail, point); } } } for (int j = 0; j < list2.Count; j++) { _pendingNpcInteractions.Remove(list2[j]); } } private void RemovePendingInteractionChannel(byte sourcePlayerId, bool rip, byte detail) { bool flag = (detail & 1) != 0; if (_pendingPlayerInteractions.Count > 0) { List list = new List(); foreach (KeyValuePair pendingPlayerInteraction in _pendingPlayerInteractions) { PendingPlayerInteraction value = pendingPlayerInteraction.Value; bool flag2 = ((!rip) ? (value.Kind == 1 && value.Detail == detail) : (value.Kind == 0 && (value.Detail & 1) != 0 == flag)); if (value.SourcePlayerId == sourcePlayerId && flag2) { list.Add(pendingPlayerInteraction.Key); } } for (int i = 0; i < list.Count; i++) { _pendingPlayerInteractions.Remove(list[i]); } } if (_pendingNpcInteractions.Count <= 0) { return; } List list2 = new List(); foreach (KeyValuePair pendingNpcInteraction in _pendingNpcInteractions) { PendingNpcInteraction value2 = pendingNpcInteraction.Value; bool flag3 = ((!rip) ? (value2.Kind == 2 && value2.Detail == detail) : (value2.Kind == 1 && (value2.Detail & 1) != 0 == flag)); if (value2.SourcePlayerId == sourcePlayerId && flag3) { list2.Add(pendingNpcInteraction.Key); } } for (int j = 0; j < list2.Count; j++) { _pendingNpcInteractions.Remove(list2[j]); } } private static bool TryUseInteractionCooldown(Dictionary cooldowns, ulong key, float duration) { float unscaledTime = Time.unscaledTime; if (cooldowns.TryGetValue(key, out var value) && unscaledTime - value < duration) { return false; } cooldowns[key] = unscaledTime; return true; } private bool TryBeginCrushContact(ulong key) { float unscaledTime = Time.unscaledTime; float value; bool result = !_localCrushContactTimes.TryGetValue(key, out value) || unscaledTime - value > 0.3f; _localCrushContactTimes[key] = unscaledTime; return result; } private void PruneInteractionCooldowns() { float unscaledTime = Time.unscaledTime; if (unscaledTime - _lastInteractionCooldownPrune < 5f) { return; } _lastInteractionCooldownPrune = unscaledTime; PruneInteractionCooldownDictionary(_localInteractionCooldowns, unscaledTime); PruneInteractionCooldownDictionary(_hostInteractionCooldowns, unscaledTime); PruneInteractionCooldownDictionary(_localCrushContactTimes, unscaledTime); if (_recentGrabEvidence.Count > 0) { List list = new List(); foreach (KeyValuePair item in _recentGrabEvidence) { if (unscaledTime - item.Value.Time > 2f) { list.Add(item.Key); } } for (int i = 0; i < list.Count; i++) { _recentGrabEvidence.Remove(list[i]); } } if (_recentNpcGrabEvidence.Count > 0) { List list2 = new List(); foreach (KeyValuePair item2 in _recentNpcGrabEvidence) { if (unscaledTime - item2.Value.Time > 2f) { list2.Add(item2.Key); } } for (int j = 0; j < list2.Count; j++) { _recentNpcGrabEvidence.Remove(list2[j]); } } PruneCrushEvidence(_recentPlayerCrushEvidence, unscaledTime); PruneCrushEvidence(_recentNpcCrushEvidence, unscaledTime); } private static void PruneInteractionCooldownDictionary(Dictionary cooldowns, float now) { if (cooldowns.Count == 0) { return; } List list = new List(); foreach (KeyValuePair cooldown in cooldowns) { if (now - cooldown.Value > 5f) { list.Add(cooldown.Key); } } for (int i = 0; i < list.Count; i++) { cooldowns.Remove(list[i]); } } private static void PruneCrushEvidence(Dictionary evidence, float now) { if (evidence.Count == 0) { return; } List list = new List(); foreach (KeyValuePair item in evidence) { if (now - item.Value.Time > 2f) { list.Add(item.Key); } } for (int i = 0; i < list.Count; i++) { evidence.Remove(list[i]); } } private void ClearPlayerInteractionState() { _localInteractionCooldowns.Clear(); _hostInteractionCooldowns.Clear(); _localCrushContactTimes.Clear(); _recentGrabEvidence.Clear(); _recentNpcGrabEvidence.Clear(); _recentPlayerCrushEvidence.Clear(); _recentNpcCrushEvidence.Clear(); _pendingPlayerInteractions.Clear(); _pendingNpcInteractions.Clear(); _lastInteractionCooldownPrune = -999f; _nextCrushOverlapTime = 0f; _nextHostCrushObservationTime = 0f; ResetLocalRipPullState(); ClearNpcInteractionState(); } private void ClearPlayerInteractionState(byte playerId) { RemovePlayerInteractionKeys(_localInteractionCooldowns, playerId); RemovePlayerInteractionKeys(_hostInteractionCooldowns, playerId); RemovePlayerInteractionKeys(_localCrushContactTimes, playerId); RemovePlayerCrushEvidence(_recentPlayerCrushEvidence, playerId); RemovePlayerCrushEvidence(_recentNpcCrushEvidence, playerId); RemovePendingPlayerInteractions(playerId); if (_recentGrabEvidence.Count > 0) { List list = new List(); foreach (KeyValuePair item in _recentGrabEvidence) { if ((byte)(item.Key >> 1) == playerId || item.Value.TargetPlayerId == playerId) { list.Add(item.Key); } } for (int i = 0; i < list.Count; i++) { _recentGrabEvidence.Remove(list[i]); } } if (_recentNpcGrabEvidence.Count > 0) { List list2 = new List(); foreach (KeyValuePair item2 in _recentNpcGrabEvidence) { if ((byte)(item2.Key >> 1) == playerId) { list2.Add(item2.Key); } } for (int j = 0; j < list2.Count; j++) { _recentNpcGrabEvidence.Remove(list2[j]); } } if (PlayerIDManager.LocalID != null && playerId == PlayerIDManager.LocalSmallID) { ResetLocalRipPullState(); _nextCrushOverlapTime = 0f; } } private void RemovePendingPlayerInteractions(byte playerId) { if (_pendingPlayerInteractions.Count > 0) { List list = new List(); foreach (KeyValuePair pendingPlayerInteraction in _pendingPlayerInteractions) { if (pendingPlayerInteraction.Value.SourcePlayerId == playerId || pendingPlayerInteraction.Value.TargetPlayerId == playerId) { list.Add(pendingPlayerInteraction.Key); } } for (int i = 0; i < list.Count; i++) { _pendingPlayerInteractions.Remove(list[i]); } } if (_pendingNpcInteractions.Count <= 0) { return; } List list2 = new List(); foreach (KeyValuePair pendingNpcInteraction in _pendingNpcInteractions) { if (pendingNpcInteraction.Value.SourcePlayerId == playerId) { list2.Add(pendingNpcInteraction.Key); } } for (int j = 0; j < list2.Count; j++) { _pendingNpcInteractions.Remove(list2[j]); } } private void RemovePendingNpcInteractions(ushort entityId) { if (_pendingNpcInteractions.Count == 0) { return; } List list = new List(); foreach (KeyValuePair pendingNpcInteraction in _pendingNpcInteractions) { if (pendingNpcInteraction.Value.EntityId == entityId) { list.Add(pendingNpcInteraction.Key); } } for (int i = 0; i < list.Count; i++) { _pendingNpcInteractions.Remove(list[i]); } } private static void RemovePlayerInteractionKeys(Dictionary interactions, byte playerId) { if (interactions.Count == 0) { return; } List list = new List(); foreach (KeyValuePair interaction in interactions) { if (InteractionKeyReferencesPlayer(interaction.Key, playerId)) { list.Add(interaction.Key); } } for (int i = 0; i < list.Count; i++) { interactions.Remove(list[i]); } } private static void RemovePlayerCrushEvidence(Dictionary evidence, byte playerId) { if (evidence.Count == 0) { return; } List list = new List(); foreach (KeyValuePair item in evidence) { if (InteractionKeyReferencesPlayer(item.Key, playerId)) { list.Add(item.Key); } } for (int i = 0; i < list.Count; i++) { evidence.Remove(list[i]); } } private static bool InteractionKeyReferencesPlayer(ulong key, byte playerId) { bool flag = (key & 0x8000000000000000uL) != 0; bool flag2 = (key & 0x6000000000000000L) != 0; return flag ? ((byte)(key >> 40) == playerId) : (!flag2 && ((byte)(key >> 16) == playerId || (byte)(key >> 8) == playerId)); } static DeadPieceMod() { //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) HumanBodyBones[] array = new HumanBodyBones[17]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); DamageBones = (HumanBodyBones[])(object)array; FatalBones = new HashSet { (HumanBodyBones)10, (HumanBodyBones)7, (HumanBodyBones)0 }; TorsoBones = new HashSet { (HumanBodyBones)10, (HumanBodyBones)7, (HumanBodyBones)0 }; CoreNearestExcludeBones = new HashSet { (HumanBodyBones)7, (HumanBodyBones)0, (HumanBodyBones)10, (HumanBodyBones)21, (HumanBodyBones)22 }; NetworkBones = DamageBones; BoneToIndexMap = BuildBoneToIndexMap(); GameBloodPositiveKeywords = new string[10] { "blood", "bleed", "gore", "wound", "flesh", "splat", "spray", "squirt", "hemo", "burst" }; GameBloodNegativeKeywords = new string[17] { "decal", "quad", "ui", "icon", "water", "muzzle", "spark", "smoke", "steam", "dust", "fire", "flame", "ash", "shell", "brass", "laser", "confetti" }; VanillaBloodSpawnableBarcodes = new string[2] { "c1534c5a-06ef-49a4-830a-256244656361", "c1534c5a-4a64-4e30-ac16-897944656361" }; LocalHealthHudOffset = new Vector3(0.24f, 0.16f, 0.65f); HudGreen = new Color(0.15f, 1f, 0.25f, 1f); HudYellow = new Color(1f, 0.84f, 0.08f, 1f); HudRed = new Color(1f, 0.16f, 0.12f, 1f); HudViolet = new Color(0.7f, 0.2f, 1f, 1f); HudUnavailable = new Color(0.7f, 0.7f, 0.7f, 1f); HudHeadBones = (HumanBodyBones[])(object)new HumanBodyBones[1] { (HumanBodyBones)10 }; HudBodyBones = (HumanBodyBones[])(object)new HumanBodyBones[2] { (HumanBodyBones)7, default(HumanBodyBones) }; HumanBodyBones[] array2 = new HumanBodyBones[3]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); HudLeftArmBones = (HumanBodyBones[])(object)array2; HumanBodyBones[] array3 = new HumanBodyBones[3]; RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); HudRightArmBones = (HumanBodyBones[])(object)array3; HumanBodyBones[] array4 = new HumanBodyBones[3]; RuntimeHelpers.InitializeArray(array4, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); HudLeftLegBones = (HumanBodyBones[])(object)array4; HumanBodyBones[] array5 = new HumanBodyBones[3]; RuntimeHelpers.InitializeArray(array5, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); HudRightLegBones = (HumanBodyBones[])(object)array5; DefaultNpcBloodColor = new Color(0.52f, 0.012f, 0.008f, 0.96f); CrushOverlapBuffer = new Il2CppReferenceArray(64L); } } internal static class ExplosivePatches { private sealed class BlastContext { public Vector3 Origin; public float Radius; public float Damage; public bool CanProcessRemotePlayers; public readonly HashSet ProcessedRigs = new HashSet(); } private static bool _registered; [ThreadStatic] private static BlastContext _activeBlast; internal static bool IsBlastActive => _activeBlast != null; internal static bool IsDamagingBlastActive => _activeBlast != null && _activeBlast.Damage > 0f && !float.IsNaN(_activeBlast.Damage) && !float.IsInfinity(_activeBlast.Damage); internal static bool CanProcessRemotePlayerBlast => _activeBlast != null && _activeBlast.CanProcessRemotePlayers; internal static bool TryConsumeActiveBlast(int targetInstanceId, out Vector3 origin, out float radius, out float damage) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) BlastContext activeBlast = _activeBlast; origin = activeBlast?.Origin ?? Vector3.zero; radius = activeBlast?.Radius ?? 0f; damage = activeBlast?.Damage ?? 0f; return activeBlast?.ProcessedRigs.Add(targetInstanceId) ?? false; } internal static void TryRegister(Harmony harmony) { //IL_0098: 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_00ac: Expected O, but got Unknown //IL_00ac: Expected O, but got Unknown if (_registered || harmony == null) { return; } try { Type type = AccessTools.TypeByName("Il2CppSLZ.Combat.RigidbodyProjectile"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "BlowUp", (Type[])null, (Type[])null) : null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ExplosivePatches), "RigidbodyProjectileBlowUpPrefix", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(ExplosivePatches), "RigidbodyProjectileBlowUpFinalizer", (Type[])null, (Type[])null); if (!(methodInfo == null) && !(methodInfo2 == null) && !(methodInfo3 == null)) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null); _registered = true; MelonLogger.Msg("[DeadPiece] Projectile blast context patch applied."); } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Projectile blast context patch failed: " + ex.Message); } } private static void RigidbodyProjectileBlowUpPrefix(Component __instance, Attack attack, out BlastContext __state) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) __state = _activeBlast; if (!TryReadFloatMember(__instance, "BlastDamage", out var result)) { result = ((attack != null) ? attack.damage : 0f); } if (float.IsNaN(result) || float.IsInfinity(result)) { result = 0f; } TryReadFloatMember(__instance, "BlastRadius", out var result2); if (float.IsNaN(result2) || float.IsInfinity(result2) || result2 < 0f) { result2 = 0f; } Vector3 origin = ((attack != null && attack.origin != Vector3.zero) ? attack.origin : (((Object)(object)__instance != (Object)null) ? __instance.transform.position : Vector3.zero)); _activeBlast = new BlastContext { Origin = origin, Radius = result2, Damage = result, CanProcessRemotePlayers = ResolveRemotePlayerAuthority(__instance) }; } private static Exception RigidbodyProjectileBlowUpFinalizer(Exception __exception, BlastContext __state) { _activeBlast = __state; return __exception; } private static bool TryReadFloatMember(Component instance, string memberName, out float result) { result = 0f; if ((Object)(object)instance == (Object)null) { return false; } Type type = ((object)instance).GetType(); while (type != null) { FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { try { if (field.GetValue(instance) is float num) { result = num; return true; } } catch { } } PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { try { if (property.GetValue(instance) is float num2) { result = num2; return true; } } catch { } } type = type.BaseType; } return false; } private static bool ResolveRemotePlayerAuthority(Component instance) { if (!NetworkInfo.HasServer) { return true; } try { Poolee val = (((Object)(object)instance != (Object)null) ? instance.GetComponentInParent() : null); object obj; if (!((Object)(object)instance != (Object)null)) { obj = null; } else { Transform transform = instance.transform; obj = ((transform != null) ? transform.root : null); } Transform val2 = (Transform)obj; if (val == null) { val = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent() : null); } NetworkEntity val3 = default(NetworkEntity); if ((Object)(object)val != (Object)null && PooleeExtender.Cache.TryGet(val, ref val3) && val3 != null && val3.IsRegistered) { return val3.IsOwner; } } catch { } return NetworkInfo.IsHost; } } [HarmonyPatch(typeof(Player_Health), "Dying", new Type[] { typeof(float) })] internal static class ManagedPlayerDyingPatch { [HarmonyPrefix] internal static bool Prefix(Player_Health __instance) { return DeadPieceMod.Instance?.AllowPlayerHealthDying(__instance) ?? true; } } [HarmonyPatch(typeof(Player_Health), "LifeSavingDamgeDealt")] internal static class ManagedPlayerLifeSavePatch { [HarmonyPrefix] internal static bool Prefix(Player_Health __instance) { return DeadPieceMod.Instance?.AllowPlayerHealthLifeSave(__instance) ?? true; } } internal static class FusionRigLoadingFix { private static bool _registered; internal static void TryRegister(Harmony harmony) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown if (_registered || harmony == null) { return; } Type typeFromHandle = typeof(NetworkPlayer); if (typeFromHandle == null) { return; } MethodInfo methodInfo = typeFromHandle.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name.Contains("g__IsPlayerLoading")); if (methodInfo == null) { MelonLogger.Warning("[DeadPiece] Could not find Fusion's IsPlayerLoading method (NRE workaround skipped)"); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(FusionRigLoadingFix), "Prefix", (Type[])null, (Type[])null); if (!(methodInfo2 == null)) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _registered = true; MelonLogger.Msg("[DeadPiece] Applied Fusion WaitAndCreateRig NRE workaround"); } } private static bool Prefix(NetworkPlayer __instance, ref bool __result) { if (__instance == null || __instance.PlayerID == null || __instance.PlayerID.Metadata == null) { __result = true; return false; } return true; } } [HarmonyPatch(typeof(PhysGrounder), "ProcessCollision", new Type[] { typeof(Collision), typeof(bool) })] internal static class GrounderCollisionPatch { private static void Postfix(PhysGrounder __instance, Collision c) { DeadPieceMod.Instance?.OnGrounderCollision(__instance, c); } } [HarmonyPatch(typeof(Health), "Respawn")] public static class HealthRespawnPatch { [HarmonyPostfix] public static void Postfix(Health __instance) { DeadPieceMod.Instance?.OnHealthRespawn(__instance); } } [HarmonyPatch(typeof(Health), "SetAvatar", new Type[] { typeof(Avatar) })] public static class HealthSetAvatarPatch { [HarmonyPrefix] public static void Prefix(Health __instance) { DeadPieceMod.Instance?.OnHealthAvatarChanging(__instance); } [HarmonyPostfix] public static void Postfix(Health __instance, Avatar avatar) { DeadPieceMod.Instance?.OnHealthAvatarSet(__instance, avatar); } } [HarmonyPatch(typeof(Health), "SetFullHealth")] public static class HealthSetFullHealthPatch { [HarmonyPrefix] public static void Prefix(Health __instance, out float __state) { __state = (((Object)(object)__instance != (Object)null) ? __instance.curr_Health : (-1f)); } [HarmonyPostfix] public static void Postfix(Health __instance, float __state) { DeadPieceMod.Instance?.OnHealthSetFullHealth(__instance, __state); } } public static class NetworkSync { public const byte NpcHitInteraction = 0; public const byte NpcRipInteraction = 1; public const byte NpcCrushInteraction = 2; public const byte NpcStateInteraction = 3; public static bool Initialize() { try { return FusionSyncManager.InitializeSingleton(); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] Network transport initialization failed: " + ex.Message); return false; } } public static bool RegisterHandlers() { try { return FusionSyncManager.RegisterHandlers(); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] Network handler registration failed: " + ex.Message); return false; } } public static bool RegisterCallbacks(Action onLimbHit, Action onLimbSever, Action onRespawn, Action onBloodColor, Action onFullState, Func getStateMask, Func onInteractionRequest, Action onInteractionAuthoritative) { return FusionSyncManager.RegisterCallbacks(onLimbHit, onLimbSever, onRespawn, onBloodColor, onFullState, getStateMask, onInteractionRequest, onInteractionAuthoritative); } public static bool RegisterNpcCallbacks(Func onRequest, Action onAuthoritative) { return FusionSyncManager.RegisterNpcCallbacks(onRequest, onAuthoritative); } public static void ProcessMainThreadQueue() { FusionSyncManager.ProcessMainThreadQueue(); } public static void ResetSessionState() { FusionSyncManager.ResetSessionState(); } public static void ForgetPlayer(byte playerId) { FusionSyncManager.ForgetPlayer(playerId); } public static void ForgetNpc(ushort entityId) { FusionSyncManager.ForgetNpc(entityId); } public static void ClearCallbacks() { FusionSyncManager.ClearCallbacks(); } public static void SendLimbHit(byte targetPlayerId, byte boneIndex, float damage, Vector3 hitPoint) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) FusionSyncManager.Instance?.SendLimbHit(targetPlayerId, boneIndex, damage, hitPoint); } public static void SendLimbSever(byte targetPlayerId, byte boneIndex, Vector3 hitPoint, Vector3 hitNormal, float damage) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) FusionSyncManager.Instance?.SendLimbSever(targetPlayerId, boneIndex, hitPoint, hitNormal, damage); } public static void SendPlayerInteraction(byte kind, byte targetPlayerId, byte boneIndex, byte detail, Vector3 point) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) FusionSyncManager.Instance?.SendPlayerInteraction(kind, targetPlayerId, boneIndex, detail, point); } public static void SendNpcInteraction(byte kind, ushort entityId, byte boneIndex, byte detail, float value, Vector3 point) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) FusionSyncManager.Instance?.SendNpcInteraction(kind, entityId, boneIndex, detail, value, point); } public static void SendNpcState(ushort entityId, uint goneBoneMask, byte kind = 3, byte boneIndex = 0, byte detail = 0, Vector3 point = default(Vector3)) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) FusionSyncManager.Instance?.SendNpcState(entityId, goneBoneMask, kind, boneIndex, detail, point); } public static void SendRespawn(byte playerId) { FusionSyncManager.Instance?.SendRespawn(playerId); } public static void SendBloodColor(byte playerId, byte colorIndex) { FusionSyncManager.Instance?.SendBloodColor(playerId, colorIndex); } public static void SendFullState(byte playerId, uint goneBoneMask, byte bloodColorIndex, ushort sequence = 0) { FusionSyncManager.Instance?.SendFullState(playerId, goneBoneMask, bloodColorIndex, sequence); } public static void SetPlayerMetadata(byte targetPlayerId, string key, string value) { if (string.IsNullOrEmpty(key)) { return; } try { foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null && playerID.SmallID == targetPlayerId) { PlayerMetadata metadata = playerID.Metadata; if (((metadata != null) ? metadata.Metadata : null) != null) { playerID.Metadata.Metadata.TrySetMetadata(key, value ?? string.Empty); break; } } } } catch (Exception ex) { MelonLogger.Warning("[DeadPiece] Metadata update failed: " + ex.Message); } } } [HarmonyPatch(typeof(RemapRig), "ApplyMovement")] internal static class NoLegLocomotionPatch { private static void Prefix(RemapRig __instance, ref Vector2 axis, ref bool inputPressed) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) RigManager rigManager = Player.RigManager; if (!ShouldBlock(__instance)) { if ((Object)(object)__instance != (Object)null && (Object)(object)rigManager != (Object)null && (Object)(object)rigManager.remapHeptaRig == (Object)(object)__instance && DeadPieceMod.Instance != null && DeadPieceMod.Instance.ShouldApplySingleLegSpeedPenalty(rigManager)) { axis *= 0.5f; } return; } axis = Vector2.zero; inputPressed = false; __instance._currentVelocity = Vector2.zero; __instance._currentAcceleration = Vector2.zero; __instance._locoDebt = Vector2.zero; __instance._locoApplied = Vector2.zero; __instance._trackedDebt = Vector2.zero; __instance._trackedApplied = Vector2.zero; __instance._artificialDelta = Vector2.zero; } internal static bool ShouldBlock(RemapRig remapRig) { RigManager rigManager = Player.RigManager; if ((Object)(object)remapRig != (Object)null && (Object)(object)rigManager != (Object)null && (Object)(object)rigManager.remapHeptaRig == (Object)(object)remapRig && DeadPieceMod.Instance != null && DeadPieceMod.Instance.ShouldApplyLocalNoLegEffects(rigManager)) { if (DeadPieceMod.Instance.IsHoldingNimbusGun(rigManager)) { return false; } return true; } return false; } } [HarmonyPatch(typeof(RemapRig), "Jump")] internal static class NoLegJumpPatch { private static bool Prefix(RemapRig __instance) { return !NoLegLocomotionPatch.ShouldBlock(__instance); } } [HarmonyPatch(typeof(PhysicsRig), "UpdateMonofootColliders")] internal static class NoLegColliderRefreshPatch { private static void Postfix(PhysicsRig __instance) { DeadPieceMod.Instance?.SyncLegColliderState(__instance); } } [HarmonyPatch(typeof(SubBehaviourHealth), "TakeDamage", new Type[] { typeof(int), typeof(Attack) })] internal static class NpcTakeDamagePatch { internal static void Postfix(SubBehaviourHealth __instance, int m, Attack attack) { try { DeadPieceMod.Instance?.OnNpcAttack(__instance, m, attack); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] NPC damage postfix failed: " + ex); } } } [HarmonyPatch(typeof(SubBehaviourHealth), "Resurrect")] internal static class NpcHealthResurrectPatch { internal static void Postfix(SubBehaviourHealth __instance) { try { DeadPieceMod.Instance?.RestoreAndForgetNpc(__instance); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] NPC health restore failed: " + ex); } } } [HarmonyPatch(typeof(AIBrain), "OnPoolDeInitialize")] internal static class NpcPoolDeinitializePatch { internal static void Prefix(AIBrain __instance) { try { DeadPieceMod.Instance?.RestoreAndForgetNpc(__instance); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] NPC pool cleanup failed: " + ex); } } } [HarmonyPatch(typeof(AIBrain), "OnPoolInitialize")] internal static class NpcPoolInitializePatch { internal static void Prefix(AIBrain __instance) { try { DeadPieceMod.Instance?.RestoreTrackedNpcOnPoolInitialize(__instance); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] NPC pool initialization cleanup failed: " + ex); } } } [HarmonyPatch(typeof(AIBrain), "OnResurrection")] internal static class NpcBrainResurrectionPatch { internal static void Postfix(AIBrain __instance) { try { DeadPieceMod.Instance?.RestoreAndForgetNpc(__instance); } catch (Exception ex) { MelonLogger.Error("[DeadPiece] NPC resurrection restore failed: " + ex); } } } internal static class ForcePullGuard { internal static bool IsUnavailableHand(Hand hand) { return (Object)(object)hand != (Object)null && (Object)(object)hand.manager == (Object)(object)Player.RigManager && DeadPieceMod.Instance != null && DeadPieceMod.Instance.IsLocalHandUnavailable(hand); } internal static bool ShouldBlock(ForcePullGrip forcePull, Hand hand) { if ((Object)(object)forcePull == (Object)null || (Object)(object)hand == (Object)null || (Object)(object)hand.manager != (Object)(object)Player.RigManager) { return false; } if (IsUnavailableHand(hand)) { return true; } if (hand.HasAttachedObject() || (Object)(object)hand.AttachedReceiver != (Object)null || (Object)(object)hand.m_CurrentAttachedGO != (Object)null) { return true; } return (Object)(object)forcePull._grip == (Object)null || (Object)(object)hand.farHoveringReciever != (Object)(object)forcePull._grip; } internal static void Cancel(ForcePullGrip forcePull, Hand hand) { if (!((Object)(object)forcePull == (Object)null) && !((Object)(object)hand == (Object)null)) { if ((Object)(object)forcePull._pullToHand == (Object)(object)hand) { forcePull.CancelPull(hand); } if ((Object)(object)hand.farHoveringReciever == (Object)(object)forcePull._grip) { hand.farHoveringReciever = null; } } } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ForcePullGrip), "Pull")] internal static class ForcePullStartPatch { [HarmonyPrefix] private static bool Prefix(ForcePullGrip __instance, Hand hand) { if (!ForcePullGuard.ShouldBlock(__instance, hand)) { return true; } ForcePullGuard.Cancel(__instance, hand); return false; } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ForcePullGrip), "OnFarHandHoverUpdate")] internal static class ForcePullUpdatePatch { [HarmonyPrefix] private static bool Prefix(ForcePullGrip __instance, Hand hand) { if (!ForcePullGuard.ShouldBlock(__instance, hand)) { return true; } ForcePullGuard.Cancel(__instance, hand); return false; } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ForcePullGrip), "OnStartAttach")] internal static class ForcePullStartAttachPatch { [HarmonyPrefix] private static bool Prefix(ForcePullGrip __instance, Hand hand) { if (!ForcePullGuard.IsUnavailableHand(hand)) { return true; } ForcePullGuard.Cancel(__instance, hand); return false; } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ForcePullGrip), "OnForcePullComplete")] internal static class ForcePullCompletePatch { [HarmonyPrefix] private static bool Prefix(ForcePullGrip __instance, Hand hand) { if (!ForcePullGuard.IsUnavailableHand(hand)) { return true; } ForcePullGuard.Cancel(__instance, hand); return false; } } [HarmonyPatch(typeof(Hand), "OnJointBreak", new Type[] { typeof(float) })] internal static class HandJointBreakPatch { [HarmonyPrefix] private static void Prefix(Hand __instance) { DeadPieceMod.Instance?.OnHandJointBreak(__instance); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(DeadPieceMod), "ApplyDeadpieceLegUsage")] internal static class NimbusBlockApplyDeadpieceUsage { [HarmonyPrefix] private static bool Prefix(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager) { return true; } return !DeadPieceMod.Instance.IsHoldingNimbusGun(rm); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(DeadPieceMod), "LockNoLegLocomotion")] internal static class NimbusBlockLockNoLeg { [HarmonyPrefix] private static bool Prefix(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager) { return true; } return !DeadPieceMod.Instance.IsHoldingNimbusGun(rm); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(DeadPieceMod), "ApplyNoLegFallenState")] internal static class NimbusBlockFallenState { [HarmonyPrefix] private static bool Prefix(RigManager rm) { if ((Object)(object)rm == (Object)null || (Object)(object)rm != (Object)(object)Player.RigManager) { return true; } return !DeadPieceMod.Instance.IsHoldingNimbusGun(rm); } } } namespace DeadPiece.Networking { public sealed class FusionSyncManager { public const byte RequestPhase = 0; public const byte AuthoritativePhase = 1; public const byte RipInteraction = 0; public const byte CrushInteraction = 1; public const byte NpcHitInteraction = 0; public const byte NpcRipInteraction = 1; public const byte NpcCrushInteraction = 2; public const byte NpcStateInteraction = 3; private const int TrackedBoneCount = 17; private const byte MaxBloodColorIndex = 9; private const float MaxAcceptedDamage = float.MaxValue; private const int MaxQueueSize = 1024; private const int MaxRecentEvents = 4096; public static Action OnLimbHitCallback; public static Action OnLimbSeverCallback; public static Action OnRespawnCallback; public static Action OnBloodColorCallback; public static Action OnFullStateCallback; public static Func GetStateMaskCallback; public static Func OnInteractionRequestCallback; public static Action OnInteractionAuthoritativeCallback; public static Func OnNpcInteractionRequestCallback; public static Action OnNpcInteractionAuthoritativeCallback; private static readonly ConcurrentQueue MainThreadQueue = new ConcurrentQueue(); private static readonly HashSet RecentEventKeys = new HashSet(); private static readonly Queue RecentEventOrder = new Queue(); private static readonly Dictionary AuthoritativeStateSequences = new Dictionary(); private static readonly Dictionary AuthoritativeStateMasks = new Dictionary(); private static readonly Dictionary AuthoritativeBloodColors = new Dictionary(); private static readonly HashSet RespawnResetBarriers = new HashSet(); private static readonly Dictionary AuthoritativeNpcStateSequences = new Dictionary(); private static readonly Dictionary AuthoritativeNpcStateMasks = new Dictionary(); private static readonly object EventLock = new object(); private static readonly object SequenceLock = new object(); private static bool _handlersRegistered; private static bool _initializedLogged; private static byte _localPlayerId = byte.MaxValue; private static uint _eventCounter; public static FusionSyncManager Instance { get; private set; } public static bool IsReady { get; private set; } private FusionSyncManager() { } public static bool InitializeSingleton() { if (Instance == null) { Instance = new FusionSyncManager(); } RefreshLocalPlayerId(); IsReady = true; if (!_initializedLogged) { _initializedLogged = true; MelonLogger.Msg(ConsoleColor.Gray, "[DeadPiece/Net] Host-authoritative Fusion transport initialized."); } return true; } public static bool RegisterCallbacks(Action onLimbHit, Action onLimbSever, Action onRespawn, Action onBloodColor, Action onFullState, Func getStateMask, Func onInteractionRequest, Action onInteractionAuthoritative) { OnLimbHitCallback = onLimbHit; OnLimbSeverCallback = onLimbSever; OnRespawnCallback = onRespawn; OnBloodColorCallback = onBloodColor; OnFullStateCallback = onFullState; GetStateMaskCallback = getStateMask; OnInteractionRequestCallback = onInteractionRequest; OnInteractionAuthoritativeCallback = onInteractionAuthoritative; bool flag = onLimbHit != null && onLimbSever != null && onRespawn != null && onBloodColor != null && onFullState != null && getStateMask != null && onInteractionRequest != null && onInteractionAuthoritative != null; if (flag) { MelonLogger.Msg(ConsoleColor.Gray, "[DeadPiece/Net] Gameplay callbacks registered (8/8)."); } else { MelonLogger.Warning("[DeadPiece/Net] One or more gameplay callbacks are missing."); } return flag; } public static bool RegisterNpcCallbacks(Func onRequest, Action onAuthoritative) { OnNpcInteractionRequestCallback = onRequest; OnNpcInteractionAuthoritativeCallback = onAuthoritative; bool flag = onRequest != null && onAuthoritative != null; if (flag) { MelonLogger.Msg(ConsoleColor.Gray, "[DeadPiece/Net] NPC callbacks registered (2/2)."); } else { MelonLogger.Warning("[DeadPiece/Net] One or more NPC callbacks are missing."); } return flag; } public static void ClearCallbacks() { OnLimbHitCallback = null; OnLimbSeverCallback = null; OnRespawnCallback = null; OnBloodColorCallback = null; OnFullStateCallback = null; GetStateMaskCallback = null; OnInteractionRequestCallback = null; OnInteractionAuthoritativeCallback = null; OnNpcInteractionRequestCallback = null; OnNpcInteractionAuthoritativeCallback = null; } public static bool RegisterHandlers() { if (_handlersRegistered) { return true; } InitializeSingleton(); try { RegisterHandlerIfMissing(); RegisterHandlerIfMissing(); RegisterHandlerIfMissing(); RegisterHandlerIfMissing(); RegisterHandlerIfMissing(); RegisterHandlerIfMissing(); RegisterHandlerIfMissing(); _handlersRegistered = true; MelonLogger.Msg(ConsoleColor.Gray, "[DeadPiece/Net] Fusion message handlers registered once."); return true; } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] Failed to register Fusion handlers: " + ex.Message); return false; } } private static void RegisterHandlerIfMissing() where T : ModuleMessageHandler, new() { if (ModuleMessageManager.GetHandlerByType(typeof(T)) == null) { ModuleMessageManager.RegisterHandler(); } } public static void ProcessMainThreadQueue() { for (int i = 0; i < 1024; i++) { if (!MainThreadQueue.TryDequeue(out var result)) { break; } try { result?.Invoke(); } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] Main-thread network action failed: " + ex); } } } public static void ResetSessionState() { lock (EventLock) { RecentEventKeys.Clear(); RecentEventOrder.Clear(); _eventCounter = 0u; } lock (SequenceLock) { AuthoritativeStateSequences.Clear(); AuthoritativeStateMasks.Clear(); AuthoritativeBloodColors.Clear(); RespawnResetBarriers.Clear(); AuthoritativeNpcStateSequences.Clear(); AuthoritativeNpcStateMasks.Clear(); } _localPlayerId = byte.MaxValue; Action result; while (MainThreadQueue.TryDequeue(out result)) { } } public static void ForgetPlayer(byte playerId) { lock (EventLock) { int count = RecentEventOrder.Count; for (int i = 0; i < count; i++) { ulong num = RecentEventOrder.Dequeue(); if ((byte)(num >> 32) == playerId) { RecentEventKeys.Remove(num); } else { RecentEventOrder.Enqueue(num); } } } lock (SequenceLock) { AuthoritativeStateSequences.Remove(playerId); AuthoritativeStateMasks.Remove(playerId); AuthoritativeBloodColors.Remove(playerId); RespawnResetBarriers.Remove(playerId); } } public static void ForgetNpc(ushort entityId) { lock (SequenceLock) { AuthoritativeNpcStateMasks.Remove(entityId); } } private static void MarshalToMainThread(Action action) { if (action != null) { if (MainThreadQueue.Count >= 1024) { MelonLogger.Warning("[DeadPiece/Net] Main-thread queue is full; dropping a stale network action."); } else { MainThreadQueue.Enqueue(action); } } } private static void RefreshLocalPlayerId() { try { _localPlayerId = ((PlayerIDManager.LocalID != null) ? PlayerIDManager.LocalSmallID : byte.MaxValue); } catch { _localPlayerId = byte.MaxValue; } } private static byte GetLocalPlayerId() { RefreshLocalPlayerId(); return _localPlayerId; } private static bool IsKnownPlayer(byte playerId) { try { if (PlayerIDManager.LocalID != null && PlayerIDManager.LocalSmallID == playerId) { return true; } foreach (PlayerID playerID in PlayerIDManager.PlayerIDs) { if (playerID != null && playerID.SmallID == playerId) { return true; } } } catch { } return false; } private static bool RequestSenderMatches(byte? sender, byte claimedPlayerId) { if (!sender.HasValue) { return NetworkInfo.IsHost && claimedPlayerId == GetLocalPlayerId(); } return sender.Value == claimedPlayerId; } private static bool IsAuthoritativeSender(byte? sender) { if (NetworkInfo.IsHost) { return true; } try { return !sender.HasValue || sender.Value == 0; } catch { return !sender.HasValue; } } private static bool IsFinite(float value) { return !float.IsNaN(value) && !float.IsInfinity(value); } private static bool IsFinite(Vector3 value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return IsFinite(value.x) && IsFinite(value.y) && IsFinite(value.z); } private static uint NextEventId() { lock (EventLock) { _eventCounter++; if (_eventCounter == 0) { _eventCounter = 1u; } return _eventCounter; } } private static bool RememberEvent(byte sourcePlayerId, uint eventId) { ulong item = ((ulong)sourcePlayerId << 32) | eventId; lock (EventLock) { if (!RecentEventKeys.Add(item)) { return false; } RecentEventOrder.Enqueue(item); while (RecentEventOrder.Count > 4096) { RecentEventKeys.Remove(RecentEventOrder.Dequeue()); } return true; } } private static ushort NextAuthoritativeSequence(byte playerId) { lock (SequenceLock) { AuthoritativeStateSequences.TryGetValue(playerId, out var value); value++; if (value == 0) { value = 1; } AuthoritativeStateSequences[playerId] = value; return value; } } private static ushort NextNpcAuthoritativeSequence(ushort entityId) { lock (SequenceLock) { AuthoritativeNpcStateSequences.TryGetValue(entityId, out var value); value++; if (value == 0) { value = 1; } AuthoritativeNpcStateSequences[entityId] = value; return value; } } private static void StoreNpcAuthoritativeState(ushort entityId, uint goneBoneMask) { lock (SequenceLock) { AuthoritativeNpcStateMasks[entityId] = goneBoneMask & 0x1FFFF; } } private static bool AcceptNpcAuthoritativeState(ushort entityId, uint goneBoneMask, ushort sequence) { if (sequence == 0) { return false; } lock (SequenceLock) { if (AuthoritativeNpcStateSequences.TryGetValue(entityId, out var value) && (short)(sequence - value) <= 0) { return false; } AuthoritativeNpcStateSequences[entityId] = sequence; AuthoritativeNpcStateMasks[entityId] = goneBoneMask & 0x1FFFF; return true; } } private static uint GetAuthoritativeStateMask(byte playerId) { lock (SequenceLock) { if (AuthoritativeStateMasks.TryGetValue(playerId, out var value)) { return value; } } return GetStateMaskCallback?.Invoke(playerId) ?? 0; } private static void StoreAuthoritativeState(byte playerId, uint goneBoneMask, byte bloodColorIndex) { lock (SequenceLock) { AuthoritativeStateMasks[playerId] = goneBoneMask & 0x1FFFF; AuthoritativeBloodColors[playerId] = bloodColorIndex; } } private static void StoreAuthoritativeBloodColor(byte playerId, byte bloodColorIndex) { lock (SequenceLock) { AuthoritativeBloodColors[playerId] = bloodColorIndex; } } private static bool ValidateHit(byte sourcePlayerId, byte targetPlayerId, byte boneIndex, float damage, Vector3 hitPoint) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) return sourcePlayerId != byte.MaxValue && targetPlayerId != byte.MaxValue && boneIndex < 17 && IsKnownPlayer(sourcePlayerId) && IsKnownPlayer(targetPlayerId) && IsFinite(damage) && damage > 0f && damage <= float.MaxValue && IsFinite(hitPoint); } public void SendLimbHit(byte targetPlayerId, byte boneIndex, float damage, Vector3 hitPoint) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer) { return; } byte localPlayerId = GetLocalPlayerId(); MelonLogger.Msg(ConsoleColor.DarkCyan, $"[DeadPiece/Net] SendLimbHit src={localPlayerId} tgt={targetPlayerId} bone={boneIndex} dmg={damage:F1} host={NetworkInfo.IsHost}"); LimbHitData limbHitData = new LimbHitData { Phase = 0, SourcePlayerId = localPlayerId, TargetPlayerId = targetPlayerId, BoneIndex = boneIndex, Damage = damage, HitPoint = hitPoint, EventId = NextEventId() }; try { if (NetworkInfo.IsHost) { OnLimbHitReceived(limbHitData, localPlayerId); } else { MessageRelay.RelayModule(limbHitData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendLimbHit failed: " + ex.Message); } } public void OnLimbHitReceived(LimbHitData data, byte? sender) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (data == null || !ValidateHit(data.SourcePlayerId, data.TargetPlayerId, data.BoneIndex, data.Damage, data.HitPoint)) { MelonLogger.Warning("[DeadPiece/Net] Dropped invalid limb-hit packet."); } else if (data.Phase == 0) { if (!NetworkInfo.IsHost || !RequestSenderMatches(sender, data.SourcePlayerId) || (DeadPieceMod.Instance != null && !DeadPieceMod.Instance.CanHostApplyNetworkLimbDamage(data.TargetPlayerId)) || !RememberEvent(data.SourcePlayerId, data.EventId)) { MelonLogger.Warning($"[DeadPiece/Net] OnLimbHitReceived: rejected request phase host={NetworkInfo.IsHost} sender={sender} src={data.SourcePlayerId}"); return; } MelonLogger.Msg(ConsoleColor.Green, $"[DeadPiece/Net] OnLimbHitReceived: processing request tgt={data.TargetPlayerId} bone={data.BoneIndex} dmg={data.Damage:F1}"); MarshalToMainThread(delegate { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) OnLimbHitCallback?.Invoke(data.TargetPlayerId, data.BoneIndex, data.Damage, data.HitPoint, arg5: true); data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); }); } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender) && RememberEvent(data.SourcePlayerId, data.EventId)) { MelonLogger.Msg(ConsoleColor.Green, $"[DeadPiece/Net] OnLimbHitReceived: applying authoritative tgt={data.TargetPlayerId} bone={data.BoneIndex} dmg={data.Damage:F1}"); MarshalToMainThread(delegate { //IL_0032: Unknown result type (might be due to invalid IL or missing references) OnLimbHitCallback?.Invoke(data.TargetPlayerId, data.BoneIndex, data.Damage, data.HitPoint, arg5: false); }); } } public void SendLimbSever(byte targetPlayerId, byte boneIndex, Vector3 hitPoint, Vector3 hitNormal, float damage) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer) { return; } byte localPlayerId = GetLocalPlayerId(); LimbSeverData limbSeverData = new LimbSeverData { Phase = 0, SourcePlayerId = localPlayerId, TargetPlayerId = targetPlayerId, BoneIndex = boneIndex, HitPoint = hitPoint, HitNormal = hitNormal, Damage = damage, EventId = NextEventId() }; try { if (NetworkInfo.IsHost) { OnLimbSeverReceived(limbSeverData, localPlayerId); } else { MessageRelay.RelayModule(limbSeverData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendLimbSever failed: " + ex.Message); } } public void OnLimbSeverReceived(LimbSeverData data, byte? sender) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (data == null || !ValidateHit(data.SourcePlayerId, data.TargetPlayerId, data.BoneIndex, data.Damage, data.HitPoint) || !IsFinite(data.HitNormal)) { MelonLogger.Warning("[DeadPiece/Net] Dropped invalid limb-sever packet."); } else if (data.Phase == 0) { if (NetworkInfo.IsHost && RequestSenderMatches(sender, data.SourcePlayerId) && (DeadPieceMod.Instance == null || DeadPieceMod.Instance.CanHostApplyNetworkLimbDamage(data.TargetPlayerId)) && RememberEvent(data.SourcePlayerId, data.EventId)) { MarshalToMainThread(delegate { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) OnLimbSeverCallback?.Invoke(data.TargetPlayerId, data.BoneIndex, data.HitPoint, data.HitNormal, data.Damage); data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); }); } } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender) && RememberEvent(data.SourcePlayerId, data.EventId)) { MarshalToMainThread(delegate { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) OnLimbSeverCallback?.Invoke(data.TargetPlayerId, data.BoneIndex, data.HitPoint, data.HitNormal, data.Damage); }); } } public void SendPlayerInteraction(byte kind, byte targetPlayerId, byte boneIndex, byte detail, Vector3 point) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || kind > 1 || !IsFinite(point)) { return; } byte localPlayerId = GetLocalPlayerId(); PlayerInteractionData playerInteractionData = new PlayerInteractionData { Phase = 0, Kind = kind, SourcePlayerId = localPlayerId, TargetPlayerId = targetPlayerId, BoneIndex = boneIndex, Detail = detail, Point = point, EventId = NextEventId() }; try { if (NetworkInfo.IsHost) { OnPlayerInteractionReceived(playerInteractionData, localPlayerId); } else { MessageRelay.RelayModule(playerInteractionData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendPlayerInteraction failed: " + ex.Message); } } public void OnPlayerInteractionReceived(PlayerInteractionData data, byte? sender) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (data == null || data.Kind > 1 || data.SourcePlayerId == data.TargetPlayerId || !IsKnownPlayer(data.SourcePlayerId) || !IsKnownPlayer(data.TargetPlayerId) || !IsFinite(data.Point) || (data.Kind == 0 && data.BoneIndex >= 17) || (data.Kind == 1 && data.BoneIndex != byte.MaxValue)) { return; } if (data.Phase == 0) { if (!NetworkInfo.IsHost || !RequestSenderMatches(sender, data.SourcePlayerId) || (DeadPieceMod.Instance != null && !DeadPieceMod.Instance.CanHostApplyPlayerInteraction(data.TargetPlayerId)) || !RememberEvent(data.SourcePlayerId, data.EventId)) { return; } MarshalToMainThread(delegate { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) Func onInteractionRequestCallback = OnInteractionRequestCallback; if (onInteractionRequestCallback != null && onInteractionRequestCallback(data.SourcePlayerId, data.TargetPlayerId, data.Kind, data.BoneIndex, data.Detail, data.Point)) { data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); } }); } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender) && RememberEvent(data.SourcePlayerId, data.EventId)) { MarshalToMainThread(delegate { //IL_0048: Unknown result type (might be due to invalid IL or missing references) OnInteractionAuthoritativeCallback?.Invoke(data.SourcePlayerId, data.TargetPlayerId, data.Kind, data.BoneIndex, data.Detail, data.Point); }); } } public void SendNpcInteraction(byte kind, ushort entityId, byte boneIndex, byte detail, float value, Vector3 point) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || kind > 2 || boneIndex >= 17 || !IsFinite(value) || value < 0f || !IsFinite(point)) { return; } byte localPlayerId = GetLocalPlayerId(); if (!IsKnownPlayer(localPlayerId)) { return; } NpcInteractionData npcInteractionData = new NpcInteractionData { Phase = 0, Kind = kind, SourcePlayerId = localPlayerId, EntityId = entityId, BoneIndex = boneIndex, Detail = detail, Value = value, Point = point, EventId = NextEventId(), GoneBoneMask = 0u, Sequence = 0 }; try { if (NetworkInfo.IsHost) { OnNpcInteractionReceived(npcInteractionData, localPlayerId); } else { MessageRelay.RelayModule(npcInteractionData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendNpcInteraction failed: " + ex.Message); } } public void SendNpcState(ushort entityId, uint goneBoneMask, byte kind = 3, byte boneIndex = 0, byte detail = 0, Vector3 point = default(Vector3)) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || !NetworkInfo.IsHost || kind > 3 || (kind != 3 && boneIndex >= 17) || !IsFinite(point)) { return; } byte localPlayerId = GetLocalPlayerId(); if (!IsKnownPlayer(localPlayerId)) { return; } goneBoneMask &= 0x1FFFF; NpcInteractionData npcInteractionData = new NpcInteractionData { Phase = 1, Kind = kind, SourcePlayerId = localPlayerId, EntityId = entityId, BoneIndex = boneIndex, Detail = detail, Value = 0f, Point = point, EventId = NextEventId(), GoneBoneMask = goneBoneMask, Sequence = NextNpcAuthoritativeSequence(entityId) }; StoreNpcAuthoritativeState(entityId, goneBoneMask); try { MessageRelay.RelayModule(npcInteractionData, CommonMessageRoutes.ReliableToClients); } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendNpcState failed: " + ex.Message); } } public void OnNpcInteractionReceived(NpcInteractionData data, byte? sender) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (data == null || data.Kind > 3 || data.EventId == 0 || !IsFinite(data.Value) || data.Value < 0f || !IsFinite(data.Point) || (data.Kind != 3 && data.BoneIndex >= 17) || (data.Kind == 2 && data.BoneIndex != 0)) { MelonLogger.Warning("[DeadPiece/Net] Dropped invalid NPC packet."); return; } data.GoneBoneMask &= 131071u; if (data.Phase == 0) { if (data.Kind == 3 || !NetworkInfo.IsHost || !IsKnownPlayer(data.SourcePlayerId) || !RequestSenderMatches(sender, data.SourcePlayerId) || !RememberEvent(data.SourcePlayerId, data.EventId)) { return; } MarshalToMainThread(delegate { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) uint num = (uint)(((int?)OnNpcInteractionRequestCallback?.Invoke(data.SourcePlayerId, data.EntityId, data.Kind, data.BoneIndex, data.Detail, data.Value, data.Point)) ?? (-1)); if (num != uint.MaxValue) { data.GoneBoneMask = num & 0x1FFFF; data.Sequence = NextNpcAuthoritativeSequence(data.EntityId); StoreNpcAuthoritativeState(data.EntityId, data.GoneBoneMask); data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); } }); } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender) && RememberEvent(data.SourcePlayerId, data.EventId) && AcceptNpcAuthoritativeState(data.EntityId, data.GoneBoneMask, data.Sequence)) { MarshalToMainThread(delegate { //IL_0053: Unknown result type (might be due to invalid IL or missing references) OnNpcInteractionAuthoritativeCallback?.Invoke(data.EntityId, data.GoneBoneMask, data.Sequence, data.Kind, data.BoneIndex, data.Detail, data.Point); }); } } public void SendRespawn(byte playerId) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer) { return; } byte localPlayerId = GetLocalPlayerId(); if (playerId != localPlayerId) { MelonLogger.Warning("[DeadPiece/Net] Refused a state-reset request for another player."); return; } RespawnData respawnData = new RespawnData { Phase = 0, PlayerId = playerId, RequesterId = localPlayerId, EventId = NextEventId() }; try { if (NetworkInfo.IsHost) { OnRespawnReceived(respawnData, localPlayerId); } else { MessageRelay.RelayModule(respawnData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendRespawn failed: " + ex.Message); } } public void OnRespawnReceived(RespawnData data, byte? sender) { if (data == null || !IsKnownPlayer(data.PlayerId) || !IsKnownPlayer(data.RequesterId)) { return; } if (data.Phase == 0) { if (!NetworkInfo.IsHost || data.PlayerId != data.RequesterId || !RequestSenderMatches(sender, data.RequesterId) || !RememberEvent(data.RequesterId, data.EventId)) { return; } MarshalToMainThread(delegate { //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (data.PlayerId != GetLocalPlayerId()) { lock (SequenceLock) { RespawnResetBarriers.Add(data.PlayerId); } } StoreAuthoritativeState(data.PlayerId, 0u, 0); OnRespawnCallback?.Invoke(data.PlayerId); data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); }); } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender) && RememberEvent(data.RequesterId, data.EventId)) { MarshalToMainThread(delegate { OnRespawnCallback?.Invoke(data.PlayerId); }); } } public void SendBloodColor(byte playerId, byte colorIndex) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || colorIndex > 9) { return; } byte localPlayerId = GetLocalPlayerId(); BloodColorData bloodColorData = new BloodColorData { Phase = (byte)(NetworkInfo.IsHost ? 1 : 0), PlayerId = playerId, ColorIndex = colorIndex, EventId = NextEventId() }; try { if (NetworkInfo.IsHost) { if (playerId == localPlayerId || IsKnownPlayer(playerId)) { RememberEvent(localPlayerId, bloodColorData.EventId); StoreAuthoritativeBloodColor(playerId, colorIndex); MessageRelay.RelayModule(bloodColorData, CommonMessageRoutes.ReliableToClients); } } else if (playerId == localPlayerId) { MessageRelay.RelayModule(bloodColorData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendBloodColor failed: " + ex.Message); } } public void OnBloodColorReceived(BloodColorData data, byte? sender) { if (data == null || data.ColorIndex > 9 || !IsKnownPlayer(data.PlayerId)) { return; } if (data.Phase == 0) { if (NetworkInfo.IsHost && RequestSenderMatches(sender, data.PlayerId) && RememberEvent(data.PlayerId, data.EventId)) { MarshalToMainThread(delegate { //IL_0056: Unknown result type (might be due to invalid IL or missing references) StoreAuthoritativeBloodColor(data.PlayerId, data.ColorIndex); OnBloodColorCallback?.Invoke(data.PlayerId, data.ColorIndex); data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); }); } } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender) && RememberEvent(data.PlayerId, data.EventId)) { MarshalToMainThread(delegate { OnBloodColorCallback?.Invoke(data.PlayerId, data.ColorIndex); }); } } public void SendFullState(byte playerId, uint goneBoneMask, byte bloodColorIndex, ushort ignoredClientSequence = 0) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (!NetworkInfo.HasServer || bloodColorIndex > 9) { return; } goneBoneMask &= 0x1FFFF; byte localPlayerId = GetLocalPlayerId(); FullStateData fullStateData = new FullStateData { Phase = (byte)(NetworkInfo.IsHost ? 1 : 0), PlayerId = playerId, GoneBoneMask = goneBoneMask, BloodColorIndex = bloodColorIndex, Sequence = 0 }; try { if (NetworkInfo.IsHost) { if (IsKnownPlayer(playerId)) { fullStateData.Sequence = NextAuthoritativeSequence(playerId); StoreAuthoritativeState(playerId, goneBoneMask, bloodColorIndex); MessageRelay.RelayModule(fullStateData, CommonMessageRoutes.ReliableToClients); } } else if (playerId == localPlayerId) { MessageRelay.RelayModule(fullStateData, CommonMessageRoutes.ReliableToServer); } } catch (Exception ex) { MelonLogger.Error("[DeadPiece/Net] SendFullState failed: " + ex.Message); } } public void OnFullStateReceived(FullStateData data, byte? sender) { if (data == null || data.BloodColorIndex > 9 || !IsKnownPlayer(data.PlayerId)) { return; } data.GoneBoneMask &= 131071u; if (data.Phase == 0) { if (!NetworkInfo.IsHost || !RequestSenderMatches(sender, data.PlayerId)) { return; } MarshalToMainThread(delegate { //IL_0182: Unknown result type (might be due to invalid IL or missing references) bool flag = false; lock (SequenceLock) { if (RespawnResetBarriers.Contains(data.PlayerId)) { flag = true; if (data.GoneBoneMask == 0) { RespawnResetBarriers.Remove(data.PlayerId); } else { data.GoneBoneMask = 0u; } } } if ((DeadPieceMod.Instance == null || DeadPieceMod.Instance.CanHostSynchronizeNetworkLimbState(data.PlayerId)) && !flag) { uint authoritativeStateMask = GetAuthoritativeStateMask(data.PlayerId); data.GoneBoneMask = (data.GoneBoneMask | authoritativeStateMask) & 0x1FFFF; } else { data.GoneBoneMask = 0u; } data.Sequence = NextAuthoritativeSequence(data.PlayerId); StoreAuthoritativeState(data.PlayerId, data.GoneBoneMask, data.BloodColorIndex); OnFullStateCallback?.Invoke(data.PlayerId, data.GoneBoneMask, data.BloodColorIndex, data.Sequence); data.Phase = 1; MessageRelay.RelayModule(data, CommonMessageRoutes.ReliableToClients); }); } else if (data.Phase == 1 && !NetworkInfo.IsHost && IsAuthoritativeSender(sender)) { MarshalToMainThread(delegate { OnFullStateCallback?.Invoke(data.PlayerId, data.GoneBoneMask, data.BloodColorIndex, data.Sequence); }); } } } } namespace DeadPiece.Networking.Messages { public class BloodColorData : INetSerializable { public byte Phase; public byte PlayerId; public byte ColorIndex; public uint EventId; public int? GetSize() { return 7; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref PlayerId); serializer.SerializeValue(ref ColorIndex); serializer.SerializeValue(ref EventId); } } public class BloodColorMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { BloodColorData bloodColorData = ((ReceivedMessage)(ref received)).ReadData(); if (bloodColorData != null) { FusionSyncManager.Instance?.OnBloodColorReceived(bloodColorData, ((ReceivedMessage)(ref received)).Sender); } } } public class FullStateData : INetSerializable { public byte Phase; public byte PlayerId; public uint GoneBoneMask; public byte BloodColorIndex; public ushort Sequence; public int? GetSize() { return 9; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref PlayerId); serializer.SerializeValue(ref GoneBoneMask); serializer.SerializeValue(ref BloodColorIndex); serializer.SerializeValue(ref Sequence); } } public class FullStateMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { FullStateData fullStateData = ((ReceivedMessage)(ref received)).ReadData(); if (fullStateData != null) { FusionSyncManager.Instance?.OnFullStateReceived(fullStateData, ((ReceivedMessage)(ref received)).Sender); } } } public class LimbHitData : INetSerializable { public byte Phase; public byte SourcePlayerId; public byte TargetPlayerId; public byte BoneIndex; public float Damage; public Vector3 HitPoint; public uint EventId; public int? GetSize() { return 24; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref SourcePlayerId); serializer.SerializeValue(ref TargetPlayerId); serializer.SerializeValue(ref BoneIndex); serializer.SerializeValue(ref Damage); NetSerializerUnityExtensions.SerializeValue(serializer, ref HitPoint); serializer.SerializeValue(ref EventId); } } [SkipHandleWhileLoading] public class LimbHitMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { LimbHitData limbHitData = ((ReceivedMessage)(ref received)).ReadData(); if (limbHitData != null) { FusionSyncManager.Instance?.OnLimbHitReceived(limbHitData, ((ReceivedMessage)(ref received)).Sender); } } } public class LimbSeverData : INetSerializable { public byte Phase; public byte SourcePlayerId; public byte TargetPlayerId; public byte BoneIndex; public Vector3 HitPoint; public Vector3 HitNormal; public float Damage; public uint EventId; public int? GetSize() { return 36; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref SourcePlayerId); serializer.SerializeValue(ref TargetPlayerId); serializer.SerializeValue(ref BoneIndex); NetSerializerUnityExtensions.SerializeValue(serializer, ref HitPoint); NetSerializerUnityExtensions.SerializeValue(serializer, ref HitNormal); serializer.SerializeValue(ref Damage); serializer.SerializeValue(ref EventId); } } [SkipHandleWhileLoading] public class LimbSeverMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { LimbSeverData limbSeverData = ((ReceivedMessage)(ref received)).ReadData(); if (limbSeverData != null) { FusionSyncManager.Instance?.OnLimbSeverReceived(limbSeverData, ((ReceivedMessage)(ref received)).Sender); } } } public class NpcInteractionData : INetSerializable { public byte Phase; public byte Kind; public byte SourcePlayerId; public ushort EntityId; public byte BoneIndex; public byte Detail; public float Value; public Vector3 Point; public uint EventId; public uint GoneBoneMask; public ushort Sequence; public int? GetSize() { return 33; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref Kind); serializer.SerializeValue(ref SourcePlayerId); serializer.SerializeValue(ref EntityId); serializer.SerializeValue(ref BoneIndex); serializer.SerializeValue(ref Detail); serializer.SerializeValue(ref Value); NetSerializerUnityExtensions.SerializeValue(serializer, ref Point); serializer.SerializeValue(ref EventId); serializer.SerializeValue(ref GoneBoneMask); serializer.SerializeValue(ref Sequence); } } public class NpcInteractionMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { NpcInteractionData npcInteractionData = ((ReceivedMessage)(ref received)).ReadData(); if (npcInteractionData != null) { FusionSyncManager.Instance?.OnNpcInteractionReceived(npcInteractionData, ((ReceivedMessage)(ref received)).Sender); } } } public class PlayerInteractionData : INetSerializable { public byte Phase; public byte Kind; public byte SourcePlayerId; public byte TargetPlayerId; public byte BoneIndex; public byte Detail; public Vector3 Point; public uint EventId; public int? GetSize() { return 22; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref Kind); serializer.SerializeValue(ref SourcePlayerId); serializer.SerializeValue(ref TargetPlayerId); serializer.SerializeValue(ref BoneIndex); serializer.SerializeValue(ref Detail); NetSerializerUnityExtensions.SerializeValue(serializer, ref Point); serializer.SerializeValue(ref EventId); } } [SkipHandleWhileLoading] public class PlayerInteractionMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { PlayerInteractionData playerInteractionData = ((ReceivedMessage)(ref received)).ReadData(); if (playerInteractionData != null) { FusionSyncManager.Instance?.OnPlayerInteractionReceived(playerInteractionData, ((ReceivedMessage)(ref received)).Sender); } } } public class RespawnData : INetSerializable { public byte Phase; public byte PlayerId; public byte RequesterId; public uint EventId; public int? GetSize() { return 7; } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref Phase); serializer.SerializeValue(ref PlayerId); serializer.SerializeValue(ref RequesterId); serializer.SerializeValue(ref EventId); } } [SkipHandleWhileLoading] public class RespawnMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { RespawnData respawnData = ((ReceivedMessage)(ref received)).ReadData(); if (respawnData != null) { FusionSyncManager.Instance?.OnRespawnReceived(respawnData, ((ReceivedMessage)(ref received)).Sender); } } } } namespace DeadPiece.Unity { public class BloodEffect : MonoBehaviour { public int particleCount = 30; public float particleLifetime = 3f; public float particleSpeed = 5f; public float particleGravity = 9.8f; public Color bloodColor = new Color(0.5f, 0f, 0f); public int decalCount = 5; public float decalLifetime = 10f; public float decalSize = 0.1f; public void Initialize(float damage) { Object.Destroy((Object)(object)((Component)this).gameObject, Mathf.Max(particleLifetime, decalLifetime) + 1f); } } }