Decompiled source of StatueLife v0.2.0

StatueLife.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using HarmonyLib;
using Peak;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Voice.Unity;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace StatueLife;

[BepInPlugin("local.statuelife", "StatueLife", "0.2.0")]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class FrozenBody
	{
		private readonly Rigidbody[] rigs;

		private readonly RigidbodyConstraints[] constraints;

		private readonly Vector3[] positions;

		private readonly Quaternion[] rotations;

		private readonly Animator animator;

		private readonly float speed;

		internal FrozenBody(Character c)
		{
			rigs = (from p in c.refs.ragdoll.partDict.Values
				select ((Component)p).GetComponent<Rigidbody>() into r
				where (Object)(object)r != (Object)null
				select r).Distinct().ToArray();
			constraints = rigs.Select((Rigidbody r) => r.constraints).ToArray();
			positions = rigs.Select((Rigidbody r) => r.position).ToArray();
			rotations = rigs.Select((Rigidbody r) => r.rotation).ToArray();
			animator = c.refs.animator;
			speed = (((Object)(object)animator == (Object)null) ? 1f : animator.speed);
			Hold();
		}

		internal void Hold()
		{
			//IL_003a: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < rigs.Length; i++)
			{
				if (!((Object)(object)rigs[i] == (Object)null))
				{
					rigs[i].constraints = (RigidbodyConstraints)126;
					rigs[i].position = positions[i];
					rigs[i].rotation = rotations[i];
					if (!rigs[i].isKinematic)
					{
						rigs[i].linearVelocity = Vector3.zero;
						rigs[i].angularVelocity = Vector3.zero;
					}
				}
			}
			if ((Object)(object)animator != (Object)null)
			{
				animator.speed = 0f;
			}
		}

		internal void Restore()
		{
			for (int i = 0; i < rigs.Length; i++)
			{
				if ((Object)(object)rigs[i] != (Object)null)
				{
					rigs[i].constraints = constraints[i];
				}
			}
			if ((Object)(object)animator != (Object)null)
			{
				animator.speed = speed;
			}
		}
	}

	internal static Plugin Instance;

	internal static volatile bool LocalFrozen;

	internal static bool Curing;

	internal static readonly HashSet<Character> GivingUp = new HashSet<Character>();

	private readonly Dictionary<Character, FrozenBody> bodies = new Dictionary<Character, FrozenBody>();

	private Harmony harmony;

	private readonly HashSet<int> shatteringViews = new HashSet<int>();

	private void Awake()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		Instance = this;
		harmony = new Harmony("local.statuelife");
		try
		{
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"StatueLife 0.2.0 loaded (local player only). Friends do not need the mod. Y = shatter; blowgun = cure.");
		}
		catch (Exception ex)
		{
			harmony.UnpatchSelf();
			((BaseUnityPlugin)this).Logger.LogError((object)("StatueLife could not install its hooks; disabled. " + ex));
			((Behaviour)this).enabled = false;
		}
	}

	internal static bool Frozen(Character c)
	{
		if ((Object)(object)c != (Object)null && c.IsLocal && ((MonoBehaviourPun)c).photonView.IsMine && !c.isBot && (Object)(object)c.data != (Object)null && !c.data.dead && c.data.shouldPetrify)
		{
			return !GivingUp.Contains(c);
		}
		return false;
	}

	private void Update()
	{
		Character localCharacter = Character.localCharacter;
		LocalFrozen = Frozen(localCharacter);
		if (LocalFrozen && Application.isFocused && Keyboard.current != null && ((ButtonControl)Keyboard.current.yKey).wasPressedThisFrame && !((Object)(object)GUIManager.instance == (Object)null) && !GUIManager.instance.windowBlockingInput && !GUIManager.instance.wheelActive)
		{
			ExecuteGiveUp(localCharacter);
		}
	}

	private void ExecuteGiveUp(Character c)
	{
		if (Frozen(c))
		{
			GivingUp.Add(c);
			Release(c);
			LocalFrozen = false;
			((MonoBehaviourPun)c).photonView.RPC("RPCA_Die", (RpcTarget)0, new object[0]);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Statue shattered by give-up: " + ((MonoBehaviourPun)c).photonView.ViewID));
		}
	}

	private void LateUpdate()
	{
		foreach (Character item in new List<Character>(bodies.Keys))
		{
			if (!Frozen(item))
			{
				Release(item);
			}
		}
		foreach (Character item2 in new List<Character>(GivingUp))
		{
			if ((Object)(object)item2 == (Object)null || ((Object)(object)item2.data != (Object)null && !item2.data.dead && !item2.data.shouldPetrify))
			{
				GivingUp.Remove(item2);
			}
		}
		Character[] array = Character.AllCharacters.ToArray();
		foreach (Character val in array)
		{
			if (Frozen(val))
			{
				if (!bodies.TryGetValue(val, out var value))
				{
					value = new FrozenBody(val);
					bodies.Add(val, value);
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Living statue: " + ((MonoBehaviourPun)val).photonView.ViewID));
				}
				value.Hold();
			}
		}
	}

	internal void Release(Character c)
	{
		if (bodies.TryGetValue(c, out var value))
		{
			value.Restore();
			bodies.Remove(c);
		}
	}

	internal static void Cure(Character c)
	{
		if (Frozen(c) && ((MonoBehaviourPun)c).photonView.IsMine)
		{
			Curing = true;
			try
			{
				c.data.SetPetrify(0);
			}
			finally
			{
				Curing = false;
			}
			c.data.passOutValue = 0f;
			c.refs.afflictions.killedByDagger = false;
			AccessTools.Method(typeof(CharacterCustomization), "ClearPetrify", (Type[])null, (Type[])null).Invoke(c.refs.customization, null);
			Instance.Release(c);
			if (c.IsLocal)
			{
				LocalFrozen = false;
			}
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)("Blowgun cured statue: " + ((MonoBehaviourPun)c).photonView.ViewID));
		}
	}

	internal IEnumerator Shatter(PetrifiedScout scout)
	{
		if ((Object)(object)scout == (Object)null || !shatteringViews.Add(((MonoBehaviourPun)scout).photonView.ViewID))
		{
			yield break;
		}
		yield return null;
		if (!((Object)(object)scout == (Object)null))
		{
			int viewId = ((MonoBehaviourPun)scout).photonView.ViewID;
			((MonoBehaviourPun)scout).photonView.RPC("RPC_BreakPetrifiedScout", (RpcTarget)0, new object[0]);
			if (((MonoBehaviourPun)scout).photonView.IsMine || PhotonNetwork.IsMasterClient)
			{
				PhotonNetwork.Destroy(((Component)scout).gameObject);
			}
			shatteringViews.Remove(viewId);
		}
	}

	private void OnGUI()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		if (LocalFrozen)
		{
			GUI.Box(new Rect((float)Screen.width / 2f - 240f, (float)(Screen.height - 100), 480f, 64f), "PETRIFIED — You are still alive.\nA friend's blowgun cures you. Y = shatter and die.\nVoice chat is muted while petrified.");
		}
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		foreach (FrozenBody value in bodies.Values)
		{
			value.Restore();
		}
		bodies.Clear();
		GivingUp.Clear();
		shatteringViews.Clear();
		LocalFrozen = false;
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}
}
[HarmonyPatch(typeof(Character), "HandleLife")]
internal static class LifePatch
{
	private static bool Prefix(Character __instance)
	{
		if (!Plugin.Frozen(__instance))
		{
			return true;
		}
		__instance.data.passOutValue = 1f;
		return false;
	}
}
[HarmonyPatch]
internal static class DeathPatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		try
		{
			string[] array = new string[7] { "Die", "DieInstantly", "DieInstantlyLocal", "RPCA_Die", "RPCA_SetDead", "PassOut", "RPCA_PassOut" };
			foreach (string name in array)
			{
				yield return AccessTools.Method(typeof(Character), name, (Type[])null, (Type[])null);
			}
		}
		finally
		{
		}
	}

	private static bool Prefix(Character __instance)
	{
		return !Plugin.Frozen(__instance);
	}
}
[HarmonyPatch(typeof(CharacterData), "SetPetrify")]
internal static class PermanentPatch
{
	private static bool Prefix(CharacterData __instance, int __0, ref bool __state)
	{
		Character component = ((Component)__instance).GetComponent<Character>();
		__state = (Object)(object)component != (Object)null && component.IsLocal && __instance.shouldPetrify;
		if (!Plugin.Curing && Plugin.Frozen(component))
		{
			return __0 >= 100;
		}
		return true;
	}

