Decompiled source of BoneyCam v0.1.3

Mods/BoneyCam.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using BoneyCam;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Combat;
using Il2CppSLZ.Data;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.PuppetMasta;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VRMK;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "BoneyCam", "0.1.3", "Geozek", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BoneyCam
{
	public sealed class Mod : MelonMod
	{
		internal static Mod Instance;

		internal Settings S;

		internal Blood Blood;

		internal SoundEffects Sounds;

		private ChestCamera bodycam;

		private bool menuReady;

		private float nextMenu;

		private float nextError;

		public static event Action<Vector3, Vector3, Color> DropletEmitted;

		public static void ReceiveDroplet(Vector3 position, Vector3 velocity, Color color)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			Mod instance = Instance;
			if (instance != null && instance.S.Enabled.Value)
			{
				try
				{
					instance.Blood.Receive(position, velocity, color);
				}
				catch (Exception e)
				{
					instance.Error(e);
				}
			}
		}

		internal static void ShareDroplet(Vector3 position, Vector3 velocity, Color color)
		{
			//IL_000b: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mod.DropletEmitted?.Invoke(position, velocity, color);
			}
			catch (Exception e)
			{
				Instance?.Error(e);
			}
		}

		public override void OnInitializeMelon()
		{
			Instance = this;
			S = new Settings();
			Blood = new Blood(this);
			bodycam = new ChestCamera(this);
			Sounds = new SoundEffects(this);
			((MelonBase)this).LoggerInstance.Msg("BoneyCam 0.1.3: directional low-poly splashes, separate splash limits; 31 recorded blood drips and optional explosion ringing. Author: Geozek.");
		}

		public override void OnUpdate()
		{
			try
			{
				Sounds.Tick();
			}
			catch (Exception e)
			{
				Sounds.Clear();
				Error(e);
			}
			try
			{
				if (!menuReady && Time.unscaledTime >= nextMenu)
				{
					nextMenu = Time.unscaledTime + 2f;
					if (Page.Root != null)
					{
						S.Menu(this);
						menuReady = true;
					}
				}
				if (!S.Camera.Value && !S.Headcam.Value)
				{
					bodycam.Release();
				}
			}
			catch (Exception e2)
			{
				Error(e2);
			}
		}

		internal void AfterRigLateUpdate(RigManager rig)
		{
			if ((Object)(object)rig != (Object)(object)Player.RigManager)
			{
				return;
			}
			try
			{
				bodycam.Tick();
			}
			catch (Exception e)
			{
				bodycam.Release();
				Error(e);
			}
		}

		public override void OnLateUpdate()
		{
			try
			{
				Blood.Tick(Mathf.Min(Time.deltaTime, 0.05f));
			}
			catch (Exception e)
			{
				Error(e);
			}
		}

		public override void OnFixedUpdate()
		{
			try
			{
				Blood.CheckNoseImpact();
			}
			catch (Exception e)
			{
				Error(e);
			}
		}

		public override void OnSceneWasUnloaded(int index, string name)
		{
			Sounds.Clear();
			Blood.Clear();
			bodycam.Release();
		}

		public override void OnDeinitializeMelon()
		{
			Sounds.Clear();
			Blood.Dispose();
			bodycam.Release();
			S.Category.SaveToFile(false);
			Instance = null;
		}

		internal void Error(Exception e)
		{
			if (!(Time.unscaledTime < nextError))
			{
				nextError = Time.unscaledTime + 5f;
				((MelonBase)this).LoggerInstance.Warning(e.ToString());
			}
		}

		internal void Log(string text)
		{
			((MelonBase)this).LoggerInstance.Msg(text);
		}

		internal void Status()
		{
			Log(Blood.Status + "; camera=" + bodycam.Status);
		}
	}
	internal sealed class Settings
	{
		internal readonly MelonPreferences_Category Category = MelonPreferences.CreateCategory("BoneyCam");

		private readonly List<Action> resetControls = new List<Action>();

		internal MelonPreferences_Entry<bool> Enabled;

		internal MelonPreferences_Entry<bool> Drips;

		internal MelonPreferences_Entry<bool> Pools;

		internal MelonPreferences_Entry<bool> Melee;

		internal MelonPreferences_Entry<bool> DeadOnly;

		internal MelonPreferences_Entry<bool> Camera;

		internal MelonPreferences_Entry<bool> Debug;

		internal MelonPreferences_Entry<bool> Shine;

		internal MelonPreferences_Entry<bool> ReplaceVanilla;

		internal MelonPreferences_Entry<bool> NpcColors;

		internal MelonPreferences_Entry<bool> VariedShapes;

		internal MelonPreferences_Entry<float> SurfaceTrailLength;

		internal MelonPreferences_Entry<float> SurfaceTrailChance;

		internal MelonPreferences_Entry<bool> Headcam;

		internal MelonPreferences_Entry<float> HeadFov;

		internal MelonPreferences_Entry<float> HeadX;

		internal MelonPreferences_Entry<float> HeadY;

		internal MelonPreferences_Entry<float> HeadZ;

		internal MelonPreferences_Entry<float> HeadPitch;

		internal MelonPreferences_Entry<float> HeadYaw;

		internal MelonPreferences_Entry<float> HeadRoll;

		internal MelonPreferences_Entry<float> HeadSmooth;

		internal MelonPreferences_Entry<bool> SurfaceTrails;

		internal MelonPreferences_Entry<bool> Ringing;

		internal MelonPreferences_Entry<bool> DripSounds;

		internal MelonPreferences_Entry<float> RingVolume;

		internal MelonPreferences_Entry<float> RingDuration;

		internal MelonPreferences_Entry<float> RingRange;

		internal MelonPreferences_Entry<float> DripVolume;

		internal MelonPreferences_Entry<float> RingDelayMs;

		internal MelonPreferences_Entry<float> RingFadeDownMs;

		internal MelonPreferences_Entry<bool> Nosebleeds;

		internal MelonPreferences_Entry<float> NoseSpeed;

		internal MelonPreferences_Entry<float> NoseDuration;

		internal MelonPreferences_Entry<float> WallStainScale;

		internal MelonPreferences_Entry<bool> CeilingDrips;

		internal MelonPreferences_Entry<float> Duration;

		internal MelonPreferences_Entry<float> Rate;

		internal MelonPreferences_Entry<float> DropSize;

		internal MelonPreferences_Entry<float> PoolGrowth;

		internal MelonPreferences_Entry<float> PoolRadius;

		internal MelonPreferences_Entry<float> Lifetime;

		internal MelonPreferences_Entry<float> DryTime;

		internal MelonPreferences_Entry<float> Red;

		internal MelonPreferences_Entry<float> Green;

		internal MelonPreferences_Entry<float> Blue;

		internal MelonPreferences_Entry<float> Opacity;

		internal MelonPreferences_Entry<float> Fov;

		internal MelonPreferences_Entry<float> X;

		internal MelonPreferences_Entry<float> Y;

		internal MelonPreferences_Entry<float> Z;

		internal MelonPreferences_Entry<float> Pitch;

		internal MelonPreferences_Entry<float> Yaw;

		internal MelonPreferences_Entry<float> Roll;

		internal MelonPreferences_Entry<float> Smooth;

		internal MelonPreferences_Entry<float> WetGloss;

		internal MelonPreferences_Entry<float> DryGloss;

		internal MelonPreferences_Entry<int> Wounds;

		internal MelonPreferences_Entry<int> Drops;

		internal MelonPreferences_Entry<int> Stains;

		internal MelonPreferences_Entry<int> SplashStains;

		internal MelonPreferences_Entry<int> SprayDrops;

		internal MelonPreferences_Entry<int> SprayExtraDrops;

		internal MelonPreferences_Entry<bool> ExitSpray;

		internal MelonPreferences_Entry<bool> PlayerBleeding;

		internal MelonPreferences_Entry<float> SprayChance;

		internal MelonPreferences_Entry<float> SpraySpeed;

		internal MelonPreferences_Entry<float> SpraySpread;

		internal MelonPreferences_Entry<float> SprayFloorShare;

		internal Settings()
		{
			Ringing = B("ExplosionRinging", v: true);
			DripSounds = B("BloodImpactSounds", v: true);
			RingVolume = F("RingingVolume", 0.15f);
			RingDuration = F("RingingSeconds", 12f);
			RingRange = F("RingingDistance", 12f);
			RingDelayMs = F("RingingDelayMilliseconds", 25f);
			RingFadeDownMs = F("RingingFadeDownMilliseconds", 40f);
			MelonPreferences_Entry<bool> val = B("FastRingingApplied", v: false);
			if (!val.Value)
			{
				RingDelayMs.Value = 25f;
				RingFadeDownMs.Value = 40f;
				val.Value = true;
				Category.SaveToFile(false);
			}
			DripVolume = F("BloodImpactVolume", 0.35f);
			SurfaceTrails = B("SurfaceBloodTrails", v: true);
			SurfaceTrailLength = F("SurfaceBloodTrailLength", 1f);
			SurfaceTrailChance = F("SurfaceBloodTailChance", 0.5f);
			WallStainScale = F("WallStainScale", 0.6f);
			CeilingDrips = B("CeilingBloodDrips", v: true);
			bool value = B("WallImpactNosebleeds", v: false).Value;
			bool value2 = B("NpcBluntFaceNosebleeds", v: true).Value;
			Nosebleeds = B("NosebleedsEnabled", value || value2);
			Nosebleeds.DefaultValue = true;
			NoseSpeed = F("NosebleedMinimumSpeed", 2.5f);
			NoseDuration = F("NosebleedSeconds", 8f);
			PlayerBleeding = B("PlayerBleeding", v: true);
			Enabled = B("BloodEnabled", v: true);
			Drips = B("DripsEnabled", v: true);
			Pools = B("PoolsEnabled", v: true);
			ReplaceVanilla = B("SuppressVanillaBloodImpacts", v: true);
			NpcColors = B("UseNpcBloodColors", v: true);
			VariedShapes = B("VariedStainShapes", v: true);
			ExitSpray = B("GunshotExitSpray", v: true);
			SprayChance = F("ExitSprayChance", 0.8f);
			SprayDrops = I("ExitSprayDroplets", 6);
			SpraySpeed = F("ExitSpraySpeed", 4f);
			SpraySpread = F("ExitSprayConeDegrees", 18f);
			SprayFloorShare = F("ExitSprayFloorShare", 0.5f);
			SprayExtraDrops = I("ExitSprayExtraHitDroplets", 4);
			Melee = B("SharpMeleeBleeding", v: true);
			DeadOnly = B("BleedOnlyWhenDead", v: false);
			Camera = B("BodycamEnabled", v: false);
			Debug = B("VerboseLogging", v: false);
			Duration = F("BleedSeconds", 15f);
			Rate = F("DropsPerSecond", 5f);
			DropSize = F("DropDiameter", 0.009f);
			PoolGrowth = F("AreaPerDrop", 0.0018f);
			PoolRadius = F("MaximumPoolRadius", 0.35f);
			Lifetime = F("StainLifetimeSeconds", 300f);
			DryTime = F("DryingSeconds", 60f);
			MelonPreferences_Entry<bool> val2 = B("FiveMinuteLifetimeApplied", v: false);
			if (!val2.Value)
			{
				Lifetime.Value = 300f;
				val2.Value = true;
				Category.SaveToFile(false);
			}
			Red = F("BloodRed", 0.3f);
			Green = F("BloodGreen", 0.012f);
			Blue = F("BloodBlue", 0.018f);
			Opacity = F("Opacity", 1f);
			Shine = B("WetBloodShine", v: true);
			WetGloss = F("WetSmoothness", 0.95f);
			DryGloss = F("DrySmoothness", 0.15f);
			Wounds = I("MaxWounds", 32);
			Drops = I("MaxDrops", 96);
			Stains = I("MaxStains", 200);
			SplashStains = I("MaxSmallSplashMarks", 256);
			Fov = F("BodycamFov", 100f);
			X = F("CameraRight", 0f);
			Y = F("CameraUp", 0.11f);
			Z = F("CameraForward", 0.2f);
			Pitch = F("CameraPitch", 12f);
			Yaw = F("CameraYaw", 0f);
			Roll = F("CameraRoll", 0f);
			Smooth = F("CameraSmoothing", 0f);
			Headcam = B("HeadcamEnabled", v: false);
			HeadFov = F("HeadcamFov", 100f);
			HeadX = F("HeadcamRight", 0.19f);
			HeadY = F("HeadcamUp", 0.16f);
			HeadZ = F("HeadcamForward", 0.17f);
			HeadPitch = F("HeadcamPitch", 0f);
			HeadYaw = F("HeadcamYaw", 0f);
			HeadRoll = F("HeadcamRoll", 0f);
			HeadSmooth = F("HeadcamSmoothing", 0f);
		}

		private MelonPreferences_Entry<bool> B(string n, bool v)
		{
			return Category.CreateEntry<bool>(n, v, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		}

		private MelonPreferences_Entry<float> F(string n, float v)
		{
			return Category.CreateEntry<float>(n, v, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		}

		private MelonPreferences_Entry<int> I(string n, int v)
		{
			return Category.CreateEntry<int>(n, v, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		}

		internal static float V(MelonPreferences_Entry<float> e, float min, float max, float fallback)
		{
			if (!float.IsFinite(e.Value))
			{
				return fallback;
			}
			return Math.Clamp(e.Value, min, max);
		}

		internal void Menu(Mod mod)
		{
			//IL_0038: 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_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_081f: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_08fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0926: Unknown result type (might be due to invalid IL or missing references)
			resetControls.Clear();
			Page obj = Page.Root.CreatePage("BoneyCam", new Color(0.8f, 0.12f, 0.16f), 8, true);
			Page p = obj.CreatePage("Blood & Wounds", Color.red, 8, true);
			Toggle(p, "Blood enabled", Enabled);
			Toggle(p, "Player bleeding", PlayerBleeding);
			Toggle(p, "Visible droplets", Drips);
			Toggle(p, "Pools grow and merge", Pools);
			Toggle(p, "Sharp melee bleeding", Melee);
			Toggle(p, "Only bleed after death", DeadOnly);
			Toggle(p, "Suppress vanilla blood impacts", ReplaceVanilla);
			Slider(p, "Bleed duration (seconds)", Duration, 1f, 2f, 120f);
			Slider(p, "Drops per second", Rate, 0.5f, 0.5f, 12f);
			Slider(p, "Drop diameter (m)", DropSize, 0.002f, 0.003f, 0.03f);
			Page p2 = obj.CreatePage("Gunshot Exit Spray", Color.red, 8, true);
			Toggle(p2, "Exit spray enabled", ExitSpray);
			Slider(p2, "Chance (0 to 1)", SprayChance, 0.1f, 0f, 1f);
			Integer(p2, "Spray amount (droplets)", SprayDrops, 1, 3, 64);
			Slider(p2, "Speed (m/s)", SpraySpeed, 0.5f, 1f, 8f);
			Slider(p2, "Cone angle (degrees)", SpraySpread, 2f, 2f, 35f);
			Slider(p2, "Floor share (0 to 1)", SprayFloorShare, 0.1f, 0f, 1f);
			Integer(p2, "Extra droplets per additional hit", SprayExtraDrops, 1, 0, 32);
			Page p3 = obj.CreatePage("Pools & Appearance", Color.red, 8, true);
			Toggle(p3, "Use NPC blood colours", NpcColors);
			Toggle(p3, "Varied stain shapes", VariedShapes);
			Toggle(p3, "Scattered splash droplets", SurfaceTrails);
			Slider(p3, "Splash spread multiplier", SurfaceTrailLength, 0.1f, 0.2f, 2f);
			Slider(p3, "Splash chance (0 to 1)", SurfaceTrailChance, 0.05f, 0f, 1f);
			Toggle(p3, "Ceiling drips (10 seconds)", CeilingDrips);
			Slider(p3, "Wall stain scale (relative to floor)", WallStainScale, 0.1f, 0.2f, 1f);
			Slider(p3, "Pool area per drop", PoolGrowth, 0.0003f, 0.0003f, 0.008f);
			Slider(p3, "Maximum pool radius (m)", PoolRadius, 0.05f, 0.05f, 1f);
			Slider(p3, "Stain lifetime (seconds)", Lifetime, 30f, 10f, 900f);
			Slider(p3, "Drying time (seconds)", DryTime, 5f, 5f, 300f);
			Slider(p3, "Red", Red, 0.025f, 0f, 1f);
			Slider(p3, "Green", Green, 0.01f, 0f, 1f);
			Slider(p3, "Blue", Blue, 0.01f, 0f, 1f);
			Slider(p3, "Opacity", Opacity, 0.05f, 0.1f, 1f);
			Toggle(p3, "Wet blood shine", Shine);
			Slider(p3, "Wet smoothness", WetGloss, 0.05f, 0f, 1f);
			Slider(p3, "Dry smoothness", DryGloss, 0.05f, 0f, 1f);
			Page p4 = obj.CreatePage("Bodycam", Color.cyan, 10, true);
			Toggle(p4, "Enable bodycam", Camera);
			Slider(p4, "Field of view", Fov, 5f, 50f, 130f);
			Slider(p4, "Right offset (m)", X, 0.01f, -0.5f, 0.5f);
			Slider(p4, "Up offset (m)", Y, 0.01f, -0.5f, 0.5f);
			Slider(p4, "Forward offset (m)", Z, 0.01f, 0.05f, 0.6f);
			Slider(p4, "Pitch down (degrees)", Pitch, 2f, -60f, 60f);
			Slider(p4, "Yaw (degrees)", Yaw, 2f, -90f, 90f);
			Slider(p4, "Roll (degrees)", Roll, 2f, -45f, 45f);
			Slider(p4, "Smoothing (seconds)", Smooth, 0.01f, 0f, 0.5f);
			Page p5 = obj.CreatePage("Helmetcam", Color.cyan, 10, true);
			Toggle(p5, "Enable helmetcam", Headcam);
			Slider(p5, "Field of view", HeadFov, 5f, 50f, 130f);
			Slider(p5, "Right offset (m)", HeadX, 0.01f, -0.5f, 0.5f);
			Slider(p5, "Up offset (m)", HeadY, 0.01f, -0.5f, 0.5f);
			Slider(p5, "Forward offset (m)", HeadZ, 0.01f, -0.5f, 0.6f);
			Slider(p5, "Pitch down (degrees)", HeadPitch, 2f, -60f, 60f);
			Slider(p5, "Yaw (degrees)", HeadYaw, 2f, -90f, 90f);
			Slider(p5, "Roll (degrees)", HeadRoll, 2f, -45f, 45f);
			Slider(p5, "Smoothing (seconds)", HeadSmooth, 0.01f, 0f, 0.5f);
			Toggle(p, "Nosebleeds", Nosebleeds);
			Slider(p, "Minimum head impact speed (m/s)", NoseSpeed, 0.25f, 0.5f, 10f);
			Slider(p, "Nosebleed duration (seconds)", NoseDuration, 1f, 1f, 30f);
			Page val = obj.CreatePage("Sound Effects", Color.cyan, 10, true);
			Toggle(val, "Blood impact sounds", DripSounds);
			Slider(val, "Blood impact volume", DripVolume, 0.05f, 0f, 1f);
			Toggle(val, "Explosion ringing", Ringing);
			Slider(val, "Ringing volume", RingVolume, 0.01f, 0f, 0.35f);
			Slider(val, "Ringing duration (seconds)", RingDuration, 1f, 1f, 15f);
			Slider(val, "Ringing distance (m)", RingRange, 1f, 2f, 30f);
			Slider(val, "Explosion audio delay (ms)", RingDelayMs, 5f, 0f, 500f);
			Slider(val, "Game audio fade-down (ms)", RingFadeDownMs, 5f, 0f, 500f);
			val.CreateFunction("Preview ringing (when enabled)", Color.yellow, (Action)mod.Sounds.Preview);
			Page val2 = obj.CreatePage("Limits & Diagnostics", Color.white, 10, true);
			Integer(val2, "Maximum wounds", Wounds, 4, 4, 64);
			Integer(val2, "Maximum droplets", Drops, 16, 16, 256);
			Integer(val2, "Maximum surface stains", Stains, 20, 20, 400);
			Toggle(val2, "Verbose logs", Debug);
			Integer(val2, "Maximum small splash marks", SplashStains, 32, 32, 1024);
			val2.CreateFunction("Print status to log", Color.white, (Action)mod.Status);
			val2.CreateFunction("Clear all BoneyCam blood", Color.white, (Action)mod.Blood.Clear);
			val2.CreateFunction("Test drips in front of player", Color.yellow, (Action)mod.Blood.Test);
			val2.CreateFunction("Reset all settings to defaults", Color.yellow, (Action)delegate
			{
				ResetDefaults(mod);
			});
			mod.Log("BoneMenu ready. Use Limits & Diagnostics / Test drips to test rendering without shooting an NPC.");
		}

		private void ResetDefaults(Mod mod)
		{
			foreach (Action resetControl in resetControls)
			{
				resetControl();
			}
			Category.SaveToFile(false);
			mod.Log("All BoneyCam settings reset to defaults and saved.");
		}

		private void Toggle(Page p, string n, MelonPreferences_Entry<bool> e)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			BoolElement control = p.CreateBool(n, Color.white, e.Value, (Action<bool>)delegate(bool v)
			{
				e.Value = v;
				Category.SaveToFile(false);
			});
			resetControls.Add(delegate
			{
				((MelonPreferences_Entry)e).ResetToDefault();
				control.Value = e.Value;
			});
		}

		private void Slider(Page p, string n, MelonPreferences_Entry<float> e, float step, float min, float max)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			FloatElement control = p.CreateFloat(n, Color.white, V(e, min, max, min), step, min, max, (Action<float>)delegate(float v)
			{
				e.Value = v;
				Category.SaveToFile(false);
			});
			resetControls.Add(delegate
			{
				((MelonPreferences_Entry)e).ResetToDefault();
				control.Value = V(e, min, max, min);
			});
		}

		private void Integer(Page p, string n, MelonPreferences_Entry<int> e, int step, int min, int max)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			IntElement control = p.CreateInt(n, Color.white, Math.Clamp(e.Value, min, max), step, min, max, (Action<int>)delegate(int v)
			{
				e.Value = v;
				Category.SaveToFile(false);
			});
			resetControls.Add(delegate
			{
				((MelonPreferences_Entry)e).ResetToDefault();
				control.Value = Math.Clamp(e.Value, min, max);
			});
		}
	}
	[HarmonyPatch(typeof(PlayerDamageReceiver), "ReceiveAttack")]
	internal static class PlayerBloodHook
	{
		private static void Prefix(PlayerDamageReceiver __instance, Attack attack)
		{
			try
			{
				Mod.Instance?.Blood.PlayerHit(__instance, attack);
			}
			catch (Exception e)
			{
				Mod.Instance?.Error(e);
			}
		}
	}
	[HarmonyPatch(typeof(SubBehaviourHealth), "TakeDamage")]
	internal static class DamageHook
	{
		private static void Prefix(SubBehaviourHealth __instance, int m, Attack attack)
		{
			try
			{
				Mod.Instance?.Blood.Hit(__instance, m, attack);
			}
			catch (Exception e)
			{
				Mod.Instance?.Error(e);
			}
		}
	}
	[HarmonyPatch(typeof(RigManager), "LateUpdate")]
	internal static class RigLateHook
	{
		private static void Postfix(RigManager __instance)
		{
			Mod.Instance?.AfterRigLateUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(Projectile), "ExecuteEventCallback")]
	internal static class ProjectileHook
	{
		internal sealed class Shot
		{
			internal Vector3 Origin;

			internal Vector3 Direction;

			internal Collider Collider;

			private readonly HashSet<int> sprayOwners = new HashSet<int>();

			internal bool ClaimSpray(int owner)
			{
				return sprayOwners.Add(owner);
			}

			internal bool Matches(Attack a)
			{
				//IL_0004: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Invalid comparison between Unknown and I4
				//IL_000d: 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_0018: 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_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_0042: 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_004a: 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)
				if (a != null && (int)a.attackType == 1)
				{
					Vector3 val = a.origin - Origin;
					if (((Vector3)(ref val)).sqrMagnitude < 0.0004f)
					{
						val = a.direction;
						if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
						{
							val = a.direction;
							return Vector3.Dot(((Vector3)(ref val)).normalized, ((Vector3)(ref Direction)).normalized) > 0.99f;
						}
					}
				}
				return false;
			}
		}

		[ThreadStatic]
		internal static Shot ActiveAttack;

		internal static Shot Match(Attack a)
		{
			if (ActiveAttack == null || !ActiveAttack.Matches(a))
			{
				return null;
			}
			return ActiveAttack;
		}

		private static void Prefix(Projectile __instance, out Shot __state)
		{
			//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_0027: 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)
			__state = ActiveAttack;
			Attack attack = __instance._attack;
			ActiveAttack = ((attack != null) ? new Shot
			{
				Origin = attack.origin,
				Direction = attack.direction,
				Collider = attack.collider
			} : null);
		}

		private static Exception Finalizer(Exception __exception, Shot __state)
		{
			ActiveAttack = __state;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ImpactProperties), "ReceiveAttack")]
	internal static class NativeBloodHook
	{
		private static int suppressed;

		private static bool Prefix(ImpactProperties __instance)
		{
			Mod instance = Mod.Instance;
			if (instance == null || !instance.S.Enabled.Value || !instance.S.ReplaceVanilla.Value || !Object.op_Implicit((Object)(object)__instance))
			{
				return true;
			}
			try
			{
				DataCardReference<SurfaceDataCard> surfaceDataCard = __instance.SurfaceDataCard;
				object obj;
				if (surfaceDataCard == null)
				{
					obj = null;
				}
				else
				{
					Barcode barcode = ((ScannableReference)surfaceDataCard).Barcode;
					obj = ((barcode != null) ? barcode.ID : null);
				}
				string id = (string)obj;
				SurfaceData surfaceData = __instance.surfaceData;
				if ((!BloodPalette.IsHydraulic(id) || !Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInParent<PuppetMaster>())) && !BloodPalette.IsBloodSurface(id) && (!Object.op_Implicit((Object)(object)surfaceData) || ((Object)surfaceData).name != "Blood Surface"))
				{
					return true;
				}
				if (suppressed++ < 6 || instance.S.Debug.Value)
				{
					instance.Log("Suppressed native Blood surface impact VFX; BoneyCam damage hook remains separate.");
				}
				return false;
			}
			catch (Exception e)
			{
				instance.Error(e);
				return true;
			}
		}
	}
	internal static class BloodLayers
	{
		internal static int FindFree(int occupied)
		{
			for (int i = 0; i < 16; i++)
			{
				if ((occupied & (1 << i)) == 0)
				{
					return i;
				}
			}
			return -1;
		}

		internal static float Offset(int layer)
		{
			return 0.002f + (float)layer * 0.0005f;
		}
	}
	internal static class BloodPalette
	{
		internal static bool IsHydraulic(string id)
		{
			return id == "SLZ.Backlot.SurfaceDataCard.Hydraulic";
		}

		internal static bool IsBloodSurface(string id)
		{
			switch (id)
			{
			default:
				return id == "SLZ.BONELAB.Content.SurfaceDataCard.ZapperPurple";
			case "SLZ.Backlot.SurfaceDataCard.Blood":
			case "SLZ.Backlot.SurfaceDataCard.Bioluminescent":
			case "SLZ.BONELAB.Content.SurfaceDataCard.ZapperOrange":
			case "SLZ.BONELAB.Content.SurfaceDataCard.ZapperGreen":
				return true;
			}
		}

		internal static Color Normalize(Color c, Color fallback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0029: 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_0035: 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_0084: 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_00a8: 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)
			if (!float.IsFinite(c.r) || !float.IsFinite(c.g) || !float.IsFinite(c.b))
			{
				return fallback;
			}
			float num = Mathf.Max(c.r, Mathf.Max(c.g, c.b));
			if (num <= 0f)
			{
				return new Color(0f, 0f, 0f, 1f);
			}
			float num2 = ((num > 1f) ? (1f / num) : 1f);
			return new Color(Mathf.Max(0f, c.r) * num2, Mathf.Max(0f, c.g) * num2, Mathf.Max(0f, c.b) * num2, 1f);
		}

		internal static Color Fallback(string id, Color fallback)
		{
			//IL_005a: 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_0075: 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_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_00aa: 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_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_00c6: 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)
			return (Color)(id switch
			{
				"SLZ.Backlot.SurfaceDataCard.Hydraulic" => new Color(0.03773582f, 0.03773582f, 0.03773582f, 1f), 
				"SLZ.BONELAB.Content.SurfaceDataCard.ZapperOrange" => Normalize(new Color(2.251858f, 0.643388f, 0.266229f), fallback), 
				"SLZ.BONELAB.Content.SurfaceDataCard.ZapperGreen" => Normalize(new Color(0.700217f, 2.065593f, 0.14615f), fallback), 
				"SLZ.BONELAB.Content.SurfaceDataCard.ZapperPurple" => Normalize(new Color(0.3f, 0f, 1.584314f), fallback), 
				"SLZ.Backlot.SurfaceDataCard.Bioluminescent" => Normalize(new Color(0f, 0.707035f, 2.113208f), fallback), 
				_ => fallback, 
			});
		}

		internal static Color Mix(Color a, float areaA, Color b, float areaB)
		{
			//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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Color.Lerp(a, b, areaB / Mathf.Max(1E-06f, areaA + areaB));
		}
	}
	[HarmonyPatch(typeof(AIBrain), "OnPoolDeInitialize")]
	internal static class DespawnHook
	{
		private static void Prefix(AIBrain __instance)
		{
			Mod.Instance?.Blood.Forget(__instance.puppetMaster);
		}
	}
	[HarmonyPatch(typeof(AIBrain), "OnResurrection")]
	internal static class ReviveHook
	{
		private static void Prefix(AIBrain __instance)
		{
			Mod.Instance?.Blood.Forget(__instance.puppetMaster);
		}
	}
	internal static class BloodImpact
	{
		internal static float Footprint(float speed, float strength)
		{
			if (!float.IsFinite(speed))
			{
				speed = 2f;
			}
			if (!float.IsFinite(strength))
			{
				strength = 1f;
			}
			float num = 0.8f + 0.1f * Math.Clamp(speed, 0f, 12f);
			return Math.Clamp(1f + (num - 1f) * Math.Clamp(strength, 0f, 2f), 0.5f, 3f);
		}
	}
	internal sealed class ExitSprayBurst
	{
		internal float Until;

		internal bool Passed;

		internal int Attempts;

		internal int Emitted;

		internal int Qualified;

		internal int Take(int first, int extra, int available)
		{
			int num = Math.Min((Qualified++ == 0) ? Math.Clamp(first, 3, 64) : Math.Clamp(extra, 0, 32), Math.Min(Math.Max(0, available), 64 - Emitted));
			Emitted += num;
			return num;
		}
	}
	internal sealed class Blood
	{
		private sealed class Wound
		{
			internal bool Nose;

			internal bool BluntNose;

			internal Color Color;

			internal PuppetMaster Owner;

			internal RigManager PlayerOwner;

			internal Health PlayerHealth;

			internal int AvatarId;

			internal bool WasDead;

			internal Transform Anchor;

			internal Rigidbody Body;

			internal Vector3 Local;

			internal float End;

			internal float Next;

			internal float LastHit;
		}

		private sealed class Drop
		{
			internal Color Color;

			internal Renderer Renderer;

			internal GameObject Go;

			internal Vector3 Position;

			internal Vector3 Velocity;

			internal float Age;
		}

		private sealed class Stain
		{
			internal Stain TrailSource;

			internal float TrailReveal;

			internal float CeilingEnd;

			internal float NextCeilingDrip;

			internal Color Color;

			internal GameObject Go;

			internal Collider Surface;

			internal Vector3 LocalPoint;

			internal Vector3 LocalNormal;

			internal Vector3 LocalTangent;

			internal int Layer;

			internal int Shape;

			internal bool TrailMark;

			internal bool SmallSurface;

			internal float ReservedRadius;

			internal float Area;

			internal float Radius;

			internal float Last;

			internal float Created;

			internal Renderer Renderer;

			internal MaterialPropertyBlock Block = new MaterialPropertyBlock();
		}

		private readonly Mod mod;

		private readonly List<Wound> wounds = new List<Wound>();

		private readonly List<Drop> drops = new List<Drop>();

		private readonly Stack<Drop> spareDrops = new Stack<Drop>();

		private readonly MaterialPropertyBlock dropBlock = new MaterialPropertyBlock();

		private readonly List<Stain> stains = new List<Stain>();

		private int mainStainCount;

		private int splashStainCount;

		private Material material;

		private Material wetMaterial;

		private bool triedWetShader;

		private Mesh[] stainMeshes;

		private Mesh[] splashMeshes;

		private Texture2D[] masTextures;

		private float lastWet = -1f;

		private float lastDry = -1f;

		private Texture2D texture;

		private int received;

		private int emitted;

		private int landed;

		private readonly Dictionary<int, ExitSprayBurst> sprayTimes = new Dictionary<int, ExitSprayBurst>();

		private float nextSpray;

		private int sprayed;

		private int sprayReports;

		private int confirmedShots;

		private string sprayResult = "no shot received";

		private double tickMs;

		private double maxTickMs;

		private float nextStainUpdate;

		private float lastStainUpdate;

		private readonly Il2CppStructArray<RaycastHit> rayHits = new Il2CppStructArray<RaycastHit>(32L);

		private Transform noseTrackedHead;

		private Vector3 noseLastPosition;

		private Vector3 noseLastVelocity;

		private float noseCooldown;

		private readonly Il2CppStructArray<RaycastHit> noseHits = new Il2CppStructArray<RaycastHit>(8L);

		private readonly Dictionary<int, float> noseRollTimes = new Dictionary<int, float>();

		private bool meshDiagnosticLogged;

		private int trailQueries;

		private int trailMarks;

		private float trailCredit = 40f;

		private bool directionDiagnosticLogged;

		private Settings S => mod.S;

		internal string Status => $"wounds={wounds.Count}, drops={drops.Count}, stains={mainStainCount}, small splashes={splashStainCount}, hits={received}, confirmed bullets={confirmedShots}, exit bursts={sprayed}, spray={sprayResult}, emitted={emitted}, landed={landed}, blood CPU ms={tickMs:F2}, peak={maxTickMs:F2}";

		private void RemoveStain(int index)
		{
			Stain stain = stains[index];
			if (stain.TrailMark)
			{
				splashStainCount--;
			}
			else
			{
				mainStainCount--;
			}
			DestroyStain(stain);
			stains.RemoveAt(index);
		}

		private void TrimStains(bool small, int limit)
		{
			int num = (small ? splashStainCount : mainStainCount) - limit;
			int num2 = 0;
			while (num > 0 && num2 < stains.Count)
			{
				if (stains[num2].TrailMark == small)
				{
					RemoveStain(num2);
					num--;
				}
				else
				{
					num2++;
				}
			}
		}

		private static void DestroyStain(Stain p)
		{
			if (Object.op_Implicit((Object)(object)p.Go))
			{
				Object.Destroy((Object)(object)p.Go);
			}
		}

		internal Blood(Mod mod)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			this.mod = mod;
		}

		internal void CheckNoseImpact()
		{
			//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_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_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_00d8: 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_00df: 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_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_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_010f: 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_00f6: 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_0115: 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_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_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_0147: 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_01b1: 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_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: 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_0204: 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_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: 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)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: 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_02f7: 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_0263: 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_0381: 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_0388: Unknown result type (might be due to invalid IL or missing references)
			RigManager rigManager = Player.RigManager;
			Transform val = ((Object.op_Implicit((Object)(object)rigManager) && Object.op_Implicit((Object)(object)rigManager.physicsRig)) ? ((Rig)rigManager.physicsRig).m_head : null);
			if (!S.Enabled.Value || !S.PlayerBleeding.Value || !S.Nosebleeds.Value || !Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)rigManager.avatar) || !Object.op_Implicit((Object)(object)rigManager.health) || !rigManager.health.alive)
			{
				noseTrackedHead = null;
				noseLastVelocity = Vector3.zero;
				return;
			}
			Vector3 position = val.position;
			if ((Object)(object)val != (Object)(object)noseTrackedHead)
			{
				noseTrackedHead = val;
				noseLastPosition = position;
				noseLastVelocity = Vector3.zero;
				return;
			}
			Vector3 val2 = position - noseLastPosition;
			noseLastPosition = position;
			Rigidbody componentInParent = ((Component)val).GetComponentInParent<Rigidbody>();
			Vector3 val3 = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.GetPointVelocity(position) : (val2 / Mathf.Max(0.001f, Time.fixedDeltaTime)));
			Vector3 val4 = ((((Vector3)(ref val3)).sqrMagnitude >= ((Vector3)(ref noseLastVelocity)).sqrMagnitude) ? val3 : noseLastVelocity);
			noseLastVelocity = val3;
			if (!Finite(position) || !Finite(val4) || ((Vector3)(ref val2)).sqrMagnitude > 1f || ((Vector3)(ref val4)).sqrMagnitude > 400f || Time.time < noseCooldown)
			{
				return;
			}
			float num = Settings.V(S.NoseSpeed, 0.5f, 10f, 2.5f);
			if (((Vector3)(ref val4)).sqrMagnitude < num * num)
			{
				return;
			}
			Vector3 normalized = ((Vector3)(ref val4)).normalized;
			Transform head = Player.Head;
			if (!Object.op_Implicit((Object)(object)head) || Vector3.Dot(head.forward, normalized) < 0.4f)
			{
				return;
			}
			int num2 = Physics.RaycastNonAlloc(position, normalized, noseHits, 0.18f, -5, (QueryTriggerInteraction)1);
			bool flag = false;
			for (int i = 0; i < num2; i++)
			{
				RaycastHit val5 = ((Il2CppArrayBase<RaycastHit>)(object)noseHits)[i];
				Collider collider = ((RaycastHit)(ref val5)).collider;
				if (Object.op_Implicit((Object)(object)collider) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent<RigManager>()) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent<PuppetMaster>()) && !Object.op_Implicit((Object)(object)collider.attachedRigidbody) && !(Mathf.Abs(((RaycastHit)(ref val5)).normal.y) > 0.5f) && !(0f - Vector3.Dot(val4, ((RaycastHit)(ref val5)).normal) < num))
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				Animator animator = rigManager.avatar.animator;
				Transform val6 = ((Object.op_Implicit((Object)(object)animator) && animator.isHuman) ? animator.GetBoneTransform((HumanBodyBones)10) : val);
				if (!Object.op_Implicit((Object)(object)val6))
				{
					val6 = val;
				}
				Vector3 val7 = val6.position + head.forward * 0.09f - head.up * 0.025f;
				while (wounds.Count >= Math.Clamp(S.Wounds.Value, 4, 64))
				{
					wounds.RemoveAt(0);
				}
				wounds.Add(new Wound
				{
					Nose = true,
					PlayerOwner = rigManager,
					PlayerHealth = rigManager.health,
					AvatarId = ((Object)rigManager.avatar).GetInstanceID(),
					Anchor = val6,
					Body = componentInParent,
					Color = CustomColor(),
					Local = val6.InverseTransformPoint(val7),
					End = Time.time + Settings.V(S.NoseDuration, 1f, 30f, 8f),
					Next = Time.time,
					LastHit = Time.time
				});
				noseCooldown = Time.time + 5f;
				if (S.Debug.Value)
				{
					mod.Log("Wall impact nosebleed: head approach speed=" + ((Vector3)(ref val4)).magnitude.ToString("F2") + " m/s");
				}
			}
		}

		private bool WoundValid(Wound wound)
		{
			if (wound.BluntNose && !S.Nosebleeds.Value)
			{
				return false;
			}
			if (wound.Nose && !S.Nosebleeds.Value)
			{
				return false;
			}
			if (Object.op_Implicit((Object)(object)wound.PlayerOwner))
			{
				RigManager playerOwner = wound.PlayerOwner;
				if (!S.PlayerBleeding.Value || !Object.op_Implicit((Object)(object)wound.PlayerHealth) || !Object.op_Implicit((Object)(object)playerOwner.avatar) || ((Object)playerOwner.avatar).GetInstanceID() != wound.AvatarId)
				{
					return false;
				}
				bool flag = !wound.PlayerHealth.alive;
				if (wound.WasDead && !flag)
				{
					return false;
				}
				wound.WasDead = flag;
				return true;
			}
			return Object.op_Implicit((Object)(object)wound.Owner);
		}

		internal void PlayerHit(PlayerDamageReceiver receiver, Attack attack)
		{
			//IL_003d: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Invalid comparison between Unknown and I4
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			//IL_0144: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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_0160: 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_0207: Invalid comparison between Unknown and I4
			//IL_021e: 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_01a9: 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_01b0: 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_01d7: 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_0267: 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_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: 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)
			if (!S.Enabled.Value || !S.PlayerBleeding.Value || !Object.op_Implicit((Object)(object)receiver) || attack == null || !(attack.damage > 0f) || !Finite(attack.origin))
			{
				return;
			}
			AttackType attackType = attack.attackType;
			if ((int)attackType != 1 && (!S.Melee.Value || ((int)attackType != 16 && (int)attackType != 32)))
			{
				return;
			}
			Health health = receiver.health;
			RigManager val = (Object.op_Implicit((Object)(object)health) ? health._rigManager : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = ((Component)receiver).GetComponentInParent<RigManager>();
			}
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)health) || !Object.op_Implicit((Object)(object)val.avatar))
			{
				return;
			}
			ProjectileHook.Shot shot = ProjectileHook.Match(attack);
			Collider val2 = ((shot != null && Object.op_Implicit((Object)(object)shot.Collider)) ? shot.Collider : attack.collider);
			if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)((Component)val2).GetComponentInParent<RigManager>() != (Object)(object)val)
			{
				val2 = ((Component)receiver).GetComponent<Collider>();
			}
			if (!Object.op_Implicit((Object)(object)val2) || !val2.enabled || !((Component)val2).gameObject.activeInHierarchy || (Object)(object)((Component)val2).GetComponentInParent<RigManager>() != (Object)(object)val)
			{
				return;
			}
			Rigidbody attachedRigidbody = val2.attachedRigidbody;
			Transform transform = ((Component)val2).transform;
			Vector3 val3 = val2.ClosestPoint(attack.origin);
			if (!Finite(val3))
			{
				return;
			}
			Color val4 = CustomColor();
			ImpactProperties component = ((Component)val2).GetComponent<ImpactProperties>();
			if (Object.op_Implicit((Object)(object)component))
			{
				DataCardReference<SurfaceDataCard> surfaceDataCard = component.SurfaceDataCard;
				object obj;
				if (surfaceDataCard == null)
				{
					obj = null;
				}
				else
				{
					Barcode barcode = ((ScannableReference)surfaceDataCard).Barcode;
					obj = ((barcode != null) ? barcode.ID : null);
				}
				string id = (string)obj;
				if (BloodPalette.IsBloodSurface(id) || BloodPalette.IsHydraulic(id))
				{
					val4 = BloodPalette.Fallback(id, val4);
					if (!BloodPalette.IsHydraulic(id) && Object.op_Implicit((Object)(object)component.surfaceData))
					{
						val4 = BloodPalette.Normalize(component.surfaceData.ParicleColorTint, val4);
					}
				}
			}
			received++;
			float time = Time.time;
			if (S.ExitSpray.Value && (int)attackType == 1 && shot != null)
			{
				confirmedShots++;
				TryExitSpray(null, val2, val3, attack, val4, val);
			}
			foreach (Wound wound in wounds)
			{
				if (!((Object)(object)wound.PlayerOwner == (Object)(object)val) || !((Object)(object)wound.Anchor == (Object)(object)transform))
				{
					continue;
				}
				Vector3 val5 = transform.TransformPoint(wound.Local) - val3;
				if (((Vector3)(ref val5)).sqrMagnitude < 0.0036f)
				{
					if (time - wound.LastHit > 0.08f)
					{
						wound.End = time + Settings.V(S.Duration, 2f, 120f, 15f);
						wound.LastHit = time;
					}
					return;
				}
			}
			while (wounds.Count >= Math.Clamp(S.Wounds.Value, 4, 64))
			{
				wounds.RemoveAt(0);
			}
			wounds.Add(new Wound
			{
				PlayerOwner = val,
				PlayerHealth = health,
				AvatarId = ((Object)val.avatar).GetInstanceID(),
				WasDead = !health.alive,
				Anchor = transform,
				Body = attachedRigidbody,
				Color = val4,
				Local = transform.InverseTransformPoint(val3),
				End = time + Settings.V(S.Duration, 2f, 120f, 15f),
				Next = time + 0.12f,
				LastHit = time
			});
			if (received <= 8 || S.Debug.Value)
			{
				mod.Log("Player wound on " + ((Object)transform).name + "; " + Status);
			}
		}

		internal unsafe void Hit(SubBehaviourHealth health, int muscleIndex, Attack attack)
		{
			//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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Invalid comparison between Unknown and I4
			//IL_00be: 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_01ca: 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_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: 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_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: 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_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Invalid comparison between Unknown and I4
			//IL_0262: 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_0227: 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_022e: 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_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: 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_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
			if (!S.Enabled.Value || health == null || attack == null || !health.isOrganic || !(attack.damage > 0f))
			{
				return;
			}
			AttackType attackType = attack.attackType;
			bool flag = S.Nosebleeds.Value && (int)attackType == 2;
			if (!flag && (int)attackType != 1 && (!S.Melee.Value || ((int)attackType != 16 && (int)attackType != 32)))
			{
				return;
			}
			BehaviourBase behaviour = ((SubBehaviourBase)health).behaviour;
			PuppetMaster val = ((behaviour != null) ? behaviour.puppetMaster : null);
			ProjectileHook.Shot shot = ProjectileHook.Match(attack);
			Collider val2 = ((shot != null && Object.op_Implicit((Object)(object)shot.Collider)) ? shot.Collider : attack.collider);
			if (!Object.op_Implicit((Object)(object)val) || val.muscles == null || !Finite(attack.origin))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)val2))
			{
				val2 = ResolveNetworkCollider(val, muscleIndex, attack.origin);
			}
			if (!Object.op_Implicit((Object)(object)val2) || !((Component)val2).gameObject.activeInHierarchy)
			{
				return;
			}
			Transform val3 = null;
			Rigidbody val4 = null;
			Muscle muscle = null;
			if (val.muscles == null)
			{
				return;
			}
			Rigidbody attachedRigidbody = val2.attachedRigidbody;
			if (!Object.op_Implicit((Object)(object)attachedRigidbody))
			{
				return;
			}
			foreach (Muscle item in (Il2CppArrayBase<Muscle>)(object)val.muscles)
			{
				object obj;
				if (item == null)
				{
					obj = null;
				}
				else
				{
					MarrowBody marrowBody = item.marrowBody;
					obj = ((marrowBody != null) ? marrowBody._rigidbody : null);
				}
				Rigidbody val5 = (Rigidbody)obj;
				if (Object.op_Implicit((Object)(object)val5) && (Object)(object)attachedRigidbody == (Object)(object)val5)
				{
					val3 = ((Component)val5).transform;
					val4 = val5;
					muscle = item;
					break;
				}
			}
			if (!Object.op_Implicit((Object)(object)val3))
			{
				return;
			}
			ImpactProperties val6 = ((Component)val2).GetComponent<ImpactProperties>();
			if (!Object.op_Implicit((Object)(object)val6))
			{
				val6 = ((Component)val3).GetComponent<ImpactProperties>();
			}
			if (!Object.op_Implicit((Object)(object)val6))
			{
				val6 = ((Component)val2).GetComponentInParent<ImpactProperties>();
			}
			Color val7 = CustomColor();
			if (Object.op_Implicit((Object)(object)val6))
			{
				DataCardReference<SurfaceDataCard> surfaceDataCard = val6.SurfaceDataCard;
				object obj2;
				if (surfaceDataCard == null)
				{
					obj2 = null;
				}
				else
				{
					Barcode barcode = ((ScannableReference)surfaceDataCard).Barcode;
					obj2 = ((barcode != null) ? barcode.ID : null);
				}
				string text = (string)obj2;
				val7 = BloodPalette.Fallback(text, val7);
				if (!BloodPalette.IsHydraulic(text) && Object.op_Implicit((Object)(object)val6.surfaceData))
				{
					val7 = BloodPalette.Normalize(val6.surfaceData.ParicleColorTint, val7);
				}
				if (received < 8 || S.Debug.Value)
				{
					Mod obj3 = mod;
					Color val8 = val7;
					obj3.Log("NPC blood surface=" + text + "; tint=" + ((object)(*(Color*)(&val8))/*cast due to .constrained prefix*/).ToString());
				}
			}
			received++;
			Vector3 val9 = val2.ClosestPoint(attack.origin);
			if (!Finite(val9))
			{
				return;
			}
			float time = Time.time;
			if (flag)
			{
				TryBluntNose(val, muscle, val2, val4, val9, val7, time);
				return;
			}
			if (S.ExitSpray.Value && (int)attackType == 1)
			{
				if (shot != null)
				{
					confirmedShots++;
					TryExitSpray(val, val2, val9, attack, val7);
				}
				else
				{
					SprayNote("no matching projectile callback");
				}
			}
			val3 = ((Component)val2).transform;
			Vector3 val10;
			foreach (Wound wound in wounds)
			{
				if (!((Object)(object)wound.Owner == (Object)(object)val) || !((Object)(object)wound.Anchor == (Object)(object)val3))
				{
					continue;
				}
				val10 = val3.TransformPoint(wound.Local) - val9;
				if (((Vector3)(ref val10)).sqrMagnitude < 0.0036f)
				{
					if (time - wound.LastHit > 0.08f)
					{
						wound.End = time + Settings.V(S.Duration, 2f, 120f, 15f);
						wound.LastHit = time;
					}
					return;
				}
			}
			while (wounds.Count >= Math.Clamp(S.Wounds.Value, 4, 64))
			{
				wounds.RemoveAt(0);
			}
			wounds.Add(new Wound
			{
				Color = val7,
				Owner = val,
				Anchor = val3,
				Body = val4,
				Local = val3.InverseTransformPoint(val9),
				End = time + Settings.V(S.Duration, 2f, 120f, 15f),
				Next = time + 0.12f,
				LastHit = time
			});
			if (received <= 8 || S.Debug.Value)
			{
				Mod obj4 = mod;
				string[] obj5 = new string[10]
				{
					"Wound registered: collider=",
					((Object)val2).name,
					"; physics=",
					((Object)val4).name,
					"; anchor=",
					((Object)val3).name,
					"; hit=",
					null,
					null,
					null
				};
				val10 = val9;
				obj5[7] = ((object)(*(Vector3*)(&val10))/*cast due to .constrained prefix*/).ToString();
				obj5[8] = "; ";
				obj5[9] = Status;
				obj4.Log(string.Concat(obj5));
			}
		}

		private void TryBluntNose(PuppetMaster owner, Muscle muscle, Collider collider, Rigidbody body, Vector3 point, Color color, float now)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//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_00da: 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)
			//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_00f0: 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_0106: 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_0092: 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_00a1: 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_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_00c2: 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_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_0180: 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_0187: 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_0190: 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_01a4: 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_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)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			if (muscle == null || muscle.props == null || (int)muscle.props.group != 2 || !Object.op_Implicit((Object)(object)owner.targetRoot))
			{
				return;
			}
			Vector3 val = owner.targetRoot.forward;
			Animator targetAnimator = owner.targetAnimator;
			if (Object.op_Implicit((Object)(object)targetAnimator) && targetAnimator.isHuman)
			{
				Transform boneTransform = targetAnimator.GetBoneTransform((HumanBodyBones)10);
				Transform boneTransform2 = targetAnimator.GetBoneTransform((HumanBodyBones)21);
				Transform boneTransform3 = targetAnimator.GetBoneTransform((HumanBodyBones)22);
				if (Object.op_Implicit((Object)(object)boneTransform) && Object.op_Implicit((Object)(object)boneTransform2) && Object.op_Implicit((Object)(object)boneTransform3))
				{
					Vector3 val2 = Vector3.ProjectOnPlane((boneTransform2.position + boneTransform3.position) * 0.5f - boneTransform.position, owner.targetRoot.up);
					if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
					{
						val = ((Vector3)(ref val2)).normalized;
					}
				}
			}
			Bounds bounds = collider.bounds;
			Vector3 val3 = point - ((Bounds)(ref bounds)).center;
			if (((Vector3)(ref val3)).sqrMagnitude < 1E-06f || Vector3.Dot(((Vector3)(ref val3)).normalized, val) < 0.25f)
			{
				return;
			}
			int instanceID = ((Object)owner).GetInstanceID();
			if (noseRollTimes.TryGetValue(instanceID, out var value) && now - value < 0.35f)
			{
				return;
			}
			if (noseRollTimes.Count >= 128)
			{
				noseRollTimes.Clear();
			}
			noseRollTimes[instanceID] = now;
			if (Random.value >= 0.5f)
			{
				return;
			}
			bounds = collider.bounds;
			Vector3 center = ((Bounds)(ref bounds)).center;
			Vector3 val4 = val;
			bounds = collider.bounds;
			Vector3 extents = ((Bounds)(ref bounds)).extents;
			Vector3 val5 = collider.ClosestPoint(center + val4 * (((Vector3)(ref extents)).magnitude + 0.05f));
			if (!Finite(val5))
			{
				return;
			}
			foreach (Wound wound in wounds)
			{
				if (wound.BluntNose && (Object)(object)wound.Owner == (Object)(object)owner)
				{
					wound.End = now + Settings.V(S.NoseDuration, 1f, 30f, 8f);
					wound.LastHit = now;
					return;
				}
			}
			while (wounds.Count >= Math.Clamp(S.Wounds.Value, 4, 64))
			{
				wounds.RemoveAt(0);
			}
			wounds.Add(new Wound
			{
				BluntNose = true,
				Owner = owner,
				Anchor = ((Component)collider).transform,
				Body = body,
				Color = color,
				Local = ((Component)collider).transform.InverseTransformPoint(val5),
				End = now + Settings.V(S.NoseDuration, 1f, 30f, 8f),
				Next = now,
				LastHit = now
			});
			if (S.Debug.Value)
			{
				mod.Log("NPC face nosebleed: blunt hit passed 50% roll; collider=" + ((Object)collider).name);
			}
		}

		private static Collider NearestBodyCollider(Rigidbody body, Vector3 origin)
		{
			//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_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_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)body))
			{
				return null;
			}
			Collider result = null;
			float num = float.MaxValue;
			foreach (Collider componentsInChild in ((Component)body).GetComponentsInChildren<Collider>(true))
			{
				if (Object.op_Implicit((Object)(object)componentsInChild) && componentsInChild.enabled && !componentsInChild.isTrigger && ((Component)componentsInChild).gameObject.activeInHierarchy && !((Object)(object)componentsInChild.attachedRigidbody != (Object)(object)body))
				{
					Vector3 val = componentsInChild.ClosestPoint(origin) - origin;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						result = componentsInChild;
					}
				}
			}
			return result;
		}

		private static Collider ResolveNetworkCollider(PuppetMaster owner, int muscleIndex, Vector3 origin)
		{
			//IL_0033: 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_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_008e: 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)
			Il2CppReferenceArray<Muscle> muscles = owner.muscles;
			if (muscleIndex >= 0 && muscleIndex < ((Il2CppArrayBase<Muscle>)(object)muscles).Length)
			{
				Muscle obj = ((Il2CppArrayBase<Muscle>)(object)muscles)[muscleIndex];
				object body;
				if (obj == null)
				{
					body = null;
				}
				else
				{
					MarrowBody marrowBody = obj.marrowBody;
					body = ((marrowBody != null) ? marrowBody._rigidbody : null);
				}
				Collider val = NearestBodyCollider((Rigidbody)body, origin);
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			Collider result = null;
			float num = 0.0625f;
			foreach (Muscle item in (Il2CppArrayBase<Muscle>)(object)muscles)
			{
				object body2;
				if (item == null)
				{
					body2 = null;
				}
				else
				{
					MarrowBody marrowBody2 = item.marrowBody;
					body2 = ((marrowBody2 != null) ? marrowBody2._rigidbody : null);
				}
				Collider val2 = NearestBodyCollider((Rigidbody)body2, origin);
				if (Object.op_Implicit((Object)(object)val2))
				{
					Vector3 val3 = val2.ClosestPoint(origin) - origin;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						result = val2;
					}
				}
			}
			return result;
		}

		internal void Forget(PuppetMaster owner)
		{
			wounds.RemoveAll((Wound w) => (Object)(object)w.Owner == (Object)(object)owner);
			if (Object.op_Implicit((Object)(object)owner))
			{
				sprayTimes.Remove(((Object)owner).GetInstanceID());
				noseRollTimes.Remove(((Object)owner).GetInstanceID());
			}
		}

		private void SprayNote(string reason)
		{
			sprayResult = reason;
			if (sprayReports++ < 16 || S.Debug.Value)
			{
				mod.Log("Exit spray: " + reason);
			}
		}

		private static bool OwnCollider(PuppetMaster owner, Collider c, RigManager player = null)
		{
			if (Object.op_Implicit((Object)(object)player))
			{
				return (Object)(object)((Component)c).GetComponentInParent<RigManager>() == (Object)(object)player;
			}
			if (!Object.op_Implicit((Object)(object)owner))
			{
				return false;
			}
			if ((Object)(object)((Component)c).GetComponentInParent<PuppetMaster>() == (Object)(object)owner)
			{
				return true;
			}
			Rigidbody attachedRigidbody = c.attachedRigidbody;
			if (!Object.op_Implicit((Object)(object)attachedRigidbody))
			{
				return false;
			}
			foreach (Muscle item in (Il2CppArrayBase<Muscle>)(object)owner.muscles)
			{
				object obj;
				if (item == null)
				{
					obj = null;
				}
				else
				{
					MarrowBody marrowBody = item.marrowBody;
					obj = ((marrowBody != null) ? marrowBody._rigidbody : null);
				}
				if ((Object)obj == (Object)(object)attachedRigidbody)
				{
					return true;
				}
			}
			return false;
		}

		private void TryExitSpray(PuppetMaster owner, Collider collider, Vector3 point, Attack attack, Color color, RigManager player = null)
		{
			//IL_000b: 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_0156: 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_015f: 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_0167: 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_0170: 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_01ab: 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_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_01ba: 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_01c1: 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_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: 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)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: 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_022c: 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_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: 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_02d4: 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_02e7: 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_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: 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_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: 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_03d6: 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_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0448: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: 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_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			if (!attack.backFacing && Finite(attack.direction))
			{
				Vector3 val = attack.direction;
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
				{
					float time = Time.time;
					int num = (Object.op_Implicit((Object)(object)player) ? ((Object)player).GetInstanceID() : ((Object)owner).GetInstanceID());
					ProjectileHook.Shot shot = ProjectileHook.Match(attack);
					if (shot == null || !shot.ClaimSpray(num))
					{
						return;
					}
					if (!sprayTimes.TryGetValue(num, out var value) || time >= value.Until)
					{
						if (time < nextSpray)
						{
							SprayNote("global burst cooldown");
							return;
						}
						if (sprayTimes.Count >= 64)
						{
							sprayTimes.Clear();
						}
						value = new ExitSprayBurst
						{
							Until = time + 0.15f,
							Passed = (Random.value < Settings.V(S.SprayChance, 0f, 1f, 0.8f))
						};
						sprayTimes[num] = value;
						nextSpray = time + 0.04f;
					}
					if (!value.Passed)
					{
						SprayNote("burst chance skipped");
						return;
					}
					if (value.Attempts++ >= 16 || value.Emitted >= 64)
					{
						SprayNote("burst budget reached");
						return;
					}
					val = attack.direction;
					Vector3 normalized = ((Vector3)(ref val)).normalized;
					Bounds bounds = collider.bounds;
					val = ((Bounds)(ref bounds)).extents;
					float num2 = ((Vector3)(ref val)).magnitude * 2f + 0.05f;
					if (!float.IsFinite(num2) || num2 > 3f)
					{
						SprayNote("hit collider too large");
						return;
					}
					RaycastHit val2 = default(RaycastHit);
					if (!collider.Raycast(new Ray(point + normalized * num2, -normalized), ref val2, num2))
					{
						SprayNote("no far-side collider intersection");
						return;
					}
					float num3 = Vector3.Dot(((RaycastHit)(ref val2)).point - point, normalized);
					if (!Finite(((RaycastHit)(ref val2)).point) || num3 < 0.015f || Vector3.Dot(((RaycastHit)(ref val2)).normal, normalized) < 0.05f)
					{
						SprayNote("glancing hit or no exit thickness");
						return;
					}
					int num4 = Physics.RaycastNonAlloc(point + normalized * 0.002f, normalized, rayHits, num3 + 0.01f, -5, (QueryTriggerInteraction)1);
					if (num4 == ((Il2CppArrayBase<RaycastHit>)(object)rayHits).Length)
					{
						SprayNote("obstruction buffer full");
						return;
					}
					for (int i = 0; i < num4; i++)
					{
						RaycastHit val3 = ((Il2CppArrayBase<RaycastHit>)(object)rayHits)[i];
						Collider collider2 = ((RaycastHit)(ref val3)).collider;
						if (Object.op_Implicit((Object)(object)collider2) && (Object)(object)collider2 != (Object)(object)collider && !OwnCollider(owner, collider2, player))
						{
							SprayNote("exit blocked by " + ((Object)collider2).name);
							return;
						}
					}
					val = Vector3.Cross(normalized, (Mathf.Abs(normalized.y) < 0.9f) ? Vector3.up : Vector3.right);
					Vector3 normalized2 = ((Vector3)(ref val)).normalized;
					Vector3 val4 = Vector3.Cross(normalized, normalized2);
					float num5 = Mathf.Tan(Settings.V(S.SpraySpread, 2f, 35f, 18f) * ((float)Math.PI / 180f));
					int num6 = value.Take(S.SprayDrops.Value, S.SprayExtraDrops.Value, Math.Clamp(S.Drops.Value, 16, 256) - drops.Count);
					if (num6 == 0)
					{
						SprayNote("no additional droplet budget");
						return;
					}
					int num7 = Math.Clamp((int)Math.Round((float)num6 * Settings.V(S.SprayFloorShare, 0f, 1f, 0.5f)), 0, num6);
					for (int j = 0; j < num6; j++)
					{
						Vector2 val5 = Random.insideUnitCircle * num5;
						val = normalized + normalized2 * val5.x + val4 * val5.y;
						Vector3 val6 = ((Vector3)(ref val)).normalized * Settings.V(S.SpraySpeed, 1f, 8f, 4f) * Random.Range(0.65f, 1.15f);
						if (j < num7)
						{
							val6 *= Random.Range(0.3f, 0.55f);
							val6.y = Mathf.Min(val6.y, 0f - Random.Range(0.6f, 1.4f));
						}
						Emit(((RaycastHit)(ref val2)).point + normalized * 0.004f, color, val6, collider.attachedRigidbody);
					}
					if (value.Qualified == 1)
					{
						sprayed++;
					}
					SprayNote("exit hit " + value.Qualified + "; added=" + num6 + "; burst total=" + value.Emitted + "; source=" + ((Object)collider).name);
					return;
				}
			}
			SprayNote("back-facing or invalid direction");
		}

		private static bool Finite(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			if (float.IsFinite(v.x) && float.IsFinite(v.y))
			{
				return float.IsFinite(v.z);
			}
			return false;
		}

		private void Resources()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0185: 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)
			if (Object.op_Implicit((Object)(object)material))
			{
				return;
			}
			Shader val = Shader.Find("Sprites/Default");
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = Shader.Find("Unlit/Transparent");
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("No supported transparent blood shader found.");
			}
			material = new Material(val);
			((Object)material).name = "BoneyCam blood";
			((Object)material).hideFlags = (HideFlags)32;
			material.renderQueue = 3000;
			texture = new Texture2D(64, 64, (TextureFormat)4, false);
			((Object)texture).hideFlags = (HideFlags)32;
			((Texture)texture).wrapMode = (TextureWrapMode)1;
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					float num = ((float)j - 31.5f) / 31.5f;
					float num2 = ((float)i - 31.5f) / 31.5f;
					float num3 = Mathf.Atan2(num2, num);
					float num4 = Mathf.Clamp01((0.8f + 0.05f * Mathf.Sin(num3 * 7f) + 0.04f * Mathf.Sin(num3 * 11f + 1.7f) - Mathf.Sqrt(num * num + num2 * num2)) * 24f);
					texture.SetPixel(j, i, new Color(1f, 1f, 1f, num4));
				}
			}
			texture.Apply();
			material.mainTexture = (Texture)(object)texture;
			material.color = Color.white;
			mod.Log("Blood renderer initialized with " + ((Object)val).name);
		}

		private GameObject Visual(string name, PrimitiveType shape)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Resources();
			GameObject obj = GameObject.CreatePrimitive(shape);
			((Object)obj).name = name;
			obj.layer = 2;
			Collider component = obj.GetComponent<Collider>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.enabled = false;
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = obj.GetComponent<Renderer>();
			component2.sharedMaterial = material;
			component2.shadowCastingMode = (ShadowCastingMode)0;
			component2.receiveShadows = false;
			return obj;
		}

		private Color CustomColor()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			return new Color(Settings.V(S.Red, 0f, 1f, 0.3f), Settings.V(S.Green, 0f, 1f, 0.012f), Settings.V(S.Blue, 0f, 1f, 0.018f), 1f);
		}

		private Color Tint(Color source, float dry, float alpha)
		{
			//IL_001a: 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_001b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			Color val = (S.NpcColors.Value ? source : CustomColor());
			float num = Mathf.Lerp(1f, 0.38f, dry);
			return new Color(val.r * num, val.g * num, val.b * num, alpha);
		}

		private Material SurfaceMaterial()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			if (!S.Shine.Value)
			{
				return material;
			}
			if (Object.op_Implicit((Object)(object)wetMaterial))
			{
				return wetMaterial;
			}
			if (triedWetShader)
			{
				return material;
			}
			triedWetShader = true;
			Shader val = Shader.Find("SLZ/LitMAS/LitMAS Standard");
			if (!Object.op_Implicit((Object)(object)val) || !val.isSupported)
			{
				mod.Log("LitMAS unavailable; using transparent unlit blood.");
				return material;
			}
			wetMaterial = new Material(val);
			((Object)wetMaterial).name = "BoneyCam LitMAS blood";
			((Object)wetMaterial).hideFlags = (HideFlags)32;
			if (!wetMaterial.HasProperty("_BaseMap") || !wetMaterial.HasProperty("_BaseColor") || !wetMaterial.HasProperty("_MetallicGlossMap") || !wetMaterial.HasProperty("_Surface") || !wetMaterial.HasProperty("_BlendSrc") || !wetMaterial.HasProperty("_BlendDst") || !wetMaterial.HasProperty("_ZWrite"))
			{
				Object.Destroy((Object)(object)wetMaterial);
				wetMaterial = null;
				mod.Log("LitMAS fade inputs unavailable; using transparent unlit blood.");
				return material;
			}
			wetMaterial.SetTexture("_BaseMap", (Texture)(object)Texture2D.whiteTexture);
			wetMaterial.SetColor("_BaseColor", Color.white);
			wetMaterial.SetFloat("_Normals", 0f);
			wetMaterial.SetFloat("_Emission", 0f);
			wetMaterial.SetFloat("_Details", 0f);
			wetMaterial.SetFloat("_Surface", 2f);
			wetMaterial.SetFloat("_BlendSrc", 5f);
			wetMaterial.SetFloat("_BlendDst", 10f);
			wetMaterial.SetFloat("_ZWrite", 0f);
			wetMaterial.SetFloat("_Cull", 2f);
			wetMaterial.SetFloat("_SSROff", 1f);
			wetMaterial.EnableKeyword("_NO_SSR");
			wetMaterial.SetOverrideTag("RenderType", "Transparent");
			wetMaterial.renderQueue = 3000;
			mod.Log("Wet sheen initialized: LitMAS Fade; opacity and expiry fade preserve stain dimensions.");
			return wetMaterial;
		}

		private void BuildWetMesh()
		{
			//IL_012d: 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_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_015d: 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_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Expected O, but got Unknown
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: 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_0263: 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)
			bool flag = !meshDiagnosticLogged;
			meshDiagnosticLogged = true;
			if (flag)
			{
				mod.Log("DIAG combined: starting mesh generation.");
			}
			for (int i = 0; i < 2; i++)
			{
				bool flag2 = i == 1;
				bool flag3 = (flag2 ? splashMeshes : stainMeshes) != null;
				if (flag2)
				{
					if (splashMeshes == null)
					{
						splashMeshes = (Mesh[])(object)new Mesh[8];
					}
				}
				else if (stainMeshes == null)
				{
					stainMeshes = (Mesh[])(object)new Mesh[8];
				}
				Mesh[] array = (flag2 ? splashMeshes : stainMeshes);
				int num = (flag2 ? 8 : 64);
				for (int j = 0; j < array.Length; j++)
				{
					if (Object.op_Implicit((Object)(object)array[j]))
					{
						continue;
					}
					if (flag3)
					{
						mod.Log("Rebuilding missing " + (flag2 ? "splash" : "stain") + " mesh variant " + j);
					}
					Vector3[] array2 = (Vector3[])(object)new Vector3[num + 1];
					Vector3[] array3 = (Vector3[])(object)new Vector3[num + 1];
					Vector4[] array4 = (Vector4[])(object)new Vector4[num + 1];
					Vector2[] array5 = (Vector2[])(object)new Vector2[num + 1];
					int[] array6 = new int[num * 3];
					for (int k = 0; k <= num; k++)
					{
						array4[k] = new Vector4(1f, 0f, 0f, -1f);
					}
					array3[0] = Vector3.back;
					array5[0] = new Vector2(0.5f, 0.5f);
					for (int l = 0; l < num; l++)
					{
						float num2 = (float)(l * 2) * (float)Math.PI / (float)num;
						float num3 = 0.37f + 0.045f * Mathf.Sin(num2 * (float)(3 + j) + (float)j * 0.71f) + 0.025f * Mathf.Sin(num2 * (float)(9 + j) + 1.7f + (float)j);
						if (flag2)
						{
							num3 = 0.37f + 0.025f * Mathf.Sin(num2 * 3f + (float)j * 0.71f) + 0.012f * Mathf.Sin(num2 * 2f + (float)j);
						}
						float num4 = 1f - (float)(j % 4) * 0.055f;
						array2[l + 1] = new Vector3(Mathf.Cos(num2) * num3 * num4, Mathf.Sin(num2) * num3, 0f);
						array3[l + 1] = Vector3.back;
						array5[l + 1] = new Vector2(0.5f, 0.5f);
						array6[l * 3] = 0;
						array6[l * 3 + 1] = (l + 1) % num + 1;
						array6[l * 3 + 2] = l + 1;
					}
					Mesh val = new Mesh();
					((Object)val).name = "BoneyCam " + (flag2 ? "low-poly splash" : "stain") + " variant " + j;
					((Object)val).hideFlags = (HideFlags)32;
					val.vertices = Il2CppStructArray<Vector3>.op_Implicit(array2);
					val.normals = Il2CppStructArray<Vector3>.op_Implicit(array3);
					val.tangents = Il2CppStructArray<Vector4>.op_Implicit(array4);
					val.uv = Il2CppStructArray<Vector2>.op_Implicit(array5);
					val.triangles = Il2CppStructArray<int>.op_Implicit(array6);
					val.RecalculateBounds();
					array[j] = val;
				}
			}
			if (flag)
			{
				mod.Log("DIAG combined: mesh generation completed, main=64 triangles, splash=8.");
			}
		}

		private Texture2D Mas(float dry)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00d6: 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)
			if (masTextures == null)
			{
				masTextures = (Texture2D[])(object)new Texture2D[16];
			}
			float num = Settings.V(S.WetGloss, 0f, 1f, 0.95f);
			float num2 = Settings.V(S.DryGloss, 0f, 1f, 0.15f);
			bool flag = num != lastWet || num2 != lastDry;
			for (int i = 0; i < 16; i++)
			{
				if (!Object.op_Implicit((Object)(object)masTextures[i]))
				{
					Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false, true);
					((Object)val).name = "BoneyCam wetness " + i;
					((Object)val).hideFlags = (HideFlags)32;
					val.SetPixel(0, 0, new Color(0f, 1f, Mathf.Lerp(num, num2, (float)i / 15f), 1f));
					val.Apply();
					masTextures[i] = val;
				}
				else if (flag)
				{
					masTextures[i].SetPixel(0, 0, new Color(0f, 1f, Mathf.Lerp(num, num2, (float)i / 15f), 1f));
					masTextures[i].Apply();
				}
			}
			lastWet = num;
			lastDry = num2;
			return masTextures[Math.Clamp((int)(dry * 15f), 0, 15)];
		}

		private void Emit(Vector3 position, Color color, Vector3? velocity = null, Rigidbody sourceBody = null, bool share = true)
		{
			//IL_00b7: 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_00d9: 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_011a: 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_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_016a: 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_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: 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_01d5: 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_01af: 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_01ba: 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 (drops.Count >= Math.Clamp(S.Drops.Value, 16, 256))
			{
				return;
			}
			Drop drop = ((spareDrops.Count > 0) ? spareDrops.Pop() : new Drop());
			if (!Object.op_Implicit((Object)(object)drop.Go))
			{
				drop.Go = Visual("BoneyCam droplet", (PrimitiveType)0);
				drop.Renderer = drop.Go.GetComponent<Renderer>();
			}
			GameObject go = drop.Go;
			go.SetActive(true);
			float num = Settings.V(S.DropSize, 0.003f, 0.03f, 0.009f);
			go.transform.localScale = new Vector3(num, num * 1.5f, num);
			go.transform.position = position;
			dropBlock.SetColor("_Color", Tint(color, 0f, 1f));
			drop.Renderer.SetPropertyBlock(dropBlock);
			go.GetComponent<Renderer>().enabled = S.Drips.Value;
			drop.Color = color;
			drop.Position = position;
			drop.Age = 0f;
			drop.Velocity = (Vector3)(((??)velocity) ?? new Vector3(Random.Range(-0.03f, 0.03f), -0.08f, Random.Range(-0.03f, 0.03f)));
			drops.Add(drop);
			emitted++;
			if (Object.op_Implicit((Object)(object)sourceBody))
			{
				Vector3 pointVelocity = sourceBody.GetPointVelocity(position);
				if (Finite(pointVelocity))
				{
					drop.Velocity += Vector3.ClampMagnitude(pointVelocity, 20f);
				}
			}
			if (share)
			{
				Mod.ShareDroplet(drop.Position, drop.Velocity, drop.Color);
			}
		}

		internal void Receive(Vector3 position, Vector3 velocity, Color color)
		{
			//IL_0000: 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_0020: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if (Finite(position) && Finite(velocity) && !(((Vector3)(ref velocity)).sqrMagnitude > 10000f))
			{
				Emit(position, color, velocity, null, share: false);
			}
		}

		internal void Test()
		{
			//IL_005b: 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_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_0075: 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_0084: 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_008f: 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_00a2: 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)
			if (!S.Enabled.Value)
			{
				mod.Log("Enable blood before running the test.");
				return;
			}
			RigManager rigManager = Player.RigManager;
			object obj;
			if (rigManager == null)
			{
				obj = null;
			}
			else
			{
				ControllerRig controllerRig = rigManager.controllerRig;
				obj = ((controllerRig != null) ? ((Rig)controllerRig).m_head : null);
			}
			Transform val = (Transform)obj;
			if (!Object.op_Implicit((Object)(object)val))
			{
				mod.Log("Test unavailable: player head not ready.");
				return;
			}
			Vector3 val2 = val.position + val.forward * 0.65f - Vector3.up * 0.3f;
			for (int i = 0; i < 12; i++)
			{
				Emit(val2 + Vector3.up * ((float)i * 0.025f), CustomColor());
			}
			mod.Log("Emitted 12 test drops in front of the player. " + Status);
		}

		internal void Tick(float dt)
		{
			long timestamp = Stopwatch.GetTimestamp();
			try
			{
				TickBlood(dt);
			}
			finally
			{
				tickMs = (double)(Stopwatch.GetTimestamp() - timestamp) * 1000.0 / (double)Stopwatch.Frequency;
				maxTickMs = Math.Max(maxTickMs, tickMs);
			}
		}

		private void TickBlood(float dt)
		{
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: 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_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: 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_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: 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_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0490: 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_0376: 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_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0593: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Unknown result type (might be due to invalid IL or missing

Mods/BoneyCamFusion.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BoneyCam;
using BoneyCamFusion;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Player;
using LabFusion.SDK.Modules;
using LabFusion.Scene;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: MelonInfo(typeof(Bridge), "BoneyCam Fusion Blood Sync", "0.1.21", "Geozek", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : System.Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(/*Could not decode attribute arguments.*/)]
	internal sealed class RefSafetyRulesAttribute : System.Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BoneyCamFusion
{
	public class BloodData : INetSerializable
	{
		public const int Size = 294;

		public byte Protocol = 1;

		public byte Count;

		public uint Sequence;

		public float[] Values = new float[72];

		public int? GetSize()
		{
			return 294;
		}

		public void Serialize(INetSerializer s)
		{
			s.SerializeValue(ref Protocol);
			s.SerializeValue(ref Sequence);
			s.SerializeValue(ref Count);
			for (int i = 0; i < 72; i++)
			{
				s.SerializeValue(ref Values[i]);
			}
		}

		public bool Valid()
		{
			if (Protocol != 1 || Count < 1 || Count > 8 || Values == null || Values.Length != 72)
			{
				return false;
			}
			for (int i = 0; i < Count; i++)
			{
				for (int j = 0; j < 9; j++)
				{
					float num = Values[i * 9 + j];
					if (!float.IsFinite(num) || Math.Abs(num) > (float)((j < 3) ? 100000 : ((j >= 6) ? 1 : 100)) || (j >= 6 && num < 0f))
					{
						return false;
					}
				}
			}
			return true;
		}

		public static bool Newer(uint a, uint b)
		{
			return (int)(a - b) > 0;
		}
	}
	public class BloodMessage : ModuleMessageHandler
	{
		protected override void OnHandleMessage(ReceivedMessage received)
		{
			if (((ReceivedMessage)(ref received)).Sender.HasValue && ((ReceivedMessage)(ref received)).Bytes != null && ((ReceivedMessage)(ref received)).Bytes.Length == 294)
			{
				BloodData bloodData = ((ReceivedMessage)(ref received)).ReadData<BloodData>();
				if (bloodData.Valid())
				{
					Bridge.Queue(((ReceivedMessage)(ref received)).Sender.Value, bloodData);
				}
			}
		}
	}
	public class Bridge : MelonMod
	{
		private struct Incoming
		{
			internal byte Sender;

			internal BloodData Data;
		}

		private struct Drop
		{
			internal Vector3 Position;

			internal Vector3 Velocity;

			internal Color Color;
		}

		private static readonly object gate = new object();

		private static readonly Queue<Incoming> incoming = new Queue<Incoming>();

		private readonly Queue<Drop> outgoing = new Queue<Drop>();

		private readonly Dictionary<byte, uint> sequences = new Dictionary<byte, uint>();

		private bool ready;

		private bool connected;

		private uint sequence;

		private float nextSend;

		private float nextLog;

		private float nextError;

		private int sent;

		private int receivedCount;

		private int applied;

		private int dropped;

		public override void OnInitializeMelon()
		{
		}

		internal static void Queue(byte sender, BloodData data)
		{
			lock (gate)
			{
				if (incoming.Count < 64)
				{
					incoming.Enqueue(new Incoming
					{
						Sender = sender,
						Data = data
					});
				}
			}
		}

		private void Capture(Vector3 position, Vector3 velocity, Color color)
		{
			//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_004e: 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_005d: 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)
			if (ready && NetworkInfo.HasServer && PlayerIDManager.HasOtherPlayers)
			{
				if (outgoing.Count >= 256)
				{
					dropped++;
					return;
				}
				outgoing.Enqueue(new Drop
				{
					Position = NetworkTransformManager.EncodePosition(position),
					Velocity = velocity,
					Color = color
				});
			}
		}

		public override void OnUpdate()
		{
			//IL_039a: 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_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: 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_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: 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_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)
			//IL_0169: 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_0195: 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)
			try
			{
				if (!ready)
				{
					if (ModuleMessageManager.GetHandlerByType(typeof(BloodMessage)) == null)
					{
						ModuleMessageManager.RegisterHandler<BloodMessage>();
					}
					Mod.DropletEmitted += Capture;
					ready = true;
					((MelonBase)this).LoggerInstance.Msg("Fusion blood sharing ready. Both peers require BoneyCam and BoneyCamFusion 0.1.21.");
				}
				if (!NetworkInfo.HasServer)
				{
					if (connected)
					{
						Clear();
						sequences.Clear();
					}
					connected = false;
					return;
				}
				connected = true;
				uint b = default(uint);
				for (int num = 0; num < 16; num++)
				{
					Incoming incoming;
					lock (gate)
					{
						if (Bridge.incoming.Count == 0)
						{
							break;
						}
						incoming = Bridge.incoming.Dequeue();
						goto IL_00bd;
					}
					IL_00bd:
					if (incoming.Sender != PlayerIDManager.LocalSmallID && PlayerIDManager.HasPlayerID(incoming.Sender))
					{
						BloodData data = incoming.Data;
						if (!sequences.TryGetValue(incoming.Sender, ref b) || BloodData.Newer(data.Sequence, b))
						{
							sequences[incoming.Sender] = data.Sequence;
							receivedCount++;
							for (int i = 0; i < data.Count; i++)
							{
								int num2 = i * 9;
								Vector3 val = NetworkTransformManager.DecodePosition(new Vector3(data.Values[num2], data.Values[num2 + 1], data.Values[num2 + 2]));
								if (NetworkTransformManager.IsInBounds(val))
								{
									Mod.ReceiveDroplet(val, new Vector3(data.Values[num2 + 3], data.Values[num2 + 4], data.Values[num2 + 5]), new Color(data.Values[num2 + 6], data.Values[num2 + 7], data.Values[num2 + 8], 1f));
									applied++;
								}
							}
						}
					}
				}
				if (Time.unscaledTime >= nextSend)
				{
					nextSend = Time.unscaledTime + 0.05f;
					for (int j = 0; j < 4; j++)
					{
						if (outgoing.Count <= 0)
						{
							break;
						}
						BloodData bloodData = new BloodData
						{
							Sequence = ++sequence
						};
						while (bloodData.Count < 8 && outgoing.Count > 0)
						{
							Drop drop = outgoing.Dequeue();
							int num3 = bloodData.Count * 9;
							bloodData.Values[num3] = drop.Position.x;
							bloodData.Values[num3 + 1] = drop.Position.y;
							bloodData.Values[num3 + 2] = drop.Position.z;
							bloodData.Values[num3 + 3] = drop.Velocity.x;
							bloodData.Values[num3 + 4] = drop.Velocity.y;
							bloodData.Values[num3 + 5] = drop.Velocity.z;
							bloodData.Values[num3 + 6] = Math.Clamp(drop.Color.r, 0f, 1f);
							bloodData.Values[num3 + 7] = Math.Clamp(drop.Color.g, 0f, 1f);
							bloodData.Values[num3 + 8] = Math.Clamp(drop.Color.b, 0f, 1f);
							bloodData.Count++;
						}
						if (bloodData.Valid())
						{
							MessageRelay.RelayModule<BloodMessage, BloodData>(bloodData, new MessageRoute((RelayType)3, (NetworkChannel)1));
							sent++;
						}
					}
				}
				if (Time.unscaledTime >= nextLog)
				{
					nextLog = Time.unscaledTime + 15f;
					((MelonBase)this).LoggerInstance.Msg($"Blood sync: sent packets={sent}, received={receivedCount}, applied droplets={applied}, queued={outgoing.Count}, overflow={dropped}");
				}
			}
			catch (System.Exception ex)
			{
				if (Time.unscaledTime >= nextError)
				{
					nextError = Time.unscaledTime + 5f;
					((MelonBase)this).LoggerInstance.Warning(((object)ex).ToString());
				}
			}
		}

		private void Clear()
		{
			outgoing.Clear();
			lock (gate)
			{
				incoming.Clear();
			}
		}

		public override void OnSceneWasUnloaded(int index, string name)
		{
			Clear();
		}

		public override void OnDeinitializeMelon()
		{
			if (ready)
			{
				Mod.DropletEmitted -= Capture;
			}
			Clear();
		}
	}
}