Decompiled source of NoDeathGB v1.0.1

Mods/NoDeathGB.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MelonLoader;
using Microsoft.CodeAnalysis;
using NoDeathGB;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "NoDeathGB", "1.0.0", "NoDeathGB", null)]
[assembly: MelonGame("Boneloaf", "Gang Beasts")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("NoDeathGB")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NoDeathGB")]
[assembly: AssemblyTitle("NoDeathGB")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
namespace NoDeathGB
{
	public class Mod : MelonMod
	{
		private static AudioClip? warpSound;

		private static bool ready;

		private static string? lastScene;

		private static bool searching;

		internal static int lastWarpFrame = -999;

		internal static bool inGuard;

		internal static Type? actorType;

		private static Type? actorStateType;

		private static Type? deathTypeType;

		internal const int ACTORSTATE_DEAD = 1;

		internal const int ACTORSTATE_UNCONSCIOUS = 2;

		private const int ACTORSTATE_STAND = 4;

		internal static object? standStateValue;

		internal static object? noneDeathTypeValue;

		public override void OnInitializeMelon()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Expected O, but got Unknown
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Expected O, but got Unknown
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			//IL_059b: Expected O, but got Unknown
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Expected O, but got Unknown
			Harmony val = new Harmony("NoDeathGB");
			int num = 0;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				string text = assembly.GetName().Name ?? "";
				if (text != "Il2CppAssembly-CSharp" && text != "Il2CppFemur" && text != "Il2CppGB" && text != "Assembly-CSharp")
				{
					continue;
				}
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					types = ex.Types;
				}
				catch
				{
					continue;
				}
				Type[] source = (from t in types
					where t != null
					select (t)).ToArray();
				if (actorType == null)
				{
					actorType = source.FirstOrDefault((Type t) => t.Name == "Actor");
				}
				if (actorStateType == null)
				{
					actorStateType = source.FirstOrDefault((Type t) => t.Name == "ActorState");
				}
				if (deathTypeType == null)
				{
					deathTypeType = source.FirstOrDefault((Type t) => t.Name == "DeathType");
				}
				if (standStateValue == null && actorStateType != null)
				{
					standStateValue = Enum.ToObject(actorStateType, 4);
					MelonLogger.Msg($"Alive state = Stand ({4})");
				}
				if (noneDeathTypeValue == null && deathTypeType != null)
				{
					int value = (from int v in Enum.GetValues(deathTypeType)
						orderby v
						select v).First();
					noneDeathTypeValue = Enum.ToObject(deathTypeType, value);
					MelonLogger.Msg($"None death type = {value}");
				}
				Type type = source.FirstOrDefault((Type t) => t.Name == "HealthTracker");
				MethodInfo[] array;
				if (type != null)
				{
					MelonLogger.Msg("Targeting: " + type.FullName);
					array = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
						where m.Name == "Kill" && !m.IsGenericMethod
						select m).ToArray();
					foreach (MethodInfo methodInfo in array)
					{
						try
						{
							val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "BlockDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							MelonLogger.Msg("  Patched Kill(" + string.Join(", ", from p in methodInfo.GetParameters()
								select p.ParameterType.Name) + ")");
							num++;
						}
						catch (Exception ex2)
						{
							MelonLogger.Warning("  Skip Kill: " + ex2.Message);
						}
					}
				}
				if (actorType != null)
				{
					MelonLogger.Msg("Targeting: " + actorType.FullName);
					MethodInfo method = actorType.GetMethod("set_actorState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method != null && !method.IsGenericMethod)
					{
						try
						{
							val.Patch((MethodBase)method, new HarmonyMethod(typeof(Patches), "BlockActorStateChange", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							MelonLogger.Msg("  Patched set_actorState");
							num++;
						}
						catch (Exception ex3)
						{
							MelonLogger.Warning("  Skip set_actorState: " + ex3.Message);
						}
					}
				}
				Type type2 = source.FirstOrDefault((Type t) => t.Name == "BreakJointsOnDeath");
				if (type2 != null)
				{
					array = (from m in type2.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
						where m.Name == "OnDeath" && !m.IsGenericMethod
						select m).ToArray();
					foreach (MethodInfo methodInfo2 in array)
					{
						try
						{
							val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Patches), "BlockDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							MelonLogger.Msg("  Patched BreakJointsOnDeath.OnDeath");
							num++;
						}
						catch (Exception ex4)
						{
							MelonLogger.Warning("  Skip OnDeath: " + ex4.Message);
						}
					}
				}
				Type type3 = source.FirstOrDefault((Type t) => t.Name == "ActorDeathAudio");
				if (!(type3 != null))
				{
					continue;
				}
				array = (from m in type3.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.Name == "OnBeastDeath" && !m.IsGenericMethod
					select m).ToArray();
				foreach (MethodInfo methodInfo3 in array)
				{
					try
					{
						val.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Patches), "BlockDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						MelonLogger.Msg("  Patched ActorDeathAudio.OnBeastDeath");
						num++;
					}
					catch (Exception ex5)
					{
						MelonLogger.Warning("  Skip OnBeastDeath: " + ex5.Message);
					}
				}
			}
			ready = true;
			MelonLogger.Msg($"NoDeathGB ready — {num} patches applied");
		}

		public override void OnUpdate()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!ready || actorType == null || inGuard)
			{
				return;
			}
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				if (name != lastScene)
				{
					lastScene = name;
					warpSound = null;
					if (!searching)
					{
						searching = true;
						MelonCoroutines.Start(FindWarpSound(name));
					}
				}
			}
			catch
			{
			}
			inGuard = true;
			try
			{
				foreach (MonoBehaviour item in Object.FindObjectsOfType<MonoBehaviour>())
				{
					if (!((Object)(object)item == (Object)null) && !(((object)item).GetType() != actorType) && IsLocalActor(item))
					{
						ForceAlive(item);
					}
				}
			}
			catch
			{
			}
			finally
			{
				inGuard = false;
			}
		}

		internal static bool IsLocalActor(object actorObj)
		{
			Type type = actorObj.GetType();
			PropertyInfo property = type.GetProperty("IsLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				try
				{
					object value = property.GetValue(actorObj);
					if (value is bool)
					{
						return (bool)value;
					}
				}
				catch
				{
				}
			}
			FieldInfo field = type.GetField("isLocalPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				try
				{
					object value2 = field.GetValue(actorObj);
					if (value2 is bool)
					{
						return (bool)value2;
					}
				}
				catch
				{
				}
			}
			FieldInfo field2 = type.GetField("_aiMember", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field2 != null)
			{
				try
				{
					object value3 = field2.GetValue(actorObj);
					bool flag = default(bool);
					int num;
					if (value3 is bool)
					{
						flag = (bool)value3;
						num = 1;
					}
					else
					{
						num = 0;
					}
					if (((uint)num & (flag ? 1u : 0u)) != 0)
					{
						return false;
					}
				}
				catch
				{
				}
			}
			PropertyInfo property2 = type.GetProperty("IsAI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property2 != null)
			{
				try
				{
					object value4 = property2.GetValue(actorObj);
					bool flag2 = default(bool);
					int num2;
					if (value4 is bool)
					{
						flag2 = (bool)value4;
						num2 = 1;
					}
					else
					{
						num2 = 0;
					}
					if (((uint)num2 & (flag2 ? 1u : 0u)) != 0)
					{
						return false;
					}
				}
				catch
				{
				}
			}
			FieldInfo field3 = type.GetField("_controllerID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field3 != null)
			{
				try
				{
					object value5 = field3.GetValue(actorObj);
					if (value5 is int)
					{
						int num3 = (int)value5;
						if (num3 < 0)
						{
							return false;
						}
					}
				}
				catch
				{
				}
			}
			return true;
		}

		private void ForceAlive(MonoBehaviour actor)
		{
			Type type = ((object)actor).GetType();
			if (actorStateType != null && standStateValue != null)
			{
				try
				{
					FieldInfo field = type.GetField("_actorState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null)
					{
						object value = field.GetValue(actor);
						if (value != null)
						{
							int num = (int)value;
							if (num == 1 || num == 2)
							{
								field.SetValue(actor, standStateValue);
							}
						}
					}
				}
				catch
				{
				}
			}
			if (deathTypeType != null && noneDeathTypeValue != null)
			{
				try
				{
					FieldInfo field2 = type.GetField("deathType", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field2 != null)
					{
						object value2 = field2.GetValue(actor);
						if (value2 != null && !value2.Equals(noneDeathTypeValue))
						{
							field2.SetValue(actor, noneDeathTypeValue);
						}
					}
				}
				catch
				{
				}
			}
			try
			{
				FieldInfo field3 = type.GetField("isWrapped", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field3 != null && field3.FieldType == typeof(bool))
				{
					object value3 = field3.GetValue(actor);
					bool flag = default(bool);
					int num2;
					if (value3 is bool)
					{
						flag = (bool)value3;
						num2 = 1;
					}
					else
					{
						num2 = 0;
					}
					if (((uint)num2 & (flag ? 1u : 0u)) != 0)
					{
						field3.SetValue(actor, false);
					}
				}
			}
			catch
			{
			}
			try
			{
				if (!((Component)actor).gameObject.activeSelf)
				{
					((Component)actor).gameObject.SetActive(true);
				}
				if (actor != null && !((Behaviour)actor).enabled)
				{
					((Behaviour)actor).enabled = true;
				}
			}
			catch
			{
			}
		}

		private IEnumerator FindWarpSound(string scene)
		{
			yield return (object)new WaitForSeconds(2f);
			Il2CppArrayBase<AudioClip> val = Resources.FindObjectsOfTypeAll<AudioClip>();
			string text = scene.ToLower();
			foreach (AudioClip item in val)
			{
				if ((Object)(object)item != (Object)null && ((Object)item).name.Equals(scene + " Warp 1", StringComparison.OrdinalIgnoreCase))
				{
					warpSound = item;
					MelonLogger.Msg("Warp sound: " + ((Object)item).name);
					searching = false;
					yield break;
				}
			}
			foreach (AudioClip item2 in val)
			{
				if ((Object)(object)item2 == (Object)null || !((Object)item2).name.ToLower().Contains("warp"))
				{
					continue;
				}
				string text2 = ((Object)item2).name.ToLower();
				string[] array = text.Split('_', ' ', '-');
				foreach (string text3 in array)
				{
					if (text3.Length >= 2 && text2.Contains(text3))
					{
						warpSound = item2;
						MelonLogger.Msg("Warp sound: " + ((Object)item2).name);
						searching = false;
						yield break;
					}
				}
			}
			foreach (AudioClip item3 in val)
			{
				if ((Object)(object)item3 != (Object)null && ((Object)item3).name.Contains("Warp"))
				{
					warpSound = item3;
					MelonLogger.Msg("Warp sound (fallback): " + ((Object)item3).name);
					searching = false;
					yield break;
				}
			}
			MelonLogger.Warning("No warp sound found for: " + scene);
			searching = false;
		}

		public static AudioClip? GetWarpSound()
		{
			return warpSound;
		}
	}
	public static class Patches
	{
		public static bool BlockDeath(object __instance)
		{
			if (Mod.inGuard)
			{
				return false;
			}
			object obj = FindActor(__instance);
			if (obj == null)
			{
				return true;
			}
			if (!Mod.IsLocalActor(obj))
			{
				return true;
			}
			Mod.inGuard = true;
			try
			{
				PlayWarp(__instance);
			}
			finally
			{
				Mod.inGuard = false;
			}
			return false;
		}

		public static bool BlockActorStateChange(object __instance, object value)
		{
			if (Mod.inGuard)
			{
				return false;
			}
			if (!Mod.IsLocalActor(__instance))
			{
				return true;
			}
			int num = (int)value;
			if (num == 1 || num == 2)
			{
				Mod.inGuard = true;
				try
				{
					PlayWarp(__instance);
				}
				finally
				{
					Mod.inGuard = false;
				}
				return false;
			}
			return true;
		}

		private static object? FindActor(object inst)
		{
			if (inst.GetType().Name == "Actor")
			{
				return inst;
			}
			Component val = (Component)((inst is Component) ? inst : null);
			if (val != null)
			{
				foreach (Component component in val.GetComponents<Component>())
				{
					if ((Object)(object)component != (Object)null && ((object)component).GetType().Name == "Actor")
					{
						return component;
					}
				}
				if ((Object)(object)val.transform.parent != (Object)null)
				{
					foreach (Component component2 in ((Component)val.transform.parent).GetComponents<Component>())
					{
						if ((Object)(object)component2 != (Object)null && ((object)component2).GetType().Name == "Actor")
						{
							return component2;
						}
					}
				}
			}
			return null;
		}

		private static void PlayWarp(object inst)
		{
			AudioClip warpSound = Mod.GetWarpSound();
			if ((Object)(object)warpSound == (Object)null || Time.frameCount - Mod.lastWarpFrame < 60)
			{
				return;
			}
			Component val = (Component)((inst is Component) ? inst : null);
			if (val == null)
			{
				return;
			}
			Mod.lastWarpFrame = Time.frameCount;
			try
			{
				AudioSource val2 = val.gameObject.GetComponent<AudioSource>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = val.gameObject.AddComponent<AudioSource>();
				}
				val2.PlayOneShot(warpSound);
			}
			catch
			{
			}
		}
	}
}