Decompiled source of BLOODLABReborn v0.1.1

Mods/BloodLab.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BloodLab.Blood;
using BloodLab.Configuration;
using BloodLab.Core;
using BloodLab.Droplet;
using BloodLab.Effects;
using BloodLab.Stain;
using BloodLab.Utilities;
using BoneLib.BoneMenu;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.PuppetMasta;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(BloodLabMod), "BloodLab", "0.1.1", "leonfwfw", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BloodLab")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BloodLab")]
[assembly: AssemblyTitle("BloodLab")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 BloodLab.Utilities
{
	public static class SurfaceUtils
	{
		public static Quaternion AlignToNormal(Vector3 normal)
		{
			//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)
			//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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref normal)).sqrMagnitude < 0.0001f)
			{
				normal = Vector3.up;
			}
			((Vector3)(ref normal)).Normalize();
			Vector3 val = ((Mathf.Abs(Vector3.Dot(normal, Vector3.up)) > 0.95f) ? Vector3.forward : Vector3.up);
			Quaternion val2 = Quaternion.LookRotation(-normal, val);
			float num = Random.Range(0f, 360f);
			return val2 * Quaternion.Euler(0f, 0f, num);
		}

		public static Vector3 SafeOffset(Vector3 point, Vector3 normal, float distance = 0.01f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return point + ((Vector3)(ref normal)).normalized * distance;
		}
	}
}
namespace BloodLab.Stain
{
	[RegisterTypeInIl2Cpp]
	public class BloodStain : MonoBehaviour
	{
		private static Mesh _sharedQuadMesh;

		private static Shader _cachedShader;

		private static bool _shaderResolved;

		private MeshRenderer _renderer;

		private MaterialPropertyBlock _propertyBlock;

		private float _timer;

		private float _lifetime;

		private float _targetSize;

		private float _visualSize;

		public Vector3 WorldPosition => ((Component)this).transform.position;

		public BloodStain(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Awake()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//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_00a5: Expected O, but got Unknown
			EnsureSharedMesh();
			MeshFilter val = ((Component)this).GetComponent<MeshFilter>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)this).gameObject.AddComponent<MeshFilter>();
			}
			val.sharedMesh = _sharedQuadMesh;
			_renderer = ((Component)this).GetComponent<MeshRenderer>();
			if ((Object)(object)_renderer == (Object)null)
			{
				_renderer = ((Component)this).gameObject.AddComponent<MeshRenderer>();
			}
			((Renderer)_renderer).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_renderer).receiveShadows = false;
			Shader val2 = ResolveWorkingShader();
			if ((Object)(object)val2 != (Object)null)
			{
				((Renderer)_renderer).sharedMaterial = new Material(val2)
				{
					hideFlags = (HideFlags)61
				};
			}
			_propertyBlock = new MaterialPropertyBlock();
		}

		public void PlaceOnGround(Vector3 worldPosition, Vector3 groundNormal, Texture2D texture, float startSize)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			((Component)this).transform.SetParent(BloodEffectManager.RootTransform, true);
			((Component)this).transform.position = SurfaceUtils.SafeOffset(worldPosition, groundNormal, 0.006f);
			((Component)this).transform.rotation = SurfaceUtils.AlignToNormal(groundNormal);
			_visualSize = 0f;
			_targetSize = startSize;
			((Component)this).transform.localScale = Vector3.zero;
			if ((Object)(object)texture != (Object)null && (Object)(object)_renderer != (Object)null && (Object)(object)((Renderer)_renderer).sharedMaterial != (Object)null)
			{
				_propertyBlock.Clear();
				((Renderer)_renderer).GetPropertyBlock(_propertyBlock);
				_propertyBlock.SetTexture("_MainTex", (Texture)(object)texture);
				((Renderer)_renderer).SetPropertyBlock(_propertyBlock);
			}
			_timer = 0f;
			_lifetime = 60f;
		}

		public void Grow(float amount, float maxSize)
		{
			float num = Mathf.Min(_targetSize + amount, maxSize);
			_targetSize = Mathf.Max(_targetSize, num);
			_timer = 0f;
		}

		private void Update()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)this == (Object)null)
			{
				return;
			}
			try
			{
				if (!Mathf.Approximately(_visualSize, _targetSize))
				{
					_visualSize = Mathf.MoveTowards(_visualSize, _targetSize, BloodLabPreferences.StainGrowthSpeed.Value * Time.deltaTime * 0.1f);
					((Component)this).transform.localScale = new Vector3(_visualSize, _visualSize, 1f);
				}
				_timer += Time.deltaTime;
				if (_timer >= _lifetime)
				{
					BloodEffectManager.ReleaseStain(this);
				}
			}
			catch
			{
			}
		}

		private static Shader ResolveWorkingShader()
		{
			if (_shaderResolved)
			{
				return _cachedShader;
			}
			_shaderResolved = true;
			string[] array = new string[4] { "Sprites/Default", "Unlit/Transparent", "Unlit/Texture", "UI/Default" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				Shader val = Shader.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					_cachedShader = val;
					return _cachedShader;
				}
			}
			Renderer val2 = Object.FindObjectOfType<Renderer>();
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMaterial != (Object)null && (Object)(object)val2.sharedMaterial.shader != (Object)null)
			{
				_cachedShader = val2.sharedMaterial.shader;
				return _cachedShader;
			}
			_shaderResolved = false;
			return null;
		}

		private static void EnsureSharedMesh()
		{
			//IL_0015: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_sharedQuadMesh != (Object)null))
			{
				_sharedQuadMesh = new Mesh
				{
					name = "BloodLab_StainQuadMesh",
					hideFlags = (HideFlags)61
				};
				_sharedQuadMesh.vertices = Il2CppStructArray<Vector3>.op_Implicit((Vector3[])(object)new Vector3[4]
				{
					new Vector3(-0.5f, -0.5f, 0f),
					new Vector3(0.5f, -0.5f, 0f),
					new Vector3(0.5f, 0.5f, 0f),
					new Vector3(-0.5f, 0.5f, 0f)
				});
				_sharedQuadMesh.uv = Il2CppStructArray<Vector2>.op_Implicit((Vector2[])(object)new Vector2[4]
				{
					new Vector2(0f, 0f),
					new Vector2(1f, 0f),
					new Vector2(1f, 1f),
					new Vector2(0f, 1f)
				});
				_sharedQuadMesh.triangles = Il2CppStructArray<int>.op_Implicit(new int[6] { 0, 2, 1, 0, 3, 2 });
				_sharedQuadMesh.RecalculateNormals();
				_sharedQuadMesh.RecalculateBounds();
			}
		}
	}
}
namespace BloodLab.Effects
{
	public enum ImpactSource
	{
		Projectile,
		Melee
	}
	public struct ImpactData
	{
		public Vector3 Position;

