Decompiled source of Better DeadHead v1.0.3

DeadHeadWASD.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DeadHeadWASD")]
[assembly: AssemblyTitle("DeadHeadWASD")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Empress.DeadHeadDrive
{
	[BepInPlugin("Empress.DeadHeadDrive", "DeadHeadDrive", "1.1.2")]
	public class DeadHeadDrivePlugin : BaseUnityPlugin, IOnEventCallback, IConnectionCallbacks, IInRoomCallbacks
	{
		internal struct InputState
		{
			public Vector2 Dir;

			public float Time;
		}

		public const string PluginGuid = "Empress.DeadHeadDrive";

		public const string PluginName = "DeadHeadDrive";

		public const string PluginVersion = "1.1.2";

		internal const byte EventCode = 177;

		internal static ConfigEntry<bool> EnableWASD = null;

		internal static ConfigEntry<float> Acceleration = null;

		internal static ConfigEntry<float> MaxSpeed = null;

		internal static ConfigEntry<float> EnergyDrainMultiplier = null;

		internal static ConfigEntry<float> ExtraDrainWhileMoving = null;

		private static readonly Dictionary<int, InputState> Inputs = new Dictionary<int, InputState>();

		internal static DeadHeadDrivePlugin Instance { get; private set; } = null;


		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			EnableWASD = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "EnableWASD", true, "Allow WASD movement for the spectated death head.");
			Acceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "Acceleration", 20f, "Acceleration (m/s^2) applied while holding WASD. Uses ForceMode.Acceleration.");
			MaxSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "MaxSpeed", 7.5f, "Horizontal speed cap for the head when using WASD.");
			EnergyDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Energy", "EnergyDrainMultiplier", 0.5f, "Multiplier on head-energy drain (<1 slower, >1 faster).");
			ExtraDrainWhileMoving = ((BaseUnityPlugin)this).Config.Bind<float>("Energy", "ExtraDrainWhileMoving", 0f, "Extra energy drained per second while moving with WASD.");
			GameObject val = new GameObject("__DeadHeadDrive_Runtime")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)(object)val);
			val.AddComponent<DeadHeadDriveRuntime>();
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} ready");
		}

		private void OnDestroy()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll(Assembly.GetExecutingAssembly());
		}

		internal static void ClearInputs()
		{
			Inputs.Clear();
		}

		public void OnEvent(EventData photonEvent)
		{
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			if (!DeadHeadDriveRuntime.RuntimeActive || !PhotonNetwork.IsMasterClient || photonEvent.Code != 177 || !(photonEvent.CustomData is object[] array) || array.Length < 3)
			{
				return;
			}
			int num = (int)array[0];
			float num2 = (float)array[1];
			float num3 = (float)array[2];
			PhotonView val = PhotonView.Find(num);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			PlayerDeathHead component = ((Component)val).GetComponent<PlayerDeathHead>();
			if (Object.op_Implicit((Object)(object)component))
			{
				PlayerAvatar playerAvatar = component.playerAvatar;
				if (Object.op_Implicit((Object)(object)playerAvatar) && Object.op_Implicit((Object)(object)playerAvatar.photonView) && playerAvatar.photonView.OwnerActorNr == photonEvent.Sender)
				{
					Inputs[num] = new InputState
					{
						Dir = new Vector2(num2, num3),
						Time = Time.time
					};
				}
			}
		}

		public void OnConnected()
		{
		}

		public void OnConnectedToMaster()
		{
		}

		public void OnDisconnected(DisconnectCause cause)
		{
			DeadHeadDriveRuntime.FullDeactivate();
		}

		public void OnRegionListReceived(RegionHandler regionHandler)
		{
		}

		public void OnCustomAuthenticationResponse(Dictionary<string, object> data)
		{
		}

		public void OnCustomAuthenticationFailed(string debugMessage)
		{
		}

		public void OnJoinedRoom()
		{
			DeadHeadDriveRuntime.TryActivate();
		}

		public void OnLeftRoom()
		{
			DeadHeadDriveRuntime.FullDeactivate();
		}

		public void OnPlayerEnteredRoom(Player newPlayer)
		{
		}

		public void OnPlayerLeftRoom(Player otherPlayer)
		{
		}

		public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
		}

		public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		public void OnMasterClientSwitched(Player newMasterClient)
		{
		}

		internal static bool TryGetInput(PlayerDeathHead head, out Vector2 dir)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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)
			dir = Vector2.zero;
			if (!DeadHeadDriveRuntime.RuntimeActive)
			{
				return false;
			}
			PhotonView photonView = head.photonView;
			if (!Object.op_Implicit((Object)(object)photonView))
			{
				return false;
			}
			if (!Inputs.TryGetValue(photonView.ViewID, out var value))
			{
				return false;
			}
			if (Time.time - value.Time > 0.25f)
			{
				return false;
			}
			dir = value.Dir;
			return ((Vector2)(ref dir)).sqrMagnitude > 0.0001f;
		}
	}
	internal sealed class DeadHeadDriveRuntime : MonoBehaviour
	{
		private static DeadHeadDriveRuntime? _inst;

		private bool _wasActive;

		internal static bool RuntimeActive { get; private set; }

		private void Awake()
		{
			if (Object.op_Implicit((Object)(object)_inst) && (Object)(object)_inst != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			_inst = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			SceneManager.activeSceneChanged += OnSceneChanged;
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= OnSceneChanged;
			FullDeactivate();
		}

		private static void OnSceneChanged(Scene a, Scene b)
		{
			FullDeactivate();
		}

		private void OnDisable()
		{
			FullDeactivate();
		}

		private void Update()
		{
			try
			{
				if (!RuntimeReady())
				{
					if (_wasActive)
					{
						FullDeactivate();
					}
				}
				else if (!_wasActive)
				{
					TryActivate();
				}
			}
			catch
			{
			}
		}

		internal static bool RuntimeReady()
		{
			if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom)
			{
				return false;
			}
			if (SemiFunc.MenuLevel())
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)LevelGenerator.Instance) || !LevelGenerator.Instance.Generated)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)PlayerAvatar.instance))
			{
				return false;
			}
			return true;
		}

		internal static void TryActivate()
		{
			DeadHeadDriveRuntime inst = _inst;
			if (Object.op_Implicit((Object)(object)inst) && !inst._wasActive && RuntimeReady())
			{
				PhotonNetwork.AddCallbackTarget((object)DeadHeadDrivePlugin.Instance);
				PhotonNetwork.AddCallbackTarget((object)DeadHeadDrivePlugin.Instance);
				PhotonNetwork.AddCallbackTarget((object)DeadHeadDrivePlugin.Instance);
				RuntimeActive = true;
				inst._wasActive = true;
				DeadHeadDrivePlugin.Logger.LogDebug((object)"[DeadHeadDrive] Runtime activated (in-room, level generated).");
			}
		}

		internal static void FullDeactivate()
		{
			DeadHeadDriveRuntime inst = _inst;
			if (!Object.op_Implicit((Object)(object)inst))
			{
				DeadHeadDrivePlugin.ClearInputs();
				return;
			}
			if (!inst._wasActive && !RuntimeActive)
			{
				DeadHeadDrivePlugin.ClearInputs();
				return;
			}
			RuntimeActive = false;
			inst._wasActive = false;
			PhotonNetwork.RemoveCallbackTarget((object)DeadHeadDrivePlugin.Instance);
			PhotonNetwork.RemoveCallbackTarget((object)DeadHeadDrivePlugin.Instance);
			PhotonNetwork.RemoveCallbackTarget((object)DeadHeadDrivePlugin.Instance);
			DeadHeadDrivePlugin.ClearInputs();
			DeadHeadDrivePlugin.Logger.LogDebug((object)"[DeadHeadDrive] Runtime deactivated (menu/lobby or scene change).");
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "HeadEnergyLogic")]
	public static class Patch_SpectateCamera_HeadEnergyLogic
	{
		private static FieldInfo? f_headEnergy;

		private static void Prepare()
		{
			f_headEnergy = AccessTools.Field(typeof(SpectateCamera), "headEnergy");
		}

		private static void Prefix(SpectateCamera __instance, out float __state)
		{
			__state = GetEnergy(__instance);
		}

		private static void Postfix(SpectateCamera __instance, float __state)
		{
			if (DeadHeadDriveRuntime.RuntimeActive)
			{
				float energy = GetEnergy(__instance);
				float num = Mathf.Max(0f, DeadHeadDrivePlugin.EnergyDrainMultiplier.Value);
				if (energy < __state && num != 1f)
				{
					float num2 = __state - energy;
					float num3 = num2 * num;
					float num4 = num2 - num3;
					SetEnergy(__instance, Mathf.Clamp01(energy + num4));
				}
			}
		}

		private static float GetEnergy(SpectateCamera inst)
		{
			if (f_headEnergy == null)
			{
				f_headEnergy = AccessTools.Field(typeof(SpectateCamera), "headEnergy");
			}
			return ((object)f_headEnergy == null) ? 0f : ((float)f_headEnergy.GetValue(inst));
		}

		private static void SetEnergy(SpectateCamera inst, float value)
		{
			if (f_headEnergy == null)
			{
				f_headEnergy = AccessTools.Field(typeof(SpectateCamera), "headEnergy");
			}
			f_headEnergy?.SetValue(inst, value);
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Update")]
	public static class Patch_PlayerDeathHead_Update_SendInput
	{
		private static FieldInfo? f_spectated;

		private static FieldInfo? f_overrideSpectated;

		private static void Prepare()
		{
			f_spectated = AccessTools.Field(typeof(PlayerDeathHead), "spectated");
			f_overrideSpectated = AccessTools.Field(typeof(PlayerDeathHead), "overrideSpectated");
		}

		private static void Postfix(PlayerDeathHead __instance)
		{
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			if (!DeadHeadDriveRuntime.RuntimeActive || !DeadHeadDrivePlugin.EnableWASD.Value || (Object)(object)__instance.playerAvatar == (Object)null || !__instance.playerAvatar.isLocal)
			{
				return;
			}
			object obj = f_spectated?.GetValue(__instance);
			if (!(obj is bool) || !(bool)obj)
			{
				return;
			}
			obj = f_overrideSpectated?.GetValue(__instance);
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0)
			{
				return;
			}
			SpectateCamera instance = SpectateCamera.instance;
			if ((Object)(object)instance != (Object)null)
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(SpectateCamera), "headEnergy");
				if (fieldInfo != null && (float)fieldInfo.GetValue(instance) <= 0f)
				{
					return;
				}
			}
			float num2 = SemiFunc.InputMovementX();
			float num3 = SemiFunc.InputMovementY();
			if (Mathf.Abs(num2) < 0.01f && Mathf.Abs(num3) < 0.01f)
			{
				Send(__instance, 0f, 0f);
				return;
			}
			Transform transform = ((Component)__instance.playerAvatar.localCamera).transform;
			Vector3 forward = transform.forward;
			forward.y = 0f;
			((Vector3)(ref forward)).Normalize();
			Vector3 right = transform.right;
			right.y = 0f;
			((Vector3)(ref right)).Normalize();
			Vector3 val = forward * num3 + right * num2;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				Send(__instance, 0f, 0f);
				return;
			}
			((Vector3)(ref val)).Normalize();
			Send(__instance, val.x, val.z);
			float num4 = Mathf.Max(0f, DeadHeadDrivePlugin.ExtraDrainWhileMoving.Value);
			if (num4 > 0f && (Object)(object)instance != (Object)null)
			{
				FieldInfo fieldInfo2 = AccessTools.Field(typeof(SpectateCamera), "headEnergy");
				if (fieldInfo2 != null)
				{
					float num5 = (float)fieldInfo2.GetValue(instance);
					num5 = Mathf.Clamp01(num5 - num4 * Time.deltaTime);
					fieldInfo2.SetValue(instance, num5);
				}
			}
		}

		private static void Send(PlayerDeathHead inst, float dx, float dz)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (DeadHeadDriveRuntime.RuntimeActive)
			{
				PhotonView photonView = inst.photonView;
				if (Object.op_Implicit((Object)(object)photonView))
				{
					object[] array = new object[3] { photonView.ViewID, dx, dz };
					RaiseEventOptions val = new RaiseEventOptions
					{
						Receivers = (ReceiverGroup)2
					};
					PhotonNetwork.RaiseEvent((byte)177, (object)array, val, SendOptions.SendUnreliable);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "FixedUpdate")]
	public static class Patch_PlayerDeathHead_FixedUpdate_Apply
	{
		private static FieldInfo? f_spectated;

		private static FieldInfo? f_overrideSpectated;

		private static FieldInfo? f_physGrabObject;

		private static FieldInfo? f_rb;

		private static void Prepare()
		{
			f_spectated = AccessTools.Field(typeof(PlayerDeathHead), "spectated");
			f_overrideSpectated = AccessTools.Field(typeof(PlayerDeathHead), "overrideSpectated");
			f_physGrabObject = AccessTools.Field(typeof(PlayerDeathHead), "physGrabObject");
			f_rb = AccessTools.Field(typeof(PhysGrabObject), "rb");
		}

		private static void Postfix(PlayerDeathHead __instance)
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			if (!DeadHeadDriveRuntime.RuntimeActive || !PhotonNetwork.IsMasterClient || !DeadHeadDrivePlugin.EnableWASD.Value)
			{
				return;
			}
			object obj = f_spectated?.GetValue(__instance);
			if (!(obj is bool) || !(bool)obj)
			{
				return;
			}
			obj = f_overrideSpectated?.GetValue(__instance);
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0 || !DeadHeadDrivePlugin.TryGetInput(__instance, out var dir))
			{
				return;
			}
			object obj2 = f_physGrabObject?.GetValue(__instance);
			if (obj2 == null)
			{
				return;
			}
			object? obj3 = f_rb?.GetValue(obj2);
			Rigidbody val = (Rigidbody)((obj3 is Rigidbody) ? obj3 : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				float num2 = Mathf.Max(0f, DeadHeadDrivePlugin.Acceleration.Value);
				val.AddForce(new Vector3(dir.x, 0f, dir.y) * num2, (ForceMode)5);
				float num3 = Mathf.Max(0f, DeadHeadDrivePlugin.MaxSpeed.Value);
				Vector3 velocity = val.velocity;
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(velocity.x, 0f, velocity.z);
				if (((Vector3)(ref val2)).magnitude > num3)
				{
					Vector3 val3 = ((Vector3)(ref val2)).normalized * num3;
					val.velocity = new Vector3(val3.x, velocity.y, val3.z);
				}
			}
		}
	}
}