Decompiled source of TeamPing v1.0.1

plugins\TeamPing.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TeamPing.Config;
using TeamPing.Core;
using TeamPing.Network;
using TeamPing.UI;
using TeamPing.Utils;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TeamPing")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("TeamPing")]
[assembly: AssemblyTitle("TeamPing")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 TeamPing
{
	[BepInPlugin("com.juanma.teamping", "TeamPing", "1.0.1")]
	[BepInProcess("REPO.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.juanma.teamping";

		public const string PluginName = "TeamPing";

		public const string PluginVersion = "1.0.1";

		private static Plugin? _activeInstance;

		private ModConfig? _modConfig;

		private GameBindings? _bindings;

		private PingController? _pingController;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			Scene activeScene = SceneManager.GetActiveScene();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[TeamPing] Loaded v1.0.1");
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}/Lifecycle] Awake: unity={1}, gameVersion={2}, scene={3}[{4}], config={5}", "TeamPing", Application.unityVersion, Application.version, ((Scene)(ref activeScene)).name, ((Scene)(ref activeScene)).buildIndex, ((BaseUnityPlugin)this).Config.ConfigFilePath));
			_modConfig = new ModConfig(((BaseUnityPlugin)this).Config);
			_bindings = new GameBindings(((BaseUnityPlugin)this).Logger);
			if (_bindings.Resolve())
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[TeamPing] Game bindings resolved.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[TeamPing] Some optional bindings are unavailable; affected metadata will be hidden safely.");
			}
			_pingController = new PingController(_modConfig, _bindings, ((BaseUnityPlugin)this).Logger);
			_activeInstance = this;
			_harmony = new Harmony("com.juanma.teamping");
			MethodInfo methodInfo = AccessTools.Method(typeof(Plugin), "GameUpdatePostfix", (Type[])null, (Type[])null);
			int num = 0;
			if (methodInfo != null)
			{
				num += (InstallUpdateHook(typeof(GameDirector), methodInfo) ? 1 : 0);
				num += (InstallUpdateHook(typeof(RunManager), methodInfo) ? 1 : 0);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}/Lifecycle] Safe update hooks installed: {1}/2. Plugin Update remains as a guarded fallback.", "TeamPing", num));
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[TeamPing] Ready. Press the middle mouse button while aiming at an object or surface.");
		}

		private void Update()
		{
			_pingController?.Tick(Time.unscaledDeltaTime);
		}

		private static void GameUpdatePostfix()
		{
			_activeInstance?._pingController?.Tick(Time.unscaledDeltaTime);
		}

		private bool InstallUpdateHook(Type gameType, MethodInfo postfix)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(gameType, "Update", (Type[])null, (Type[])null);
			if (methodInfo == null || _harmony == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[TeamPing/Lifecycle] Update hook unavailable for " + gameType.Name + "."));
				return false;
			}
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			return true;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}/Scene] Loaded: {1}[{2}], mode={3}, frame={4}", "TeamPing", ((Scene)(ref scene)).name, ((Scene)(ref scene)).buildIndex, mode, Time.frameCount));
			_pingController?.HandleSceneChanged();
		}

		private void OnActiveSceneChanged(Scene previous, Scene current)
		{
			ModConfig? modConfig = _modConfig;
			if (modConfig != null && modConfig.DebugLogging.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[TeamPing/Scene] Active scene: " + ((Scene)(ref previous)).name + " -> " + ((Scene)(ref current)).name));
			}
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[TeamPing/Lifecycle] Shutdown started.");
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.activeSceneChanged -= OnActiveSceneChanged;
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)_activeInstance == (Object)(object)this)
			{
				_activeInstance = null;
			}
			_pingController?.Dispose();
			_modConfig?.Dispose();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[TeamPing/Lifecycle] Shutdown complete.");
		}
	}
}
namespace TeamPing.Utils
{
	internal static class TextureUtils
	{
		public static Sprite CreateRoundedRectSprite(string name, int width, int height, int radius, int borderThickness = 0)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, false)
			{
				name = name + "_Texture",
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			Color32[] array = (Color32[])(object)new Color32[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					bool flag = InsideRoundedRect((float)j + 0.5f, (float)i + 0.5f, width, height, radius, 0);
					bool flag2 = borderThickness > 0 && InsideRoundedRect((float)j + 0.5f, (float)i + 0.5f, width, height, Mathf.Max(0, radius - borderThickness), borderThickness);
					array[i * width + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)((flag && !flag2) ? byte.MaxValue : 0));
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)width, (float)height), new Vector2(0.5f, 0.5f), 100f);
			((Object)obj).name = name;
			((Object)obj).hideFlags = (HideFlags)61;
			return obj;
		}

		private static bool InsideRoundedRect(float x, float y, int width, int height, int radius, int inset)
		{
			int num = width - inset;
			int num2 = height - inset;
			if (x < (float)inset || x > (float)num || y < (float)inset || y > (float)num2)
			{
				return false;
			}
			if (radius <= 0)
			{
				return true;
			}
			float num3 = Mathf.Clamp(x, (float)(inset + radius), (float)(num - radius));
			float num4 = Mathf.Clamp(y, (float)(inset + radius), (float)(num2 - radius));
			float num5 = x - num3;
			float num6 = y - num4;
			return num5 * num5 + num6 * num6 <= (float)(radius * radius);
		}
	}
}
namespace TeamPing.UI
{
	public sealed class PingHudController : IDisposable
	{
		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		private readonly PingStyles _styles;

		private readonly List<PingMarker> _markers = new List<PingMarker>();

		private GameObject? _canvasRoot;

		private RectTransform? _canvasRect;

		private AudioSource? _audioSource;

		public PingHudController(ModConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
			_styles = new PingStyles(config);
		}

		public void Show(PingData ping)
		{
			EnsureCanvas();
			if (!((Object)(object)_canvasRect == (Object)null))
			{
				int num = Mathf.Clamp(_config.MaxPingsPerPlayer.Value, 1, 8);
				while (CountForSender(ping.SenderActorNumber) >= num)
				{
					RemoveOldestForSender(ping.SenderActorNumber);
				}
				PingMarker item = new PingMarker(ping, (Transform)(object)_canvasRect, _config, _styles);
				_markers.Add(item);
				PlaySound();
			}
		}

		public void Tick(float unscaledDeltaTime, Camera? camera, bool gameplayActive)
		{
			if ((Object)(object)_canvasRoot == (Object)null)
			{
				if (_markers.Count > 0)
				{
					ClearMarkersOnly();
				}
				return;
			}
			_canvasRoot.SetActive(gameplayActive && _config.Enabled.Value);
			if (!gameplayActive || (Object)(object)camera == (Object)null || (Object)(object)_canvasRect == (Object)null)
			{
				return;
			}
			for (int num = _markers.Count - 1; num >= 0; num--)
			{
				if (!_markers[num].Tick(unscaledDeltaTime, camera, _canvasRect))
				{
					_markers[num].Dispose();
					_markers.RemoveAt(num);
				}
			}
		}

		public void ApplyConfig()
		{
			_styles.Refresh();
			foreach (PingMarker marker in _markers)
			{
				marker.ApplyConfig();
			}
			if ((Object)(object)_audioSource != (Object)null)
			{
				_audioSource.volume = Mathf.Clamp01(_config.SoundVolume.Value);
			}
		}

		public void Clear()
		{
			ClearMarkersOnly();
		}