		public Vector3 Normal;

		public Vector3 Direction;

		public Collider HitCollider;

		public GameObject HitObject;

		public bool IsLivingEntity;

		public float Intensity;

		public ImpactSource Source;
	}
	public static class ImpactHooks
	{
		[HarmonyPatch(typeof(Projectile), "Awake")]
		public static class ProjectileAwakePatch
		{
			public static void Postfix(Projectile __instance)
			{
				try
				{
					if ((Object)(object)__instance == (Object)null || __instance.onCollision == null)
					{
						return;
					}
					((UnityEvent<Collider, Vector3, Vector3>)(object)__instance.onCollision).AddListener(UnityAction<Collider, Vector3, Vector3>.op_Implicit((Action<Collider, Vector3, Vector3>)delegate(Collider hitCollider, Vector3 worldPoint, Vector3 normal)
					{
						//IL_0039: Unknown result type (might be due to invalid IL or missing references)
						//IL_0026: Unknown result type (might be due to invalid IL or missing references)
						//IL_0027: Unknown result type (might be due to invalid IL or missing references)
						//IL_003e: Unknown result type (might be due to invalid IL or missing references)
						//IL_004a: 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_0052: Unknown result type (might be due to invalid IL or missing references)
						//IL_0053: Unknown result type (might be due to invalid IL or missing references)
						//IL_005a: Unknown result type (might be due to invalid IL or missing references)
						//IL_005b: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							if (!((Object)(object)hitCollider == (Object)null))
							{
								Vector3 direction = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).transform.forward : (-normal));
								ImpactData data = new ImpactData
								{
									Position = worldPoint,
									Normal = normal,
									Direction = direction,
									HitCollider = hitCollider,
									HitObject = ((Component)hitCollider).gameObject,
									IsLivingEntity = IsLivingTarget(hitCollider),
									Intensity = 1f,
									Source = ImpactSource.Projectile
								};
								MainThreadDispatcher.Enqueue(delegate
								{
									BloodEffectManager.HandleImpact(data);
								});
							}
						}
						catch (Exception ex2)
						{
							MelonLogger.Error("[BloodLab] cant process projectile impact: " + ex2);
						}
					}));
				}
				catch (Exception ex)
				{
					MelonLogger.Error("[BloodLab] failed to hook Projectile.Awake: " + ex);
				}
			}
		}

		[HarmonyPatch(typeof(SubBehaviourHealth), "TakeDamage")]
		public static class TakeDamagePatch
		{
			public static void Postfix(SubBehaviourHealth __instance, int m, Attack attack)
			{
				//IL_0022: 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_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: 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_008a: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Collider collider = attack.collider;
					if (!((Object)(object)collider == (Object)null))
					{
						ResolveMeleeHitPoint(attack.origin, collider, out var point, out var normal);
						Vector3 val = point - attack.origin;
						Vector3 val2;
						if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f))
						{
							val2 = -normal;
						}
						else
						{
							val = point - attack.origin;
							val2 = ((Vector3)(ref val)).normalized;
						}
						Vector3 direction = val2;
						ImpactData data = new ImpactData
						{
							Position = point,
							Normal = normal,
							Direction = direction,
							HitCollider = collider,
							HitObject = ((Component)collider).gameObject,
							IsLivingEntity = true,
							Intensity = Mathf.Clamp01((float)m / 25f),
							Source = ImpactSource.Melee
						};
						MainThreadDispatcher.Enqueue(delegate
						{
							BloodEffectManager.HandleImpact(data);
						});
					}
				}
				catch (Exception ex)
				{
					MelonLogger.Error("[BloodLab] melee damage failed to process: " + ex);
				}
			}
		}

		private static void ResolveMeleeHitPoint(Vector3 origin, Collider col, out Vector3 point, out Vector3 normal)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = col.bounds;
			Vector3 center = ((Bounds)(ref bounds)).center;
			Vector3 val = center - origin;
			RaycastHit val2 = default(RaycastHit);
			if (((Vector3)(ref val)).sqrMagnitude > 0.0001f && Physics.Raycast(origin, ((Vector3)(ref val)).normalized, ref val2, ((Vector3)(ref val)).magnitude + 1f) && (Object)(object)((RaycastHit)(ref val2)).collider == (Object)(object)col)
			{
				point = ((RaycastHit)(ref val2)).point;
				normal = ((RaycastHit)(ref val2)).normal;
				return;
			}
			point = col.ClosestPoint(origin);
			Vector3 val3 = point - origin;
			Vector3 val4;
			if (!(((Vector3)(ref val3)).sqrMagnitude > 0.0001f))
			{
				val4 = ((Component)col).transform.up;
			}
			else
			{
				val3 = point - origin;
				val4 = ((Vector3)(ref val3)).normalized;
			}
			normal = val4;
		}

		private static bool IsLivingTarget(Collider hitCollider)
		{
			AIBrain componentInParent = ((Component)hitCollider).GetComponentInParent<AIBrain>();
			return (Object)(object)componentInParent != (Object)null && !componentInParent.isDead;
		}
	}
	public static class MainThreadDispatcher
	{
		private static readonly Queue<Action> _queue = new Queue<Action>();

		private static readonly object _lock = new object();

		public static void Enqueue(Action action)
		{
			if (action == null)
			{
				return;
			}
			lock (_lock)
			{
				_queue.Enqueue(action);
			}
		}

		public static void ProcessQueue()
		{
			while (true)
			{
				Action action;
				lock (_lock)
				{
					if (_queue.Count == 0)
					{
						break;
					}
					action = _queue.Dequeue();
				}
				try
				{
					action();
				}
				catch (Exception ex)
				{
					MelonLogger.Error("[BloodLab] queued action failed: " + ex);
				}
			}
		}
	}
}
namespace BloodLab.Droplet
{
	[RegisterTypeInIl2Cpp]
	public class BleedWound : MonoBehaviour
	{
		private Transform _trackedTransform;

