using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using Mirror;
using MoveClasses;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("RespawnMod_M4GMaR")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RespawnMod_M4GMaR")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("fc922182-bb62-4b0d-8de5-46794294d7cf")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.yourname.respawnmod", "Respawn Mod", "1.9.4")]
public class RespawnMod : BaseUnityPlugin
{
[HarmonyPatch(typeof(StaminaManager), "UpdateStaminaJobItems")]
private class Patch_StaminaManager_UpdateStaminaJobItems
{
private static void Prefix(StaminaManager __instance)
{
try
{
for (int num = __instance.staminaItems.Count - 1; num >= 0; num--)
{
StaminaItem val = __instance.staminaItems[num];
if (val == null || (Object)(object)val.playerHealth == (Object)null || (Object)(object)((Component)val.playerHealth).gameObject == (Object)null)
{
__instance.staminaItems.RemoveAt(num);
}
}
}
catch (Exception arg)
{
Debug.LogWarning((object)$"[RespawnMod-DEBUG] Error cleaning staminaItems: {arg}");
}
}
}
[HarmonyPatch(typeof(LargeBladeTrigger), "FixedUpdate")]
private class Patch_LargeBladeTrigger_FixedUpdate
{
private static readonly FieldInfo fiWeapon = AccessTools.Field(typeof(LargeBladeTrigger), "weapon");
private static readonly FieldInfo fiDisableLocalLogic = AccessTools.Field(typeof(LargeBladeTrigger), "disableLocalLogic");
private static readonly FieldInfo fiPenetratingColliders = AccessTools.Field(typeof(LargeBladeTrigger), "penetratingColliders");
private static readonly FieldInfo fiPenetratingGameObjects = AccessTools.Field(typeof(LargeBladeTrigger), "penetratingGameObjects");
private static bool Prefix(LargeBladeTrigger __instance)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Expected O, but got Unknown
try
{
if (fiWeapon == null || fiDisableLocalLogic == null || fiPenetratingColliders == null || fiPenetratingGameObjects == null)
{
return true;
}
if ((bool)fiDisableLocalLogic.GetValue(__instance))
{
return false;
}
Weapon val = (Weapon)fiWeapon.GetValue(__instance);
if ((Object)(object)val != (Object)null)
{
return true;
}
if ((Object)(object)((Component)__instance).transform != (Object)null && (Object)(object)((Component)__instance).transform.parent != (Object)null)
{
Weapon component = ((Component)((Component)__instance).transform.parent).GetComponent<Weapon>();
if ((Object)(object)component != (Object)null)
{
fiWeapon.SetValue(__instance, component);
return true;
}
}
IList<Collider> list = fiPenetratingColliders.GetValue(__instance) as IList<Collider>;
IList<GameObject> list2 = fiPenetratingGameObjects.GetValue(__instance) as IList<GameObject>;
try
{
list?.Clear();
}
catch
{
}
try
{
list2?.Clear();
}
catch
{
}
fiDisableLocalLogic.SetValue(__instance, true);
Debug.LogWarning((object)"[RespawnMod] LargeBladeTrigger: weapon missing — disabled trigger logic to avoid NRE.");
return false;
}
catch (Exception ex)
{
Debug.LogWarning((object)("[RespawnMod] Patch_LargeBladeTrigger_FixedUpdate exception: " + ex));
return true;
}
}
}
[HarmonyPatch(typeof(Weapon), "IgnoreCollision")]
private class Patch_Weapon_IgnoreCollision
{
private static bool Prefix(Weapon __instance, Collider[] colliders, bool ignore = true)
{
try
{
if (colliders == null)
{
return false;
}
List<Collider> bladeColliders = __instance.bladeColliders;
if (bladeColliders == null || bladeColliders.Count == 0)
{
return false;
}
foreach (Collider val in colliders)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
foreach (Collider item in bladeColliders)
{
if (!((Object)(object)item == (Object)null))
{
try
{
Physics.IgnoreCollision(val, item, ignore);
}
catch (Exception)
{
}
}
}
}
}
catch (Exception ex2)
{
Debug.LogWarning((object)("[RespawnMod] Patch_Weapon_IgnoreCollision exception: " + ex2));
}
return false;
}
}
public static GameObject leftHandWeapon = null;
public static GameObject rightHandWeapon = null;
private static readonly Dictionary<PlayerHealth, float> RespawningPlayers = new Dictionary<PlayerHealth, float>();
private static readonly Dictionary<Rigidbody, float> OrphanedObjects = new Dictionary<Rigidbody, float>();
private Coroutine _cleanerCoroutine;
private Coroutine PositionSyncCoroutine;
public static RespawnMod Instance { get; private set; }
private void Awake()
{
((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61;
Instance = this;
Harmony.CreateAndPatchAll(typeof(RespawnMod), (string)null);
((BaseUnityPlugin)this).Logger.LogInfo((object)"AWAKE: Hooking into SceneManager.sceneLoaded");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("SCENE LOADED: " + ((Scene)(ref scene)).name));
RespawningPlayers.Clear();
if (_cleanerCoroutine != null)
{
((MonoBehaviour)this).StopCoroutine(_cleanerCoroutine);
_cleanerCoroutine = null;
}
if (PositionSyncCoroutine != null)
{
((MonoBehaviour)this).StopCoroutine(PositionSyncCoroutine);
PositionSyncCoroutine = null;
}
if (NetworkServer.active)
{
_cleanerCoroutine = ((MonoBehaviour)this).StartCoroutine(Cleaner());
}
}
private static void CleanRespawningPlayers()
{
float time = Time.time;
List<PlayerHealth> list = new List<PlayerHealth>();
foreach (KeyValuePair<PlayerHealth, float> respawningPlayer in RespawningPlayers)
{
PlayerHealth key = respawningPlayer.Key;
float value = respawningPlayer.Value;
if ((Object)(object)key == (Object)null || time - value > 10f)
{
list.Add(key);
}
}
foreach (PlayerHealth item in list)
{
RespawningPlayers.Remove(item);
if ((Object)(object)item != (Object)null)
{
item.Die((DeathReason)3);
}
}
}
private static IEnumerator TrackAndCleanOrphanedObjects()
{
float now = Time.time;
Rigidbody[] rigidbodies = Object.FindObjectsOfType<Rigidbody>();
Rigidbody[] array = rigidbodies;
foreach (Rigidbody rb in array)
{
if (!((Object)(object)((Component)rb).GetComponentInParent<PlayerHealth>() != (Object)null))
{
if (!OrphanedObjects.ContainsKey(rb))
{
OrphanedObjects[rb] = now;
}
else if (now - OrphanedObjects[rb] > 30f)
{
yield return ((MonoBehaviour)Instance).StartCoroutine(SafeDestroyGameObject(((Component)rb).gameObject));
OrphanedObjects.Remove(rb);
}
}
else if (OrphanedObjects.ContainsKey(rb))
{
OrphanedObjects.Remove(rb);
}
}
List<Rigidbody> nullKeys = new List<Rigidbody>();
foreach (KeyValuePair<Rigidbody, float> kvp in OrphanedObjects)
{
if ((Object)(object)kvp.Key == (Object)null)
{
nullKeys.Add(kvp.Key);
}
}
foreach (Rigidbody key in nullKeys)
{
OrphanedObjects.Remove(key);
}
}
private static IEnumerator Cleaner()
{
while (true)
{
yield return (object)new WaitForSeconds(5f);
CleanRespawningPlayers();
((MonoBehaviour)Instance).StartCoroutine(TrackAndCleanOrphanedObjects());
if ((Object)(object)StaminaManager.singleton != (Object)null)
{
StaminaManager.singleton.HandleExistingJob();
StaminaManager.singleton.staminaItems.RemoveAll((StaminaItem si) => si == null);
typeof(StaminaManager).GetMethod("ScheduleNextJob", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(StaminaManager.singleton, null);
}
}
}
[HarmonyPatch(typeof(PlayerHealth), "Die")]
[HarmonyPrefix]
private static bool PreventOriginalDeath(PlayerHealth __instance)
{
if (!NetworkServer.active)
{
return false;
}
if (RespawningPlayers.ContainsKey(__instance))
{
return false;
}
Debug.Log((object)("[RespawnMod-DEBUG] Player " + ((__instance != null) ? ((Object)__instance).name : null) + " triggered Die()"));
RespawningPlayers[__instance] = Time.time;
((MonoBehaviour)Instance).StartCoroutine(SimulateDeathAndResurrect(__instance));
return false;
}
private static IEnumerator SimulateDeathAndResurrect(PlayerHealth player)
{
PlayerHealth obj = player;
Debug.Log((object)("[RespawnMod-DEBUG] Simulating death for " + ((obj != null) ? ((Object)obj).name : null)));
if ((Object)(object)player == (Object)null || !NetworkServer.active)
{
Debug.LogWarning((object)"[RespawnMod-DEBUG] Invalid player or server not active");
RespawningPlayers.Remove(player);
yield break;
}
try
{
SetAllJointStrengths(player, 0f);
SetBallHolderJointStrength(player, 0f);
player?.bleedableOrgans?.ForEach(delegate(WeaponDamageablePart organ)
{
organ.StopDestroyVisuals();
});
}
catch (Exception ex2)
{
Exception ex = ex2;
Debug.LogWarning((object)$"[RespawnMod-DEBUG] Error setting joint strengths: {ex}");
}
try
{
if (player.leftHand?.currentlyGrabbedItem != null)
{
Weapon weapon = player.leftHand.currentlyGrabbedItem.GetWeapon();
leftHandWeapon = ((weapon != null) ? ((Component)weapon).gameObject : null);
}
if (player.rightHand?.currentlyGrabbedItem != null)
{
Weapon weapon2 = player.rightHand.currentlyGrabbedItem.GetWeapon();
rightHandWeapon = ((weapon2 != null) ? ((Component)weapon2).gameObject : null);
}
}
catch
{
}
try
{
((MonoBehaviour)player).Invoke("HandleHandsOnDeath", 0.4f);
}
catch
{
}
yield return (object)new WaitForSecondsRealtime(0.05f);
float elapsed = 0f;
while (elapsed < 5f && (Object)(object)player != (Object)null && (Object)(object)((Component)player).gameObject != (Object)null)
{
elapsed += Time.deltaTime;
try
{
SetAllJointStrengths(player, 0f);
}
catch
{
}
yield return null;
}
PlayerMultiplayerInputManager inputManager = FindInputManager(player);
if ((Object)(object)StaminaManager.singleton != (Object)null)
{
StaminaManager.singleton.HandleExistingJob();
StaminaManager.singleton.staminaItems.RemoveAll((StaminaItem si) => si == null || (Object)(object)si.playerHealth == (Object)(object)player);
typeof(StaminaManager).GetMethod("ScheduleNextJob", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(StaminaManager.singleton, null);
}
try
{
((MonoBehaviour)player).Invoke("HandleHandsOnDeath", 0.4f);
}
catch
{
}
yield return (object)new WaitForSeconds(0.41f);
if ((Object)(object)inputManager != (Object)null)
{
try
{
((MonoBehaviour)player).Invoke("HandleHandsOnDeath", 0.1f);
}
catch
{
}
yield return ((MonoBehaviour)Instance).StartCoroutine(SafeDestroyGameObject(leftHandWeapon));
leftHandWeapon = null;
try
{
((MonoBehaviour)player).Invoke("HandleHandsOnDeath", 0.1f);
}
catch
{
}
yield return ((MonoBehaviour)Instance).StartCoroutine(SafeDestroyGameObject(rightHandWeapon));
rightHandWeapon = null;
try
{
((MonoBehaviour)player).Invoke("HandleHandsOnDeath", 0.1f);
}
catch
{
}
RespawnMod instance = Instance;
PlayerHealth obj9 = player;
yield return ((MonoBehaviour)instance).StartCoroutine(SafeDestroyGameObject((obj9 != null) ? ((Component)obj9).gameObject : null));
ResetInputManager(inputManager);
yield return (object)new WaitForSecondsRealtime(0.4f);
yield return ((MonoBehaviour)Instance).StartCoroutine(Instance.Resurrect(inputManager));
}
else
{
Debug.Log((object)"InputManager not found, destroying character");
RespawnMod instance2 = Instance;
PlayerHealth obj10 = player;
yield return ((MonoBehaviour)instance2).StartCoroutine(SafeDestroyGameObject((obj10 != null) ? ((Component)obj10).gameObject : null));
}
}
private static IEnumerator SafeDestroyGameObject(GameObject go)
{
if ((Object)(object)go == (Object)null)
{
yield break;
}
go.layer = 9;
foreach (Transform item in go.transform)
{
Transform child = item;
((Component)child).gameObject.layer = 9;
}
yield return (object)new WaitForFixedUpdate();
Transform transform = go.transform;
transform.position += new Vector3(128f, 128f, 128f);
yield return (object)new WaitForSeconds(0.1f);
try
{
NetworkIdentity nid = go.GetComponent<NetworkIdentity>();
if ((Object)(object)nid != (Object)null && nid.netId != 0 && NetworkServer.spawned.ContainsKey(nid.netId))
{
NetworkServer.Destroy(go);
}
else
{
Object.Destroy((Object)(object)go);
}
}
catch
{
}
}
public IEnumerator Resurrect(PlayerMultiplayerInputManager IM)
{
IM.moveSet = IM.multiplayerRoomPlayer.selectedMoveSet;
IM.equippedEquipment = IM.multiplayerRoomPlayer.selectedEquipment.ToList();
yield return (object)new WaitForSecondsRealtime(0.4f);
IM.AttemptToCreatePlayerCharacter();
yield return (object)new WaitForSecondsRealtime(0.2f);
Type ftpType = AccessTools.TypeByName("FeelThePunch");
if (!(ftpType != null))
{
yield break;
}
object instance = ftpType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (instance != null)
{
MethodInfo method = ftpType.GetMethod("DelayedSetup", BindingFlags.Instance | BindingFlags.Public);
if (method != null)
{
((MonoBehaviour)Instance).StartCoroutine((IEnumerator)method.Invoke(instance, null));
}
}
}
private static PlayerMultiplayerInputManager FindInputManager(PlayerHealth player)
{
if ((Object)(object)player == (Object)null)
{
return null;
}
NetworkIdentity nid = ((Component)player).GetComponent<NetworkIdentity>();
if ((Object)(object)nid == (Object)null)
{
return null;
}
return ((IEnumerable<PlayerMultiplayerInputManager>)Resources.FindObjectsOfTypeAll<PlayerMultiplayerInputManager>()).FirstOrDefault((Func<PlayerMultiplayerInputManager, bool>)delegate(PlayerMultiplayerInputManager mgr)
{
try
{
Traverse<uint> val = Traverse.Create((object)mgr).Field<uint>("playerHealthIdentity");
return val != null && val.Value == nid.netId;
}
catch
{
return false;
}
});
}
private static void ResetInputManager(PlayerMultiplayerInputManager mgr)
{
if ((Object)(object)mgr == (Object)null)
{
return;
}
Debug.Log((object)"[RespawnMod-DEBUG] Resetting InputManager fields");
try
{
Traverse val = Traverse.Create((object)mgr);
val.Field("playerHealth").SetValue((object)null);
val.Field("playerHealthInitialized").SetValue((object)false);
val.Field("playerHealthIdentity").SetValue((object)0u);
MultiplayerRoomPlayer multiplayerRoomPlayer = mgr.multiplayerRoomPlayer;
if ((Object)(object)multiplayerRoomPlayer != (Object)null)
{
Traverse val2 = Traverse.Create((object)multiplayerRoomPlayer);
try
{
val2.Field("joinedMidGame").SetValue((object)false);
return;
}
catch
{
return;
}
}
}
catch (Exception arg)
{
Debug.LogWarning((object)$"[RespawnMod-DEBUG] Error resetting input manager: {arg}");
}
}
private static void SetAllJointStrengths(PlayerHealth player, float strength)
{
JointStrength[] componentsInChildren = ((Component)player).GetComponentsInChildren<JointStrength>();
foreach (JointStrength val in componentsInChildren)
{
try
{
val.SetStrengthPercent(strength);
}
catch
{
}
}
}
private static void SetBallHolderJointStrength(PlayerHealth player, float strengthPercent)
{
//IL_0018: 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_002b: 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_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)player.ballHolderjoint == (Object)null))
{
JointDrive val = default(JointDrive);
JointDrive angularXDrive = player.ballHolderjoint.angularXDrive;
((JointDrive)(ref val)).positionSpring = ((JointDrive)(ref angularXDrive)).positionSpring * (strengthPercent / 100f);
angularXDrive = player.ballHolderjoint.angularXDrive;
((JointDrive)(ref val)).positionDamper = ((JointDrive)(ref angularXDrive)).positionDamper * (strengthPercent / 100f);
angularXDrive = player.ballHolderjoint.angularXDrive;
((JointDrive)(ref val)).maximumForce = ((JointDrive)(ref angularXDrive)).maximumForce;
JointDrive val2 = val;
player.ballHolderjoint.angularXDrive = val2;
player.ballHolderjoint.angularYZDrive = val2;
}
}
[HarmonyPatch(typeof(MultiplayerRoomPlayer), "GetJoinedMidGame")]
[HarmonyPrefix]
private static bool ForceGetJoinedMidGameFalse(ref bool __result)
{
__result = false;
return false;
}
[HarmonyPatch(typeof(PlayerHealth), "HandleDeath")]
[HarmonyPrefix]
private static bool PreventHandleDeath()
{
return false;
}
[HarmonyPatch(typeof(PlayerHealth), "HandleClientDeath")]
[HarmonyPrefix]
private static bool PreventClientDeath()
{
return false;
}
[HarmonyPatch(typeof(PlayerInputManager), "HandlePlayerDeath")]
[HarmonyPrefix]
private static bool PreventInputDisabling()
{
return false;
}
[HarmonyPatch(typeof(PlayerAnimator), "PlayerDied")]
[HarmonyPrefix]
private static bool PreventAnimatorDeathState()
{
return false;
}
}