		private void EnsureCanvas()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvasRoot != (Object)null) || !((Object)(object)_canvasRect != (Object)null))
			{
				ClearMarkersOnly();
				_canvasRoot = new GameObject("TeamPing_Canvas", new Type[4]
				{
					typeof(RectTransform),
					typeof(Canvas),
					typeof(CanvasScaler),
					typeof(AudioSource)
				});
				((Object)_canvasRoot).hideFlags = (HideFlags)61;
				_canvasRect = (RectTransform)_canvasRoot.transform;
				_canvasRect.anchorMin = Vector2.zero;
				_canvasRect.anchorMax = Vector2.one;
				_canvasRect.offsetMin = Vector2.zero;
				_canvasRect.offsetMax = Vector2.zero;
				Canvas component = _canvasRoot.GetComponent<Canvas>();
				component.renderMode = (RenderMode)0;
				component.sortingOrder = 32000;
				CanvasScaler component2 = _canvasRoot.GetComponent<CanvasScaler>();
				component2.uiScaleMode = (ScaleMode)1;
				component2.referenceResolution = new Vector2(1920f, 1080f);
				component2.screenMatchMode = (ScreenMatchMode)0;
				component2.matchWidthOrHeight = 0.5f;
				_audioSource = _canvasRoot.GetComponent<AudioSource>();
				_audioSource.playOnAwake = false;
				_audioSource.loop = false;
				_audioSource.spatialBlend = 0f;
				_audioSource.ignoreListenerPause = true;
				_audioSource.clip = _styles.PingClip;
				_audioSource.volume = Mathf.Clamp01(_config.SoundVolume.Value);
				_logger.LogInfo((object)"[TeamPing/UI] Ping canvas created.");
			}
		}

		private int CountForSender(int senderActorNumber)
		{
			int num = 0;
			foreach (PingMarker marker in _markers)
			{
				if (marker.SenderActorNumber == senderActorNumber)
				{
					num++;
				}
			}
			return num;
		}

		private void RemoveOldestForSender(int senderActorNumber)
		{
			int num = -1;
			float num2 = float.PositiveInfinity;
			for (int i = 0; i < _markers.Count; i++)
			{
				if (_markers[i].SenderActorNumber == senderActorNumber && !(_markers[i].CreatedAt >= num2))
				{
					num2 = _markers[i].CreatedAt;
					num = i;
				}
			}
			if (num >= 0)
			{
				_markers[num].Dispose();
				_markers.RemoveAt(num);
			}
		}

		private void PlaySound()
		{
			if (_config.SoundEnabled.Value && !((Object)(object)_audioSource == (Object)null) && !((Object)(object)_styles.PingClip == (Object)null))
			{
				_audioSource.volume = Mathf.Clamp01(_config.SoundVolume.Value);
				_audioSource.PlayOneShot(_styles.PingClip, 1f);
			}
		}

		private void ClearMarkersOnly()
		{
			foreach (PingMarker marker in _markers)
			{
				marker.Dispose();
			}
			_markers.Clear();
		}

		public void Dispose()
		{
			ClearMarkersOnly();
			if ((Object)(object)_canvasRoot != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasRoot);
			}
			_canvasRoot = null;
			_canvasRect = null;
			_audioSource = null;
			_styles.Dispose();
		}
	}
	public sealed class PingMarker : IDisposable
	{
		private readonly PingData _data;

		private readonly ModConfig _config;

		private readonly PingStyles _styles;

		private readonly GameObject _root;

		private readonly RectTransform _rootRect;

		private readonly CanvasGroup _canvasGroup;

		private readonly Image _diamond;

		private readonly Shadow _diamondGlow;

		private readonly Image _dot;

		private readonly Image _panel;

		private readonly Image _accent;

		private readonly Text _labelText;

		private readonly Text _detailsText;

		private readonly Text _edgeArrow;

		private readonly float _expiresAt;

		private Transform? _targetTransform;

		private Vector3 _targetLocalOffset;

		private Vector3 _lastWorldPosition;

		private float _nextTargetLookup;

		private bool _disposed;

		public int SenderActorNumber => _data.SenderActorNumber;

		public float CreatedAt { get; } = Time.unscaledTime;

		public PingMarker(PingData data, Transform parent, ModConfig config, PingStyles styles)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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)
			//IL_0196: 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_01b5: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Expected O, but got Unknown
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Expected O, but got Unknown
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Expected O, but got Unknown
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_048b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_053c: Unknown result type (might be due to invalid IL or missing references)
			//IL_055a: Expected O, but got Unknown
			//IL_05b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_062e: Expected O, but got Unknown
			//IL_0696: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b4: Expected O, but got Unknown
			//IL_06fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0711: Unknown result type (might be due to invalid IL or missing references)
			_data = data;
			_config = config;
			_styles = styles;
			_lastWorldPosition = data.WorldPosition;
			_expiresAt = CreatedAt + Mathf.Clamp(config.Duration.Value, 1f, 30f);
			_root = CreateUiObject("Ping_" + data.SenderActorNumber + "_" + data.PingId, parent, typeof(CanvasGroup));
			_rootRect = (RectTransform)_root.transform;
			_rootRect.anchorMin = new Vector2(0.5f, 0.5f);
			_rootRect.anchorMax = new Vector2(0.5f, 0.5f);
			_rootRect.pivot = new Vector2(0.5f, 0.5f);
			_rootRect.sizeDelta = new Vector2(240f, 104f);
			_canvasGroup = _root.GetComponent<CanvasGroup>();
			_canvasGroup.interactable = false;
			_canvasGroup.blocksRaycasts = false;
			GameObject val = CreateUiObject("Target", _root.transform, typeof(CanvasRenderer), typeof(Image), typeof(Shadow));
			RectTransform val2 = (RectTransform)val.transform;
			SetCentered(val2, 0f, 23f, 38f, 38f);
			((Transform)val2).localRotation = Quaternion.Euler(0f, 0f, 45f);
			_diamond = val.GetComponent<Image>();
			_diamond.sprite = styles.DiamondBorderSprite;
			((Graphic)_diamond).raycastTarget = false;
			_diamondGlow = val.GetComponent<Shadow>();
			_diamondGlow.effectDistance = new Vector2(2f, -2f);
			_diamondGlow.useGraphicAlpha = true;
			GameObject obj = CreateUiObject("ChromaticGhost", val.transform, typeof(CanvasRenderer), typeof(Image));
			RectTransform val3 = (RectTransform)obj.transform;
			Stretch(val3);
			val3.anchoredPosition = new Vector2(-2f, 1f);
			Image component = obj.GetComponent<Image>();
			component.sprite = styles.DiamondBorderSprite;
			((Graphic)component).color = new Color(0.08f, 0.55f, 1f, 0.3f);
			((Graphic)component).raycastTarget = false;
			((Component)component).transform.SetAsFirstSibling();
			GameObject val4 = CreateUiObject("Dot", _root.transform, typeof(CanvasRenderer), typeof(Image), typeof(Shadow));
			SetCentered((RectTransform)val4.transform, 0f, 23f, 10f, 10f);
			_dot = val4.GetComponent<Image>();
			_dot.sprite = styles.DotSprite;
			((Graphic)_dot).raycastTarget = false;
			Shadow component2 = val4.GetComponent<Shadow>();
			component2.effectDistance = new Vector2(1f, -1f);
			component2.useGraphicAlpha = true;
			GameObject val5 = CreateUiObject("Info", _root.transform, typeof(CanvasRenderer), typeof(Image), typeof(Shadow));
			SetCentered((RectTransform)val5.transform, 0f, -28f, 220f, 46f);
			_panel = val5.GetComponent<Image>();
			_panel.sprite = styles.PanelSprite;
			((Graphic)_panel).raycastTarget = false;
			Shadow component3 = val5.GetComponent<Shadow>();
			component3.effectColor = new Color(0f, 0f, 0f, 0.82f);
			component3.effectDistance = new Vector2(2f, -2f);
			component3.useGraphicAlpha = true;
			GameObject val6 = CreateUiObject("Accent", val5.transform, typeof(CanvasRenderer), typeof(Image));
			RectTransform val7 = (RectTransform)val6.transform;
			val7.anchorMin = new Vector2(0f, 0f);
			val7.anchorMax = new Vector2(0f, 1f);
			val7.pivot = new Vector2(0f, 0.5f);
			val7.anchoredPosition = Vector2.zero;
			val7.sizeDelta = new Vector2(3f, 0f);
			_accent = val6.GetComponent<Image>();
			((Graphic)_accent).raycastTarget = false;
			GameObject val8 = CreateUiObject("Label", val5.transform, typeof(CanvasRenderer), typeof(Text), typeof(Shadow));
			SetTopLeft((RectTransform)val8.transform, 11f, 2f, 198f, 24f);
			_labelText = val8.GetComponent<Text>();
			ConfigureText(_labelText, 16, (FontStyle)1, (TextAnchor)3);
			_labelText.resizeTextForBestFit = true;
			_labelText.resizeTextMinSize = 10;
			_labelText.resizeTextMaxSize = 16;
			Shadow component4 = val8.GetComponent<Shadow>();
			component4.effectColor = new Color(0f, 0f, 0f, 0.9f);
			component4.effectDistance = new Vector2(1f, -1f);
			GameObject val9 = CreateUiObject("Details", val5.transform, typeof(CanvasRenderer), typeof(Text));
			SetTopLeft((RectTransform)val9.transform, 11f, 24f, 198f, 18f);
			_detailsText = val9.GetComponent<Text>();
			ConfigureText(_detailsText, 11, (FontStyle)1, (TextAnchor)3);
			GameObject val10 = CreateUiObject("EdgeArrow", _root.transform, typeof(CanvasRenderer), typeof(Text), typeof(Shadow));
			SetCentered((RectTransform)val10.transform, 0f, 49f, 30f, 24f);
			_edgeArrow = val10.GetComponent<Text>();
			ConfigureText(_edgeArrow, 21, (FontStyle)1, (TextAnchor)4);
			_edgeArrow.text = "▲";
			Shadow component5 = val10.GetComponent<Shadow>();
			component5.effectColor = new Color(0f, 0f, 0f, 0.85f);
			component5.effectDistance = new Vector2(1f, -1f);
			((Component)_edgeArrow).gameObject.SetActive(false);
			ResolveTargetTransform();
			ApplyConfig();
		}

		public bool Tick(float unscaledDeltaTime, Camera camera, RectTransform canvasRect)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: 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_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || (Object)(object)_root == (Object)null)
			{
				return false;
			}
			float unscaledTime = Time.unscaledTime;
			float num = _expiresAt - unscaledTime;
			if (num <= 0f)
			{
				return false;
			}
			if (_data.ViewId > 0 && (Object)(object)_targetTransform == (Object)null && unscaledTime >= _nextTargetLookup)
			{
				_nextTargetLookup = unscaledTime + 0.5f;
				ResolveTargetTransform();
			}
			if ((Object)(object)_targetTransform != (Object)null)
			{
				_lastWorldPosition = _targetTransform.TransformPoint(_targetLocalOffset);
			}
			Vector3 val = _lastWorldPosition;
			if (_data.Kind == PingTargetKind.Location)
			{
				Vector3 surfaceNormal = _data.SurfaceNormal;
				if (((Vector3)(ref surfaceNormal)).sqrMagnitude > 0.01f)
				{
					Vector3 val2 = val;
					surfaceNormal = _data.SurfaceNormal;
					val = val2 + ((Vector3)(ref surfaceNormal)).normalized * 0.06f;
				}
			}
			Vector3 val3 = camera.WorldToViewportPoint(val);
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(val3.x * (float)Screen.width, val3.y * (float)Screen.height, val3.z);
			bool num2 = val4.z <= 0f;
			if (num2)
			{
				val4.x = (float)Screen.width - val4.x;
				val4.y = (float)Screen.height - val4.y;
			}
			Vector2 val5 = default(Vector2);
			((Vector2)(ref val5))..ctor(val4.x, val4.y);
			float num3 = Mathf.Clamp(_config.MarkerScale.Value, 0.5f, 2f);
			float num4 = 125f * num3;
			float num5 = 78f * num3;
			bool flag = num2 || val4.x < num4 || val4.x > (float)Screen.width - num4 || val4.y < num5 || val4.y > (float)Screen.height - num5;
			if (flag && !_config.ScreenEdgeIndicators.Value)
			{
				_root.SetActive(false);
				return true;
			}
			_root.SetActive(true);
			val4.x = Mathf.Clamp(val4.x, num4, (float)Screen.width - num4);
			val4.y = Mathf.Clamp(val4.y, num5, (float)Screen.height - num5);
			Vector2 anchoredPosition = default(Vector2);
			if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, Vector2.op_Implicit(val4), (Camera)null, ref anchoredPosition))
			{
				_rootRect.anchoredPosition = anchoredPosition;
			}
			((Component)_edgeArrow).gameObject.SetActive(flag);
			if (flag)
			{
				Vector2 val6 = val5 - new Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.5f);
				if (((Vector2)(ref val6)).sqrMagnitude < 0.001f)
				{
					val6 = Vector2.up;
				}
				float num6 = Mathf.Atan2(val6.y, val6.x) * 57.29578f - 90f;
				((Transform)((Graphic)_edgeArrow).rectTransform).localRotation = Quaternion.Euler(0f, 0f, num6);
			}
			float num7 = unscaledTime - CreatedAt;
			float num8 = Mathf.Clamp01(num7 / 0.14f);
			float num9 = Mathf.Clamp01(num / 0.55f);
			_canvasGroup.alpha = Mathf.Min(num8, num9);
			float num10 = 1f + Mathf.Sin(num7 * 7.5f) * 0.035f;
			((Transform)_rootRect).localScale = Vector3.one * num3 * num10;
			((Transform)((Graphic)_diamond).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 45f + Mathf.Sin(num7 * 2.8f) * 2.5f);
			UpdateDetails(Vector3.Distance(((Component)camera).transform.position, val));
			return true;
		}

		public void ApplyConfig()
		{
			//IL_0011: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			Color val = _styles.ColorFor(_data.Kind);
			((Graphic)_diamond).color = val;
			_diamondGlow.effectColor = new Color(val.r, val.g, val.b, 0.55f);
			((Graphic)_dot).color = val;
			((Graphic)_accent).color = val;
			((Graphic)_edgeArrow).color = val;
			((Graphic)_labelText).color = _styles.TextColor;
			((Graphic)_detailsText).color = _styles.MutedTextColor;
			((Graphic)_panel).color = _styles.PanelColor;
			_labelText.text = (string.IsNullOrWhiteSpace(_data.Label) ? "PING" : _data.Label.Trim().ToUpperInvariant());
			UpdateDetails(0f);
		}

		private void UpdateDetails(float distance)
		{
			List<string> list = new List<string>(3);
			if (_config.ShowSender.Value && !string.IsNullOrWhiteSpace(_data.SenderName))
			{
				list.Add(_data.SenderName.Trim().ToUpperInvariant());
			}
			if (_data.HasValue)
			{
				list.Add("$" + _data.Value.ToString("N0", CultureInfo.InvariantCulture));
			}
			if (_config.ShowDistance.Value && distance > 0f)
			{
				list.Add(Mathf.RoundToInt(distance) + " M");
			}
			_detailsText.text = string.Join("  /  ", list);
		}

		private void ResolveTargetTransform()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (_data.ViewId <= 0)
			{
				return;
			}
			try
			{
				PhotonView val = PhotonView.Find(_data.ViewId);
				if (!((Object)(object)val == (Object)null))
				{
					_targetTransform = ((Component)val).transform;
					_targetLocalOffset = _targetTransform.InverseTransformPoint(_lastWorldPosition);
				}
			}
			catch
			{
				_targetTransform = null;
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				if ((Object)(object)_root != (Object)null)
				{
					Object.Destroy((Object)(object)_root);
				}
				_targetTransform = null;
			}
		}

		private void ConfigureText(Text text, int size, FontStyle style, TextAnchor alignment)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			text.font = _styles.Font;
			text.fontSize = size;
			text.fontStyle = style;
			text.alignment = alignment;
			text.horizontalOverflow = (HorizontalWrapMode)1;
			text.verticalOverflow = (VerticalWrapMode)0;
			text.supportRichText = false;
			((Graphic)text).raycastTarget = false;
		}

		private static GameObject CreateUiObject(string name, Transform parent, params Type[] components)
		{
			//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)
			//IL_0035: Expected O, but got Unknown
			Type[] array = new Type[components.Length + 1];
			array[0] = typeof(RectTransform);
			components.CopyTo(array, 1);
			GameObject val = new GameObject(name, array);
			val.transform.SetParent(parent, false);
			return val;
		}

		private static void SetCentered(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0.5f, 0.5f);
			rect.anchorMax = new Vector2(0.5f, 0.5f);
			rect.pivot = new Vector2(0.5f, 0.5f);
			rect.anchoredPosition = new Vector2(x, y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private static void SetTopLeft(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, 1f);
			rect.anchorMax = new Vector2(0f, 1f);
			rect.pivot = new Vector2(0f, 1f);
			rect.anchoredPosition = new Vector2(x, 0f - y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private static void Stretch(RectTransform rect)
		{
			//IL_0001: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = Vector2.zero;
			rect.offsetMax = Vector2.zero;
		}
	}
	public sealed class PingStyles
	{
		private readonly ModConfig _config;

		private readonly List<Sprite> _sprites = new List<Sprite>();

		private readonly bool _ownsFont;

		public Font Font { get; }

		public Sprite PanelSprite { get; }

		public Sprite DiamondBorderSprite { get; }

		public Sprite DotSprite { get; }

		public AudioClip PingClip { get; }

		public Color ValuableColor { get; private set; }

		public Color ItemColor { get; private set; }

		public Color CartColor { get; private set; }

		public Color PlayerColor { get; private set; }

		public Color LocationColor { get; private set; }

		public Color PanelColor { get; } = new Color(0.008f, 0.014f, 0.018f, 0.82f);

		public Color TextColor { get; } = new Color(0.95f, 1f, 0.96f, 1f);

		public Color MutedTextColor { get; } = new Color(0.72f, 0.78f, 0.75f, 1f);

		public PingStyles(ModConfig config)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			_config = config;
			Font = Font.CreateDynamicFontFromOSFont(new string[4] { "Bahnschrift SemiCondensed", "Arial Narrow", "Segoe UI Semibold", "Arial" }, 18);
			if ((Object)(object)Font != (Object)null)
			{
				_ownsFont = true;
			}
			else
			{
				Font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
			PanelSprite = Add(TextureUtils.CreateRoundedRectSprite("TeamPing_Panel", 220, 46, 3));
			DiamondBorderSprite = Add(TextureUtils.CreateRoundedRectSprite("TeamPing_Diamond", 42, 42, 4, 3));
			DotSprite = Add(TextureUtils.CreateRoundedRectSprite("TeamPing_Dot", 16, 16, 8));
			PingClip = CreatePingClip();
			Refresh();
		}

		public void Refresh()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			ValuableColor = Parse(_config.ValuableColor.Value, new Color(0.38f, 1f, 0.53f, 1f));
			ItemColor = Parse(_config.ItemColor.Value, new Color(0.33f, 0.85f, 1f, 1f));
			CartColor = Parse(_config.CartColor.Value, new Color(1f, 0.68f, 0.26f, 1f));
			PlayerColor = Parse(_config.PlayerColor.Value, new Color(0.84f, 0.54f, 1f, 1f));
			LocationColor = Parse(_config.LocationColor.Value, new Color(1f, 0.95f, 0.66f, 1f));
		}

		public Color ColorFor(PingTargetKind kind)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(kind switch
			{
				PingTargetKind.Valuable => ValuableColor, 
				PingTargetKind.Item => ItemColor, 
				PingTargetKind.Cart => CartColor, 
				PingTargetKind.Player => PlayerColor, 
				PingTargetKind.Object => ItemColor, 
				_ => LocationColor, 
			});
		}

		public void Dispose()
		{
			foreach (Sprite sprite in _sprites)
			{
				if (!((Object)(object)sprite == (Object)null))
				{
					Texture2D texture = sprite.texture;
					Object.Destroy((Object)(object)sprite);
					if ((Object)(object)texture != (Object)null)
					{
						Object.Destroy((Object)(object)texture);
					}
				}
			}
			_sprites.Clear();
			if ((Object)(object)PingClip != (Object)null)
			{
				Object.Destroy((Object)(object)PingClip);
			}
			if (_ownsFont && (Object)(object)Font != (Object)null)
			{
				Object.Destroy((Object)(object)Font);
			}
		}

		private Sprite Add(Sprite sprite)
		{
			_sprites.Add(sprite);
			return sprite;
		}

		private static Color Parse(string value, Color fallback)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			if (!ColorUtility.TryParseHtmlString(value, ref result))
			{
				return fallback;
			}
			return result;
		}

		private static AudioClip CreatePingClip()
		{
			int num = Mathf.CeilToInt(7056f);
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				float num2 = (float)i / 44100f;
				float num3 = ((num2 < 0.055f) ? 690f : 980f);
				float num4 = Mathf.Exp(-18f * num2) * Mathf.Clamp01(num2 * 90f);
				array[i] = Mathf.Sin(MathF.PI * 2f * num3 * num2) * num4 * 0.36f;
			}
			AudioClip obj = AudioClip.Create("TeamPing_Sound", num, 1, 44100, false);
			((Object)obj).hideFlags = (HideFlags)61;
			obj.SetData(array, 0);
			return obj;
		}
	}
}
namespace TeamPing.Network
{
	public sealed class PingNetwork : IDisposable
	{
		private const byte EventCode = 181;