		private Vector3 _localOffset;

		private Transform _ignoreRoot;

		private float _elapsed;

		private float _tickTimer;

		private float _intensity;

		private float _startDelay;

		private float _forcedPoolMaxSize;

		public BleedWound(IntPtr ptr)
			: base(ptr)
		{
		}

		public void Begin(Transform trackedTransform, Vector3 initialWorldPosition, Transform ignoreRoot, float intensity, float startDelay = 0f, float forcedPoolMaxSize = -1f)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			_trackedTransform = trackedTransform;
			_ignoreRoot = ignoreRoot;
			_intensity = intensity;
			_elapsed = 0f;
			_startDelay = Mathf.Max(0f, startDelay);
			_forcedPoolMaxSize = forcedPoolMaxSize;
			_tickTimer = _startDelay;
			if ((Object)(object)_trackedTransform != (Object)null)
			{
				_localOffset = _trackedTransform.InverseTransformPoint(initialWorldPosition);
			}
		}

		private void Update()
		{
			if ((Object)(object)this == (Object)null)
			{
				return;
			}
			if (!BloodLabPreferences.EnableBleeding.Value || (Object)(object)_trackedTransform == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			_elapsed += Time.deltaTime;
			_tickTimer += Time.deltaTime;
			if (_elapsed >= BloodLabPreferences.BleedDurationSeconds.Value + _startDelay)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else if (_tickTimer >= BloodLabPreferences.BleedIntervalSeconds.Value)
			{
				_tickTimer = 0f;
				EmitTick();
			}
		}

		private void EmitTick()
		{
			//IL_0008: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = _trackedTransform.TransformPoint(_localOffset);
			float poolMaxSizeOverride = ((_forcedPoolMaxSize > 0f) ? _forcedPoolMaxSize : BloodLabPreferences.BleedPoolMaxSize.Value);
			int num = Mathf.Clamp(Mathf.RoundToInt((float)BloodLabPreferences.BleedDropletsPerTick.Value * Mathf.Clamp(_intensity, 0.5f, 2f)), 1, 10);
			for (int i = 0; i < num; i++)
			{
				BloodDroplet dropletFromPool = BloodEffectManager.GetDropletFromPool();
				dropletFromPool.PoolMaxSizeOverride = poolMaxSizeOverride;
				Vector3 val = Vector3.down * 1.1f + Random.insideUnitSphere * 0.7f;
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				float speed = Random.Range(0.4f, 1.3f);
				dropletFromPool.Launch(position, normalized, speed, _ignoreRoot);
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	public class BloodDroplet : MonoBehaviour
	{
		private static Mesh _sharedQuadMesh;

		private static Shader _cachedShader;

		private static bool _shaderResolved;

		private Rigidbody _rb;

		private SphereCollider _collider;

		private MeshRenderer _renderer;

		private MaterialPropertyBlock _propertyBlock;

		private float _timer;

		private float _lifetime;

		private bool _hasLanded;

		private Vector3 _lastPosition;

		public float PoolMaxSizeOverride = -1f;

		public BloodDroplet(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Awake()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//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_00a5: Expected O, but got Unknown
			EnsureSharedMesh();
			MeshFilter val = ((Component)this).GetComponent<MeshFilter>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)this).gameObject.AddComponent<MeshFilter>();
			}
			val.sharedMesh = _sharedQuadMesh;
			_renderer = ((Component)this).GetComponent<MeshRenderer>();
			if ((Object)(object)_renderer == (Object)null)
			{
				_renderer = ((Component)this).gameObject.AddComponent<MeshRenderer>();
			}
			((Renderer)_renderer).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_renderer).receiveShadows = false;
			Shader val2 = ResolveWorkingShader();
			if ((Object)(object)val2 != (Object)null)
			{
				((Renderer)_renderer).sharedMaterial = new Material(val2)
				{
					hideFlags = (HideFlags)61
				};
			}
			_propertyBlock = new MaterialPropertyBlock();
			_collider = ((Component)this).GetComponent<SphereCollider>();
			if ((Object)(object)_collider == (Object)null)
			{
				_collider = ((Component)this).gameObject.AddComponent<SphereCollider>();
			}
			_collider.radius = 0.03f;
			((Collider)_collider).isTrigger = true;
			_rb = ((Component)this).GetComponent<Rigidbody>();
			if ((Object)(object)_rb == (Object)null)
			{
				_rb = ((Component)this).gameObject.AddComponent<Rigidbody>();
			}
			_rb.useGravity = true;
			_rb.mass = 0.001f;
			_rb.drag = 0.3f;
		}