	private static void Postfix(CharacterData __instance, bool __state)
	{
		if (!__state || __instance.shouldPetrify)
		{
			return;
		}
		Character component = ((Component)__instance).GetComponent<Character>();
		if (!((Object)(object)component == (Object)null))
		{
			__instance.passOutValue = 0f;
			if ((Object)(object)component.refs.customization != (Object)null)
			{
				AccessTools.Field(typeof(CharacterCustomization), "petrifyStarted").SetValue(component.refs.customization, false);
			}
			Plugin.Instance.Release(component);
			if (component.IsLocal)
			{
				Plugin.LocalFrozen = false;
			}
		}
	}
}
[HarmonyPatch(typeof(CharacterInput), "Sample")]
internal static class InputPatch
{
	private static readonly FieldInfo[] Buttons = (from f in typeof(CharacterInput).GetFields(BindingFlags.Instance | BindingFlags.Public)
		where f.FieldType == typeof(bool) && f.Name != "pauseWasPressed" && f.Name != "itemSwitchBlocked"
		select f).ToArray();

	private static void Postfix(CharacterInput __instance)
	{
		//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)
		Character localCharacter = Character.localCharacter;
		if (Plugin.Frozen(localCharacter) && object.ReferenceEquals(localCharacter.input, __instance))
		{
			FieldInfo[] buttons = Buttons;
			foreach (FieldInfo fieldInfo in buttons)
			{
				fieldInfo.SetValue(__instance, false);
			}
			__instance.movementInput = Vector2.zero;
			__instance.scrollInput = 0f;
		}
	}
}
[HarmonyPatch]
internal static class MovePatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		try
		{
			string[] array = new string[5] { "CheckMovement", "CheckJump", "CheckSprint", "CheckGravity", "CheckStand" };
			foreach (string name in array)
			{
				yield return AccessTools.Method(typeof(Character), name, (Type[])null, (Type[])null);
			}
		}
		finally
		{
		}
	}

	private static void Postfix(Character __instance, ref bool __result)
	{
		if (Plugin.Frozen(__instance))
		{
			__result = false;
		}
	}
}
[HarmonyPatch]
internal static class SlotsPatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		try
		{
			string[] array = new string[4] { "SelectSlotWasPressed", "SelectSlotIsPressed", "HotbarKeyWasPressed", "HotbarKeyIsPressed" };
			foreach (string name in array)
			{
				yield return AccessTools.Method(typeof(CharacterInput), name, (Type[])null, (Type[])null);
			}
		}
		finally
		{
		}
	}

	private static void Postfix(CharacterInput __instance, ref bool __result)
	{
		Character localCharacter = Character.localCharacter;
		if (Plugin.Frozen(localCharacter) && object.ReferenceEquals(localCharacter.input, __instance))
		{
			__result = false;
		}
	}
}
[HarmonyPatch(typeof(CharacterData), "set_dead")]
internal static class DeadSetterPatch
{
	private static bool Prefix(CharacterData __instance, bool __0)
	{
		if (__0)
		{
			return !Plugin.Frozen(((Component)__instance).GetComponent<Character>());
		}
		return true;
	}
}
[HarmonyPatch(typeof(Action_RaycastDart), "RPC_DartImpact")]
internal static class DartPatch
{
	private static void Prefix(int __0, ref Character __state)
	{
		Character val = default(Character);
		if (Character.GetCharacterWithPhotonID(__0, ref val) && Plugin.Frozen(val) && ((MonoBehaviourPun)val).photonView.IsMine)
		{
			__state = val;
		}
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		MethodInfo original = AccessTools.Method(typeof(CharacterAfflictions), "AddAffliction", new Type[2]
		{
			typeof(Affliction),
			typeof(bool)
		}, (Type[])null);
		MethodInfo replacement = AccessTools.Method(typeof(DartPatch), "ApplyDartAffliction", (Type[])null, (Type[])null);
		int replaced = 0;
		foreach (CodeInstruction instruction in instructions)
		{
			if (CodeInstructionExtensions.Calls(instruction, original))
			{
				instruction.opcode = OpCodes.Call;
				instruction.operand = replacement;
				replaced++;
			}
			yield return instruction;
		}
		if (replaced != 1)
		{
			throw new InvalidOperationException("Unexpected blowgun implementation; refusing partial patch.");
		}
	}