		private const string Signature = "com.juanma.teamping";

		private const byte ProtocolVersion = 1;

		private const float RemoteMinimumInterval = 0.15f;

		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		private readonly Dictionary<int, float> _lastRemoteEventTime = new Dictionary<int, float>();

		private LoadBalancingClient? _subscribedClient;

		public event Action<PingData>? PingReceived;

		public PingNetwork(ModConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
			RefreshSubscription();
		}

		public void Tick()
		{
			RefreshSubscription();
		}

		public bool Broadcast(PingData ping)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.InRoom || !PhotonNetwork.IsConnectedAndReady)
			{
				return false;
			}
			object[] array = new object[10]
			{
				"com.juanma.teamping",
				(byte)1,
				(byte)ping.Kind,
				ping.PingId,
				ping.ViewId,
				ping.WorldPosition,
				ping.SurfaceNormal,
				SanitizeLabel(ping.Label),
				ping.HasValue ? ping.Value : (-1),
				ping.ServerTimestamp
			};
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0,
				CachingOption = (EventCaching)0
			};
			bool flag = PhotonNetwork.RaiseEvent((byte)181, (object)array, val, SendOptions.SendReliable);
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)string.Format("[TeamPing/Network] Outgoing ping: sent={0}, actor={1}, id={2}, kind={3}, view={4}, label='{5}', value={6}", flag, ping.SenderActorNumber, ping.PingId, ping.Kind, ping.ViewId, ping.Label, ping.HasValue ? ping.Value.ToString() : "hidden"));
			}
			return flag;
		}

		public string GetActorName(int actorNumber)
		{
			if (actorNumber <= 0)
			{
				return "PLAYER";
			}
			try
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom != null && currentRoom.Players.TryGetValue(actorNumber, out var value) && !string.IsNullOrWhiteSpace(value.NickName))
				{
					return value.NickName.Trim();
				}
			}
			catch
			{
			}
			return "PLAYER";
		}

		private void RefreshSubscription()
		{
			LoadBalancingClient networkingClient = PhotonNetwork.NetworkingClient;
			if (networkingClient != _subscribedClient)
			{
				if (_subscribedClient != null)
				{
					_subscribedClient.EventReceived -= OnEventReceived;
				}
				_subscribedClient = networkingClient;
				if (_subscribedClient != null)
				{
					_subscribedClient.EventReceived += OnEventReceived;
					_logger.LogInfo((object)"[TeamPing/Network] Photon custom-event listener attached.");
				}
			}
		}

		private void OnEventReceived(EventData eventData)
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			if (eventData.Code != 181 || !(eventData.CustomData is object[] array) || array.Length != 10 || !(array[0] is string text) || text != "com.juanma.teamping" || !(array[1] is byte b) || b != 1)
			{
				return;
			}
			int sender = eventData.Sender;
			if (sender <= 0 || !AllowRemoteSender(sender))
			{
				return;
			}
			if (!(array[2] is byte b2) || !Enum.IsDefined(typeof(PingTargetKind), b2) || !(array[3] is int num) || !(array[4] is int num2) || !(array[5] is Vector3 val) || !(array[6] is Vector3 val2) || !(array[7] is string value) || !(array[8] is int num3) || !(array[9] is int num4))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogWarning((object)$"[TeamPing/Network] Rejected malformed payload from actor {sender}.");
				}
			}
			else
			{
				if (!IsFinite(val) || !IsFinite(val2) || ((Vector3)(ref val)).sqrMagnitude > 1E+09f)
				{
					return;
				}
				int num5 = PhotonNetwork.ServerTimestamp - num4;
				if (num5 <= 15000 && num5 >= -2000)
				{
					string label = SanitizeLabel(value);
					int num6 = Mathf.Clamp(num3, -1, 100000000);
					PingData pingData = new PingData(num, sender, GetActorName(sender), (PingTargetKind)b2, Mathf.Max(0, num2), val, val2, label, num6 >= 0, Mathf.Max(0, num6), num4);
					if (_config.DebugLogging.Value)
					{
						_logger.LogInfo((object)$"[TeamPing/Network] Incoming ping: actor={sender}, id={num}, kind={pingData.Kind}, view={pingData.ViewId}, ageMs={num5}");
					}
					this.PingReceived?.Invoke(pingData);
				}
			}
		}

		private bool AllowRemoteSender(int actorNumber)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (_lastRemoteEventTime.TryGetValue(actorNumber, out var value) && realtimeSinceStartup - value < 0.15f)
			{
				return false;
			}
			_lastRemoteEventTime[actorNumber] = realtimeSinceStartup;
			return true;
		}

		public void Dispose()
		{
			if (_subscribedClient != null)
			{
				_subscribedClient.EventReceived -= OnEventReceived;
			}
			_subscribedClient = null;
			_lastRemoteEventTime.Clear();
			this.PingReceived = null;
		}

		private static string SanitizeLabel(string? value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return "PING";
			}
			char[] array = new char[Mathf.Min(64, value.Length)];
			int num = 0;
			string text = value.Trim();
			foreach (char c in text)
			{
				if (num >= array.Length)
				{
					break;
				}
				if (!char.IsControl(c))
				{
					array[num++] = c;
				}
			}
			if (num != 0)
			{
				return new string(array, 0, num);
			}
			return "PING";
		}

		private static bool IsFinite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (IsFinite(value.x) && IsFinite(value.y))
			{
				return IsFinite(value.z);
			}
			return false;
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
}
namespace TeamPing.Core
{
	public sealed class GameBindings
	{
		private readonly ManualLogSource _logger;

