Decompiled source of Jester Adrenaline v1.1.0

BepInEx\plugins\JesterAdrenaline\JesterAdrenaline.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("JesterAdrenaline")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("JesterAdrenaline")]
[assembly: AssemblyTitle("JesterAdrenaline")]
[assembly: AssemblyVersion("1.0.0.0")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[BepInPlugin("wiktor.jesterstamina", "Jester Adrenaline", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(JesterAI), "Update")]
	private static class JesterUpdatePatch
	{
		private static void Postfix(JesterAI __instance)
		{
			ReportJesterState(__instance);
		}
	}

	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	private static class PlayerUpdatePatch
	{
		private static void Postfix(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)(object)StartOfRound.Instance?.localPlayerController)
			{
				UpdateNetworking();
				UpdatePlayerBoost(__instance);
			}
		}
	}

	private sealed class ManualLogSourceAdapter
	{
		private readonly ManualLogSource source;

		public ManualLogSourceAdapter(ManualLogSource source)
		{
			this.source = source;
		}

		public void LogInfo(string message)
		{
			source.LogInfo((object)message);
		}
	}

	[CompilerGenerated]
	private static class <>O
	{
		public static HandleNamedMessageDelegate <0>__OnChaseStateMessage;
	}

	private const string ModGuid = "wiktor.jesterstamina";

	private const string ModName = "Jester Adrenaline";

	private const string ModVersion = "1.1.0";

	private const int JesterChasingState = 2;

	private const string ChaseStateMessageName = "wiktor.jesterstamina.ChaseState";

	private const float ChaseSignalTimeout = 0.75f;

	private const float NetworkSendInterval = 0.15f;

	private static readonly FieldInfo HasEnteredChaseModeFullyField = typeof(JesterAI).GetField("hasEnteredChaseModeFully", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static ConfigEntry<float> speedMultiplier;

	private static ConfigEntry<bool> debugLogs;

	private static ManualLogSourceAdapter logger;

	private static readonly Harmony Harmony = new Harmony("wiktor.jesterstamina");

	private static PlayerControllerB boostedPlayer;

	private static float originalMovementSpeed;

	private static float appliedMovementSpeed;

	private static bool hasAppliedSpeedBoost;

	private static bool wasJesterChasing;

	private static float lastJesterChaseTime = -999f;

	private static bool networkJesterChasing;

	private static float lastNetworkChaseSignalTime = -999f;

	private static float nextNetworkSendTime;

	private static bool lastSentChaseState;

	private static bool hasSentChaseState;

	private static bool messageRegistered;

	private static NetworkManager registeredNetworkManager;

	private static float nextDebugTime;

	private void Awake()
	{
		logger = new ManualLogSourceAdapter(((BaseUnityPlugin)this).Logger);
		speedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SpeedMultiplier", 1.15f, "How much faster the local player runs while a Jester is chasing. 1.15 = 15% faster.");
		debugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogs", false, "Enable extra logs when Jester chase mode starts or ends.");
		Harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Jester Adrenaline 1.1.0 loaded.");
	}

	private static bool IsJesterChasingRecently()
	{
		NetworkManager singleton = NetworkManager.Singleton;
		if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
		{
			return false;
		}
		if (singleton.IsHost || singleton.IsServer)
		{
			return Time.time - lastJesterChaseTime <= 0.75f;
		}
		if (networkJesterChasing)
		{
			return Time.time - lastNetworkChaseSignalTime <= 0.75f;
		}
		return false;
	}

	private static void UpdatePlayerBoost(PlayerControllerB player)
	{
		if ((Object)(object)player == (Object)null)
		{
			RemoveBoost();
			return;
		}
		bool flag = IsJesterChasingRecently();
		if (flag)
		{
			ApplyBoost(player);
		}
		else
		{
			RemoveBoost();
		}
		if (debugLogs.Value && flag != wasJesterChasing)
		{
			logger.LogInfo(flag ? "Jester chase detected. Stamina and speed boost enabled." : "Jester chase ended. Speed boost removed.");
		}
		wasJesterChasing = flag;
	}

	private static void ReportJesterState(JesterAI jester)
	{
		if ((Object)(object)jester == (Object)null)
		{
			return;
		}
		NetworkManager singleton = NetworkManager.Singleton;
		if ((Object)(object)singleton == (Object)null || !singleton.IsListening || (!singleton.IsHost && !singleton.IsServer))
		{
			return;
		}
		bool flag = default(bool);
		int num;
		if (HasEnteredChaseModeFullyField != null)
		{
			object value = HasEnteredChaseModeFullyField.GetValue(jester);
			if (value is bool)
			{
				flag = (bool)value;
				num = 1;
			}
			else
			{
				num = 0;
			}
		}
		else
		{
			num = 0;
		}
		bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		bool flag3 = ((EnemyAI)jester).currentBehaviourStateIndex >= 2 || flag2;
		if (flag3)
		{
			lastJesterChaseTime = Time.time;
		}
		if (debugLogs.Value && Time.time >= nextDebugTime)
		{
			nextDebugTime = Time.time + 2f;
			logger.LogInfo($"Jester patched update; state={((EnemyAI)jester).currentBehaviourStateIndex}, hasEnteredChaseModeFully={flag2}, chasing={flag3}");
		}
	}

	private static void UpdateNetworking()
	{
		//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)
		//IL_007f: Expected O, but got Unknown
		NetworkManager singleton = NetworkManager.Singleton;
		if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null)
		{
			ResetNetworking();
			return;
		}
		if (!messageRegistered || (Object)(object)registeredNetworkManager != (Object)(object)singleton)
		{
			NetworkManager obj = registeredNetworkManager;
			if (obj != null)
			{
				CustomMessagingManager customMessagingManager = obj.CustomMessagingManager;
				if (customMessagingManager != null)
				{
					customMessagingManager.UnregisterNamedMessageHandler("wiktor.jesterstamina.ChaseState");
				}
			}
			CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager;
			object obj2 = <>O.<0>__OnChaseStateMessage;
			if (obj2 == null)
			{
				HandleNamedMessageDelegate val = OnChaseStateMessage;
				<>O.<0>__OnChaseStateMessage = val;
				obj2 = (object)val;
			}
			customMessagingManager2.RegisterNamedMessageHandler("wiktor.jesterstamina.ChaseState", (HandleNamedMessageDelegate)obj2);
			registeredNetworkManager = singleton;
			messageRegistered = true;
			logger.LogInfo("Registered network chase-state message handler.");
		}
		if (singleton.IsHost || singleton.IsServer)
		{
			bool flag = Time.time - lastJesterChaseTime <= 0.75f;
			if (Time.time >= nextNetworkSendTime || !hasSentChaseState || flag != lastSentChaseState)
			{
				nextNetworkSendTime = Time.time + 0.15f;
				lastSentChaseState = flag;
				hasSentChaseState = true;
				networkJesterChasing = flag;
				lastNetworkChaseSignalTime = Time.time;
				SendChaseStateToClients(singleton, flag);
			}
		}
	}

	private static void ResetNetworking()
	{
		if (messageRegistered && (Object)(object)registeredNetworkManager != (Object)null && registeredNetworkManager.CustomMessagingManager != null)
		{
			registeredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("wiktor.jesterstamina.ChaseState");
		}
		messageRegistered = false;
		registeredNetworkManager = null;
		networkJesterChasing = false;
		hasSentChaseState = false;
		lastSentChaseState = false;
		lastNetworkChaseSignalTime = -999f;
	}

	private static void SendChaseStateToClients(NetworkManager networkManager, bool isChasing)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		FastBufferWriter val = default(FastBufferWriter);
		((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1);
		try
		{
			((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref isChasing, default(ForPrimitives));
			networkManager.CustomMessagingManager.SendNamedMessageToAll("wiktor.jesterstamina.ChaseState", val, (NetworkDelivery)0);
		}
		finally
		{
			((IDisposable)(FastBufferWriter)(ref val)).Dispose();
		}
	}

	private static void OnChaseStateMessage(ulong senderClientId, FastBufferReader reader)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		NetworkManager singleton = NetworkManager.Singleton;
		if (!((Object)(object)singleton == (Object)null) && (singleton.IsHost || senderClientId == 0L))
		{
			bool flag = default(bool);
			((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives));
			networkJesterChasing = flag;
			lastNetworkChaseSignalTime = Time.time;
			if (debugLogs.Value)
			{
				logger.LogInfo($"Received host Jester chase state: {flag}");
			}
		}
	}

	private static void ApplyBoost(PlayerControllerB player)
	{
		player.sprintMeter = 1f;
		player.isExhausted = false;
		if (!hasAppliedSpeedBoost || (Object)(object)boostedPlayer != (Object)(object)player)
		{
			RemoveBoost();
			boostedPlayer = player;
			originalMovementSpeed = player.movementSpeed;
			hasAppliedSpeedBoost = true;
		}
		float num = Mathf.Max(1f, speedMultiplier.Value);
		appliedMovementSpeed = originalMovementSpeed * num;
		player.movementSpeed = appliedMovementSpeed;
	}

	private static void RemoveBoost()
	{
		if (!hasAppliedSpeedBoost || (Object)(object)boostedPlayer == (Object)null)
		{
			hasAppliedSpeedBoost = false;
			boostedPlayer = null;
			return;
		}
		if (Mathf.Approximately(boostedPlayer.movementSpeed, appliedMovementSpeed))
		{
			boostedPlayer.movementSpeed = originalMovementSpeed;
		}
		hasAppliedSpeedBoost = false;
		boostedPlayer = null;
		appliedMovementSpeed = 0f;
		originalMovementSpeed = 0f;
	}
}