Decompiled source of LethalPisserNetworkFixExperimental v1.3.0

BepInEx/Plugins/LethalPisserNetworkFix[Experimental]/LethalPisserNetworkFix.dll

Decompiled 4 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[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("LethalPisserNetworkFix")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LethalPisserNetworkFix")]
[assembly: AssemblyTitle("LethalPisserNetworkFix")]
[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 LethalPisserNetworkFix
{
	[BepInPlugin("Potatoh.LethalPisserNetworkFix", "Lethal Pisser Network Fix", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Potatoh.LethalPisserNetworkFix";

		public const string PluginName = "Lethal Pisser Network Fix";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log = null;

		internal static readonly Dictionary<object, float> NextHeartbeatByInstance = new Dictionary<object, float>();

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			new Harmony("Potatoh.LethalPisserNetworkFix").PatchAll();
			Log.LogInfo((object)"Lethal Pisser Network Fix 1.0.0 loaded.");
		}
	}
	[HarmonyPatch]
	internal static class LethalPisserPatches
	{
		private const float HeartbeatInterval = 0.33f;

		private static readonly Type? OriginalType = AccessTools.TypeByName("LethalPisser.LethalPisserPlugin");

		private static readonly FieldInfo? LocalPlayerIsPeeingField = ((OriginalType == null) ? null : AccessTools.Field(OriginalType, "localPlayerIsPeeing"));

		private static readonly MethodInfo? GetLocalPlayerMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "GetLocalPlayer", (Type[])null, (Type[])null));

		private static readonly MethodInfo? SendPeeStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "SendPeeState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? TryReadStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "TryReadState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? SetPeeStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "SetPeeState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? BroadcastPeeStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "BroadcastPeeState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? FindPlayerByPlayerClientIdMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "FindPlayerByPlayerClientId", (Type[])null, (Type[])null));

		[HarmonyTargetMethod]
		private static MethodBase? TargetUpdate()
		{
			return (OriginalType == null) ? null : AccessTools.Method(OriginalType, "Update", (Type[])null, (Type[])null);
		}

		[HarmonyPostfix]
		private static void UpdatePostfix(object __instance)
		{
			try
			{
				if (LocalPlayerIsPeeingField == null || GetLocalPlayerMethod == null || SendPeeStateMethod == null)
				{
					return;
				}
				if (!(bool)LocalPlayerIsPeeingField.GetValue(__instance))
				{
					Plugin.NextHeartbeatByInstance.Remove(__instance);
				}
				else if (!(Time.time < GetNextHeartbeat(__instance)))
				{
					Plugin.NextHeartbeatByInstance[__instance] = Time.time + 0.33f;
					object? obj = GetLocalPlayerMethod.Invoke(null, null);
					PlayerControllerB val = (PlayerControllerB)((obj is PlayerControllerB) ? obj : null);
					if (!((Object)(object)val == (Object)null))
					{
						SendPeeStateMethod.Invoke(__instance, new object[2] { val.playerClientId, true });
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Heartbeat postfix failed: " + ex.Message));
			}
		}

		private static float GetNextHeartbeat(object instance)
		{
			float value;
			return Plugin.NextHeartbeatByInstance.TryGetValue(instance, out value) ? value : 0f;
		}
	}
	[HarmonyPatch]
	internal static class LethalPisserRequestPatch
	{
		private static readonly Type? OriginalType = AccessTools.TypeByName("LethalPisser.LethalPisserPlugin");

		private static readonly MethodInfo? TryReadStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "TryReadState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? SetPeeStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "SetPeeState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? BroadcastPeeStateMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "BroadcastPeeState", (Type[])null, (Type[])null));

		private static readonly MethodInfo? FindPlayerByPlayerClientIdMethod = ((OriginalType == null) ? null : AccessTools.Method(OriginalType, "FindPlayerByPlayerClientId", (Type[])null, (Type[])null));

		[HarmonyTargetMethod]
		private static MethodBase? TargetHandleRequestMessage()
		{
			return (OriginalType == null) ? null : AccessTools.Method(OriginalType, "HandleRequestMessage", (Type[])null, (Type[])null);
		}

		[HarmonyPrefix]
		private static bool HandleRequestMessagePrefix(object __instance, ulong senderClientId, FastBufferReader reader)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsServer)
				{
					return false;
				}
				if (TryReadStateMethod == null || SetPeeStateMethod == null || BroadcastPeeStateMethod == null || FindPlayerByPlayerClientIdMethod == null)
				{
					return true;
				}
				object[] array = new object[3] { reader, 0uL, false };
				if (!(bool)TryReadStateMethod.Invoke(null, array))
				{
					return false;
				}
				ulong num = (ulong)array[1];
				bool flag = (bool)array[2];
				object? obj = FindPlayerByPlayerClientIdMethod.Invoke(null, new object[1] { num });
				PlayerControllerB val = (PlayerControllerB)((obj is PlayerControllerB) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				bool flag2 = val.actualClientId == senderClientId;
				bool flag3 = val.playerClientId == senderClientId;
				if (!flag2 && !flag3)
				{
					Plugin.Log.LogWarning((object)($"Rejected pee request: playerClientId={num}, " + $"actualClientId={val.actualClientId}, senderClientId={senderClientId}"));
					return false;
				}
				SetPeeStateMethod.Invoke(__instance, new object[2] { num, flag });
				BroadcastPeeStateMethod.Invoke(__instance, new object[2] { num, flag });
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("HandleRequestMessage prefix failed, falling back to original: " + ex.Message));
				return true;
			}
		}
	}
}