		private FieldInfo? _valuableCurrentValueField;

		private FieldInfo? _valuableValueSetField;

		private FieldInfo? _itemValueField;

		private FieldInfo? _itemNameField;

		private FieldInfo? _hasNeverBeenGrabbedField;

		private FieldInfo? _deadSetField;

		private FieldInfo? _isDisabledField;

		private FieldInfo? _runStartedField;

		private bool _readFailureReported;

		public GameBindings(ManualLogSource logger)
		{
			_logger = logger;
		}

		public bool Resolve()
		{
			_valuableCurrentValueField = ResolveField(typeof(ValuableObject), "dollarValueCurrent", typeof(float));
			_valuableValueSetField = ResolveField(typeof(ValuableObject), "dollarValueSet", typeof(bool));
			_itemValueField = ResolveField(typeof(ItemAttributes), "value", typeof(int));
			_itemNameField = ResolveField(typeof(ItemAttributes), "itemName", typeof(string));
			_hasNeverBeenGrabbedField = ResolveField(typeof(PhysGrabObject), "hasNeverBeenGrabbed", typeof(bool));
			_deadSetField = ResolveField(typeof(PlayerAvatar), "deadSet", typeof(bool));
			_isDisabledField = ResolveField(typeof(PlayerAvatar), "isDisabled", typeof(bool));
			_runStartedField = ResolveField(typeof(RunManager), "runStarted", typeof(bool));
			if (_valuableCurrentValueField != null && _itemValueField != null && _deadSetField != null)
			{
				return _runStartedField != null;
			}
			return false;
		}

