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
{
}
}
}
}