	private static void ApplyDartAffliction(CharacterAfflictions target, Affliction affliction, bool fromRPC)
	{
		Character component = ((Component)target).GetComponent<Character>();
		if (!Plugin.Frozen(component))
		{
			target.AddAffliction(affliction, fromRPC);
		}
	}

	private static void Postfix(Character __state)
	{
		if ((Object)(object)__state != (Object)null)
		{
			Plugin.Cure(__state);
		}
	}
}
[HarmonyPatch(typeof(PetrifiedScout), "RPC_SpawnPetrifiedScout")]
internal static class ShatterPatch
{
	private static void Postfix(PetrifiedScout __instance, int __0)
	{
		Character val = default(Character);
		if (Character.GetCharacterWithPhotonID(__0, ref val) && val.IsLocal && Plugin.GivingUp.Contains(val))
		{
			((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.Instance.Shatter(__instance));
		}
	}
}
[HarmonyPatch(typeof(CharacterVoiceHandler), "PushToTalk")]
internal static class TransmitPatch
{
	private static void Postfix(CharacterVoiceHandler __instance, Character ___m_character, Recorder ___m_Recorder, ref bool ___m_currentlyTransmitting)
	{
		if (Plugin.Frozen(___m_character))
		{
			__instance.transmitting = false;
			___m_currentlyTransmitting = false;
			if ((Object)(object)___m_Recorder != (Object)null)
			{
				___m_Recorder.TransmitEnabled = false;
			}
		}
	}
}
[HarmonyPatch(typeof(CharacterVoiceHandler), "OnAudioFilterRead")]
internal static class ReceivePatch
{
	private static void Postfix(float[] __0)
	{
		if (Plugin.LocalFrozen && __0 != null)
		{
			Array.Clear(__0, 0, __0.Length);
		}
	}
}