		public void SetTexture(Texture2D texture)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)texture == (Object)null) && !((Object)(object)_renderer == (Object)null) && !((Object)(object)((Renderer)_renderer).sharedMaterial == (Object)null))
			{
				_propertyBlock.Clear();
				((Renderer)_renderer).GetPropertyBlock(_propertyBlock);
				_propertyBlock.SetTexture("_MainTex", (Texture)(object)texture);
				_propertyBlock.SetColor("_Color", Color.white);
				((Renderer)_renderer).SetPropertyBlock(_propertyBlock);
			}
		}

		public void Launch(Vector3 position, Vector3 direction, float speed, Transform ignoreRoot)
		{
			//IL_0019: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.SetParent(BloodEffectManager.RootTransform, true);
			((Component)this).transform.position = position;
			_lastPosition = position;
			if ((Object)(object)Camera.main != (Object)null)
			{
				Vector3 val = ((Component)Camera.main).transform.position - ((Component)this).transform.position;
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				((Component)this).transform.rotation = Quaternion.LookRotation(normalized);
			}
			((Component)this).transform.localScale = Vector3.one * BloodLabPreferences.DropletVisualScale.Value;
			((Collider)_collider).enabled = true;
			_rb.velocity = ((Vector3)(ref direction)).normalized * speed;
			_timer = 0f;
			_hasLanded = false;
			_lifetime = BloodLabPreferences.DropletLifetime.Value;
		}

		private void Update()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)this == (Object)null) && !_hasLanded)
			{
				_timer += Time.deltaTime;
				if (_timer >= _lifetime)
				{
					BloodEffectManager.ReleaseDroplet(this);
					return;
				}
				CheckPathForLanding();
				_lastPosition = ((Component)this).transform.position;
			}
		}

		private void CheckPathForLanding()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = position - _lastPosition;
			float num = ((Vector3)(ref val)).magnitude + 0.03f;
			if (!(num < 0.001f))
			{
				Vector3 val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.down);
				RaycastHit val3 = default(RaycastHit);
				if (Physics.Raycast(_lastPosition, val2, ref val3, num) && !IsCharacterCollider(((RaycastHit)(ref val3)).collider))
				{
					Land(((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal);
				}
			}
		}

		private void OnTriggerEnter(Collider other)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)this == (Object)null) && !_hasLanded && !((Object)(object)other == (Object)null) && !IsCharacterCollider(other))
			{
				Vector3 val = other.ClosestPoint(((Component)this).transform.position);
				Vector3 val2 = ((Component)this).transform.position - val;
				Vector3 val3;
				if (!(((Vector3)(ref val2)).sqrMagnitude > 0.0001f))
				{
					val3 = Vector3.up;
				}
				else
				{
					val2 = ((Component)this).transform.position - val;
					val3 = ((Vector3)(ref val2)).normalized;
				}
				Vector3 normal = val3;
				Land(val, normal);
			}
		}

		private void Land(Vector3 point, Vector3 normal)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!_hasLanded)
			{
				_hasLanded = true;
				BloodEffectManager.HandleDropletLanded(point, normal, PoolMaxSizeOverride);
				BloodEffectManager.ReleaseDroplet(this);
			}
		}

		private static bool IsCharacterCollider(Collider col)
		{
			if ((Object)(object)((Component)col).GetComponentInParent<AIBrain>() != (Object)null)
			{
				return true;
			}
			int num = LayerMask.NameToLayer("EnemyColliders");
			if (num >= 0 && ((Component)col).gameObject.layer == num)
			{
				return true;
			}
			Rigidbody attachedRigidbody = col.attachedRigidbody;
			if ((Object)(object)attachedRigidbody != (Object)null && !attachedRigidbody.isKinematic)
			{
				return true;
			}
			return false;
		}

		private static Shader ResolveWorkingShader()
		{
			if (_shaderResolved)
			{
				return _cachedShader;
			}
			_shaderResolved = true;
			string[] array = new string[4] { "Sprites/Default", "Unlit/Transparent", "Unlit/Texture", "UI/Default" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				Shader val = Shader.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					_cachedShader = val;
					return _cachedShader;
				}
			}
			Renderer val2 = Object.FindObjectOfType<Renderer>();
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMaterial != (Object)null && (Object)(object)val2.sharedMaterial.shader != (Object)null)
			{
				_cachedShader = val2.sharedMaterial.shader;
				return _cachedShader;
			}
			_shaderResolved = false;
			return null;
		}

		private static void EnsureSharedMesh()
		{
			//IL_0015: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_sharedQuadMesh != (Object)null))
			{
				_sharedQuadMesh = new Mesh
				{
					name = "BloodLab_DropletQuadMesh",
					hideFlags = (HideFlags)61
				};
				_sharedQuadMesh.vertices = Il2CppStructArray<Vector3>.op_Implicit((Vector3[])(object)new Vector3[4]
				{
					new Vector3(-0.5f, -0.5f, 0f),
					new Vector3(0.5f, -0.5f, 0f),
					new Vector3(0.5f, 0.5f, 0f),
					new Vector3(-0.5f, 0.5f, 0f)
				});
				_sharedQuadMesh.uv = Il2CppStructArray<Vector2>.op_Implicit((Vector2[])(object)new Vector2[4]
				{
					new Vector2(0f, 0f),
					new Vector2(1f, 0f),
					new Vector2(1f, 1f),
					new Vector2(0f, 1f)
				});
				_sharedQuadMesh.triangles = Il2CppStructArray<int>.op_Implicit(new int[6] { 0, 2, 1, 0, 3, 2 });
				_sharedQuadMesh.RecalculateNormals();
				_sharedQuadMesh.RecalculateBounds();
			}
		}
	}
}
namespace BloodLab.Core
{
	public class BloodLabMod : MelonMod
	{
		private Harmony _harmony;