		public bool IsGameplayActive(out string phase)
		{
			phase = "unavailable";
			try
			{
				RunManager instance = RunManager.instance;
				if ((Object)(object)instance == (Object)null)
				{
					phase = "RunManager missing";
					return false;
				}
				if (SemiFunc.IsMainMenu())
				{
					phase = "main menu";
					return false;
				}
				if (!TryRead<bool>(_runStartedField, instance, out var value) || !value)
				{
					phase = "run not started";
					return false;
				}
				if (SemiFunc.RunIsLevel())
				{
					phase = "mission level";
				}
				else if (SemiFunc.RunIsShop())
				{
					phase = "shop";
				}
				else if (SemiFunc.RunIsLobby())
				{
					phase = "run lobby";
				}
				else if (SemiFunc.RunIsTutorial())
				{
					phase = "tutorial";
				}
				else if (SemiFunc.RunIsArena())
				{
					phase = "arena";
				}
				else
				{
					phase = "active run";
				}
				return true;
			}
			catch (Exception ex)
			{
				phase = "state error: " + ex.GetType().Name;
				return false;
			}
		}

		public PlayerAvatar? GetLocalPlayer()
		{
			try
			{
				PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			catch
			{
			}
			try
			{
				return ((Object)(object)PlayerController.instance != (Object)null) ? PlayerController.instance.playerAvatarScript : null;
			}
			catch
			{
				return null;
			}
		}

		public Camera? GetGameplayCamera()
		{
			try
			{
				if ((Object)(object)CameraUtils.Instance != (Object)null && (Object)(object)CameraUtils.Instance.MainCamera != (Object)null)
				{
					return CameraUtils.Instance.MainCamera;
				}
			}
			catch
			{
			}
			return Camera.main;
		}

		public bool CanLocalPlayerPing(out string reason)
		{
			reason = string.Empty;
			PlayerAvatar localPlayer = GetLocalPlayer();
			if ((Object)(object)localPlayer == (Object)null)
			{
				reason = "local PlayerAvatar unavailable";
				return false;
			}
			if (TryRead<bool>(_deadSetField, localPlayer, out var value) && value)
			{
				reason = "local player is dead";
				return false;
			}
			if (TryRead<bool>(_isDisabledField, localPlayer, out var value2) && value2)
			{
				reason = "local player is disabled";
				return false;
			}
			if ((Object)(object)GetGameplayCamera() == (Object)null)
			{
				reason = "gameplay camera unavailable";
				return false;
			}
			try
			{
				if ((Object)(object)PlayerController.instance != (Object)null && !PlayerController.instance.CanInteract)
				{
					reason = "gameplay interaction is currently disabled";
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		public string GetPlayerName(PlayerAvatar? player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "PLAYER";
			}
			try
			{
				string text = SemiFunc.PlayerGetName(player);
				return string.IsNullOrWhiteSpace(text) ? "PLAYER" : text.Trim();
			}
			catch
			{
				return "PLAYER";
			}
		}

		public string GetItemName(ItemAttributes item)
		{
			if (TryRead<string>(_itemNameField, item, out var value) && !string.IsNullOrWhiteSpace(value))
			{
				return value.Trim();
			}
			return CleanObjectName(((Object)((Component)item).gameObject).name, "ITEM");
		}

		public bool TryGetValuableValue(ValuableObject valuable, PhysGrabObject? physObject, ValueDisplayMode mode, out int value)
		{
			value = 0;
			switch (mode)
			{
			case ValueDisplayMode.Never:
				return false;
			case ValueDisplayMode.AfterFirstGrab:
				if (HasNeverBeenGrabbed(physObject))
				{
					return false;
				}
				break;
			}
			if (_valuableValueSetField != null && TryRead<bool>(_valuableValueSetField, valuable, out var value2) && !value2)
			{
				return false;
			}
			if (!TryRead<float>(_valuableCurrentValueField, valuable, out var value3) || !IsFinite(value3) || value3 < 0f)
			{
				return false;
			}
			value = Mathf.RoundToInt(value3);
			return true;
		}

		public bool TryGetItemValue(ItemAttributes item, PhysGrabObject? physObject, ValueDisplayMode mode, out int value)
		{
			value = 0;
			switch (mode)
			{
			case ValueDisplayMode.Never:
				return false;
			case ValueDisplayMode.AfterFirstGrab:
				if (HasNeverBeenGrabbed(physObject))
				{
					return false;
				}
				break;
			}
			if (TryRead<int>(_itemValueField, item, out value))
			{
				return value > 0;
			}
			return false;
		}

		private bool HasNeverBeenGrabbed(PhysGrabObject? physObject)
		{
			bool value = default(bool);
			return (Object)(object)physObject != (Object)null && TryRead<bool>(_hasNeverBeenGrabbedField, physObject, out value) && value;
		}

		public static string CleanObjectName(string? rawName, string fallback)
		{
			if (string.IsNullOrWhiteSpace(rawName))
			{
				return fallback;
			}
			string text = rawName.Replace("(Clone)", string.Empty).Trim();
			string[] array = new string[6] { "Valuable ", "Valuable_", "Valuable-", "Item ", "Item_", "Prefab " };
			foreach (string text2 in array)
			{
				if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
				{
					text = text.Substring(text2.Length);
					break;
				}
			}
			text = text.Replace('_', ' ').Replace('-', ' ');
			StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
			for (int j = 0; j < text.Length; j++)
			{
				char c = text[j];
				if (j > 0 && char.IsUpper(c) && char.IsLower(text[j - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			string text3 = stringBuilder.ToString().Trim();
			if (!string.IsNullOrWhiteSpace(text3))
			{
				return text3;
			}
			return fallback;
		}

		private FieldInfo? ResolveField(Type type, string name, Type expectedType)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null || field.FieldType != expectedType)
			{
				_logger.LogWarning((object)("[TeamPing/Bindings] Missing field " + type.Name + "." + name + " (" + expectedType.Name + ")."));
				return null;
			}
			return field;
		}

		private bool TryRead<T>(FieldInfo? field, object target, out T value)
		{
			value = default(T);
			if (field == null || target == null)
			{
				return false;
			}
			try
			{
				if (field.GetValue(target) is T val)
				{
					value = val;
					return true;
				}
			}
			catch (Exception ex)
			{
				if (!_readFailureReported)
				{
					_readFailureReported = true;
					_logger.LogWarning((object)("[TeamPing/Bindings] Field read failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			return false;
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	public sealed class PingController : IDisposable
	{
		private readonly ModConfig _config;

		private readonly GameBindings _bindings;

		private readonly PingTargetResolver _targetResolver;

		private readonly PingNetwork _network;

		private readonly PingHudController _hud;

		private readonly ManualLogSource _logger;

		private int _lastTickFrame = -1;

		private int _nextPingId;

		private float _lastLocalPingTime = float.NegativeInfinity;

		private string _lastPhase = string.Empty;

		private bool _disposed;

		public PingController(ModConfig config, GameBindings bindings, ManualLogSource logger)
		{
			_config = config;
			_bindings = bindings;
			_logger = logger;
			_targetResolver = new PingTargetResolver(bindings, config, logger);
			_network = new PingNetwork(config, logger);
			_hud = new PingHudController(config, logger);
			_network.PingReceived += OnRemotePing;
			_config.Changed += OnConfigChanged;
		}

		public void Tick(float unscaledDeltaTime)
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || _lastTickFrame == Time.frameCount)
			{
				return;
			}
			_lastTickFrame = Time.frameCount;
			_config.PollForExternalChanges(unscaledDeltaTime);
			_network.Tick();
			string phase = (_config.Enabled.Value ? "checking" : "disabled by config");
			bool flag = _config.Enabled.Value && _bindings.IsGameplayActive(out phase);
			if (_config.DebugLogging.Value && _lastPhase != phase)
			{
				_lastPhase = phase;
				_logger.LogInfo((object)$"[TeamPing/Lifecycle] Gameplay phase changed: {phase}, active={flag}");
			}
			_hud.Tick(unscaledDeltaTime, _bindings.GetGameplayCamera(), flag);
			if (flag)
			{
				KeyboardShortcut value = _config.PingKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					TryCreateLocalPing();
				}
			}
		}

		public void HandleSceneChanged()
		{
			_hud.Clear();
			_lastLocalPingTime = float.NegativeInfinity;
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)"[TeamPing/Lifecycle] Scene changed; active pings cleared.");
			}
		}

		private void TryCreateLocalPing()
		{
			//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_01b6: Unknown result type (might be due to invalid IL or missing references)
			float unscaledTime = Time.unscaledTime;
			float num = Mathf.Clamp(_config.Cooldown.Value, 0.1f, 10f);
			if (unscaledTime - _lastLocalPingTime < num)
			{
				return;
			}
			if (!_bindings.CanLocalPlayerPing(out string reason))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)("[TeamPing/Input] Ping ignored: " + reason + "."));
				}
				return;
			}
			if (!_targetResolver.TryResolve(out PingTarget target, out reason))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)("[TeamPing/Input] No ping created: " + reason + "."));
				}
				return;
			}
			_lastLocalPingTime = unscaledTime;
			int num2 = ((PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0);
			string senderName = ((num2 > 0) ? _network.GetActorName(num2) : _bindings.GetPlayerName(_bindings.GetLocalPlayer()));
			int serverTimestamp = (PhotonNetwork.IsConnected ? PhotonNetwork.ServerTimestamp : Environment.TickCount);
			PingData ping = new PingData(++_nextPingId, num2, senderName, target.Kind, target.ViewId, target.WorldPosition, target.SurfaceNormal, target.Label, target.HasValue, target.Value, serverTimestamp);
			_hud.Show(ping);
			_network.Broadcast(ping);
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)string.Format("[TeamPing/Input] Created {0} ping at {1}, view={2}, label='{3}', value={4}", target.Kind, target.WorldPosition, target.ViewId, target.Label, target.HasValue ? target.Value.ToString() : "hidden"));
			}
		}

		private void OnRemotePing(PingData ping)
		{
			if (_config.Enabled.Value && _bindings.IsGameplayActive(out string _))
			{
				_hud.Show(ping);
			}
		}

		private void OnConfigChanged()
		{
			_hud.ApplyConfig();
			_logger.LogInfo((object)"[TeamPing/Config] Configuration applied without restarting the game.");
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				_config.Changed -= OnConfigChanged;
				_network.PingReceived -= OnRemotePing;
				_network.Dispose();
				_hud.Dispose();
			}
		}
	}
	public enum PingTargetKind : byte
	{
		Location,
		Valuable,
		Item,
		Cart,
		Player,
		Object
	}
	public readonly struct PingTarget
	{
		public PingTargetKind Kind { get; }

		public int ViewId { get; }

		public Vector3 WorldPosition { get; }

		public Vector3 SurfaceNormal { get; }

		public string Label { get; }

		public bool HasValue { get; }

		public int Value { get; }

		public PingTarget(PingTargetKind kind, int viewId, Vector3 worldPosition, Vector3 surfaceNormal, string label, bool hasValue, int value)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			Kind = kind;
			ViewId = viewId;
			WorldPosition = worldPosition;
			SurfaceNormal = surfaceNormal;
			Label = label;
			HasValue = hasValue;
			Value = value;
		}
	}
	public sealed class PingData
	{
		public int PingId { get; }

		public int SenderActorNumber { get; }

		public string SenderName { get; }

		public PingTargetKind Kind { get; }

		public int ViewId { get; }

		public Vector3 WorldPosition { get; }

		public Vector3 SurfaceNormal { get; }

		public string Label { get; }

		public bool HasValue { get; }

		public int Value { get; }

		public int ServerTimestamp { get; }

		public PingData(int pingId, int senderActorNumber, string senderName, PingTargetKind kind, int viewId, Vector3 worldPosition, Vector3 surfaceNormal, string label, bool hasValue, int value, int serverTimestamp)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			PingId = pingId;
			SenderActorNumber = senderActorNumber;
			SenderName = senderName;
			Kind = kind;
			ViewId = viewId;
			WorldPosition = worldPosition;
			SurfaceNormal = surfaceNormal;
			Label = label;
			HasValue = hasValue;
			Value = value;
			ServerTimestamp = serverTimestamp;
		}
	}
	public sealed class PingTargetResolver
	{
		private readonly GameBindings _bindings;

		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		public PingTargetResolver(GameBindings bindings, ModConfig config, ManualLogSource logger)
		{
			_bindings = bindings;
			_config = config;
			_logger = logger;
		}

		public bool TryResolve(out PingTarget target, out string failure)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			target = default(PingTarget);
			failure = string.Empty;
			Camera gameplayCamera = _bindings.GetGameplayCamera();
			PlayerAvatar localPlayer = _bindings.GetLocalPlayer();
			if ((Object)(object)gameplayCamera == (Object)null)
			{
				failure = "gameplay camera unavailable";
				return false;
			}
			float num = Mathf.Clamp(_config.Range.Value, 2f, 100f);
			RaycastHit[] array = Physics.RaycastAll(gameplayCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f)), num, -5, (QueryTriggerInteraction)1);
			if (array.Length == 0)
			{
				failure = "the crosshair did not hit a surface";
				return false;
			}
			Array.Sort(array, (RaycastHit left, RaycastHit right) => ((RaycastHit)(ref left)).distance.CompareTo(((RaycastHit)(ref right)).distance));
			RaycastHit[] array2 = array;
			for (int num2 = 0; num2 < array2.Length; num2++)
			{
				RaycastHit hit = array2[num2];
				Collider collider = ((RaycastHit)(ref hit)).collider;
				if ((Object)(object)collider == (Object)null || ((Object)(object)localPlayer != (Object)null && ((Component)collider).transform.IsChildOf(((Component)localPlayer).transform)))
				{
					continue;
				}
				try
				{
					target = Classify(hit, localPlayer);
					return true;
				}
				catch (MissingReferenceException)
				{
				}
				catch (Exception ex2)
				{
					failure = ex2.GetType().Name + ": " + ex2.Message;
					if (_config.DebugLogging.Value)
					{
						_logger.LogWarning((object)("[TeamPing/Target] Failed to classify hit '" + ((Object)collider).name + "': " + failure));
					}
					return false;
				}
			}
			failure = "only the local player was hit";
			return false;
		}

		private PingTarget Classify(RaycastHit hit, PlayerAvatar? localPlayer)
		{
			//IL_006d: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			Collider collider = ((RaycastHit)(ref hit)).collider;
			PlayerAvatar componentInParent = ((Component)collider).GetComponentInParent<PlayerAvatar>();
			if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)localPlayer)
			{
				return new PingTarget(PingTargetKind.Player, ViewId(componentInParent.photonView), ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, _bindings.GetPlayerName(componentInParent), hasValue: false, 0);
			}
			PhysGrabCart componentInParent2 = ((Component)collider).GetComponentInParent<PhysGrabCart>();
			if ((Object)(object)componentInParent2 != (Object)null)
			{
				return new PingTarget(PingTargetKind.Cart, ViewId(((Component)componentInParent2).GetComponentInParent<PhotonView>()), ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, "C.A.R.T.", hasValue: false, 0);
			}
			PhysGrabObject componentInParent3 = ((Component)collider).GetComponentInParent<PhysGrabObject>();
			if ((Object)(object)componentInParent3 != (Object)null)
			{
				int viewId = ViewId(((Component)componentInParent3).GetComponent<PhotonView>() ?? ((Component)componentInParent3).GetComponentInParent<PhotonView>());
				ValuableObject val = ((Component)componentInParent3).GetComponent<ValuableObject>() ?? ((Component)componentInParent3).GetComponentInChildren<ValuableObject>();
				if ((Object)(object)val != (Object)null)
				{
					int value;
					bool hasValue = _bindings.TryGetValuableValue(val, componentInParent3, _config.ValueMode.Value, out value);
					return new PingTarget(PingTargetKind.Valuable, viewId, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, GameBindings.CleanObjectName(((Object)((Component)val).gameObject).name, "VALUABLE"), hasValue, value);
				}
				ItemAttributes val2 = ((Component)componentInParent3).GetComponent<ItemAttributes>() ?? ((Component)componentInParent3).GetComponentInChildren<ItemAttributes>();
				if ((Object)(object)val2 != (Object)null)
				{
					int value2;
					bool hasValue2 = _bindings.TryGetItemValue(val2, componentInParent3, _config.ValueMode.Value, out value2);
					return new PingTarget(PingTargetKind.Item, viewId, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, _bindings.GetItemName(val2), hasValue2, value2);
				}
				return new PingTarget(PingTargetKind.Object, viewId, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, GameBindings.CleanObjectName(((Object)((Component)componentInParent3).gameObject).name, "OBJECT"), hasValue: false, 0);
			}
			string label = (string.IsNullOrWhiteSpace(_config.LocationLabel.Value) ? "LOOK HERE" : _config.LocationLabel.Value.Trim());
			return new PingTarget(PingTargetKind.Location, 0, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, label, hasValue: false, 0);
		}

		private static int ViewId(PhotonView? view)
		{
			if (!((Object)(object)view != (Object)null) || view.ViewID <= 0)
			{
				return 0;
			}
			return view.ViewID;
		}
	}
}
namespace TeamPing.Config
{
	public enum ValueDisplayMode
	{
		Always,
		AfterFirstGrab,
		Never
	}
	public sealed class ModConfig : IDisposable
	{
		private const float ExternalReloadInterval = 0.5f;

