Decompiled source of HomigradLight v5.0.0

HomigradLight.dll

Decompiled 10 hours ago
using System;
using System.Collections;
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 HarmonyLib;
using Homigrad;
using LabFusion.Marrow;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.SDK.Gamemodes;
using LabFusion.Senders;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(HomigradLightMod), "Homigrad Light", "5.0.0", "Homigrad", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("HomigradLight")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HomigradLight")]
[assembly: AssemblyTitle("HomigradLight")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 Homigrad
{
	internal static class DeadPieceBridge
	{
		private static readonly string[] LimbBones = new string[14]
		{
			"LeftShoulder", "RightShoulder", "LeftUpperArm", "RightUpperArm", "LeftLowerArm", "RightLowerArm", "LeftHand", "RightHand", "LeftUpperLeg", "RightUpperLeg",
			"LeftLowerLeg", "RightLowerLeg", "LeftFoot", "RightFoot"
		};

		private static bool _resolved;

		private static bool _loggedMissing;

		private static bool _loggedOk;

		private static object? _mod;

		private static MethodInfo? _onBoneHit;

		private static Type? _humanBodyBones;

		private static Type? _vector3Type;

		private static MethodInfo? _opEquality;

		private static bool _tearLimbs = true;

		private static float _tearSpeed = 12f;

		private static float _limbDamage = 9999f;

		public static bool TearLimbsOnFall
		{
			get
			{
				return _tearLimbs;
			}
			set
			{
				_tearLimbs = value;
			}
		}

		public static bool TearLegsOnFall
		{
			get
			{
				return _tearLimbs;
			}
			set
			{
				_tearLimbs = value;
			}
		}

		public static float TearSpeed
		{
			get
			{
				return _tearSpeed;
			}
			set
			{
				_tearSpeed = Math.Clamp(value, 5f, 40f);
			}
		}

		public static bool IsDeadPieceLoaded()
		{
			Ensure();
			if (_mod != null)
			{
				return _onBoneHit != null;
			}
			return false;
		}

		public static void TryTearLegsFromFall(float fallVelocityY, object? physicsRig, object? rigManager)
		{
			TryTearLimbsFromFall(fallVelocityY, physicsRig, rigManager);
		}

		public static void TryTearLimbsFromFall(float fallVelocityY, object? physicsRig, object? rigManager)
		{
			if (!_tearLimbs || fallVelocityY > 0f - _tearSpeed)
			{
				return;
			}
			Ensure();
			if (_mod == null || _onBoneHit == null || rigManager == null || IsUnityNull(rigManager))
			{
				if (!_loggedMissing)
				{
					_loggedMissing = true;
					MelonLogger.Warning("[Homigrad] DeadPiece.dll not found — fall won't tear limbs. Install Deadpiece.dll in Mods.");
				}
				return;
			}
			try
			{
				object bodyHitPoint = GetBodyHitPoint(physicsRig);
				string[] limbBones = LimbBones;
				foreach (string boneName in limbBones)
				{
					HitBone(rigManager, boneName, bodyHitPoint);
				}
				if (!_loggedOk)
				{
					_loggedOk = true;
					MelonLogger.Msg("[Homigrad] DeadPiece 0.7.7+: hard falls tear all limbs.");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] DeadPiece limb tear failed: " + ex.Message);
			}
		}

		private static void HitBone(object rigManager, string boneName, object hitPoint)
		{
			if (_humanBodyBones == null || _onBoneHit == null)
			{
				return;
			}
			try
			{
				if (Enum.IsDefined(_humanBodyBones, boneName))
				{
					object obj = Enum.Parse(_humanBodyBones, boneName);
					_onBoneHit.Invoke(_mod, new object[4] { rigManager, obj, _limbDamage, hitPoint });
				}
			}
			catch
			{
			}
		}

		private static object GetBodyHitPoint(object? physicsRig)
		{
			try
			{
				if (physicsRig != null)
				{
					string[] array = new string[5] { "m_chest", "chest", "m_pelvis", "pelvis", "feet" };
					foreach (string name in array)
					{
						object obj = physicsRig.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(physicsRig) ?? physicsRig.GetType().GetProperty(name)?.GetValue(physicsRig);
						object obj2 = obj?.GetType().GetProperty("transform")?.GetValue(obj);
						object obj3 = obj2?.GetType().GetProperty("position")?.GetValue(obj2);
						if (obj3 != null)
						{
							return obj3;
						}
					}
				}
			}
			catch
			{
			}
			return Activator.CreateInstance(_vector3Type, 0f, 0f, 0f);
		}

		private static void Ensure()
		{
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			try
			{
				_vector3Type = Type.GetType("UnityEngine.Vector3, UnityEngine.CoreModule") ?? FindType("UnityEngine.Vector3");
				_humanBodyBones = FindType("UnityEngine.HumanBodyBones") ?? Type.GetType("UnityEngine.HumanBodyBones, UnityEngine.AnimationModule") ?? Type.GetType("UnityEngine.HumanBodyBones, UnityEngine.CoreModule");
				_opEquality = (Type.GetType("UnityEngine.Object, UnityEngine.CoreModule") ?? FindType("UnityEngine.Object"))?.GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public);
				Type type = FindType("MelonLoader.MelonBase") ?? FindType("MelonLoader.MelonMod");
				Type type2 = FindType("DeadPiece.DeadPieceMod");
				if (type2 == null)
				{
					return;
				}
				object obj = (type?.GetProperty("RegisteredMelons", BindingFlags.Static | BindingFlags.Public))?.GetValue(null);
				if (obj != null)
				{
					foreach (object item in (IEnumerable)obj)
					{
						if (item != null && type2.IsInstanceOfType(item))
						{
							_mod = item;
							break;
						}
					}
				}
				if (_mod == null)
				{
					_mod = (type2.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public) ?? type2.BaseType?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy))?.GetValue(null);
				}
				if (_mod == null)
				{
					return;
				}
				MethodInfo[] methods = type2.GetMethods(BindingFlags.Instance | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name == "OnBoneHit" && methodInfo.GetParameters().Length == 4)
					{
						_onBoneHit = methodInfo;
						break;
					}
				}
				if (!(_onBoneHit == null))
				{
					return;
				}
				methods = type2.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (methodInfo2.Name == "ApplyBoneHit" && methodInfo2.GetParameters().Length >= 4)
					{
						_onBoneHit = methodInfo2;
						break;
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] DeadPiece bridge init: " + ex.Message);
			}
		}

		private static bool IsUnityNull(object? obj)
		{
			if (obj == null)
			{
				return true;
			}
			try
			{
				if (_opEquality != null)
				{
					return (bool)_opEquality.Invoke(null, new object[2] { obj, null });
				}
			}
			catch
			{
			}
			return false;
		}

		private static Type? FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(fullName);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}
	}
	internal static class FallDamage
	{
		private static bool _enabled = true;

		private static float _threshold = 7f;

		private static float _multiplier = 1.5f;

		private static float _ragdollHealthPercentage = 25f;

		private static bool _ragdollFromFallDamage = true;

		private static bool _ragdollFlingingFix = true;

		private static bool _sceneReady;

		private static bool _previousGrounded;

		private static bool _hasRagdolledFromCrumble;

		private static bool _previousLegsKinematic;

		private static bool _loggedReady;

		private static bool _loggedFail;

		private static Type? _playerType;

		private static Type? _vector3Type;

		private static MethodInfo? _opEquality;

		private static bool _typesResolved;

		public static bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				_enabled = value;
			}
		}

		public static float MinSpeed
		{
			get
			{
				return _threshold;
			}
			set
			{
				_threshold = Math.Clamp(value, 0f, 100f);
			}
		}

		public static float Threshold
		{
			get
			{
				return _threshold;
			}
			set
			{
				_threshold = Math.Clamp(value, 0f, 100f);
			}
		}

		public static float Multiplier
		{
			get
			{
				return _multiplier;
			}
			set
			{
				_multiplier = Math.Clamp(value, 0f, 100f);
			}
		}

		public static float DamagePerMs
		{
			get
			{
				return _multiplier;
			}
			set
			{
				_multiplier = Math.Clamp(value, 0f, 100f);
			}
		}

		public static float RagdollHealthPercentage
		{
			get
			{
				return _ragdollHealthPercentage;
			}
			set
			{
				_ragdollHealthPercentage = Math.Clamp(value, 0f, 100f);
			}
		}

		public static bool RagdollFromFallDamage
		{
			get
			{
				return _ragdollFromFallDamage;
			}
			set
			{
				_ragdollFromFallDamage = value;
			}
		}

		public static bool RagdollFlingingFix
		{
			get
			{
				return _ragdollFlingingFix;
			}
			set
			{
				_ragdollFlingingFix = value;
			}
		}

		public static void Reset()
		{
			_sceneReady = false;
			_previousGrounded = false;
			_hasRagdolledFromCrumble = false;
			_previousLegsKinematic = true;
		}

		public static void Tick(bool active)
		{
			if (!_enabled || !active)
			{
				return;
			}
			EnsureTypes();
			if (_playerType == null)
			{
				return;
			}
			try
			{
				if (!TryGetPhysicsRig(out object physicsRig) || !TryGetRigManager(out object rigManager))
				{
					return;
				}
				if (!_sceneReady)
				{
					if (TryGetGrounded(physicsRig, out var grounded))
					{
						_previousGrounded = grounded;
						_previousLegsKinematic = GetLegsKinematic(physicsRig);
						_sceneReady = true;
						if (!_loggedReady)
						{
							_loggedReady = true;
							MelonLogger.Msg("[Homigrad] Crumble-style fall damage ready.");
						}
					}
					return;
				}
				object health = GetHealth(rigManager);
				if (health == null)
				{
					return;
				}
				float floatProp = GetFloatProp(health, "curr_Health");
				float num = GetFloatProp(health, "max_Health");
				if (num <= 0.01f)
				{
					num = 1f;
				}
				float num2 = floatProp / num * 100f;
				bool legsKinematic = GetLegsKinematic(physicsRig);
				if (num2 >= _ragdollHealthPercentage && !legsKinematic && floatProp > 0f && _hasRagdolledFromCrumble)
				{
					Invoke(physicsRig, "UnRagdollRig");
					legsKinematic = GetLegsKinematic(physicsRig);
				}
				if (_hasRagdolledFromCrumble && legsKinematic)
				{
					_hasRagdolledFromCrumble = false;
				}
				if (!_previousLegsKinematic && legsKinematic && _ragdollFlingingFix)
				{
					TryTeleportAboveFeet(physicsRig, rigManager);
				}
				_previousLegsKinematic = legsKinematic;
				if (!TryGetGrounded(physicsRig, out var grounded2))
				{
					return;
				}
				if (grounded2 && !_previousGrounded)
				{
					float wholeBodyVelocityY = GetWholeBodyVelocityY(physicsRig);
					if (wholeBodyVelocityY < 0f - _threshold)
					{
						float num3 = Math.Abs(wholeBodyVelocityY + _threshold) * _multiplier;
						TakeDamage(health, num3);
						DeadPieceBridge.TryTearLimbsFromFall(wholeBodyVelocityY, physicsRig, GetRigManager());
						if (GetFloatProp(health, "curr_Health") / Math.Max(0.01f, GetFloatProp(health, "max_Health")) * 100f <= _ragdollHealthPercentage && _ragdollFromFallDamage)
						{
							RagdollUtil.SafeRagdoll(physicsRig);
							_hasRagdolledFromCrumble = true;
							try
							{
								HomigradSounds.OnFallImpact(num3, Math.Abs(wholeBodyVelocityY), fractured: true);
								PainOverlay.NotifyDamage(num3, fractured: true);
							}
							catch
							{
							}
						}
						else
						{
							try
							{
								HomigradSounds.OnFallImpact(num3, Math.Abs(wholeBodyVelocityY), fractured: false);
								PainOverlay.NotifyDamage(num3);
							}
							catch
							{
							}
						}
					}
				}
				_previousGrounded = grounded2;
			}
			catch (Exception ex)
			{
				if (!_loggedFail)
				{
					_loggedFail = true;
					MelonLogger.Warning("[Homigrad] Crumble fall damage error: " + ex.Message);
				}
			}
		}

		private static void EnsureTypes()
		{
			if (!_typesResolved)
			{
				_typesResolved = true;
				_playerType = FindType("BoneLib.Player");
				_vector3Type = Type.GetType("UnityEngine.Vector3, UnityEngine.CoreModule") ?? FindType("UnityEngine.Vector3");
				_opEquality = (Type.GetType("UnityEngine.Object, UnityEngine.CoreModule") ?? FindType("UnityEngine.Object"))?.GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public);
			}
		}

		private static bool TryGetPhysicsRig(out object physicsRig)
		{
			physicsRig = null;
			try
			{
				object obj = _playerType.GetField("physicsRig", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? _playerType.GetProperty("physicsRig", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? _playerType.GetProperty("PhysicsRig", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null || IsUnityNull(obj))
				{
					return false;
				}
				physicsRig = obj;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static object? GetRigManager()
		{
			if (!TryGetRigManager(out object rigManager))
			{
				return null;
			}
			return rigManager;
		}

		private static bool TryGetRigManager(out object rigManager)
		{
			rigManager = null;
			try
			{
				object obj = _playerType.GetField("rigManager", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? _playerType.GetProperty("rigManager", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? _playerType.GetProperty("RigManager", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null || IsUnityNull(obj))
				{
					return false;
				}
				rigManager = obj;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static object? GetHealth(object rigManager)
		{
			object obj = rigManager.GetType().GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(rigManager);
			if (obj == null)
			{
				PropertyInfo? property = rigManager.GetType().GetProperty("health");
				if ((object)property == null)
				{
					return null;
				}
				obj = property.GetValue(rigManager);
			}
			return obj;
		}

		private static bool TryGetGrounded(object physicsRig, out bool grounded)
		{
			grounded = false;
			try
			{
				object obj = physicsRig.GetType().GetField("feet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(physicsRig) ?? physicsRig.GetType().GetProperty("feet")?.GetValue(physicsRig);
				if (obj == null)
				{
					return false;
				}
				object componentByName = GetComponentByName(obj, "PhysGrounder");
				if (componentByName == null)
				{
					return false;
				}
				if ((componentByName.GetType().GetField("isGrounded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(componentByName) ?? componentByName.GetType().GetProperty("isGrounded")?.GetValue(componentByName)) is bool flag)
				{
					grounded = flag;
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static float GetWholeBodyVelocityY(object physicsRig)
		{
			try
			{
				object obj = physicsRig.GetType().GetProperty("wholeBodyVelocity")?.GetValue(physicsRig) ?? physicsRig.GetType().GetField("wholeBodyVelocity", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(physicsRig);
				if (obj == null)
				{
					return 0f;
				}
				return Convert.ToSingle(obj.GetType().GetField("y")?.GetValue(obj) ?? obj.GetType().GetProperty("y")?.GetValue(obj));
			}
			catch
			{
				return 0f;
			}
		}

		private static bool GetLegsKinematic(object physicsRig)
		{
			try
			{
				object obj = physicsRig.GetType().GetField("_legsKinematic", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(physicsRig) ?? physicsRig.GetType().GetProperty("_legsKinematic")?.GetValue(physicsRig) ?? physicsRig.GetType().GetProperty("legsKinematic")?.GetValue(physicsRig);
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch
			{
				return true;
			}
		}

		private static void TakeDamage(object health, float damage)
		{
			MethodInfo[] methods = health.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!string.Equals(methodInfo.Name, "TAKEDAMAGE", StringComparison.OrdinalIgnoreCase) && !string.Equals(methodInfo.Name, "TakeDamage", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 0 || parameters[0].ParameterType != typeof(float))
				{
					continue;
				}
				object[] array = new object[parameters.Length];
				array[0] = damage;
				for (int j = 1; j < parameters.Length; j++)
				{
					Type parameterType = parameters[j].ParameterType;
					if (parameterType == typeof(bool))
					{
						array[j] = false;
					}
					else if (parameterType.IsValueType)
					{
						array[j] = Activator.CreateInstance(parameterType);
					}
					else
					{
						array[j] = null;
					}
				}
				methodInfo.Invoke(health, array);
				break;
			}
		}

		private static void TryTeleportAboveFeet(object physicsRig, object rigManager)
		{
			try
			{
				object obj = physicsRig.GetType().GetField("feet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(physicsRig) ?? physicsRig.GetType().GetProperty("feet")?.GetValue(physicsRig);
				object obj2 = obj?.GetType().GetProperty("transform")?.GetValue(obj);
				object obj3 = obj2?.GetType().GetProperty("position")?.GetValue(obj2);
				if (obj3 == null || _vector3Type == null)
				{
					return;
				}
				float num = GetFloat(obj3, "x");
				float num2 = GetFloat(obj3, "y") + 0.5f;
				float num3 = GetFloat(obj3, "z");
				object obj4 = Activator.CreateInstance(_vector3Type, num, num2, num3);
				MethodInfo method = rigManager.GetType().GetMethod("Teleport", new Type[1] { _vector3Type });
				if (method != null)
				{
					method.Invoke(rigManager, new object[1] { obj4 });
					return;
				}
				MethodInfo[] methods = rigManager.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != "Teleport")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length < 1 || !(parameters[0].ParameterType == _vector3Type))
					{
						continue;
					}
					object[] array = new object[parameters.Length];
					array[0] = obj4;
					for (int j = 1; j < parameters.Length; j++)
					{
						if (parameters[j].ParameterType == typeof(bool))
						{
							array[j] = false;
						}
						else if (parameters[j].ParameterType.IsValueType)
						{
							array[j] = Activator.CreateInstance(parameters[j].ParameterType);
						}
						else
						{
							array[j] = null;
						}
					}
					methodInfo.Invoke(rigManager, array);
					break;
				}
			}
			catch
			{
			}
		}

		private static object? GetComponentByName(object host, string typeName)
		{
			try
			{
				object obj = host.GetType().GetProperty("gameObject")?.GetValue(host) ?? host;
				MethodInfo method = obj.GetType().GetMethod("GetComponents", new Type[1] { typeof(Type) });
				MethodInfo[] methods = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != "GetComponent") && methodInfo.GetParameters().Length == 1 && !(methodInfo.GetParameters()[0].ParameterType != typeof(string)))
					{
						object obj2 = methodInfo.Invoke(obj, new object[1] { typeName });
						if (obj2 != null && !IsUnityNull(obj2))
						{
							return obj2;
						}
					}
				}
				Type type = FindType("UnityEngine.Component") ?? Type.GetType("UnityEngine.Component, UnityEngine.CoreModule");
				if (type != null && method != null && method.Invoke(obj, new object[1] { type }) is Array array)
				{
					foreach (object item in array)
					{
						if (item != null && item.GetType().Name.IndexOf(typeName, StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return item;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static void Invoke(object target, string method)
		{
			try
			{
				target.GetType().GetMethod(method, Type.EmptyTypes)?.Invoke(target, null);
			}
			catch
			{
			}
		}

		private static float GetFloatProp(object target, string name)
		{
			try
			{
				object obj = target.GetType().GetProperty(name)?.GetValue(target) ?? target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target);
				return (obj == null) ? 0f : Convert.ToSingle(obj);
			}
			catch
			{
				return 0f;
			}
		}

		private static float GetFloat(object v, string name)
		{
			return Convert.ToSingle(v.GetType().GetField(name)?.GetValue(v) ?? v.GetType().GetProperty(name).GetValue(v));
		}

		private static bool IsUnityNull(object? obj)
		{
			if (obj == null)
			{
				return true;
			}
			try
			{
				if (_opEquality != null)
				{
					return (bool)_opEquality.Invoke(null, new object[2] { obj, null });
				}
			}
			catch
			{
			}
			return false;
		}

		private static Type? FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(fullName);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}
	}
	internal static class HolsterHiderBridge
	{
		private static bool _applied;

		private static object?[]? _savedVisibilities;

		private static bool _loggedMissing;

		public static bool IsHolsterHiderLoaded()
		{
			return FindType("HolsterHider.HolsterHiderMod") != null;
		}

		public static bool IsSyncLoaded()
		{
			if (!(FindType("HolsterHiderSync.HolsterHiderSync") != null))
			{
				return FindType("HolsterHiderModule.HolsterHiderModule") != null;
			}
			return true;
		}

		public static void ApplyInvisibleForHomigrad()
		{
			try
			{
				Type type = FindType("HolsterHider.HolsterHiderMod");
				Type type2 = FindType("HolsterHider.HolsterVisibility");
				if (type == null || type2 == null)
				{
					if (!_loggedMissing)
					{
						_loggedMissing = true;
						MelonLogger.Warning("[Homigrad] Holster Hider not loaded — install HolsterHider.dll (and HolsterHiderSync.dll) into Mods.");
					}
					return;
				}
				object obj = type.GetField("LocalBodyConfig", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null || !(obj.GetType().GetProperty("HolsterConfigs")?.GetValue(obj) is Array { Length: not 0 } array))
				{
					return;
				}
				object value = Enum.Parse(type2, "INVISIBLE");
				_savedVisibilities = new object[array.Length];
				for (int i = 0; i < array.Length; i++)
				{
					object value2 = array.GetValue(i);
					if (value2 != null)
					{
						FieldInfo field = value2.GetType().GetField("Visibility");
						if (!(field == null))
						{
							_savedVisibilities[i] = field.GetValue(value2);
							field.SetValue(value2, value);
						}
					}
				}
				type.GetMethod("UpdateHolsters", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null);
				_applied = true;
				MelonLogger.Msg("[Homigrad] Holster Hider → all slots INVISIBLE for this round.");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] HolsterHiderBridge apply failed: " + ex.Message);
			}
		}

		public static void Restore()
		{
			if (!_applied)
			{
				return;
			}
			try
			{
				Type type = FindType("HolsterHider.HolsterHiderMod");
				if (type == null || _savedVisibilities == null)
				{
					_applied = false;
					return;
				}
				object obj = type.GetField("LocalBodyConfig", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if ((obj?.GetType().GetProperty("HolsterConfigs"))?.GetValue(obj) is Array array)
				{
					for (int i = 0; i < array.Length && i < _savedVisibilities.Length; i++)
					{
						object value = array.GetValue(i);
						object obj2 = _savedVisibilities[i];
						if (value != null && obj2 != null)
						{
							value.GetType().GetField("Visibility")?.SetValue(value, obj2);
						}
					}
				}
				type.GetMethod("UpdateHolsters", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null);
				MelonLogger.Msg("[Homigrad] Holster Hider settings restored.");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] HolsterHiderBridge restore failed: " + ex.Message);
			}
			finally
			{
				_applied = false;
				_savedVisibilities = null;
			}
		}

		private static Type? FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(fullName);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}
	}
	public sealed class HomigradLightMod : MelonMod
	{
		private Harmony? _harmony;

		public override void OnInitializeMelon()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			try
			{
				HomigradServerGate.Init();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("Server gate init: " + ex.Message);
			}
			try
			{
				_harmony = new Harmony("HomigradLight.Features");
				SelfHarmFeature.InitHarmony(_harmony);
			}
			catch (Exception ex2)
			{
				((MelonBase)this).LoggerInstance.Warning("Harmony features: " + ex2.Message);
			}
			try
			{
				HomigradSounds.Init();
			}
			catch (Exception ex3)
			{
				((MelonBase)this).LoggerInstance.Warning("Sounds init: " + ex3.Message);
			}
			try
			{
				PainOverlay.Init();
			}
			catch (Exception ex4)
			{
				((MelonBase)this).LoggerInstance.Warning("Pain overlay init: " + ex4.Message);
			}
			((MelonBase)this).LoggerInstance.Msg("Homigrad Light 5.0.0 — client build, official server only.");
		}

		public override void OnLateInitializeMelon()
		{
			if (!HomigradServerGate.IsActive)
			{
				((MelonBase)this).LoggerInstance.Msg("Homigrad Light idle: " + HomigradServerGate.BlockReason);
				return;
			}
			if (DeadPieceBridge.IsDeadPieceLoaded())
			{
				((MelonBase)this).LoggerInstance.Msg("DeadPiece detected (0.7.7+) - hard falls tear all limbs.");
			}
			if (SelfHarmFeature.Enabled)
			{
				try
				{
					SelfHarmFeature.Apply();
				}
				catch (Exception ex)
				{
					((MelonBase)this).LoggerInstance.Warning("SelfHarm apply: " + ex.Message);
				}
			}
			if (WallClimbFeature.Enabled)
			{
				((MelonBase)this).LoggerInstance.Msg("Wall climb enabled — squeeze grip near walls to climb.");
			}
		}

		public override void OnUpdate()
		{
			try
			{
				HomigradServerGate.Tick();
			}
			catch
			{
			}
			if (!HomigradServerGate.IsActive)
			{
				return;
			}
			try
			{
				FallDamage.Tick(active: true);
			}
			catch
			{
			}
			try
			{
				HomigradSounds.Tick();
			}
			catch
			{
			}
			try
			{
				PainOverlay.Tick();
			}
			catch
			{
			}
			try
			{
				SelfHarmFeature.Tick(active: true);
			}
			catch
			{
			}
			try
			{
				WallClimbFeature.Tick(active: true);
			}
			catch
			{
			}
		}
	}
	internal static class HomigradOfficial
	{
		public const string MetaKey = "hg_official";

		public const string MetaToken = "HG2026";
	}
	internal static class HomigradServerGate
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ServerEvent <0>__OnSessionChanged;

			public static ServerEvent <1>__OnDisconnected;

			public static UpdateEvent <2>__Refresh;

			public static Action <3>__Refresh;
		}

		public const string OfficialMetaKey = "hg_official";

		public const string DefaultMetaToken = "HG2026";

		private static readonly HashSet<ulong> HostIds = new HashSet<ulong>();

		private static string _metaToken = "HG2026";

		private static bool _hooks;

		private static bool _loggedState;

		private static float _nextRefresh;

		public static bool IsActive { get; private set; }

		public static string BlockReason { get; private set; } = "Not on official Homigrad server.";

		public static void Init()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//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)
			//IL_006e: Expected O, but got Unknown
			//IL_0083: 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_008e: Expected O, but got Unknown
			LoadConfig();
			if (_hooks)
			{
				return;
			}
			_hooks = true;
			try
			{
				object obj = <>O.<0>__OnSessionChanged;
				if (obj == null)
				{
					ServerEvent val = OnSessionChanged;
					<>O.<0>__OnSessionChanged = val;
					obj = (object)val;
				}
				MultiplayerHooking.OnJoinedServer += (ServerEvent)obj;
				object obj2 = <>O.<0>__OnSessionChanged;
				if (obj2 == null)
				{
					ServerEvent val2 = OnSessionChanged;
					<>O.<0>__OnSessionChanged = val2;
					obj2 = (object)val2;
				}
				MultiplayerHooking.OnStartedServer += (ServerEvent)obj2;
				object obj3 = <>O.<1>__OnDisconnected;
				if (obj3 == null)
				{
					ServerEvent val3 = OnDisconnected;
					<>O.<1>__OnDisconnected = val3;
					obj3 = (object)val3;
				}
				MultiplayerHooking.OnDisconnected += (ServerEvent)obj3;
				object obj4 = <>O.<2>__Refresh;
				if (obj4 == null)
				{
					UpdateEvent val4 = Refresh;
					<>O.<2>__Refresh = val4;
					obj4 = (object)val4;
				}
				MultiplayerHooking.OnMainSceneInitialized += (UpdateEvent)obj4;
				LobbyInfoManager.OnLobbyInfoChanged += Refresh;
				GamemodeManager.OnGamemodeStarted += Refresh;
				GamemodeManager.OnGamemodeStopped += Refresh;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad Light] Gate hooks: " + ex.Message);
			}
			Refresh();
			MelonLogger.Msg("[Homigrad Light] Official-host config: " + ConfigPath());
		}

		public static void Tick()
		{
			if (Time.realtimeSinceStartup >= _nextRefresh)
			{
				_nextRefresh = Time.realtimeSinceStartup + 1f;
				Refresh();
			}
		}

		public static bool CanHostOfficial()
		{
			if (!NetworkInfo.HasServer)
			{
				return false;
			}
			return HostIds.Contains(GetSessionHostId());
		}

		public static void StampOfficialGamemode(Gamemode? gm)
		{
			if (((gm != null) ? gm.Metadata : null) == null || !NetworkInfo.IsHost || !CanHostOfficial())
			{
				return;
			}
			try
			{
				gm.Metadata.TrySetMetadata("hg_official", _metaToken);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad Light] Stamp metadata: " + ex.Message);
			}
		}

		public static bool RequireActive(string feature)
		{
			if (IsActive)
			{
				return true;
			}
			MelonLogger.Msg("[Homigrad Light] Blocked (" + feature + "): " + BlockReason);
			return false;
		}

		private static void OnSessionChanged()
		{
			_loggedState = false;
			Refresh();
		}

		private static void OnDisconnected()
		{
			_loggedState = false;
			IsActive = false;
			BlockReason = "Not connected to a server.";
		}

		private static void Refresh()
		{
			bool isActive = IsActive;
			if (!NetworkInfo.HasServer)
			{
				IsActive = false;
				BlockReason = "Homigrad Light works only on the official Homigrad server.";
				LogStateIfChanged(isActive);
				return;
			}
			ulong sessionHostId = GetSessionHostId();
			if (sessionHostId == 0L)
			{
				IsActive = false;
				BlockReason = "Waiting for lobby info...";
				LogStateIfChanged(isActive);
				return;
			}
			if (HostIds.Contains(sessionHostId))
			{
				IsActive = true;
				BlockReason = string.Empty;
				LogStateIfChanged(isActive);
				return;
			}
			if (TryReadOfficialMetadata(out string _))
			{
				IsActive = true;
				BlockReason = string.Empty;
				LogStateIfChanged(isActive);
				return;
			}
			IsActive = false;
			if (NetworkInfo.IsHost)
			{
				BlockReason = "Own server is not official. Join the Homigrad server instead.";
			}
			else
			{
				BlockReason = "This server is not the official Homigrad server.";
			}
			if (!_loggedState)
			{
				MelonLogger.Msg($"[Homigrad Light] Inactive — host Steam ID {sessionHostId}. Official hosts file: {ConfigPath()}");
			}
			LogStateIfChanged(isActive);
		}

		private static void LogStateIfChanged(bool wasActive)
		{
			if (wasActive != IsActive || !_loggedState)
			{
				_loggedState = true;
				if (IsActive)
				{
					MelonLogger.Msg("[Homigrad Light] Active — official Homigrad server.");
				}
				else
				{
					MelonLogger.Msg("[Homigrad Light] Inactive — " + BlockReason);
				}
			}
		}

		private static bool TryReadOfficialMetadata(out string value)
		{
			value = string.Empty;
			try
			{
				Gamemode val = default(Gamemode);
				string text = default(string);
				if (GamemodeManager.TryGetGamemode<Gamemode>(ref val) && ((val != null) ? val.Metadata : null) != null && val.Metadata.TryGetMetadata("hg_official", ref text) && text == _metaToken)
				{
					value = text;
					return true;
				}
				Gamemode activeGamemode = GamemodeManager.ActiveGamemode;
				string text2 = default(string);
				if (((activeGamemode != null) ? activeGamemode.Metadata : null) != null && GamemodeManager.ActiveGamemode.Metadata.TryGetMetadata("hg_official", ref text2) && text2 == _metaToken)
				{
					value = text2;
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static ulong GetSessionHostId()
		{
			try
			{
				ulong lobbyID = LobbyInfoManager.LobbyInfo.LobbyID;
				if (lobbyID != 0L)
				{
					return lobbyID;
				}
			}
			catch
			{
			}
			try
			{
				PlayerID hostID = PlayerIDManager.GetHostID();
				if (hostID != null && hostID.PlatformID != 0L)
				{
					return hostID.PlatformID;
				}
			}
			catch
			{
			}
			return 0uL;
		}

		private static string ConfigPath()
		{
			return Path.Combine(MelonEnvironment.UserDataDirectory, "Homigrad", "official_hosts.json");
		}

		private static void LoadConfig()
		{
			HostIds.Clear();
			_metaToken = "HG2026";
			string path = ConfigPath();
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				if (!File.Exists(path))
				{
					File.WriteAllText(path, "{\n  \"officialHostIds\": [],\n  \"metadataToken\": \"HG2026\"\n}\n");
					return;
				}
				string json = File.ReadAllText(path);
				foreach (ulong item in ParseIds(json, "officialHostIds"))
				{
					HostIds.Add(item);
				}
				string text = ParseString(json, "metadataToken");
				if (!string.IsNullOrWhiteSpace(text))
				{
					_metaToken = text.Trim();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad Light] Config load: " + ex.Message);
			}
		}

		private static IEnumerable<ulong> ParseIds(string json, string key)
		{
			int num = json.IndexOf(key, StringComparison.OrdinalIgnoreCase);
			if (num < 0)
			{
				yield break;
			}
			int num2 = json.IndexOf('[', num);
			int num3 = json.IndexOf(']', num2 + 1);
			if (num2 < 0 || num3 <= num2)
			{
				yield break;
			}
			string text = json.Substring(num2 + 1, num3 - num2 - 1);
			string[] array = text.Split(',', StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (ulong.TryParse(array[i].Trim().Trim('"'), out var result) && result != 0L)
				{
					yield return result;
				}
			}
		}

		private static string? ParseString(string json, string key)
		{
			int num = json.IndexOf(key, StringComparison.OrdinalIgnoreCase);
			if (num < 0)
			{
				return null;
			}
			int num2 = json.IndexOf(':', num);
			if (num2 < 0)
			{
				return null;
			}
			int num3 = json.IndexOf('"', num2 + 1);
			if (num3 < 0)
			{
				return null;
			}
			int num4 = json.IndexOf('"', num3 + 1);
			if (num4 <= num3)
			{
				return null;
			}
			return json.Substring(num3 + 1, num4 - num3 - 1);
		}
	}
	internal static class HomigradSounds
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static PlayerAction <0>__OnPlayerAction;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UpdateEvent <>9__49_0;

			internal void <Init>b__49_0()
			{
				ResetScene();
			}
		}

		private static bool _ready;

		private static bool _hooks;

		private static float _nextFoot;

		private static float _nextBreathPulse;

		private static float _lastHealth = -1f;

		private static float _lastMaxHealth = 100f;

		private static Vector3 _lastPos;

		private static bool _hasLastPos;

		private static float _painCooldown;

		private static object? _clipBreath;

		private static object? _clipPain;

		private static object? _clipDeath;

		private static object? _clipFracture;

		private static object? _clipFoot;

		private static object? _clipHit;

		private static object? _breathSource;

		private static object? _breathGo;

		public static bool Enabled { get; set; } = true;

		public static bool BreathEnabled { get; set; } = true;

		public static bool PainEnabled { get; set; } = true;

		public static bool DeathEnabled { get; set; } = true;

		public static bool FractureEnabled { get; set; } = true;

		public static bool FootstepEnabled { get; set; } = true;

		public static bool HitEnabled { get; set; } = true;

		public static float Volume { get; set; } = 0.85f;

		public static void Init()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//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_004d: Expected O, but got Unknown
			if (_hooks)
			{
				return;
			}
			_hooks = true;
			try
			{
				object obj = <>O.<0>__OnPlayerAction;
				if (obj == null)
				{
					PlayerAction val = OnPlayerAction;
					<>O.<0>__OnPlayerAction = val;
					obj = (object)val;
				}
				MultiplayerHooking.OnPlayerAction += (PlayerAction)obj;
				object obj2 = <>c.<>9__49_0;
				if (obj2 == null)
				{
					UpdateEvent val2 = delegate
					{
						ResetScene();
					};
					<>c.<>9__49_0 = val2;
					obj2 = (object)val2;
				}
				MultiplayerHooking.OnMainSceneInitialized += (UpdateEvent)obj2;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[HomigradSounds] Hook: " + ex.Message);
			}
			EnsureClips();
		}

		public static void Tick()
		{
			if (!Enabled)
			{
				return;
			}
			EnsureClips();
			if (!_ready)
			{
				return;
			}
			if (!TryGetHealth(out var hp, out var maxHp))
			{
				StopBreathLoop();
				return;
			}
			if (_lastHealth >= 0f && hp < _lastHealth - 0.5f && PainEnabled)
			{
				float num = _lastHealth - hp;
				if ((float)Environment.TickCount / 1000f >= _painCooldown)
				{
					_painCooldown = (float)Environment.TickCount / 1000f + 0.35f;
					PlayPain(Mathf.Clamp(num / 8f, 0.35f, 1f));
					try
					{
						PainOverlay.NotifyDamage(num);
					}
					catch
					{
					}
				}
			}
			_lastHealth = hp;
			_lastMaxHealth = maxHp;
			UpdateBreath(hp, maxHp);
			UpdateFootsteps();
		}

		public static void OnFallImpact(float damage, float impactSpeed, bool fractured)
		{
			if (Enabled)
			{
				if (PainEnabled && damage > 0.5f)
				{
					PlayPain(Mathf.Clamp(damage / 12f, 0.4f, 1f));
				}
				if (fractured && FractureEnabled)
				{
					PlayFracture();
				}
				else if (HitEnabled && impactSpeed > 4f)
				{
					PlayHit(Mathf.Clamp(impactSpeed / 14f, 0.3f, 1f));
				}
			}
		}

		private static void OnPlayerAction(PlayerID id, PlayerActionType type, PlayerID? other = null)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected I4, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || id == null || !id.IsMe)
			{
				return;
			}
			switch (type - 2)
			{
			case 0:
			case 5:
				if (DeathEnabled)
				{
					PlayDeath();
				}
				StopBreathLoop();
				break;
			case 1:
			case 3:
				if (PainEnabled)
				{
					PlayPain(0.75f);
				}
				break;
			case 2:
				if (HitEnabled)
				{
					PlayHit(0.55f, GetPlayerHead(other));
				}
				break;
			case 4:
				break;
			}
		}

		private static void ResetScene()
		{
			_hasLastPos = false;
			_lastHealth = -1f;
			StopBreathLoop();
		}

		private static void EnsureClips()
		{
			if (_ready)
			{
				return;
			}
			try
			{
				_clipBreath = MakeNoiseLoop("HG_Breath", 1.2f, 0.08f, 90f, 0.35f);
				_clipPain = MakeToneBurst("HG_Pain", 0.35f, 420f, 880f, 0.55f);
				_clipDeath = MakeToneBurst("HG_Death", 0.9f, 320f, 80f, 0.7f);
				_clipFracture = MakeCrack("HG_Fracture", 0.18f);
				_clipFoot = MakeNoiseBurst("HG_Foot", 0.12f, 0.25f, 180f);
				_clipHit = MakeToneBurst("HG_Hit", 0.14f, 160f, 60f, 0.65f);
				_ready = _clipBreath != null && _clipPain != null;
				if (_ready)
				{
					MelonLogger.Msg("[Homigrad] Immersive sounds ready (breath/pain/death/fracture/foot/hit).");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[HomigradSounds] Clip init: " + ex.Message);
			}
		}

		private static void UpdateBreath(float hp, float maxHp)
		{
			if (!BreathEnabled)
			{
				StopBreathLoop();
				return;
			}
			float num = ((maxHp > 0.01f) ? (hp / maxHp) : 1f);
			if (!(num < 0.72f) || !(hp > 0.01f))
			{
				StopBreathLoop();
				return;
			}
			float num2 = Mathf.Clamp01((0.72f - num) / 0.55f);
			EnsureBreathSource();
			if (_breathSource == null)
			{
				return;
			}
			try
			{
				Type type = _breathSource.GetType();
				object obj = type.GetProperty("isPlaying")?.GetValue(_breathSource);
				if (!(obj is bool) || !(bool)obj)
				{
					type.GetProperty("loop")?.SetValue(_breathSource, true);
					type.GetProperty("clip")?.SetValue(_breathSource, _clipBreath);
					type.GetMethod("Play")?.Invoke(_breathSource, null);
				}
				float num3 = Volume * (0.15f + num2 * 0.55f);
				type.GetProperty("volume")?.SetValue(_breathSource, num3);
				type.GetProperty("pitch")?.SetValue(_breathSource, 0.85f + num2 * 0.35f);
				TrySetMixerReflect(_breathSource, "InHead");
			}
			catch
			{
			}
		}

		private static void UpdateFootsteps()
		{
			//IL_0033: 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_0044: 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_006d: 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_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_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (!FootstepEnabled || !TryGetFeetPos(out var pos))
			{
				return;
			}
			float num = (float)Environment.TickCount / 1000f;
			if (!_hasLastPos)
			{
				_lastPos = pos;
				_hasLastPos = true;
				return;
			}
			float num2 = Vector3.Distance(new Vector3(pos.x, 0f, pos.z), new Vector3(_lastPos.x, 0f, _lastPos.z));
			_lastPos = pos;
			if (!(num < _nextFoot) && !(num2 < 0.35f) && TryGetGrounded(out var grounded) && grounded && TryGetSpeed(out var speed) && !(speed < 1.1f))
			{
				_nextFoot = num + Mathf.Clamp(0.55f - speed * 0.04f, 0.28f, 0.55f);
				PlayFoot(pos);
			}
		}

		public static void PlayPain(float intensity)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			PlayOneShot(_clipPain, GetLocalHead(), inHead: true, 0.5f + intensity * 0.5f, 0.9f + intensity * 0.25f);
		}

		public static void PlayDeath()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			PlayOneShot(_clipDeath, GetLocalHead(), inHead: true, Volume, 0.95f);
		}

		public static void PlayFracture()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			PlayOneShot(_clipFracture, GetLocalHead(), inHead: false, Volume, Random.Range(0.92f, 1.08f));
		}

		public static void PlayFoot(Vector3 pos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			PlayOneShot(_clipFoot, pos, inHead: false, Volume * 0.45f, Random.Range(0.88f, 1.12f));
		}

		public static void PlayHit(float intensity, Vector3? at = null)
		{
			//IL_0019: 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)
			PlayOneShot(_clipHit, (Vector3)(((??)at) ?? GetLocalHead()), inHead: false, Volume * (0.35f + intensity * 0.45f), Random.Range(0.85f, 1.15f));
		}

		private static void StopBreathLoop()
		{
			if (_breathSource == null)
			{
				return;
			}
			try
			{
				_breathSource.GetType().GetMethod("Stop")?.Invoke(_breathSource, null);
			}
			catch
			{
			}
		}

		private static void EnsureBreathSource()
		{
			if (_breathSource != null)
			{
				return;
			}
			try
			{
				Type typeFromHandle = typeof(GameObject);
				_breathGo = Activator.CreateInstance(typeFromHandle, "Homigrad_BreathLoop");
				typeFromHandle.GetProperty("hideFlags")?.SetValue(_breathGo, (object)(HideFlags)61);
				Type type = Type.GetType("UnityEngine.AudioSource, UnityEngine.AudioModule") ?? typeof(Component).Assembly.GetType("UnityEngine.AudioSource");
				if (!(type == null))
				{
					_breathSource = typeFromHandle.GetMethod("AddComponent", new Type[1] { typeof(Type) })?.Invoke(_breathGo, new object[1] { type });
					if (_breathSource != null)
					{
						type.GetProperty("spatialBlend")?.SetValue(_breathSource, 0f);
						type.GetProperty("playOnAwake")?.SetValue(_breathSource, false);
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[HomigradSounds] Breath source: " + ex.Message);
			}
		}

		private static void PlayOneShot(object? clip, Vector3 pos, bool inHead, float volScale, float pitch)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_003c: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || clip == null)
			{
				return;
			}
			try
			{
				AudioPlayerSettings val = new AudioPlayerSettings
				{
					Volume = volScale * Volume,
					Pitch = pitch,
					SpatialBlend = (inHead ? 0f : 1f)
				};
				TrySetSettingsMixer(val, inHead ? "InHead" : "HardInteraction");
				Type typeFromHandle = typeof(LocalAudioPlayer);
				if (inHead)
				{
					typeFromHandle.GetMethod("Play2dOneShot", new Type[2]
					{
						clip.GetType(),
						typeof(AudioPlayerSettings)
					})?.Invoke(null, new object[2] { clip, val });
				}
				else
				{
					typeFromHandle.GetMethod("PlayAtPoint", new Type[3]
					{
						clip.GetType(),
						typeof(Vector3),
						typeof(AudioPlayerSettings)
					})?.Invoke(null, new object[3] { clip, pos, val });
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[HomigradSounds] Play: " + ex.Message);
			}
		}

		private static void TrySetSettingsMixer(AudioPlayerSettings settings, string mixerProp)
		{
			try
			{
				object obj = typeof(LocalAudioPlayer).GetProperty(mixerProp, BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj != null)
				{
					typeof(AudioPlayerSettings).GetProperty("Mixer")?.SetValue(settings, obj);
				}
			}
			catch
			{
			}
		}

		private static void TrySetMixerReflect(object source, string mixerProp)
		{
			try
			{
				object obj = typeof(LocalAudioPlayer).GetProperty(mixerProp, BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj != null)
				{
					source.GetType().GetProperty("outputAudioMixerGroup")?.SetValue(source, obj);
				}
			}
			catch
			{
			}
		}

		private static object? MakeNoiseLoop(string name, float sec, float amp, float freq, float lfo)
		{
			int num = 44100;
			int num2 = Math.Max(1, (int)((float)num * sec));
			float[] array = new float[num2];
			float num3 = 0f;
			for (int i = 0; i < num2; i++)
			{
				float num4 = (float)i / (float)num;
				num3 += freq / (float)num;
				float num5 = 0.5f + 0.5f * Mathf.Sin(num4 * lfo * (float)Math.PI * 2f);
				array[i] = (Random.value * 2f - 1f) * amp * num5 * Mathf.Sin(num3 * (float)Math.PI * 2f);
			}
			return CreateClip(name, array, num);
		}

		private static object? MakeNoiseBurst(string name, float sec, float amp, float freq)
		{
			int num = 44100;
			int num2 = Math.Max(1, (int)((float)num * sec));
			float[] array = new float[num2];
			for (int i = 0; i < num2; i++)
			{
				float num3 = (float)i / (float)num2;
				float num4 = 1f - num3;
				array[i] = (Random.value * 2f - 1f) * amp * num4 * num4;
			}
			return CreateClip(name, array, num);
		}

		private static object? MakeToneBurst(string name, float sec, float f0, float f1, float amp)
		{
			int num = 44100;
			int num2 = Math.Max(1, (int)((float)num * sec));
			float[] array = new float[num2];
			for (int i = 0; i < num2; i++)
			{
				float num3 = (float)i / (float)num2;
				float num4 = Mathf.Lerp(f0, f1, num3);
				float num5 = (1f - num3) * (1f - num3);
				array[i] = Mathf.Sin((float)i / (float)num * num4 * (float)Math.PI * 2f) * amp * num5;
			}
			return CreateClip(name, array, num);
		}

		private static object? MakeCrack(string name, float sec)
		{
			int num = 44100;
			int num2 = Math.Max(1, (int)((float)num * sec));
			float[] array = new float[num2];
			for (int i = 0; i < num2; i++)
			{
				float num3 = (float)i / (float)num2;
				float num4 = (1f - num3) * (1f - num3) * (1f - num3);
				array[i] = ((Random.value * 2f - 1f) * 0.9f + Mathf.Sin((float)i * 0.37f) * 0.4f) * num4;
			}
			return CreateClip(name, array, num);
		}

		private static object? CreateClip(string name, float[] data, int rate)
		{
			Type type = Type.GetType("UnityEngine.AudioClip, UnityEngine.AudioModule");
			if (type == null)
			{
				return null;
			}
			object obj = type.GetMethod("Create", new Type[5]
			{
				typeof(string),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(bool)
			})?.Invoke(null, new object[5] { name, data.Length, 1, rate, false });
			type.GetMethod("SetData", new Type[2]
			{
				typeof(float[]),
				typeof(int)
			})?.Invoke(obj, new object[2] { data, 0 });
			return obj;
		}

		private static bool TryGetHealth(out float hp, out float maxHp)
		{
			hp = (maxHp = 0f);
			try
			{
				Type type = Type.GetType("LabFusion.Data.RigData, LabFusion");
				object obj = type?.GetProperty("HasPlayer")?.GetValue(null);
				if (!(obj is bool) || !(bool)obj)
				{
					return false;
				}
				object obj2 = type.GetProperty("Refs")?.GetValue(null);
				object obj3 = obj2?.GetType().GetProperty("RigManager")?.GetValue(obj2);
				object obj4 = obj3?.GetType().GetProperty("health")?.GetValue(obj3) ?? obj3?.GetType().GetField("health")?.GetValue(obj3);
				if (obj4 == null)
				{
					return false;
				}
				hp = Convert.ToSingle(obj4.GetType().GetProperty("curr_Health")?.GetValue(obj4) ?? obj4.GetType().GetField("curr_Health")?.GetValue(obj4));
				maxHp = Convert.ToSingle(obj4.GetType().GetProperty("max_Health")?.GetValue(obj4) ?? obj4.GetType().GetField("max_Health")?.GetValue(obj4));
				if (maxHp < 0.01f)
				{
					maxHp = 100f;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool TryGetFeetPos(out Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			pos = default(Vector3);
			try
			{
				Type type = Type.GetType("LabFusion.Data.RigData, LabFusion");
				object obj = type?.GetProperty("HasPlayer")?.GetValue(null);
				if (!(obj is bool) || !(bool)obj)
				{
					return false;
				}
				object obj2 = type.GetProperty("Refs")?.GetValue(null);
				object obj3 = obj2?.GetType().GetProperty("RigManager")?.GetValue(obj2);
				object obj4 = obj3?.GetType().GetProperty("physicsRig")?.GetValue(obj3);
				object obj5 = obj4?.GetType().GetProperty("feet")?.GetValue(obj4);
				object obj6 = obj5?.GetType().GetProperty("transform")?.GetValue(obj5);
				if (obj6?.GetType().GetProperty("position")?.GetValue(obj6) is Vector3 val)
				{
					pos = val;
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool TryGetGrounded(out bool grounded)
		{
			grounded = false;
			try
			{
				object obj = Type.GetType("LabFusion.Data.RigData, LabFusion")?.GetProperty("Refs")?.GetValue(null);
				object obj2 = obj?.GetType().GetProperty("RigManager")?.GetValue(obj);
				object obj3 = obj2?.GetType().GetProperty("physicsRig")?.GetValue(obj2);
				object obj4 = obj3?.GetType().GetProperty("feet")?.GetValue(obj3);
				if (obj4 == null)
				{
					return false;
				}
				object obj5 = null;
				MethodInfo method = obj4.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) });
				if (method != null)
				{
					Type type = Type.GetType("SLZ.Marrow.PhysGrounder, Il2CppSLZ.Marrow") ?? Type.GetType("SLZ.Marrow.PhysGrounder, SLZ.Marrow");
					if (type != null)
					{
						obj5 = method.Invoke(obj4, new object[1] { type });
					}
				}
				if (obj5 == null)
				{
					return false;
				}
				object obj6 = obj5.GetType().GetProperty("isGrounded")?.GetValue(obj5);
				int num;
				if (!(obj6 is bool) || !(bool)obj6)
				{
					obj6 = obj5.GetType().GetField("isGrounded")?.GetValue(obj5);
					num = ((obj6 is bool && (bool)obj6) ? 1 : 0);
				}
				else
				{
					num = 1;
				}
				grounded = (byte)num != 0;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool TryGetSpeed(out float speed)
		{
			//IL_001f: 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)
			speed = 0f;
			if (!_hasLastPos)
			{
				return false;
			}
			try
			{
				if (!TryGetFeetPos(out var pos))
				{
					return false;
				}
				speed = Vector3.Distance(pos, _lastPos) / Mathf.Max(Time.deltaTime, 0.016f);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static Vector3 GetLocalHead()
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ac: 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_00c8: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object obj = Type.GetType("LabFusion.Data.RigData, LabFusion")?.GetProperty("Refs")?.GetValue(null);
				object obj2 = obj?.GetType().GetProperty("Headset")?.GetValue(obj);
				Transform val = (Transform)((obj2 is Transform) ? obj2 : null);
				if (val != null)
				{
					return val.position;
				}
				if (obj2?.GetType().GetProperty("position")?.GetValue(obj2) is Vector3 result)
				{
					return result;
				}
			}
			catch
			{
			}
			if (!TryGetFeetPos(out var pos))
			{
				return Vector3.zero;
			}
			return pos + Vector3.up * 1.6f;
		}

		private static Vector3 GetPlayerHead(PlayerID? id)
		{
			//IL_0003: 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_0158: 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_015f: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			if (id == null)
			{
				return GetLocalHead();
			}
			try
			{
				MethodInfo[] methods = Type.GetType("LabFusion.Representation.PlayerRepUtilities, LabFusion").GetMethods(BindingFlags.Static | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != "TryGetReferences") && methodInfo.GetParameters().Length == 2)
					{
						object[] array = new object[2] { id.SmallID, null };
						object obj = methodInfo.Invoke(null, array);
						if (!(obj is bool) || !(bool)obj || array[1] == null)
						{
							break;
						}
						object value = array[1].GetType().GetProperty("RigManager").GetValue(array[1]);
						object obj2 = value.GetType().GetProperty("physicsRig")?.GetValue(value)?.GetType().GetProperty("head")?.GetValue(value.GetType().GetProperty("physicsRig").GetValue(value));
						if (obj2 == null)
						{
							break;
						}
						object obj3 = obj2.GetType().GetProperty("transform")?.GetValue(obj2);
						obj = obj3?.GetType().GetProperty("position")?.GetValue(obj3);
						if (obj is Vector3)
						{
							return (Vector3)obj;
						}
					}
				}
			}
			catch
			{
			}
			return GetLocalHead();
		}
	}
	internal static class PainOverlay
	{
		private sealed class BarUi
		{
			public Image? Bg;

			public Image? Fill;

			public Text? Label;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static PlayerAction <0>__OnPlayerAction;

			public static UpdateEvent <1>__OnSceneInit;
		}

		private static float _lastHp = -1f;

		private static float _flash;

		private static float _pulse;

		private static float _painSpike;

		private static bool _hooks;

		private static GameObject? _root;

		private static RawImage? _darkImage;

		private static RawImage? _vignetteImage;

		private static RawImage? _flashImage;

		private static RawImage? _painImage;

		private static GameObject? _hudRoot;

		private static Text? _statusText;

		private static readonly BarUi[] _bars = new BarUi[4];

		private static Texture2D? _vignetteTex;

		private static Font? _font;

		private static Transform? _headset;

		public static bool Enabled { get; set; } = true;

		public static bool ShowIndicators { get; set; } = true;

		public static bool ShowVignette { get; set; } = true;

		public static float Intensity { get; set; } = 1f;

		public static float Blood { get; private set; } = 100f;

		public static float Pain { get; private set; }

		public static float Shock { get; private set; }

		public static int Fractures { get; private set; }

		public static void Init()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (_hooks)
			{
				return;
			}
			_hooks = true;
			try
			{
				object obj = <>O.<0>__OnPlayerAction;
				if (obj == null)
				{
					PlayerAction val = OnPlayerAction;
					<>O.<0>__OnPlayerAction = val;
					obj = (object)val;
				}
				MultiplayerHooking.OnPlayerAction += (PlayerAction)obj;
				object obj2 = <>O.<1>__OnSceneInit;
				if (obj2 == null)
				{
					UpdateEvent val2 = OnSceneInit;
					<>O.<1>__OnSceneInit = val2;
					obj2 = (object)val2;
				}
				MultiplayerHooking.OnMainSceneInitialized += (UpdateEvent)obj2;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PainOverlay] Hook: " + ex.Message);
			}
		}

		private static void OnSceneInit()
		{
			DestroyUi();
			ResetAll();
		}

		public static void Tick()
		{
			if (!Enabled)
			{
				SetUiActive(active: false);
				return;
			}
			float num = Mathf.Max(Time.deltaTime, 0.016f);
			if (!TryGetHealth(out var hp, out var maxHp))
			{
				_lastHp = -1f;
				SetUiActive(active: false);
				return;
			}
			Blood = Mathf.Clamp((maxHp > 0.01f) ? (hp / maxHp * 100f) : 100f, 0f, 100f);
			if (_lastHp >= 0f && hp < _lastHp - 0.25f)
			{
				ApplyDamage(_lastHp - hp, fractured: false);
			}
			_lastHp = hp;
			Pain = Mathf.MoveTowards(Pain, 0f, num * (8f + Pain * 0.04f));
			Shock = Mathf.MoveTowards(Shock, 0f, num * (14f + Shock * 0.08f));
			_flash = Mathf.MoveTowards(_flash, 0f, num * 3.5f);
			_painSpike = Mathf.MoveTowards(_painSpike, 0f, num * 2.2f);
			_pulse = (Mathf.Sin(Time.realtimeSinceStartup * (4f + Pain * 0.05f)) * 0.5f + 0.5f) * (Pain / 100f);
			if (!EnsureUi())
			{
				SetUiActive(active: false);
			}
			else
			{
				UpdateVisuals();
			}
		}

		public static void NotifyDamage(float amount, bool fractured = false)
		{
			if (Enabled && !(amount <= 0f))
			{
				ApplyDamage(amount, fractured);
			}
		}

		public static void Reset()
		{
			ResetAll();
		}

		private static void ApplyDamage(float amount, bool fractured)
		{
			float num = Mathf.Clamp(amount / 6f, 0.15f, 1f);
			Pain = Mathf.Clamp(Pain + amount * (4.5f + num * 6f), 0f, 100f);
			Shock = Mathf.Clamp(Shock + amount * (2.5f + num * 5f), 0f, 100f);
			_flash = Mathf.Clamp(_flash + num * 0.85f, 0f, 1f);
			_painSpike = Mathf.Clamp(_painSpike + num, 0f, 1f);
			if (fractured)
			{
				Fractures = Mathf.Min(Fractures + 1, 8);
				Pain = Mathf.Clamp(Pain + 18f, 0f, 100f);
				Shock = Mathf.Clamp(Shock + 22f, 0f, 100f);
				_flash = 1f;
			}
		}

		private static void OnPlayerAction(PlayerID id, PlayerActionType type, PlayerID? other = null)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			if (Enabled && id != null && id.IsMe)
			{
				if ((int)type == 3 || (int)type == 5)
				{
					ApplyDamage(12f, fractured: false);
				}
				if ((int)type == 2 || (int)type == 7)
				{
					Pain = 100f;
					Shock = 100f;
					Blood = 0f;
					_flash = 1f;
				}
			}
		}

		private static void ResetAll()
		{
			Blood = 100f;
			Pain = (Shock = 0f);
			Fractures = 0;
			_lastHp = -1f;
			_flash = (_pulse = (_painSpike = 0f));
		}

		private static bool EnsureUi()
		{
			Transform val = TryGetHeadset();
			if ((Object)(object)val == (Object)null)
			{
				DestroyUi();
				return false;
			}
			if ((Object)(object)_root != (Object)null && (Object)(object)_headset == (Object)(object)val)
			{
				return true;
			}
			if ((Object)(object)_root != (Object)null && (Object)(object)_headset != (Object)(object)val)
			{
				DestroyUi();
			}
			_headset = val;
			CreateUi(val);
			return (Object)(object)_root != (Object)null;
		}

		private static void CreateUi(Transform headset)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_00e7: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Expected O, but got Unknown
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: 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_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: 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_0347: 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_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EnsureVignetteTex();
				EnsureFont();
				_root = new GameObject("Homigrad_PainOverlay");
				Object.DontDestroyOnLoad((Object)(object)_root);
				Type type = Type.GetType("UnityEngine.Canvas, UnityEngine.UIModule") ?? FindType("UnityEngine.Canvas");
				if (type == null)
				{
					throw new InvalidOperationException("Canvas type not found");
				}
				object obj = AddComp(_root, type);
				if (obj == null)
				{
					throw new InvalidOperationException("Canvas add failed");
				}
				type.GetProperty("renderMode")?.SetValue(obj, 2);
				type.GetProperty("overrideSorting")?.SetValue(obj, true);
				type.GetProperty("sortingOrder")?.SetValue(obj, 30000);
				RectTransform component = _root.GetComponent<RectTransform>();
				((Transform)component).SetParent(headset, false);
				((Transform)component).localPosition = new Vector3(0f, 0f, 0.045f);
				((Transform)component).localRotation = Quaternion.Euler(0f, 180f, 0f);
				((Transform)component).localScale = Vector3.one * 0.00072f;
				component.sizeDelta = new Vector2(900f, 900f);
				_darkImage = CreateStretchRaw(_root.transform, "Dark", 0);
				_vignetteImage = CreateStretchRaw(_root.transform, "Vignette", 1);
				_vignetteImage.texture = (Texture)(object)_vignetteTex;
				_flashImage = CreateStretchRaw(_root.transform, "Flash", 2);
				_painImage = CreateStretchRaw(_root.transform, "PainPulse", 3);
				_hudRoot = new GameObject("Hud");
				RectTransform val = _hudRoot.AddComponent<RectTransform>();
				((Transform)val).SetParent(_root.transform, false);
				val.anchorMin = new Vector2(0f, 0f);
				val.anchorMax = new Vector2(0f, 0f);
				val.pivot = new Vector2(0f, 0f);
				val.anchoredPosition = new Vector2(24f, 24f);
				val.sizeDelta = new Vector2(360f, 170f);
				GameObject val2 = new GameObject("Status");
				RectTransform obj2 = val2.AddComponent<RectTransform>();
				((Transform)obj2).SetParent((Transform)(object)val, false);
				obj2.anchorMin = new Vector2(0f, 1f);
				obj2.anchorMax = new Vector2(1f, 1f);
				obj2.pivot = new Vector2(0f, 1f);
				obj2.anchoredPosition = new Vector2(0f, 8f);
				obj2.sizeDelta = new Vector2(0f, 36f);
				_statusText = val2.AddComponent<Text>();
				SetupText(_statusText, 28, (FontStyle)1);
				_statusText.alignment = (TextAnchor)6;
				((Graphic)_statusText).color = new Color(1f, 0.3f, 0.25f, 0f);
				string[] array = new string[4] { "Blood", "Pain", "Shock", "Fractures" };
				Color[] array2 = (Color[])(object)new Color[4]
				{
					new Color(0.75f, 0.08f, 0.08f, 0.92f),
					new Color(0.95f, 0.35f, 0.05f, 0.92f),
					new Color(0.55f, 0.15f, 0.85f, 0.92f),
					new Color(0.85f, 0.82f, 0.2f, 0.92f)
				};
				for (int i = 0; i < 4; i++)
				{
					_bars[i] = CreateBar(val, array[i], array2[i], (float)i * 34f);
				}
				SetUiActive(active: true);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PainOverlay] VR UI create: " + ex.Message);
				DestroyUi();
			}
		}

		private static BarUi CreateBar(RectTransform parent, string name, Color fillColor, float y)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: 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_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_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = new GameObject(name).AddComponent<RectTransform>();
			((Transform)val).SetParent((Transform)(object)parent, false);
			val.anchorMin = new Vector2(0f, 0f);
			val.anchorMax = new Vector2(1f, 0f);
			val.pivot = new Vector2(0f, 0f);
			val.anchoredPosition = new Vector2(0f, y);
			val.sizeDelta = new Vector2(0f, 28f);
			GameObject val2 = new GameObject("Bg");
			RectTransform obj = val2.AddComponent<RectTransform>();
			((Transform)obj).SetParent((Transform)(object)val, false);
			StretchFull(obj);
			Image val3 = val2.AddComponent<Image>();
			((Graphic)val3).color = new Color(0f, 0f, 0f, 0.55f);
			((Graphic)val3).raycastTarget = false;
			GameObject val4 = new GameObject("Fill");
			RectTransform obj2 = val4.AddComponent<RectTransform>();
			((Transform)obj2).SetParent((Transform)(object)val, false);
			obj2.anchorMin = new Vector2(0f, 0f);
			obj2.anchorMax = new Vector2(0f, 1f);
			obj2.pivot = new Vector2(0f, 0.5f);
			obj2.anchoredPosition = new Vector2(3f, 0f);
			obj2.sizeDelta = new Vector2(0f, -6f);
			Image val5 = val4.AddComponent<Image>();
			((Graphic)val5).color = fillColor;
			((Graphic)val5).raycastTarget = false;
			GameObject val6 = new GameObject("Label");
			RectTransform obj3 = val6.AddComponent<RectTransform>();
			((Transform)obj3).SetParent((Transform)(object)val, false);
			StretchFull(obj3);
			obj3.offsetMin = new Vector2(8f, 0f);
			obj3.offsetMax = new Vector2(-8f, 0f);
			Text val7 = val6.AddComponent<Text>();
			SetupText(val7, 22, (FontStyle)1);
			val7.alignment = (TextAnchor)3;
			((Graphic)val7).color = Color.white;
			return new BarUi
			{
				Bg = val3,
				Fill = val5,
				Label = val7
			};
		}

		private static RawImage CreateStretchRaw(Transform parent, string name, int sibling)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			GameObject val = new GameObject(name);
			RectTransform obj = val.AddComponent<RectTransform>();
			((Transform)obj).SetParent(parent, false);
			StretchFull(obj);
			val.transform.SetSiblingIndex(sibling);
			RawImage obj2 = val.AddComponent<RawImage>();
			((Graphic)obj2).color = new Color(1f, 1f, 1f, 0f);
			((Graphic)obj2).raycastTarget = false;
			return obj2;
		}

		private static void StretchFull(RectTransform rt)
		{
			//IL_0001: 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_0017: 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)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.offsetMin = Vector2.zero;
			rt.offsetMax = Vector2.zero;
		}

		private static void SetupText(Text t, int size, FontStyle style)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			t.font = _font;
			t.fontSize = size;
			t.fontStyle = style;
			t.horizontalOverflow = (HorizontalWrapMode)1;
			t.verticalOverflow = (VerticalWrapMode)1;
			t.supportRichText = false;
			((Graphic)t).raycastTarget = false;
		}

		private static void UpdateVisuals()
		{
			//IL_00f6: 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_0154: 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_0392: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			float num = 1f - Blood / 100f;
			float num2 = Mathf.Clamp01(Pain / 100f * 0.55f + Shock / 100f * 0.45f + num * 0.65f);
			float num3 = 0f;
			float num4 = 0f;
			if (ShowVignette)
			{
				num3 = Mathf.Clamp01((num * 0.55f + num2 * 0.35f + _pulse * 0.15f) * Intensity) * 0.72f;
				if (Shock > 25f)
				{
					num3 += Mathf.Clamp01((Shock - 25f) / 120f) * 0.25f * Intensity;
				}
				num4 = Mathf.Clamp01(0.25f + num2 * 0.55f) * Intensity * 0.78f;
			}
			SetRawAlpha(_darkImage, new Color(0f, 0f, 0f, num3));
			SetRawAlpha(_vignetteImage, new Color(0f, 0f, 0f, num4));
			float num5 = (_flash + _painSpike * 0.6f) * Intensity * 0.45f;
			SetRawAlpha(_flashImage, new Color(0.55f, 0.02f, 0.02f, num5));
			float num6 = 0f;
			if (Pain > 35f)
			{
				num6 = (Pain - 35f) / 65f * _pulse * 0.22f * Intensity;
			}
			SetRawAlpha(_painImage, new Color(0.35f, 0f, 0f, num6));
			bool showIndicators = ShowIndicators;
			if ((Object)(object)_hudRoot != (Object)null)
			{
				_hudRoot.SetActive(showIndicators);
			}
			if (showIndicators && !((Object)(object)_statusText == (Object)null))
			{
				SetBar(_bars[0], Blood / 100f, "Blood", $"{Blood:0}%");
				SetBar(_bars[1], Pain / 100f, "Pain", $"{Pain:0}%");
				SetBar(_bars[2], Shock / 100f, "Shock", $"{Shock:0}%");
				float num7 = ((Fractures > 0) ? Mathf.Clamp01((float)Fractures / 4f) : 0f);
				SetBar(_bars[3], Mathf.Max(num7, (Fractures > 0) ? 0.15f : 0f), "Fractures", Fractures.ToString());
				bool flag = Blood < 35f || Pain > 70f || Shock > 60f;
				_statusText.text = (flag ? GetStatusText() : string.Empty);
				((Graphic)_statusText).color = new Color(1f, 0.25f, 0.2f, flag ? (0.85f + _pulse * 0.15f) : 0f);
			}
		}

		private static void SetBar(BarUi bar, float fill, string name, string value)
		{
			//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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bar.Fill == (Object)null) && !((Object)(object)bar.Label == (Object)null))
			{
				RectTransform rectTransform = ((Graphic)bar.Fill).rectTransform;
				float num;
				if (!((Object)(object)bar.Bg != (Object)null))
				{
					num = 300f;
				}
				else
				{
					Rect rect = ((Graphic)bar.Bg).rectTransform.rect;
					num = ((Rect)(ref rect)).width - 6f;
				}
				float num2 = num;
				rectTransform.sizeDelta = new Vector2(Mathf.Max(0f, num2 * Mathf.Clamp01(fill)), rectTransform.sizeDelta.y);
				bar.Label.text = name + "  " + value;
			}
		}

		private static void SetRawAlpha(RawImage? img, Color c)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)img == (Object)null))
			{
				((Graphic)img).color = c;
			}
		}

		private static string GetStatusText()
		{
			if (Blood < 20f)
			{
				return "CRITICAL — blood loss";
			}
			if (Shock > 75f)
			{
				return "SHOCK";
			}
			if (Pain > 85f)
			{
				return "SEVERE PAIN";
			}
			if (Fractures >= 3)
			{
				return "MULTIPLE FRACTURES";
			}
			if (Blood < 35f)
			{
				return "Heavy bleeding";
			}
			if (Pain > 70f)
			{
				return "Intense pain";
			}
			if (Shock > 60f)
			{
				return "Shock";
			}
			return "Injured";
		}

		private static void SetUiActive(bool active)
		{
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(active);
			}
		}

		private static void DestroyUi()
		{
			if ((Object)(object)_root != (Object)null)
			{
				try
				{
					Object.Destroy((Object)(object)_root);
				}
				catch
				{
				}
				_root = null;
			}
			_darkImage = (_vignetteImage = (_flashImage = (_painImage = null)));
			_hudRoot = null;
			_statusText = null;
			for (int i = 0; i < _bars.Length; i++)
			{
				_bars[i] = new BarUi();
			}
			_headset = null;
		}

		private static void EnsureVignetteTex()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_vignetteTex != (Object)null)
			{
				return;
			}
			_vignetteTex = new Texture2D(256, 256, (TextureFormat)4, false);
			float num = 127.5f;
			for (int i = 0; i < 256; i++)
			{
				for (int j = 0; j < 256; j++)
				{
					float num2 = ((float)j - num) / num;
					float num3 = ((float)i - num) / num;
					float num4 = Mathf.Clamp01((Mathf.Sqrt(num2 * num2 + num3 * num3) - 0.35f) / 0.65f);
					num4 *= num4;
					_vignetteTex.SetPixel(j, i, new Color(0f, 0f, 0f, num4));
				}
			}
			_vignetteTex.Apply();
		}

		private static void EnsureFont()
		{
			if (!((Object)(object)_font != (Object)null))
			{
				_font = Resources.GetBuiltinResource<Font>("Arial.ttf");
				if ((Object)(object)_font == (Object)null)
				{
					_font = Font.CreateDynamicFontFromOSFont("Arial", 24);
				}
			}
		}

		private static Transform? TryGetHeadset()
		{
			try
			{
				Type type = Type.GetType("LabFusion.Data.RigData, LabFusion");
				object obj = type?.GetProperty("HasPlayer")?.GetValue(null);
				if (!(obj is bool) || !(bool)obj)
				{
					return null;
				}
				object obj2 = type.GetProperty("Refs")?.GetValue(null);
				object? obj3 = obj2?.GetType().GetProperty("Headset")?.GetValue(obj2);
				Transform val = (Transform)((obj3 is Transform) ? obj3 : null);
				if (val != null && (Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			catch
			{
			}
			return null;
		}

		private static bool TryGetHealth(out float hp, out float maxHp)
		{
			hp = (maxHp = 0f);
			try
			{
				Type type = Type.GetType("LabFusion.Data.RigData, LabFusion");
				object obj = type?.GetProperty("HasPlayer")?.GetValue(null);
				if (!(obj is bool) || !(bool)obj)
				{
					return false;
				}
				object obj2 = type.GetProperty("Refs")?.GetValue(null);
				object obj3 = obj2?.GetType().GetProperty("RigManager")?.GetValue(obj2);
				object obj4 = obj3?.GetType().GetProperty("health")?.GetValue(obj3) ?? obj3?.GetType().GetField("health")?.GetValue(obj3);
				if (obj4 == null)
				{
					return false;
				}
				hp = Convert.ToSingle(obj4.GetType().GetProperty("curr_Health")?.GetValue(obj4) ?? obj4.GetType().GetField("curr_Health")?.GetValue(obj4));
				maxHp = Convert.ToSingle(obj4.GetType().GetProperty("max_Health")?.GetValue(obj4) ?? obj4.GetType().GetField("max_Health")?.GetValue(obj4));
				if (maxHp < 0.01f)
				{
					maxHp = 100f;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static Type? FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(fullName);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static object? AddComp(GameObject go, Type componentType)
		{
			try
			{
				MethodInfo method = typeof(GameObject).GetMethod("AddComponent", new Type[1] { typeof(Type) });
				if (method != null)
				{
					return method.Invoke(go, new object[1] { componentType });
				}
				MethodInfo[] methods = typeof(GameObject).GetMethods(BindingFlags.Instance | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != "AddComponent") && methodInfo.GetParameters().Length == 1)
					{
						object obj = ToIl2CppType(componentType);
						if (obj != null)
						{
							return methodInfo.Invoke(go, new object[1] { obj });
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static object? ToIl2CppType(Type t)
		{
			try
			{
				Type type = FindType("Il2CppInterop.Runtime.Il2CppType");
				MethodInfo methodInfo = type?.GetMethod("Of", BindingFlags.Static | BindingFlags.Public);
				if (methodInfo != null)
				{
					return methodInfo.MakeGenericMethod(t).Invoke(null, null);
				}
				return type?.GetMethod("From", new Type[1] { typeof(Type) })?.Invoke(null, new object[1] { t });
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class RagdollUtil
	{
		public static void SafeRagdoll(object physicsRig)
		{
			try
			{
				physicsRig.GetType().GetMethod("RagdollRig", Type.EmptyTypes)?.Invoke(physicsRig, null);
				TryZeroVelocity(physicsRig);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] SafeRagdoll: " + ex.Message);
			}
		}

		public static bool IsRagdolled(object physicsRig)
		{
			try
			{
				object obj = physicsRig.GetType().GetField("shutdown", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(physicsRig) ?? physicsRig.GetType().GetProperty("shutdown")?.GetValue(physicsRig);
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch
			{
				return false;
			}
		}

		private static void TryZeroVelocity(object physicsRig)
		{
			try
			{
				Type type = Type.GetType("UnityEngine.Vector3, UnityEngine.CoreModule") ?? Type.GetType("UnityEngine.Vector3, UnityEngine");
				if (type == null)
				{
					return;
				}
				object value = Activator.CreateInstance(type, 0f, 0f, 0f);
				string[] array = new string[3] { "wholeBodyVelocity", "_velocity", "velocity" };
				foreach (string name in array)
				{
					PropertyInfo property = physicsRig.GetType().GetProperty(name);
					if (property != null && property.CanWrite && property.PropertyType == type)
					{
						property.SetValue(physicsRig, value);
						continue;
					}
					FieldInfo field = physicsRig.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null && field.FieldType == type)
					{
						field.SetValue(physicsRig, value);
					}
				}
			}
			catch
			{
			}
		}
	}
	internal static class SelfHarmFeature
	{
		private static bool _enabled = true;

		private static bool _harmonyPatched;

		private static bool _typesResolved;

		private static bool _loggedReady;

		private static bool _loggedFail;

		private static float _reapplyTimer;

		private static Type? _playerType;

		private static Type? _impactPropertiesType;

		private static Type? _rigidbodyType;

		private static Type? _objectType;

		private static Type? _componentType;

		private static Type? _dataCardRefOpen;

		private static Type? _surfaceDataCardType;

		private static Type? _decalType;

		private static MethodInfo? _opEquality;

		private static MethodInfo? _opImplicit;

		private static MethodInfo? _getComponentsInChildren;

		private static MethodInfo? _getComponent;

		private static MethodInfo? _addComponent;

		private static MethodInfo? _destroy;

		private static MethodInfo? _getInstanceId;

		private static PropertyInfo? _gameObjectProp;

		private static PropertyInfo? _surfaceDataCardProp;

		private static PropertyInfo? _decalTypeProp;

		private static PropertyInfo? _testVisualDamage;

		public static bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				if (_enabled == value)
				{
					return;
				}
				_enabled = value;
				try
				{
					if (_enabled)
					{
						Apply();
					}
					else
					{
						Remove();
					}
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("[Homigrad] SelfHarm toggle: " + ex.Message);
				}
			}
		}

		public static void InitHarmony(Harmony harmony)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			if (_harmonyPatched)
			{
				return;
			}
			try
			{
				MethodInfo methodInfo = FindType("Il2CppSLZ.Bonelab.UIRig")?.GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(methodInfo == null))
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SelfHarmFeature), "OnUiRigAwake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					_harmonyPatched = true;
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] SelfHarm Harmony: " + ex.Message);
			}
		}

		private static void OnUiRigAwake()
		{
			if (!_enabled)
			{
				return;
			}
			try
			{
				Apply();
			}
			catch
			{
			}
		}

		public static void Tick(bool active)
		{
			if (!_enabled || !active)
			{
				return;
			}
			_reapplyTimer -= 1f / 60f;
			if (_reapplyTimer > 0f)
			{
				return;
			}
			_reapplyTimer = 2f;
			try
			{
				Apply();
			}
			catch
			{
			}
		}

		public static void Apply()
		{
			EnsureTypes();
			if (_impactPropertiesType == null || _playerType == null)
			{
				LogFailOnce("types missing");
			}
			else
			{
				if (!TryGetRigManager(out object rigManager) || !TryGetPhysicsRig(rigManager, out object physicsRig))
				{
					return;
				}
				SetTestVisualDamage(rigManager, value: true);
				object obj = CreateBloodSurfaceCard();
				object fieldOrProp = GetFieldOrProp(physicsRig, "feet");
				object? fieldOrProp2 = GetFieldOrProp(physicsRig, "knee");
				int instanceId = GetInstanceId(fieldOrProp);
				int instanceId2 = GetInstanceId(fieldOrProp2);
				object componentsInChildren = GetComponentsInChildren(physicsRig, _rigidbodyType);
				if (componentsInChildren == null)
				{
					return;
				}
				int num = 0;
				foreach (object item in (IEnumerable)componentsInChildren)
				{
					if (item == null || IsUnityNull(item))
					{
						continue;
					}
					object obj2 = _gameObjectProp?.GetValue(item);
					if (obj2 == null || IsUnityNull(obj2))
					{
						continue;
					}
					int instanceId3 = GetInstanceId(obj2);
					if ((instanceId3 != 0 && (instanceId3 == instanceId || instanceId3 == instanceId2)) || HasImpactProperties(obj2))
					{
						continue;
					}
					object obj3 = AddImpactProperties(obj2);
					if (obj3 == null)
					{
						continue;
					}
					if (obj != null && _surfaceDataCardProp != null)
					{
						try
						{
							_surfaceDataCardProp.SetValue(obj3, obj);
						}
						catch
						{
						}
					}
					if (_decalTypeProp != null && _decalType != null)
					{
						try
						{
							_decalTypeProp.SetValue(obj3, Enum.ToObject(_decalType, -1));
						}
						catch
						{
						}
					}
					num++;
				}
				if (!_loggedReady)
				{
					_loggedReady = true;
					MelonLogger.Msg("[Homigrad] SelfHarm active — you can hurt yourself with weapons.");
				}
				if (num > 0)
				{
					MelonLogger.Msg($"[Homigrad] SelfHarm: added ImpactProperties x{num}");
				}
			}
		}

		public static void Remove()
		{
			EnsureTypes();
			if (_impactPropertiesType == null || _playerType == null || _destroy == null || !TryGetRigManager(out object rigManager) || !TryGetPhysicsRig(rigManager, out object physicsRig))
			{
				return;
			}
			object componentsInChildren = GetComponentsInChildren(physicsRig, _rigidbodyType);
			if (componentsInChildren == null)
			{
				return;
			}
			foreach (object item in (IEnumerable)componentsInChildren)
			{
				if (item == null || IsUnityNull(item))
				{
					continue;
				}
				object obj = _gameObjectProp?.GetValue(item);
				if (obj == null || IsUnityNull(obj))
				{
					continue;
				}
				object impactProperties = GetImpactProperties(obj);
				if (impactProperties != null && !IsUnityNull(impactProperties))
				{
					try
					{
						_destroy.Invoke(null, new object[1] { impactProperties });
					}
					catch
					{
					}
				}
			}
		}

		private static void EnsureTypes()
		{
			if (_typesResolved)
			{
				return;
			}
			_typesResolved = true;
			try
			{
				_playerType = FindType("BoneLib.Player");
				_impactPropertiesType = FindType("Il2CppSLZ.Marrow.ImpactProperties");
				_rigidbodyType = Type.GetType("UnityEngine.Rigidbody, UnityEngine.PhysicsModule") ?? FindType("UnityEngine.Rigidbody");
				_objectType = Type.GetType("UnityEngine.Object, UnityEngine.CoreModule") ?? FindType("UnityEngine.Object");
				_componentType = Type.GetType("UnityEngine.Component, UnityEngine.CoreModule") ?? FindType("UnityEngine.Component");
				_dataCardRefOpen = FindType("Il2CppSLZ.Marrow.Warehouse.DataCardReference`1");
				_surfaceDataCardType = FindType("Il2CppSLZ.Marrow.Warehouse.SurfaceDataCard");
				_decalType = FindType("DecalType") ?? FindType("Il2CppSLZ.Marrow.DecalType");
				_opEquality = _objectType?.GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public);
				_opImplicit = null;
				if (_objectType != null)
				{
					MethodInfo[] methods = _objectType.GetMethods(BindingFlags.Static | BindingFlags.Public);
					foreach (MethodInfo methodInfo in methods)
					{
						if (methodInfo.Name == "op_Implicit" && methodInfo.ReturnType == typeof(bool))
						{
							_opImplicit = methodInfo;
							break;
						}
					}
				}
				if (_objectType != null)
				{
					MethodInfo[] methods = _objectType.GetMethods(BindingFlags.Static | BindingFlags.Public);
					foreach (MethodInfo methodInfo2 in methods)
					{
						if (!(methodInfo2.Name != "Destroy") && methodInfo2.GetParameters().Length == 1)
						{
							_destroy = methodInfo2;
							break;
						}
					}
				}
				_getInstanceId = _objectType?.GetMethod("GetInstanceID", BindingFlags.Instance | BindingFlags.Public);
				_gameObjectProp = _componentType?.GetProperty("gameObject");
				if (_componentType != null && _rigidbodyType != null)
				{
					MethodInfo[] methods = _componentType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
					foreach (MethodInfo methodInfo3 in methods)
					{
						if (methodInfo3.Name == "GetComponentsInChildren" && methodInfo3.IsGenericMethodDefinition && methodInfo3.GetParameters().Length == 0)
						{
							_getComponentsInChildren = methodInfo3.MakeGenericMethod(_rigidbodyType);
							break;
						}
					}
					if (_getComponentsInChildren == null)
					{
						methods = _componentType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
						foreach (MethodInfo methodInfo4 in methods)
						{
							ParameterInfo[] parameters = methodInfo4.GetParameters();
							if (methodInfo4.Name == "GetComponentsInChildren" && parameters.Length == 1 && parameters[0].ParameterType == typeof(Type))
							{
								_getComponentsInChildren = methodInfo4;
								break;
							}
						}
					}
				}
				Type type = Type.GetType("UnityEngine.GameObject, UnityEngine.CoreModule") ?? FindType("UnityEngine.GameObject");
				if (type != null && _impactPropertiesType != null)
				{
					MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
					foreach (MethodInfo methodInfo5 in methods)
					{
						if (methodInfo5.Name == "GetComponent" && methodInfo5.IsGenericMethodDefinition && methodInfo5.GetParameters().Length == 0)
						{
							_getComponent = methodInfo5.MakeGenericMethod(_impactPropertiesType);
							break;
						}
					}
					methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
					foreach (MethodInfo methodInfo6 in methods)
					{
						if (methodInfo6.Name == "AddComponent" && methodInfo6.IsGenericMethodDefinition && methodInfo6.GetParameters().Length == 0)
						{
							_addComponent = methodInfo6.MakeGenericMethod(_impactPropertiesType);
							break;
						}
					}
					if (_addComponent == null)
					{
						Type type2 = FindType("Il2CppSystem.Type");
						if (type2 != null)
						{
							_addComponent = type.GetMethod("AddComponent", new Type[1] { type2 });
						}
					}
				}
				_surfaceDataCardProp = _impactPropertiesType?.GetProperty("SurfaceDataCard");
				_decalTypeProp = _impactPropertiesType?.GetProperty("decalType");
				_testVisualDamage = FindType("Il2CppSLZ.Marrow.Health")?.GetProperty("_testVisualDamage");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Homigrad] SelfHarm init: " + ex.Message);
			}
		}

		private static object? CreateBloodSurfaceCard()
		{
			try
			{
				if (_dataCardRefOpen != null && _surfaceDataCardType != null)
				{
					Type type = _dataCardRefOpen.MakeGenericType(_surfaceDataCardType);
					ConstructorInfo constructor = type.GetConstructor(new Type[1] { typeof(string) });
					if (constructor != null)
					{
						return constructor.Invoke(new object[1] { "SLZ.Backlot.SurfaceDataCard.Blood" });
					}
					return Activator.CreateInstance(type, "SLZ.Backlot.SurfaceDataCard.Blood");
				}
				return (FindType("Il2CppSLZ.Marrow.Warehouse.DataCardReference")?.GetConstructor(new Type[1] { typeof(string) }))?.Invoke(new object[1] { "SLZ.Backlot.SurfaceDataCard.Blood" });
			}
			catch (Exception ex)
			{
				LogFailOnce("surface card: " + ex.Message);
				return null;
			}
		}

		private static object? GetComponentsInChildren(object component, Type elementType)
		{
			if (_getComponentsInChildren == null)
			{
				return null;
			}
			try
			{
				if (_getComponentsInChildren.IsGenericMethod)
				{
					return _getComponentsInChildren.Invoke(component, null);
				}
				return _getComponentsInChildren.Invoke(component, new object[1] { elementType });
			}
			catch
			{
				return null;
			}
		}

		private static bool HasImpactProperties(object go)
		{
			if (GetImpactProperties(go) != null)
			{
				return !IsUnityNull(GetImpactProperties(go));
			}
			return false;
		}

		private static object? GetImpactProperties(object go)
		{
			try
			{
				if (_getComponent != null)
				{
					return _getComponent.Invoke(go, null);
				}
			}
			catch
			{
			}
			return null;
		}

		private static object? AddImpactProperties(object go)
		{
			try
			{
				if (_addComponent == null)
				{
					return null;
				}
				if (_addComponent.IsGenericMethod)
				{
					return _addComponent.Invoke(go, null);
				}
				MethodInfo methodInfo = FindType("Il2CppSystem.Type")?.GetMethod("internal_from_handle", BindingFlags.Static | BindingFlags.Public) ?? FindType("Il2CppInterop.Runtime.Il2CppType")?.GetMethod("From", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null);
				object obj = null;
				if (methodInfo != null && methodInfo.GetParameters().Length == 1 && methodInfo.GetParameters()[0].ParameterType == typeof(Type))
				{
					obj = methodInfo.Invoke(null, new object[1] { _impactPropertiesType });
				}
				else
				{
					Type type = FindType("Il2CppInterop.Runtime.Il2CppType");
					obj = type?.GetMethod("Of", BindingFlags.Static | BindingFlags.Public)?.MakeGenericMethod(_impactPropertiesType).Invoke(null, null) ?? type?.GetMethod("From", new Type[1] { typeof(Type) })?.Invoke(null, new object[1] { _impactPropertiesType });
				}
				if (obj == null)
				{
					return null;
				}
				return _addComponent.Invoke(go, new object[1] { obj });
			}
			catch (Exception ex)
			{
				LogFailOnce("AddComponent: " + ex.Message);
				return null;
			}
		}

		private static void SetTestVisualDamage(object rigManager, bool value)
		{
			try
			{
				object fieldOrProp = GetFieldOrProp(rigManager, "health");
				if (fieldOrProp != null && !(_testVisualDamage == null))
				{
					_testVisualDamage.SetValue(fieldOrProp, value);
				}
			}
			catch
			{
			}
		}

		private static bool TryGetRigManager(out object rigManager)
		{
			rigManager = null;
			try
			{
				object obj = _playerType.GetField("rigManager", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? _playerType.GetProperty("rigManager", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? _playerType.GetProperty("RigManager", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null || IsUnityNull(obj))
				{
					return false;
				}
				rigManager = obj;
				return true;
			}
			catch
			{
				return false;
			}
		}