		public override void OnInitializeMelon()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			try
			{
				MelonLogger.Msg("[BloodLab] starting initialization...");
				if (!ClassInjector.IsTypeRegisteredInIl2Cpp<BloodStain>())
				{
					ClassInjector.RegisterTypeInIl2Cpp<BloodStain>();
				}
				if (!ClassInjector.IsTypeRegisteredInIl2Cpp<BloodDroplet>())
				{
					ClassInjector.RegisterTypeInIl2Cpp<BloodDroplet>();
				}
				if (!ClassInjector.IsTypeRegisteredInIl2Cpp<BleedWound>())
				{
					ClassInjector.RegisterTypeInIl2Cpp<BleedWound>();
				}
				MelonLogger.Msg("[BloodLab] classes registered");
				BloodLabPreferences.Initialize();
				MelonLogger.Msg("[BloodLab] preferences initialized");
				BloodTextureLibrary.Initialize();
				MelonLogger.Msg("[BloodLab] texture library initialized");
				BloodEffectManager.Initialize();
				MelonLogger.Msg("[BloodLab] effect manager initialized");
				BloodLabBoneMenu.Setup();
				MelonLogger.Msg("[BloodLab] bone menu initialized");
				_harmony = new Harmony("com.bloodlab.mod");
				_harmony.PatchAll();
				MelonLogger.Msg("[BloodLab] patches applied");
				MelonLogger.Msg("[BloodLab] initialized");
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BloodLab] error initializing: " + ex);
			}
		}

		public override void OnUpdate()
		{
			MainThreadDispatcher.ProcessQueue();
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			try
			{
				BloodTextureLibrary.Reload();
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BloodLab] couldnt reload textures: " + ex);
			}
		}
	}
}
namespace BloodLab.Configuration
{
	public static class BloodLabBoneMenu
	{
		public static void Setup()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Page root = Page.Root.CreatePage("BloodLab", Color.red, 0, true);
			SetupGeneralPage(root);
			SetupBleedingPage(root);
			SetupPoolPage(root);
		}

		private static void SetupGeneralPage(Page root)
		{
			//IL_0007: 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)
			Page val = root.CreatePage("General", Color.white, 0, true);
			val.CreateBool("Impact Particles", Color.white, BloodLabPreferences.EnableParticles.Value, (Action<bool>)delegate(bool value)
			{
				BloodLabPreferences.EnableParticles.Value = value;
				BloodLabPreferences.Save();
			});
			CreateAdjustableFloat(val, "Intensity", BloodLabPreferences.Intensity, 0.1f, 0.1f, 3f);
			CreateAdjustableFloat(val, "Droplet Size", BloodLabPreferences.DropletVisualScale, 0.01f, 0.02f, 0.3f);
			CreateAdjustableInt(val, "Max Droplets", BloodLabPreferences.MaxDroplets, 10, 10, 300);
		}

		private static void SetupBleedingPage(Page root)
		{
			//IL_0007: 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)
			Page val = root.CreatePage("Bleeding", Color.white, 0, true);
			val.CreateBool("Enable Bleeding", Color.white, BloodLabPreferences.EnableBleeding.Value, (Action<bool>)delegate(bool value)
			{
				BloodLabPreferences.EnableBleeding.Value = value;
				BloodLabPreferences.Save();
			});
			CreateAdjustableFloat(val, "Exit Wound Offset", BloodLabPreferences.ExitWoundOffset, 0.02f, 0f, 0.5f);
			CreateAdjustableFloat(val, "Bleed Duration", BloodLabPreferences.BleedDurationSeconds, 0.5f, 0.5f, 20f);
			CreateAdjustableFloat(val, "Bleed Interval", BloodLabPreferences.BleedIntervalSeconds, 0.05f, 0.05f, 2f);
			CreateAdjustableInt(val, "Droplets/ps", BloodLabPreferences.BleedDropletsPerTick, 1, 1, 10);
			CreateAdjustableFloat(val, "Bled-out Pool Max Size", BloodLabPreferences.BleedPoolMaxSize, 0.01f, 0.03f, 0.4f);
		}

