Decompiled source of NoGore v1.0.0

BepInEx/plugins/NoGore/NoGore.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NoGore")]
[assembly: AssemblyDescription("STRAFTAT: no blood and no ragdolls, client-side.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: StraftatMod(true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace NoGore;

[BepInPlugin("dorsth.straftat.nogore", "NoGore", "1.0.0")]
public sealed class NoGorePlugin : BaseUnityPlugin
{
	public const string Guid = "dorsth.straftat.nogore";

	public const string Name = "NoGore";

	public const string Version = "1.0.0";

	internal const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	internal const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> NoRagdoll;

	internal static ConfigEntry<bool> NoBlood;

	private static bool _errorLogged;

	private void Awake()
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Expected O, but got Unknown
		//IL_006f: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogMessage((object)"Dorsth was here");
		NoRagdoll = ((BaseUnityPlugin)this).Config.Bind<bool>("NoRagdoll", "Enabled", true, "Hide all ragdolls (yours too), gib pieces, and hats that come off players. Only affects your own screen.");
		NoBlood = ((BaseUnityPlugin)this).Config.Bind<bool>("NoBlood", "Enabled", true, "Remove blood effects (hit blood, splatter and kill blood). Only affects your own screen.");
		Harmony val = new Harmony("dorsth.straftat.nogore");
		RagdollHider.Install(val);
		BloodRemover.Install(val);
	}

	internal static Type FindGameType(string name)
	{
		Type type = Type.GetType(name + ", Assembly-CSharp", throwOnError: false);
		if (type != null)
		{
			return type;
		}
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			try
			{
				type = assembly.GetType(name, throwOnError: false);
			}
			catch
			{
				type = null;
			}
			if (type != null)
			{
				return type;
			}
		}
		return null;
	}

	internal static FieldInfo FindField(Type type, string name, Type expectedType)
	{
		Type type2 = type;
		while (type2 != null)
		{
			FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				if (!(expectedType == null) && !(field.FieldType == expectedType))
				{
					return null;
				}
				return field;
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	internal static void LogErrorOnce(string feature, Exception e)
	{
		if (!_errorLogged)
		{
			_errorLogged = true;
			Log.LogError((object)(feature + " hit an error (further errors are suppressed): " + e));
		}
	}
}
internal static class RagdollHider
{
	internal sealed class Death
	{
		public readonly HashSet<int> RootsBefore = new HashSet<int>();

		public object KillCam;

		public object Ragdoll;

		public object FirstPosition;

		public object Trigger;
	}

	private static Type _networkObjectType;

	private static FieldInfo _spawnedRagdoll;

	private static bool _deathHooked;

	private static PropertyInfo _isOwner;

	private static FieldInfo _killCamScript;

	private static FieldInfo _kcRagdoll;

	private static FieldInfo _kcFirstPosition;

	private static FieldInfo _kcTrigger;

	private static readonly HashSet<int> Handled = new HashSet<int>();

	private static readonly List<GameObject> NewRagdolls = new List<GameObject>();

	private static readonly List<GameObject> SceneRoots = new List<GameObject>();

	private static bool On
	{
		get
		{
			if (NoGorePlugin.NoRagdoll != null)
			{
				return NoGorePlugin.NoRagdoll.Value;
			}
			return false;
		}
	}

	internal static void Install(Harmony harmony)
	{
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Expected O, but got Unknown
		//IL_0111: Expected O, but got Unknown
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Expected O, but got Unknown
		List<string> list = new List<string>();
		try
		{
			_networkObjectType = Type.GetType("FishNet.Object.NetworkObject, FishNet.Runtime", throwOnError: false);
			Type type = NoGorePlugin.FindGameType("RagdollDress");
			MethodInfo methodInfo = ((type == null) ? null : (type.GetMethod("OnEnable", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetMethod("Awake", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)));
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(RagdollHider).GetMethod("RagdollSpawnedPostfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				list.Add("ragdolls");
			}
			Type type2 = NoGorePlugin.FindGameType("PlayerHealth");
			MethodInfo methodInfo2 = ((type2 == null) ? null : FindDeathMethod(type2));
			if (methodInfo2 != null)
			{
				_spawnedRagdoll = NoGorePlugin.FindField(type2, "spawnedRagdoll", typeof(bool));
				FindKillCam(type2);
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(RagdollHider).GetMethod("DeathPrefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), new HarmonyMethod(typeof(RagdollHider).GetMethod("DeathPostfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_deathHooked = true;
				list.Add("deaths");
			}
			Type type3 = NoGorePlugin.FindGameType("HatPosition");
			MethodInfo methodInfo3 = null;
			if (type3 != null)
			{
				string[] array = new string[3] { "Update", "LateUpdate", "FixedUpdate" };
				foreach (string name in array)
				{
					methodInfo3 = type3.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					if (methodInfo3 != null)
					{
						break;
					}
				}
			}
			if (methodInfo3 != null)
			{
				harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(RagdollHider).GetMethod("CosmeticTickPostfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				list.Add("hats");
			}
		}
		catch (Exception ex)
		{
			NoGorePlugin.Log.LogError((object)("Failed to set up NoRagdoll: " + ex));
		}
		if (list.Count == 3)
		{
			NoGorePlugin.Log.LogInfo((object)"NoRagdoll is ready.");
		}
		else if (list.Count > 0)
		{
			NoGorePlugin.Log.LogWarning((object)("NoRagdoll only partly works with this game version (hooked: " + string.Join(", ", list.ToArray()) + ")."));
		}
		else
		{
			NoGorePlugin.Log.LogError((object)"NoRagdoll couldn't find the game's ragdoll code, so it is inactive. (Did the game update?)");
		}
	}

	private static void RagdollSpawnedPostfix(MonoBehaviour __instance)
	{
		try
		{
			if (!On || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			GameObject gameObject = ((Component)__instance).gameObject;
			if (!Handled.Contains(((Object)gameObject).GetInstanceID()))
			{
				Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = false;
				}
				if (_deathHooked)
				{
					NewRagdolls.Add(gameObject);
				}
			}
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoRagdoll", e);
		}
	}

	private static void DeathPrefix(MonoBehaviour __instance, out Death __state)
	{
		__state = null;
		try
		{
			if (!On || (Object)(object)__instance == (Object)null || (_spawnedRagdoll != null && (bool)_spawnedRagdoll.GetValue(__instance)))
			{
				return;
			}
			Death death = new Death();
			List<GameObject> list = Roots();
			for (int i = 0; i < list.Count; i++)
			{
				death.RootsBefore.Add(((Object)list[i]).GetInstanceID());
			}
			if (_isOwner != null && !IsYou(__instance))
			{
				death.KillCam = _killCamScript.GetValue(__instance);
				if (death.KillCam != null)
				{
					death.Ragdoll = _kcRagdoll.GetValue(death.KillCam);
					death.FirstPosition = _kcFirstPosition.GetValue(death.KillCam);
					death.Trigger = _kcTrigger.GetValue(death.KillCam);
				}
			}
			__state = death;
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoRagdoll", e);
		}
	}

	private static void DeathPostfix(Death __state)
	{
		if (__state == null)
		{
			return;
		}
		try
		{
			List<GameObject> list = Roots();
			for (int i = 0; i < list.Count; i++)
			{
				GameObject val = list[i];
				int instanceID = ((Object)val).GetInstanceID();
				if (!__state.RootsBefore.Contains(instanceID) && !Handled.Contains(instanceID) && LooksLikeBodyDebris(val))
				{
					Hide(val);
				}
			}
			for (int j = 0; j < NewRagdolls.Count; j++)
			{
				GameObject val2 = NewRagdolls[j];
				if ((Object)(object)val2 != (Object)null && !Handled.Contains(((Object)val2).GetInstanceID()))
				{
					Hide(val2);
				}
			}
			NewRagdolls.Clear();
			if (__state.KillCam != null)
			{
				object? value = _kcRagdoll.GetValue(__state.KillCam);
				Transform val3 = (Transform)((value is Transform) ? value : null);
				if ((Object)(object)val3 != (Object)null && val3 != __state.Ragdoll && IsHidden(val3))
				{
					_kcRagdoll.SetValue(__state.KillCam, __state.Ragdoll);
					_kcFirstPosition.SetValue(__state.KillCam, __state.FirstPosition);
					_kcTrigger.SetValue(__state.KillCam, __state.Trigger);
				}
			}
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoRagdoll", e);
		}
	}

	private static void CosmeticTickPostfix(MonoBehaviour __instance)
	{
		try
		{
			if (!((Object)(object)((Component)__instance).transform.parent != (Object)null))
			{
				GameObject gameObject = ((Component)__instance).gameObject;
				if (Handled.Add(((Object)gameObject).GetInstanceID()) && On)
				{
					Hide(gameObject);
				}
			}
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoRagdoll", e);
		}
	}

	private static void Hide(GameObject go)
	{
		Handled.Add(((Object)go).GetInstanceID());
		Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			componentsInChildren[i].enabled = false;
		}
		Collider[] componentsInChildren2 = go.GetComponentsInChildren<Collider>(true);
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			componentsInChildren2[i].enabled = false;
		}
		Rigidbody[] componentsInChildren3 = go.GetComponentsInChildren<Rigidbody>(true);
		for (int i = 0; i < componentsInChildren3.Length; i++)
		{
			componentsInChildren3[i].isKinematic = true;
		}
		go.SetActive(false);
	}

	private static bool LooksLikeBodyDebris(GameObject root)
	{
		if ((Object)(object)root.GetComponentInChildren<Renderer>(true) != (Object)null && (Object)(object)root.GetComponentInChildren<Rigidbody>(true) != (Object)null && (Object)(object)root.GetComponentInChildren<Camera>(true) == (Object)null)
		{
			if (!(_networkObjectType == null))
			{
				return (Object)(object)root.GetComponentInChildren(_networkObjectType, true) == (Object)null;
			}
			return true;
		}
		return false;
	}

	private static bool IsHidden(Transform t)
	{
		while ((Object)(object)t != (Object)null)
		{
			if (Handled.Contains(((Object)((Component)t).gameObject).GetInstanceID()))
			{
				return true;
			}
			t = t.parent;
		}
		return false;
	}

	private static bool IsYou(object player)
	{
		try
		{
			return (bool)_isOwner.GetValue(player, null);
		}
		catch
		{
			return true;
		}
	}

	private static List<GameObject> Roots()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		List<GameObject> list = new List<GameObject>();
		int sceneCount = SceneManager.sceneCount;
		for (int i = 0; i < sceneCount; i++)
		{
			Scene sceneAt = SceneManager.GetSceneAt(i);
			if (((Scene)(ref sceneAt)).IsValid() && ((Scene)(ref sceneAt)).isLoaded)
			{
				((Scene)(ref sceneAt)).GetRootGameObjects(SceneRoots);
				list.AddRange(SceneRoots);
			}
		}
		SceneRoots.Clear();
		return list;
	}

	private static MethodInfo FindDeathMethod(Type playerHealth)
	{
		MethodInfo result = null;
		MethodInfo[] methods = playerHealth.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name.StartsWith("RpcLogic___ExplodeForAll", StringComparison.Ordinal))
			{
				return methodInfo;
			}
			if (methodInfo.Name == "ExplodeForAll")
			{
				result = methodInfo;
			}
		}
		return result;
	}

	private static void FindKillCam(Type playerHealth)
	{
		try
		{
			PropertyInfo property = playerHealth.GetProperty("IsOwner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo fieldInfo = NoGorePlugin.FindField(playerHealth, "killCamScript", null);
			if (!(property == null) && !(property.PropertyType != typeof(bool)) && !(fieldInfo == null))
			{
				_kcRagdoll = NoGorePlugin.FindField(fieldInfo.FieldType, "ragdoll", typeof(Transform));
				_kcFirstPosition = NoGorePlugin.FindField(fieldInfo.FieldType, "firstPosition", typeof(Vector3));
				_kcTrigger = NoGorePlugin.FindField(fieldInfo.FieldType, "triggerLookAtBody", typeof(bool));
				if (!(_kcRagdoll == null) && !(_kcFirstPosition == null) && !(_kcTrigger == null))
				{
					_killCamScript = fieldInfo;
					_isOwner = property;
				}
			}
		}
		catch (Exception ex)
		{
			NoGorePlugin.Log.LogWarning((object)("NoRagdoll couldn't find the spectator camera, so it is left as is: " + ex.Message));
		}
	}
}
internal static class BloodRemover
{
	private sealed class EmptyEffect : MonoBehaviour
	{
		private void Awake()
		{
			if ((Object)(object)((Component)this).gameObject != (Object)(object)_placeholder)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}

	private static readonly string[] WeaponBloodFields = new string[4] { "headImpact", "bodyImpact", "genericBodyImpact", "bloodSplatter" };

	private static readonly Dictionary<MethodBase, FieldInfo[]> FieldsByMethod = new Dictionary<MethodBase, FieldInfo[]>();

	private static readonly Dictionary<Type, FieldInfo[]> WeaponFieldsByType = new Dictionary<Type, FieldInfo[]>();

	private static FieldInfo _meleeWeaponScript;

	private static GameObject _placeholder;

	private static bool On
	{
		get
		{
			if (NoGorePlugin.NoBlood != null)
			{
				return NoGorePlugin.NoBlood.Value;
			}
			return false;
		}
	}

	internal static void Install(Harmony harmony)
	{
		int num = 0;
		List<string> list = new List<string>();
		try
		{
			string[] array = new string[6] { "Gun", "BeamGun", "ChargeGun", "Minigun", "Shotgun", "LargeRaycastGun" };
			foreach (string typeName in array)
			{
				num += Hook(harmony, typeName, "ShootServer", isPrefix: false, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
				num += Hook(harmony, typeName, "RpcLogic___ObserversFX", isPrefix: true, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
			}
			num += Hook(harmony, "LargeRaycastGun", "ShootServerBox", isPrefix: false, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
			num += Hook(harmony, "Weapon", "TriggerEnvironment", isPrefix: false, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
			num += Hook(harmony, "MeleeWeapon", "HitServer", isPrefix: false, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
			num += Hook(harmony, "Taser", "RpcLogic___SpawnVFX", isPrefix: true, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
			num += Hook(harmony, "RepulsiveGun", "RpcLogic___SpawnVFX", isPrefix: true, "SwapPrefix", "RestorePostfix", WeaponBloodFields, list);
			num += Hook(harmony, "PlayerHealth", "RpcLogic___ExplodeForAll", isPrefix: true, "SwapPrefix", "RestorePostfix", new string[1] { "bloodFX" }, list);
			num += Hook(harmony, "PredictedProjectile", "Awake", isPrefix: false, "SwapForGoodPrefix", null, new string[3] { "bloodVfx", "headBloodVfx", "bloodSplatter" }, list);
			num += Hook(harmony, "PhysicsGrenade", "RpcLogic___HandleExplosion", isPrefix: true, "SwapForGoodPrefix", null, new string[1] { "bloodSplatter" }, list);
			num += Hook(harmony, "PhysicsProp", "OnControllerColliderHit", isPrefix: false, "SwapForGoodPrefix", null, new string[1] { "bloodImpact" }, list);
			num += Hook(harmony, "ShrapnelBallistic", "Explode", isPrefix: false, "SwapForGoodPrefix", null, new string[1] { "bloodSplatter" }, list);
			Type type = NoGorePlugin.FindGameType("MeleeChildCollision");
			if (type != null)
			{
				_meleeWeaponScript = NoGorePlugin.FindField(type, "weaponScript", null);
			}
			if (_meleeWeaponScript != null)
			{
				num += Hook(harmony, "MeleeChildCollision", "OnCollisionEnter", isPrefix: false, "MeleePrefix", null, new string[0], list);
			}
			else
			{
				list.Add("MeleeChildCollision.weaponScript");
			}
		}
		catch (Exception ex)
		{
			NoGorePlugin.Log.LogError((object)("Failed to set up NoBlood: " + ex));
		}
		if (list.Count > 0)
		{
			NoGorePlugin.Log.LogWarning((object)("NoBlood couldn't find (game update?): " + string.Join(", ", list.ToArray())));
		}
		if (num > 0)
		{
			NoGorePlugin.Log.LogInfo((object)"NoBlood is ready.");
		}
		else
		{
			NoGorePlugin.Log.LogError((object)"NoBlood couldn't hook anything, so it is inactive. (Did the game update?)");
		}
	}

	private static int Hook(Harmony harmony, string typeName, string methodName, bool isPrefix, string prefix, string postfix, string[] fieldNames, List<string> missing)
	{
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Expected O, but got Unknown
		Type type = NoGorePlugin.FindGameType(typeName);
		List<MethodInfo> list = ((type == null) ? new List<MethodInfo>() : FindMethods(type, methodName, isPrefix));
		if (list.Count == 0)
		{
			missing.Add(typeName + "." + methodName);
			return 0;
		}
		int num = 0;
		foreach (MethodInfo item in list)
		{
			if (FieldsByMethod.ContainsKey(item))
			{
				continue;
			}
			List<FieldInfo> list2 = new List<FieldInfo>();
			foreach (string text in fieldNames)
			{
				FieldInfo fieldInfo = NoGorePlugin.FindField(item.DeclaringType, text, typeof(GameObject));
				if (fieldInfo != null)
				{
					list2.Add(fieldInfo);
				}
				else
				{
					missing.Add(item.DeclaringType.Name + "." + text);
				}
			}
			FieldsByMethod[item] = list2.ToArray();
			if (fieldNames.Length == 0 || list2.Count != 0)
			{
				try
				{
					harmony.Patch((MethodBase)item, new HarmonyMethod(typeof(BloodRemover).GetMethod(prefix, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(BloodRemover).GetMethod(postfix, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
				}
				catch (Exception ex)
				{
					NoGorePlugin.Log.LogError((object)("Failed to hook " + typeName + "." + item.Name + ": " + ex.Message));
				}
			}
		}
		return num;
	}

	private static List<MethodInfo> FindMethods(Type type, string name, bool isPrefix)
	{
		Type type2 = type;
		while (type2 != null && type2 != typeof(MonoBehaviour))
		{
			List<MethodInfo> list = new List<MethodInfo>();
			MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if ((isPrefix ? methodInfo.Name.StartsWith(name, StringComparison.Ordinal) : (methodInfo.Name == name)) && !methodInfo.IsAbstract)
				{
					list.Add(methodInfo);
				}
			}
			if (list.Count > 0)
			{
				return list;
			}
			type2 = type2.BaseType;
		}
		return new List<MethodInfo>();
	}

	private static void SwapPrefix(object __instance, MethodBase __originalMethod, out GameObject[] __state)
	{
		__state = null;
		try
		{
			if (On && __instance != null && FieldsByMethod.TryGetValue(__originalMethod, out var value))
			{
				__state = Swap(__instance, value);
			}
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoBlood", e);
		}
	}

	private static void RestorePostfix(object __instance, MethodBase __originalMethod, GameObject[] __state)
	{
		if (__state == null)
		{
			return;
		}
		try
		{
			FieldInfo[] array = FieldsByMethod[__originalMethod];
			for (int i = 0; i < array.Length; i++)
			{
				object? value = array[i].GetValue(__instance);
				if ((Object)((value is GameObject) ? value : null) == (Object)(object)_placeholder)
				{
					array[i].SetValue(__instance, __state[i]);
				}
			}
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoBlood", e);
		}
	}

	private static void SwapForGoodPrefix(object __instance, MethodBase __originalMethod)
	{
		try
		{
			if (On && __instance != null && FieldsByMethod.TryGetValue(__originalMethod, out var value))
			{
				Swap(__instance, value);
			}
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoBlood", e);
		}
	}

	private static void MeleePrefix(object __instance)
	{
		try
		{
			if (!On || __instance == null)
			{
				return;
			}
			object? value = _meleeWeaponScript.GetValue(__instance);
			Object val = (Object)((value is Object) ? value : null);
			if (val == (Object)null)
			{
				return;
			}
			Type type = ((object)val).GetType();
			if (!WeaponFieldsByType.TryGetValue(type, out var value2))
			{
				List<FieldInfo> list = new List<FieldInfo>();
				string[] weaponBloodFields = WeaponBloodFields;
				foreach (string name in weaponBloodFields)
				{
					FieldInfo fieldInfo = NoGorePlugin.FindField(type, name, typeof(GameObject));
					if (fieldInfo != null)
					{
						list.Add(fieldInfo);
					}
				}
				value2 = (WeaponFieldsByType[type] = list.ToArray());
			}
			Swap(val, value2);
		}
		catch (Exception e)
		{
			NoGorePlugin.LogErrorOnce("NoBlood", e);
		}
	}

	private static GameObject[] Swap(object instance, FieldInfo[] fields)
	{
		GameObject val = Placeholder();
		GameObject[] array = (GameObject[])(object)new GameObject[fields.Length];
		for (int i = 0; i < fields.Length; i++)
		{
			ref GameObject reference = ref array[i];
			object? value = fields[i].GetValue(instance);
			reference = (GameObject)((value is GameObject) ? value : null);
			if ((Object)(object)array[i] != (Object)null && (Object)(object)array[i] != (Object)(object)val)
			{
				fields[i].SetValue(instance, val);
			}
		}
		return array;
	}

	private static GameObject Placeholder()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)_placeholder == (Object)null)
		{
			_placeholder = new GameObject("NoGore_EmptyBlood");
			((Object)_placeholder).hideFlags = (HideFlags)61;
			_placeholder.AddComponent<EmptyEffect>();
		}
		return _placeholder;
	}
}