		private readonly List<Action> _unsubscribeActions = new List<Action>();

		private readonly ConfigFile _configFile;

		private DateTime _lastWriteTimeUtc;

		private long _lastFileLength;

		private float _externalReloadTimer;

		private bool _isReloading;

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<KeyboardShortcut> PingKey { get; }

		public ConfigEntry<float> Range { get; }

		public ConfigEntry<float> Cooldown { get; }

		public ConfigEntry<float> Duration { get; }

		public ConfigEntry<int> MaxPingsPerPlayer { get; }

		public ConfigEntry<ValueDisplayMode> ValueMode { get; }

		public ConfigEntry<string> LocationLabel { get; }

		public ConfigEntry<bool> ShowSender { get; }

		public ConfigEntry<bool> ShowDistance { get; }

		public ConfigEntry<bool> ScreenEdgeIndicators { get; }

		public ConfigEntry<float> MarkerScale { get; }

		public ConfigEntry<bool> SoundEnabled { get; }

		public ConfigEntry<float> SoundVolume { get; }

		public ConfigEntry<string> ValuableColor { get; }

		public ConfigEntry<string> ItemColor { get; }

		public ConfigEntry<string> CartColor { get; }

		public ConfigEntry<string> PlayerColor { get; }

		public ConfigEntry<string> LocationColor { get; }