		private static void SetupPoolPage(Page root)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Page page = root.CreatePage("Blood Pools", Color.white, 0, true);
			CreateAdjustableInt(page, "Max Pools", BloodLabPreferences.MaxStains, 5, 1, 200);
			CreateAdjustableFloat(page, "Max Pool Size", BloodLabPreferences.StainMaxSize, 0.05f, 0.1f, 2f);
			CreateAdjustableFloat(page, "Growth Per Droplet", BloodLabPreferences.StainGrowthPerDroplet, 0.01f, 0.005f, 0.2f);
			CreateAdjustableFloat(page, "Merge Radius", BloodLabPreferences.StainMergeRadius, 0.05f, 0.05f, 1.5f);
			CreateAdjustableFloat(page, "Growth Animation Speed", BloodLabPreferences.StainGrowthSpeed, 0.5f, 0.5f, 20f);
		}

		private static void CreateAdjustableFloat(Page page, string label, MelonPreferences_Entry<float> entry, float step, float min, float max)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			FunctionElement display = page.CreateFunction($"{label}: {entry.Value:0.00}", Color.white, (Action)delegate
			{
			});
			page.CreateFunction("- " + label, Color.yellow, (Action)delegate
			{
				entry.Value = Mathf.Clamp(entry.Value - step, min, max);
				BloodLabPreferences.Save();
				((Element)display).ElementName = $"{label}: {entry.Value:0.00}";
			});
			page.CreateFunction("+ " + label, Color.green, (Action)delegate
			{
				entry.Value = Mathf.Clamp(entry.Value + step, min, max);
				BloodLabPreferences.Save();
				((Element)display).ElementName = $"{label}: {entry.Value:0.00}";
			});
		}

		private static void CreateAdjustableInt(Page page, string label, MelonPreferences_Entry<int> entry, int step, int min, int max)
		{
			//IL_006c: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			FunctionElement display = page.CreateFunction($"{label}: {entry.Value}", Color.white, (Action)delegate
			{
			});
			page.CreateFunction("- " + label, Color.yellow, (Action)delegate
			{
				entry.Value = Mathf.Clamp(entry.Value - step, min, max);
				BloodLabPreferences.Save();
				((Element)display).ElementName = $"{label}: {entry.Value}";
			});
			page.CreateFunction("+ " + label, Color.green, (Action)delegate
			{
				entry.Value = Mathf.Clamp(entry.Value + step, min, max);
				BloodLabPreferences.Save();
				((Element)display).ElementName = $"{label}: {entry.Value}";
			});
		}
	}
	public static class BloodLabPreferences
	{
		private static MelonPreferences_Category _category;

		public static MelonPreferences_Entry<int> MaxDroplets;

		public static MelonPreferences_Entry<int> MaxStains;

		public static MelonPreferences_Entry<float> DropletVisualScale;

		public static MelonPreferences_Entry<float> DropletLifetime;

		public static MelonPreferences_Entry<float> StainMaxSize;

		public static MelonPreferences_Entry<float> StainGrowthPerDroplet;

		public static MelonPreferences_Entry<float> StainMergeRadius;

		public static MelonPreferences_Entry<float> StainGrowthSpeed;

		public static MelonPreferences_Entry<bool> EnableBleeding;

		public static MelonPreferences_Entry<float> ExitWoundOffset;

		public static MelonPreferences_Entry<float> BleedDurationSeconds;

		public static MelonPreferences_Entry<float> BleedIntervalSeconds;

		public static MelonPreferences_Entry<int> BleedDropletsPerTick;

		public static MelonPreferences_Entry<float> BleedPoolMaxSize;

		public static MelonPreferences_Entry<float> Intensity;

		public static MelonPreferences_Entry<bool> EnableParticles;

		public static void Initialize()
		{
			_category = MelonPreferences.CreateCategory("BloodLab");
			MaxDroplets = _category.CreateEntry<int>("MaxDroplets", 100, (string)null, "max number of droplets at once", false, false, (ValueValidator)null, (string)null);
			MaxStains = _category.CreateEntry<int>("MaxStains", 60, (string)null, "max number of pools", false, false, (ValueValidator)null, (string)null);
			DropletVisualScale = _category.CreateEntry<float>("DropletVisualScale", 0.18f, (string)null, "size of each droplet", false, false, (ValueValidator)null, (string)null);
			DropletLifetime = _category.CreateEntry<float>("DropletLifetimeSeconds", 12f, (string)null, "time until a droplet is recycled", false, false, (ValueValidator)null, (string)null);
			StainMaxSize = _category.CreateEntry<float>("StainMaxSize", 0.6f, (string)null, "max size a normal pool can grow to", false, false, (ValueValidator)null, (string)null);
			StainGrowthPerDroplet = _category.CreateEntry<float>("StainGrowthPerDroplet", 0.03f, (string)null, "how much a pool grows each time a droplet lands in it", false, false, (ValueValidator)null, (string)null);
			StainMergeRadius = _category.CreateEntry<float>("StainMergeRadius", 0.35f, (string)null, "how close a droplet gotta land to a pool to grow it", false, false, (ValueValidator)null, (string)null);
			StainGrowthSpeed = _category.CreateEntry<float>("StainGrowthSpeed", 4f, (string)null, "how fast pools animate", false, false, (ValueValidator)null, (string)null);
			EnableBleeding = _category.CreateEntry<bool>("EnableBleeding", true, (string)null, "toggle continuous bleeding after a hit", false, false, (ValueValidator)null, (string)null);
			ExitWoundOffset = _category.CreateEntry<float>("ExitWoundOffset", 0.15f, (string)null, "how far is the exit wound", false, false, (ValueValidator)null, (string)null);
			BleedDurationSeconds = _category.CreateEntry<float>("BleedDurationSeconds", 4f, (string)null, "how long a wound keeps bleeding after being hit", false, false, (ValueValidator)null, (string)null);
			BleedIntervalSeconds = _category.CreateEntry<float>("BleedIntervalSeconds", 0.4f, (string)null, "time between each small burst of bleeding", false, false, (ValueValidator)null, (string)null);
			BleedDropletsPerTick = _category.CreateEntry<int>("BleedDropletsPerTick", 2, (string)null, "how many droplets are released per bleeding tick", false, false, (ValueValidator)null, (string)null);
			BleedPoolMaxSize = _category.CreateEntry<float>("BleedPoolMaxSize", 0.12f, (string)null, "max size for bleed pool", false, false, (ValueValidator)null, (string)null);
			Intensity = _category.CreateEntry<float>("Intensity", 1f, (string)null, "blood intensity multiplier", false, false, (ValueValidator)null, (string)null);
			EnableParticles = _category.CreateEntry<bool>("EnableParticles", true, (string)null, "toggle impact particles", false, false, (ValueValidator)null, (string)null);
			MelonLogger.Msg("[BloodLab] preferences loaded lmao");
		}

		public static void Save()
		{
			MelonPreferences_Category category = _category;
			if (category != null)
			{
				category.SaveToFile(false);
			}
		}
	}
}
namespace BloodLab.Blood
{
	public static class BloodEffectManager
	{
		private static GameObject _root;

		private static BloodEffectPool<BloodStain> _stainPool;

		private static BloodEffectPool<BloodDroplet> _dropletPool;

		private static readonly List<BloodStain> _activeStains = new List<BloodStain>();

		public static Transform RootTransform => ((Object)(object)_root != (Object)null) ? _root.transform : null;

		public static void Initialize()
		{
			EnsureRuntimeRoot();
			if ((Object)(object)_root == (Object)null)
			{
				MelonLogger.Error("[BloodLab] BloodEffectManager failed to initialize: root is null");
				return;
			}
			try
			{
				_stainPool = new BloodEffectPool<BloodStain>(CreateStainInstance, BloodLabPreferences.MaxStains.Value, _root.transform);
				_dropletPool = new BloodEffectPool<BloodDroplet>(CreateDropletInstance, BloodLabPreferences.MaxDroplets.Value, _root.transform);
				MelonLogger.Msg("[BloodLab] BloodEffectManager initialized");
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BloodLab] BloodEffectManager initialization failed: " + ex);
			}
		}

