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();
}
}
}