		public ConfigEntry<bool> DebugLogging { get; }

		public event Action? Changed;

		public ModConfig(ConfigFile config)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			_configFile = config;
			Enabled = Bind(config, "General", "Enabled", defaultValue: true, "Enable TeamPing.");
			PingKey = Bind<KeyboardShortcut>(config, "General", "PingKey", new KeyboardShortcut((KeyCode)325, Array.Empty<KeyCode>()), "Press to ping the target under the crosshair.");
			Range = Bind(config, "General", "Range", 20f, "Maximum ping distance in metres.");
			Cooldown = Bind(config, "General", "Cooldown", 0.6f, "Minimum seconds between local pings.");
			Duration = Bind(config, "General", "Duration", 6f, "Seconds before a ping fades out.");
			MaxPingsPerPlayer = Bind(config, "General", "MaxPingsPerPlayer", 3, "Maximum simultaneous pings kept for each player.");
			ValueMode = Bind(config, "General", "ValueMode", ValueDisplayMode.Always, "Always, AfterFirstGrab, or Never. AfterFirstGrab is the most vanilla-faithful option.");
			LocationLabel = Bind(config, "General", "LocationLabel", "LOOK HERE", "Label used for surface/location pings.");
			ShowSender = Bind(config, "Appearance", "ShowSender", defaultValue: true, "Show who created each ping.");
			ShowDistance = Bind(config, "Appearance", "ShowDistance", defaultValue: true, "Show current distance to each ping.");
			ScreenEdgeIndicators = Bind(config, "Appearance", "ScreenEdgeIndicators", defaultValue: true, "Clamp off-screen pings to the screen edge.");
			MarkerScale = Bind(config, "Appearance", "MarkerScale", 1f, "Marker scale multiplier.");
			SoundEnabled = Bind(config, "Appearance", "SoundEnabled", defaultValue: true, "Play a short sound when a ping appears.");
			SoundVolume = Bind(config, "Appearance", "SoundVolume", 0.65f, "Ping sound volume from 0 to 1.");
			ValuableColor = Bind(config, "Appearance", "ValuableColor", "#61FF86", "Valuable marker color in HTML hex format.");
			ItemColor = Bind(config, "Appearance", "ItemColor", "#55D8FF", "Item marker color in HTML hex format.");
			CartColor = Bind(config, "Appearance", "CartColor", "#FFAE42", "C.A.R.T. marker color in HTML hex format.");
			PlayerColor = Bind(config, "Appearance", "PlayerColor", "#D58AFF", "Player marker color in HTML hex format.");
			LocationColor = Bind(config, "Appearance", "LocationColor", "#FFF1A8", "Location marker color in HTML hex format.");
			DebugLogging = Bind(config, "Debug", "DebugLogging", defaultValue: false, "Write useful ping diagnostics without per-frame spam.");
			CaptureFileState();
		}

