Decompiled source of PingTweaks v1.0.3

PingTweaks.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PingTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Riintouge")]
[assembly: AssemblyProduct("PingTweaks")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7af575dc-7a28-4905-ac30-ac848b9d9aa2")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.3.0")]
namespace PingTweaks;

[BepInPlugin("com.riintouge.pingtweaks", "Ping Tweaks", "1.0.3")]
[BepInProcess("valheim.exe")]
public class PingTweaks : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Chat))]
	private class ChatPatch
	{
		[HarmonyPatch("AddInworldText")]
		[HarmonyPrefix]
		private static void AddInworldTextPrefix(ref Vector3 position, ref string text, ref Type type, out string __state)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			__state = text;
			if (!IsEnabled.Value || (int)type != 3)
			{
				return;
			}
			float y = ((Component)Player.m_localPlayer).transform.position.y;
			if (position.y == 0f)
			{
				position.y = y;
			}
			else if (position.y >= 4500f)
			{
				if (!Common.IsLocalPlayerInDungeon())
				{
					position.y = y - 30f;
				}
			}
			else if (Common.IsLocalPlayerInDungeon())
			{
				position.y = y + 30f;
			}
		}

		[HarmonyPatch("AddInworldText")]
		[HarmonyPostfix]
		private static void AddInworldTextPostfix(ref Chat __instance, ref long senderID, ref Type type, ref string __state)
		{
			if ((int)type == 3 && IsEnabled.Value && !Utility.IsNullOrWhiteSpace(__state))
			{
				WorldTextInstance value = Traverse.Create((object)__instance).Method("FindExistingWorldText", new Type[1] { typeof(long) }, (object[])null).GetValue<WorldTextInstance>(new object[1] { senderID });
				if (value != null)
				{
					value.m_text = Localization.instance.Localize(__state).ToUpperInvariant();
					Traverse.Create((object)__instance).Method("UpdateWorldTextField", new Type[1] { typeof(WorldTextInstance) }, (object[])null).GetValue(new object[1] { value });
					MinimapPatch.RegeneratePingPins = true;
				}
			}
		}

		[HarmonyPatch("SendPing")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SendPingPatch(IEnumerable<CodeInstruction> instructionsIn)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructionsIn);
			for (int i = 0; i + 2 < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Ldarg_1 && list[i + 1].opcode == OpCodes.Stloc_1 && list[i + 2].opcode == OpCodes.Ldloca_S)
				{
					for (int j = i + 2; j <= i + 7; j++)
					{
						list[j].opcode = OpCodes.Nop;
					}
				}
			}
			return list;
		}

		[HarmonyPatch("UpdateWorldTextField")]
		[HarmonyPrefix]
		private static void UpdateWorldTextFieldPrefix(ref WorldTextInstance wt)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0022: 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)
			if (IsEnabled.Value && (int)wt.m_type == 3)
			{
				((Graphic)wt.m_textMeshField).color = Common.CopyColor(PingColor.Value);
			}
		}

		[HarmonyPatch("UpdateWorldTexts")]
		[HarmonyPrefix]
		private static void UpdateWorldTextsPretfix(ref float dt, ref List<WorldTextInstance> ___m_worldTexts)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			if (!IsEnabled.Value)
			{
				return;
			}
			foreach (WorldTextInstance ___m_worldText in ___m_worldTexts)
			{
				if ((int)___m_worldText.m_type == 3)
				{
					___m_worldText.m_position.y -= dt * 0.15f;
				}
			}
		}

		[HarmonyPatch("UpdateWorldTexts")]
		[HarmonyPostfix]
		private static void UpdateWorldTextsPostfix(ref float dt, ref List<WorldTextInstance> ___m_worldTexts)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled.Value)
			{
				return;
			}
			foreach (WorldTextInstance ___m_worldText in ___m_worldTexts)
			{
				if ((int)___m_worldText.m_type == 3)
				{
					((TMP_Text)___m_worldText.m_textMeshField).SetText($"{___m_worldText.m_name}\n{___m_worldText.m_text}\n{Common.PrettyPrintDistance(((Component)Player.m_localPlayer).transform.position, ___m_worldText.m_position)}");
				}
			}
		}
	}

	internal class Common
	{
		public const float DungeonFakeDepth = 30f;

		public const float DungeonMinHeight = 4500f;

		public static Color CopyColor(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Color(color.r, color.g, color.b, color.a);
		}

		public static bool IsLocalPlayerInDungeon()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)Player.m_localPlayer).transform.position.y >= 4500f;
		}

		public static string PrettyPrintDistance(Vector3 from, Vector3 to)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			CultureInfo currentCulture = CultureInfo.CurrentCulture;
			Vector3 val = to - from;
			return string.Format(currentCulture, "({0}m)", Math.Round(((Vector3)(ref val)).magnitude, 1));
		}
	}

	[HarmonyPatch(typeof(Minimap))]
	private class MinimapPatch
	{
		internal static bool RegeneratePingPins;

		internal static PinData GetClosestPin(Minimap instance, Vector3 pos, float radius, bool mustBeVisible = true)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			return Traverse.Create((object)instance).Method("GetClosestPin", new Type[3]
			{
				typeof(Vector3),
				typeof(float),
				typeof(bool)
			}, (object[])null).GetValue<PinData>(new object[3] { pos, radius, true });
		}

		private static WorldTextInstance GetClosestPing(Vector3 pos, float radius)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			List<WorldTextInstance> list = new List<WorldTextInstance>();
			Chat.instance.GetPingWorldTexts(list);
			WorldTextInstance result = null;
			float num = float.PositiveInfinity;
			foreach (WorldTextInstance item in list)
			{
				if ((int)item.m_type == 3)
				{
					float num2 = Utils.DistanceXZ(pos, item.m_position);
					if (num2 < radius && num2 < num)
					{
						result = item;
						num = num2;
					}
				}
			}
			return result;
		}

		[HarmonyPatch("MapPointToWorld")]
		[HarmonyPostfix]
		private static void MapPointToWorldPostfix(ref Vector3 __result)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (IsEnabled.Value)
			{
				if (Common.IsLocalPlayerInDungeon())
				{
					__result.y = ((Component)Player.m_localPlayer).transform.position.y;
				}
				else
				{
					Heightmap.GetHeight(__result, ref __result.y);
				}
			}
		}

		[HarmonyPatch("OnMapDblClick")]
		[HarmonyPrefix]
		private static bool OnMapDblClickPrefix(ref Minimap __instance, ref float ___m_largeZoom, ref List<PinData> ___m_pins, ref PinType ___m_selectedType)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled.Value)
			{
				return true;
			}
			Vector3 value = Traverse.Create((object)__instance).Method("ScreenToWorldPoint", new Type[1] { typeof(Vector3) }, (object[])null).GetValue<Vector3>(new object[1] { ZInput.mousePosition });
			float radius = __instance.m_removeRadius * ___m_largeZoom * 2f;
			if (GetClosestPin(__instance, value, radius) != null)
			{
				return false;
			}
			WorldTextInstance closestPing = GetClosestPing(value, radius);
			if (closestPing == null || closestPing.m_talkerID == ZNet.GetUID())
			{
				return true;
			}
			if (closestPing.m_position.y == 0f)
			{
				MapPointToWorldPostfix(ref closestPing.m_position);
			}
			__instance.AddPin(closestPing.m_position, ___m_selectedType, closestPing.m_text, SavePinnedPings.Value, false, closestPing.m_talkerID, "");
			return false;
		}

		[HarmonyPatch("UpdatePingPins")]
		[HarmonyPrefix]
		private static void UpdatePingPinsPrefix(ref Minimap __instance, ref List<PinData> ___m_pingPins)
		{
			if (!RegeneratePingPins)
			{
				return;
			}
			foreach (PinData ___m_pingPin in ___m_pingPins)
			{
				__instance.RemovePin(___m_pingPin);
			}
			___m_pingPins.Clear();
			RegeneratePingPins = false;
		}

		[HarmonyPatch("UpdatePingPins")]
		[HarmonyPostfix]
		private static void UpdatePingPinsPostfix(ref List<PinData> ___m_pingPins, ref bool ___m_pinUpdateRequired)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled.Value)
			{
				return;
			}
			List<WorldTextInstance> list = new List<WorldTextInstance>();
			Chat.instance.GetPingWorldTexts(list);
			for (int i = 0; i < list.Count; i++)
			{
				PinNameData namePinData = ___m_pingPins[i].m_NamePinData;
				TMP_Text val = ((namePinData != null) ? namePinData.PinNameText : null);
				if ((Object)(object)val != (Object)null)
				{
					WorldTextInstance val2 = list[i];
					val.SetText($"{val2.m_name}\n{val2.m_text}\n{Common.PrettyPrintDistance(((Component)Player.m_localPlayer).transform.position, val2.m_position)}");
				}
			}
		}
	}

	[HarmonyPatch(typeof(ZRoutedRpc))]
	private class ZRoutedRpcPatch
	{
		[HarmonyPatch("InvokeRoutedRPC", new Type[]
		{
			typeof(long),
			typeof(string),
			typeof(object[])
		})]
		[HarmonyPrefix]
		private static bool InvokeRoutedRPCPrefix(ref string methodName, ref object[] parameters)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled.Value || methodName.CompareTo("ChatMessage") != 0)
			{
				return true;
			}
			int? num = parameters[1] as int?;
			if (!num.HasValue || num.Value != 3)
			{
				return true;
			}
			Vector3? val = parameters[0] as Vector3?;
			if (!val.HasValue || !val.HasValue)
			{
				return true;
			}
			Vector3 val2 = val.Value;
			float y = val2.y;
			object obj = parameters[2];
			UserInfo val3 = (UserInfo)((obj is UserInfo) ? obj : null);
			string text = parameters[3] as string;
			string text2 = parameters[4] as string;
			Minimap instance = Minimap.instance;
			float value = Traverse.Create((object)instance).Field("m_largeZoom").GetValue<float>();
			PinData val4 = MinimapPatch.GetClosestPin(radius: instance.m_removeRadius * value * 2f, instance: instance, pos: val2);
			if (val4 != null)
			{
				val2 = val4.m_pos;
				if (val2.y == 0f)
				{
					val2.y = y;
				}
				if (!Utility.IsNullOrWhiteSpace(val4.m_name))
				{
					parameters[3] = val4.m_name;
					text = val4.m_NamePinData.PinNameText.text;
				}
			}
			if ((int)PingBroadcastModifier.Value != 0 && !Input.GetKey(PingBroadcastModifier.Value) && val3 != null && text != null && text2 != null)
			{
				Chat.instance.OnNewChatMessage((GameObject)null, ZNet.GetUID(), val2, (Type)3, val3, text, text2);
				return false;
			}
			parameters[0] = val2;
			return true;
		}
	}

	public static ConfigEntry<bool> IsEnabled;

	public static ConfigEntry<bool> LoadOnStart;

	public static ConfigEntry<KeyCode> PingBroadcastModifier;

	public static ConfigEntry<Color> PingColor;

	public static ConfigEntry<bool> SavePinnedPings;

	private readonly Harmony Harmony = new Harmony("com.riintouge.pingtweaks");

	private void Awake()
	{
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		IsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "Enable", true, "Whether this plugin has any effect when loaded.");
		LoadOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "LoadOnStart", true, "Whether this plugin loads on game start.");
		PingBroadcastModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("1 - General", "PingBroadcastModifier", (KeyCode)304, "If set and not \"None\", pings will only be sent to other players when the specified key is pressed.");
		PingColor = ((BaseUnityPlugin)this).Config.Bind<Color>("1 - General", "PingColor", new Color(0.6f, 0.7f, 1f, 1f), "In-world ping text color.");
		SavePinnedPings = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "SavePinnedPings", false, "Whether double-clicking on a ping from another player creates a persistent pin. Off by default to not conflict with the cartography table.");
		if (LoadOnStart.Value)
		{
			Harmony.PatchAll();
		}
	}
}