		private static void EnsureRuntimeRoot()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if ((Object)(object)_root != (Object)null)
			{
				return;
			}
			try
			{
				_root = new GameObject("BloodLab_Runtime");
				if ((Object)(object)_root == (Object)null)
				{
					MelonLogger.Error("[BloodLab] failed to create BloodLab_Runtime");
					return;
				}
				Object.DontDestroyOnLoad((Object)(object)_root);
				MelonLogger.Msg("[BloodLab] BloodEffectManager root created");
			}
			catch (Exception ex)
			{
				_root = null;
				MelonLogger.Error("[BloodLab] failed to create BloodEffectManager root: " + ex);
			}
		}

		public static void HandleImpact(ImpactData data)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if (!data.IsLivingEntity || (Object)(object)data.HitCollider == (Object)null)
			{
				return;
			}
			EnsureRuntimeRoot();
			if ((Object)(object)_root == (Object)null)
			{
				MelonLogger.Warning("[BloodLab] impact ignored");
				return;
			}
			float intensity = data.Intensity * BloodLabPreferences.Intensity.Value;
			Transform transform = ((Component)data.HitCollider).transform;
			if ((Object)(object)transform == (Object)null)
			{
				MelonLogger.Warning("[BloodLab] impact ignored");
				return;
			}
			Transform val = transform.root;
			if ((Object)(object)val == (Object)null)
			{
				val = transform;
			}
			Vector3 val2 = ((((Vector3)(ref data.Direction)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref data.Direction)).normalized : (-data.Normal));
			Vector3 startWorldPosition = data.Position + val2 * BloodLabPreferences.ExitWoundOffset.Value;
			bool flag = IsHeadTransform(transform);
			float startDelay = (flag ? 0.6f : 0f);
			float forcedPoolMaxSize = (flag ? 0.1f : (-1f));
			if (flag)
			{
				MelonLogger.Msg("[BloodLab] headshot detected on '" + ((Object)transform).name + "'");
			}
			BeginBleeding(transform, startWorldPosition, val, intensity, startDelay, forcedPoolMaxSize);
		}

		private static bool IsHeadTransform(Transform t)
		{
			Transform val = t;
			int num = 0;
			while ((Object)(object)val != (Object)null && num < 10)
			{
				if (((Object)val).name.ToLowerInvariant().Contains("head"))
				{
					return true;
				}
				val = val.parent;
				num++;
			}
			return false;
		}

		private static void BeginBleeding(Transform trackedTransform, Vector3 startWorldPosition, Transform ignoreRoot, float intensity, float startDelay = 0f, float forcedPoolMaxSize = -1f)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			if (!BloodLabPreferences.EnableBleeding.Value)
			{
				return;
			}
			EnsureRuntimeRoot();
			if ((Object)(object)_root == (Object)null)
			{
				MelonLogger.Warning("[BloodLab] bleedin: root is null");
				return;
			}
			if ((Object)(object)trackedTransform == (Object)null)
			{
				MelonLogger.Warning("[BloodLab] bleedin: tracked transform is null");
				return;
			}
			try
			{
				GameObject val = new GameObject("BloodLab_BleedWound");
				if ((Object)(object)val == (Object)null)
				{
					MelonLogger.Warning("[BloodLab] bleedin: failed to create GameObject");
					return;
				}
				Transform transform = _root.transform;
				if ((Object)(object)transform == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					MelonLogger.Warning("[BloodLab] bleedin: root transform is null");
					return;
				}
				val.transform.SetParent(transform, false);
				Component val2 = val.AddComponent(Il2CppType.Of<BleedWound>());
				if ((Object)(object)val2 == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					MelonLogger.Warning("[BloodLab] bleedin: failed to add BleedWound");
					return;
				}
				BleedWound bleedWound = ((Il2CppObjectBase)val2).TryCast<BleedWound>();
				if ((Object)(object)bleedWound == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					MelonLogger.Warning("[BloodLab] bleedin: BleedWound cast failed");
				}
				else
				{
					bleedWound.Begin(trackedTransform, startWorldPosition, ignoreRoot, intensity, startDelay, forcedPoolMaxSize);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BloodLab] failed to begin bleeding: " + ex);
			}
		}

		public static void HandleDropletLanded(Vector3 groundPosition, Vector3 groundNormal, float maxSizeOverride = -1f)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_014a: 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)
			EnsureRuntimeRoot();
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			if (_stainPool == null)
			{
				MelonLogger.Warning("[BloodLab] stain aint initialized");
				return;
			}
			float value = BloodLabPreferences.StainMergeRadius.Value;
			float value2 = BloodLabPreferences.StainGrowthPerDroplet.Value;
			float maxSize = ((maxSizeOverride > 0f) ? maxSizeOverride : BloodLabPreferences.StainMaxSize.Value);
			BloodStain bloodStain = null;
			float num = value * value;
			foreach (BloodStain activeStain in _activeStains)
			{
				if (!((Object)(object)activeStain == (Object)null))
				{
					Vector3 val = activeStain.WorldPosition - groundPosition;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (sqrMagnitude <= num)
					{
						num = sqrMagnitude;
						bloodStain = activeStain;
					}
				}
			}
			if ((Object)(object)bloodStain != (Object)null)
			{
				bloodStain.Grow(value2, maxSize);
				return;
			}
			Texture2D randomTexture = BloodTextureLibrary.GetRandomTexture(BloodTextureCategory.Stain);
			if ((Object)(object)randomTexture == (Object)null)
			{
				MelonLogger.Warning("[BloodLab] there aint no stains");
				return;
			}
			BloodStain bloodStain2 = _stainPool.Get();
			if ((Object)(object)bloodStain2 == (Object)null)
			{
				MelonLogger.Warning("[BloodLab] stain pool returned null");
				return;
			}
			bloodStain2.PlaceOnGround(groundPosition, groundNormal, randomTexture, value2);
			_activeStains.Add(bloodStain2);
		}

		public static void ReleaseStain(BloodStain stain)
		{
			if ((Object)(object)stain == (Object)null || _stainPool == null)
			{
				return;
			}
			try
			{
				_activeStains.Remove(stain);
				if ((Object)(object)_root != (Object)null)
				{
					((Component)stain).transform.SetParent(_root.transform, false);
				}
				_stainPool.Release(stain);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BloodLab] failed to release stain: " + ex);
			}
		}

		public static BloodDroplet GetDropletFromPool()
		{
			EnsureRuntimeRoot();
			if ((Object)(object)_root == (Object)null)
			{
				return null;
			}
			if (_dropletPool == null)
			{
				MelonLogger.Warning("[BloodLab] droplet pool is not initialized");
				return null;
			}
			BloodDroplet bloodDroplet = _dropletPool.Get();
			if ((Object)(object)bloodDroplet == (Object)null)
			{
				return null;
			}
			bloodDroplet.PoolMaxSizeOverride = -1f;
			Texture2D randomTexture = BloodTextureLibrary.GetRandomTexture(BloodTextureCategory.Droplet);
			bloodDroplet.SetTexture(randomTexture);
			return bloodDroplet;
		}

		public static void ReleaseDroplet(BloodDroplet droplet)
		{
			if ((Object)(object)droplet == (Object)null || _dropletPool == null)
			{
				return;
			}
			try
			{
				_dropletPool.Release(droplet);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BloodLab] failed to release droplet: " + ex);
			}
		}

		private static BloodStain CreateStainInstance()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("BloodLab_Pool");
			val.AddComponent<MeshFilter>();
			val.AddComponent<MeshRenderer>();
			Component val2 = val.AddComponent(Il2CppType.Of<BloodStain>());
			return ((Il2CppObjectBase)val2).TryCast<BloodStain>();
		}

		private static BloodDroplet CreateDropletInstance()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("BloodLab_Droplet");
			val.AddComponent<MeshFilter>();
			val.AddComponent<MeshRenderer>();
			Component val2 = val.AddComponent(Il2CppType.Of<BloodDroplet>());
			return ((Il2CppObjectBase)val2).TryCast<BloodDroplet>();
		}
	}
	public class BloodEffectPool<T> where T : Component
	{
		private readonly Stack<T> _available = new Stack<T>();

		private readonly List<T> _all = new List<T>();

		private readonly Func<T> _factory;

		private readonly int _maxSize;

		private readonly Transform _root;

		public int ActiveCount => _all.Count - _available.Count;

		public BloodEffectPool(Func<T> factory, int maxSize, Transform root)
		{
			_factory = factory;
			_maxSize = maxSize;
			_root = root;
		}

		public T Get()
		{
			T val = default(T);
			while (_available.Count > 0)
			{
				T val2 = _available.Pop();
				if ((Object)(object)val2 != (Object)null)
				{
					val = val2;
					break;
				}
				_all.Remove(val2);
			}
			if ((Object)(object)val == (Object)null)
			{
				if (_all.Count < _maxSize)
				{
					val = _factory();
					((Component)val).transform.SetParent(_root, false);
					_all.Add(val);
				}
				else
				{
					for (int i = 0; i < _all.Count; i++)
					{
						if ((Object)(object)_all[i] != (Object)null)
						{
							val = _all[i];
							_all.RemoveAt(i);
							_all.Add(val);
							break;
						}
					}
					if ((Object)(object)val == (Object)null)
					{
						val = _factory();
						((Component)val).transform.SetParent(_root, false);
						_all.Add(val);
					}
				}
			}
			((Component)val).gameObject.SetActive(true);
			return val;
		}

		public void Release(T instance)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				((Component)instance).gameObject.SetActive(false);
				if (!_available.Contains(instance))
				{
					_available.Push(instance);
				}
			}
		}
	}
	public enum BloodTextureCategory
	{
		Blood,
		Droplet,
		Stain
	}
	public static class BloodTextureLibrary
	{
		private static readonly string[] SupportedExtensions = new string[3] { ".png", ".jpg", ".jpeg" };

		private static readonly Dictionary<BloodTextureCategory, string> FolderNames = new Dictionary<BloodTextureCategory, string>
		{
			{
				BloodTextureCategory.Blood,
				"Blood"
			},
			{
				BloodTextureCategory.Droplet,
				"Droplet"
			},
			{
				BloodTextureCategory.Stain,
				"Stain"
			}
		};

		private static readonly Dictionary<BloodTextureCategory, List<Texture2D>> _texturesByCategory = new Dictionary<BloodTextureCategory, List<Texture2D>>();

		public static void Initialize()
		{
			string text = Path.Combine(MelonEnvironment.UserDataDirectory, "BLOODLAB");
			foreach (BloodTextureCategory key in FolderNames.Keys)
			{
				_texturesByCategory[key] = new List<Texture2D>();
			}
			Reload();
		}

		public static void Reload()
		{
			foreach (BloodTextureCategory key in FolderNames.Keys)
			{
				ReloadCategory(key);
			}
		}

		private static void ReloadCategory(BloodTextureCategory category)
		{
			string text = Path.Combine(MelonEnvironment.UserDataDirectory, "BLOODLAB", FolderNames[category]);
			if (!_texturesByCategory.TryGetValue(category, out var value))
			{
				value = new List<Texture2D>();
				_texturesByCategory[category] = value;
			}
			foreach (Texture2D item in value)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			value.Clear();
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
				MelonLogger.Warning("[BloodLab] textures folder made in '" + text + "'. put your images there boy");
				return;
			}
			string[] files = Directory.GetFiles(text);
			string[] array = files;
			foreach (string path in array)
			{
				string value2 = Path.GetExtension(path).ToLowerInvariant();
				if (Array.IndexOf(SupportedExtensions, value2) >= 0)
				{
					Texture2D val = LoadTexture(path);
					if ((Object)(object)val != (Object)null)
					{
						((Object)val).name = Path.GetFileNameWithoutExtension(path);
						value.Add(val);
					}
				}
			}
			MelonLogger.Msg($"[BloodLab] {value.Count} textures loaded to '{category}' from '{text}'.");
		}

		private static Texture2D LoadTexture(string path)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			try
			{
				byte[] array = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				Il2CppStructArray<byte> val2 = Il2CppStructArray<byte>.op_Implicit(array);
				if (!ImageConversion.LoadImage(val, val2))
				{
					MelonLogger.Warning("[BloodLab] we cant decode '" + path + "'");
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Object)val).hideFlags = (HideFlags)61;
				return val;
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[BloodLab] texture failed to load '{path}': {value}");
				return null;
			}
		}

		public static Texture2D GetRandomTexture(BloodTextureCategory category)
		{
			if (!_texturesByCategory.TryGetValue(category, out var value) || value.Count == 0)
			{
				return null;
			}
			return value[Random.Range(0, value.Count)];
		}
	}
}