		public bool PollForExternalChanges(float unscaledDeltaTime)
		{
			_externalReloadTimer -= Mathf.Max(0f, unscaledDeltaTime);
			if (_externalReloadTimer > 0f)
			{
				return false;
			}
			_externalReloadTimer = 0.5f;
			try
			{
				string configFilePath = _configFile.ConfigFilePath;
				if (!File.Exists(configFilePath))
				{
					return false;
				}
				FileInfo fileInfo = new FileInfo(configFilePath);
				if (fileInfo.LastWriteTimeUtc == _lastWriteTimeUtc && fileInfo.Length == _lastFileLength)
				{
					return false;
				}
				bool saveOnConfigSet = _configFile.SaveOnConfigSet;
				try
				{
					_isReloading = true;
					_configFile.SaveOnConfigSet = false;
					_configFile.Reload();
				}
				finally
				{
					_isReloading = false;
					_configFile.SaveOnConfigSet = saveOnConfigSet;
				}
				CaptureFileState();
				this.Changed?.Invoke();
				return true;
			}
			catch (IOException)
			{
				return false;
			}
			catch (UnauthorizedAccessException)
			{
				return false;
			}
		}

		private ConfigEntry<T> Bind<T>(ConfigFile config, string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> entry = config.Bind<T>(section, key, defaultValue, description);
			entry.SettingChanged += OnSettingChanged;
			_unsubscribeActions.Add(delegate
			{
				entry.SettingChanged -= OnSettingChanged;
			});
			return entry;
		}

		private void OnSettingChanged(object sender, EventArgs args)
		{
			if (!_isReloading)
			{
				this.Changed?.Invoke();
			}
		}

		private void CaptureFileState()
		{
			string configFilePath = _configFile.ConfigFilePath;
			if (File.Exists(configFilePath))
			{
				FileInfo fileInfo = new FileInfo(configFilePath);
				_lastWriteTimeUtc = fileInfo.LastWriteTimeUtc;
				_lastFileLength = fileInfo.Length;
			}
		}

		public void Dispose()
		{
			foreach (Action unsubscribeAction in _unsubscribeActions)
			{
				unsubscribeAction();
			}
			_unsubscribeActions.Clear();
		}
	}
}