using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EnhancedPing.Core;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
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("EnhancedPing")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7191e90729a136227fa75d774a7fa881c5a0faf1")]
[assembly: AssemblyProduct("EnhancedPing")]
[assembly: AssemblyTitle("EnhancedPing")]
[assembly: AssemblyVersion("1.0.0.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 EnhancedPing
{
internal sealed class EnhancedPingController
{
private readonly Plugin _plugin;
private readonly ModConfig _config;
private readonly ManualLogSource _logger;
private readonly PathPreview _preview = new PathPreview();
private readonly PingDistanceOverlay _distanceOverlay;
private readonly GhostReticleOverlay _ghostReticle = new GhostReticleOverlay();
private static readonly MethodInfo? ReceivePointMethod = AccessTools.Method(typeof(PointPinger), "ReceivePoint_Rpc", (Type[])null, (Type[])null);
private PatchCapabilities _capabilities;
private PathDrawingSession? _drawing;
private PointPinger? _drawingPinger;
private PointPinger? _drawingCarrier;
private Coroutine? _sequence;
private PointPinger? _sequencePinger;
public EnhancedPingController(Plugin plugin, ModConfig config, ManualLogSource logger)
{
_plugin = plugin;
_config = config;
_logger = logger;
_distanceOverlay = new PingDistanceOverlay(config, logger);
}
public void SetCapabilities(PatchCapabilities capabilities)
{
_capabilities = capabilities;
}
public void TickLifecycle()
{
if (!_config.Enabled.Value)
{
Reset("feature disabled");
return;
}
if (_drawing != null && ((Object)(object)_drawingPinger == (Object)null || (Object)(object)_drawingCarrier == (Object)null || (Object)(object)Character.localCharacter == (Object)null || !InputAllowed()))
{
CancelDrawing("input or character lifecycle ended");
}
if (_sequence != null && ((Object)(object)_sequencePinger == (Object)null || (Object)(object)Character.localCharacter == (Object)null))
{
CancelSequence();
}
}
public bool BeforePointPingerUpdate(PointPinger pinger, ref float timeLastPinged)
{
if (!_capabilities.Input || !_config.Enabled.Value || !IsLocalPinger(pinger))
{
return true;
}
InputAction action_ping = CharacterInput.action_ping;
if (action_ping == null)
{
return true;
}
if (_drawing != null)
{
return ContinueDrawing(pinger, action_ping, ref timeLastPinged);
}
if (!_config.PathEnabled.Value)
{
if (!_config.GhostEnabled.Value || (Object)(object)pinger.character?.data == (Object)null || !pinger.character.data.dead)
{
return true;
}
if (action_ping.WasPressedThisFrame() && CanStartEnhancedPing(pinger, timeLastPinged) && InputAllowed() && TryResolvePingCarrier(pinger, out PointPinger carrier) && TryGetPingSample(out var sample))
{
timeLastPinged = Time.time;
SendVanillaPing(carrier, sample);
}
return false;
}
if (!action_ping.WasPressedThisFrame())
{
return true;
}
CancelSequence();
if (CanStartEnhancedPing(pinger, timeLastPinged) && InputAllowed() && TryResolvePingCarrier(pinger, out PointPinger carrier2))
{
BeginDrawing(pinger, carrier2);
}
return false;
}
public void ShowDistanceLabel(PointPinger pinger, GameObject previousMarker, GameObject currentMarker)
{
if (_capabilities.Distance && !((Object)(object)pinger.character == (Object)null) && !((Object)(object)currentMarker == (Object)null) && previousMarker != currentMarker)
{
_distanceOverlay.Show(pinger.character, currentMarker);
}
}
public void InitializeDistanceOverlay(GUIManager gui)
{
if (_config.Enabled.Value && _config.DistanceEnabled.Value)
{
_distanceOverlay.Initialize(gui);
}
}
public void DestroyDistanceOverlay()
{
_distanceOverlay.Dispose();
_ghostReticle.Dispose();
}
public void UpdateDeadReticle(GUIManager gui)
{
Character localCharacter = Character.localCharacter;
bool visible = _capabilities.DeadReticle && (Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && localCharacter.data.dead && _config.Enabled.Value && _config.GhostEnabled.Value && _config.ShowReticleWhenDead.Value && Time.timeScale > 0f && !GUIManager.InPauseMenu && !gui.windowBlockingInput && !gui.wheelActive;
_ghostReticle.Update(gui, visible);
}
public void Reset(string reason)
{
bool num = _drawing != null || _sequence != null;
CancelDrawing(reason);
CancelSequence();
_distanceOverlay.Dispose();
_ghostReticle.Dispose();
if (num)
{
_logger.LogDebug((object)("Enhanced ping state reset: " + reason + "."));
}
}
private bool ContinueDrawing(PointPinger pinger, InputAction pingAction, ref float timeLastPinged)
{
PointPinger drawingCarrier = _drawingCarrier;
if ((Object)(object)pinger != (Object)(object)_drawingPinger || (Object)(object)drawingCarrier == (Object)null || !IsLivingCarrier(drawingCarrier) || !_config.PathEnabled.Value || !InputAllowed())
{
CancelDrawing("path drawing cancelled");
return false;
}
CaptureDrawingSample();
if (pingAction.IsPressed() && !pingAction.WasReleasedThisFrame())
{
return false;
}
PathDrawingResult pathDrawingResult = _drawing.Finish(_config.SafeMaximumPingPoints);
CancelDrawing("path drawing completed");
if (pathDrawingResult.Samples.Count == 0)
{
return false;
}
timeLastPinged = Time.time;
if (pathDrawingResult.TotalAngleDegrees < _config.SafeMinimumPathAngle || pathDrawingResult.Samples.Count < 2)
{
SendVanillaPing(drawingCarrier, pathDrawingResult.Samples[pathDrawingResult.Samples.Count - 1]);
return false;
}
_sequencePinger = drawingCarrier;
_sequence = ((MonoBehaviour)_plugin).StartCoroutine(SendSequence(drawingCarrier, pathDrawingResult.Samples));
return false;
}
private void BeginDrawing(PointPinger pinger, PointPinger carrier)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
CancelDrawing("new path started");
_drawing = new PathDrawingSession();
_drawingPinger = pinger;
_drawingCarrier = carrier;
if (_config.ShowPathPreview.Value)
{
_preview.Initialize(GetPlayerColor(carrier.character));
}
CaptureDrawingSample();
}
private void CaptureDrawingSample()
{
if (_drawing != null && TryGetPingSample(out var sample))
{
_drawing.Capture(sample, _config.SafeMinimumCaptureAngle);
if (_config.ShowPathPreview.Value)
{
_preview.Update(_drawing.PreviewSamples);
}
}
}
private IEnumerator SendSequence(PointPinger pinger, IReadOnlyList<RuntimePingSample> samples)
{
float num = SequenceTiming.EffectivePointDuration(samples.Count, _config.SafePreferredPointDuration, _config.SafeMaximumSequenceDuration);
WaitForSeconds wait = new WaitForSeconds(num);
for (int i = 0; i < samples.Count; i++)
{
if ((Object)(object)pinger == (Object)null)
{
break;
}
if (!IsLivingCarrier(pinger))
{
break;
}
if (!_config.Enabled.Value)
{
break;
}
SendVanillaPing(pinger, samples[i]);
if (i < samples.Count - 1)
{
yield return wait;
}
}
_sequence = null;
_sequencePinger = null;
}
private void SendVanillaPing(PointPinger pinger, RuntimePingSample sample)
{
//IL_0060: 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)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
PhotonView component = ((Component)pinger).GetComponent<PhotonView>();
if (!((Object)(object)component == (Object)null))
{
if (pinger.character == Character.localCharacter)
{
component.RPC("ReceivePoint_Rpc", (RpcTarget)0, new object[2] { sample.Point, sample.Normal });
}
else
{
component.RPC("ReceivePoint_Rpc", (RpcTarget)1, new object[2] { sample.Point, sample.Normal });
ShowPingLocally(pinger, sample);
}
}
}
private void ShowPingLocally(PointPinger pinger, RuntimePingSample sample)
{
//IL_0027: 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)
Character localCharacter = Character.localCharacter;
try
{
Character.localCharacter = pinger.character;
ReceivePointMethod?.Invoke(pinger, new object[2] { sample.Point, sample.Normal });
}
catch (Exception arg)
{
_logger.LogWarning((object)$"Could not show an enhanced ping locally: {arg}");
}
finally
{
Character.localCharacter = localCharacter;
}
}
private bool CanStartEnhancedPing(PointPinger pinger, float timeLastPinged)
{
if (Time.time - timeLastPinged < pinger.coolDown || (Object)(object)pinger.character?.data == (Object)null)
{
return false;
}
if (!pinger.character.data.fullyConscious)
{
if (_config.GhostEnabled.Value)
{
return pinger.character.data.dead;
}
return false;
}
return true;
}
private static bool TryResolvePingCarrier(PointPinger source, out PointPinger carrier)
{
carrier = null;
if ((Object)(object)source.character?.data == (Object)null)
{
return false;
}
if (!source.character.data.dead)
{
carrier = source;
return IsLivingCarrier(carrier);
}
Character specCharacter = MainCameraMovement.specCharacter;
if ((Object)(object)specCharacter == (Object)null || specCharacter == source.character || (Object)(object)specCharacter.data == (Object)null || specCharacter.data.dead)
{
return false;
}
PointPinger component = ((Component)specCharacter).GetComponent<PointPinger>();
if (!IsLivingCarrier(component))
{
return false;
}
carrier = component;
return true;
}
private static bool IsLivingCarrier(PointPinger pinger)
{
if ((Object)(object)pinger == (Object)null || (Object)(object)pinger.character?.data == (Object)null || pinger.character.data.dead)
{
return false;
}
PhotonView component = ((Component)pinger).GetComponent<PhotonView>();
if ((Object)(object)component != (Object)null)
{
return component.ViewID > 0;
}
return false;
}
private static bool IsLocalPinger(PointPinger pinger)
{
if ((Object)(object)pinger.character == (Object)null || (Object)(object)pinger.character != (Object)(object)Character.localCharacter)
{
return false;
}
PhotonView component = ((Component)pinger).GetComponent<PhotonView>();
if ((Object)(object)component != (Object)null)
{
return component.IsMine;
}
return false;
}
private static bool InputAllowed()
{
if (Time.timeScale <= 0f || GUIManager.InPauseMenu)
{
return false;
}
GUIManager instance = GUIManager.instance;
if (!((Object)(object)instance == (Object)null))
{
if (!instance.windowBlockingInput)
{
return !instance.wheelActive;
}
return false;
}
return true;
}
private static bool TryGetPingSample(out RuntimePingSample sample)
{
//IL_0019: 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)
//IL_0023: 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_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//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_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: 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_008b: Unknown result type (might be due to invalid IL or missing references)
sample = default(RuntimePingSample);
Camera main = Camera.main;
if ((Object)(object)main == (Object)null)
{
return false;
}
Ray val = main.ScreenPointToRay(Input.mousePosition);
int num = LayerMask.op_Implicit(HelperFunctions.GetMask((LayerType)1));
RaycastHit val2 = default(RaycastHit);
if (num == 0 || !Physics.Raycast(val, ref val2, float.PositiveInfinity, num))
{
return false;
}
if (!IsFinite(((Ray)(ref val)).direction) || !IsFinite(((RaycastHit)(ref val2)).point) || !IsFinite(((RaycastHit)(ref val2)).normal))
{
return false;
}
Vector3 direction = ((Ray)(ref val)).direction;
sample = new RuntimePingSample(((Vector3)(ref direction)).normalized, ((RaycastHit)(ref val2)).point, ((RaycastHit)(ref val2)).normal);
return true;
}
private void CancelDrawing(string reason)
{
if (_drawing != null)
{
_logger.LogDebug((object)("Path drawing ended: " + reason + "."));
}
_drawing = null;
_drawingPinger = null;
_drawingCarrier = null;
_preview.Dispose();
}
private void CancelSequence()
{
if (_sequence != null)
{
((MonoBehaviour)_plugin).StopCoroutine(_sequence);
}
_sequence = null;
_sequencePinger = null;
}
private static Color GetPlayerColor(Character character)
{
//IL_000b: 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_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
try
{
return character.refs.customization.PlayerColor;
}
catch
{
return Color.white;
}
}
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;
}
}
internal sealed class GhostReticleOverlay
{
private Canvas? _canvas;
private Image? _image;
private GUIManager? _gui;
public void Update(GUIManager gui, bool visible)
{
if (!visible)
{
if ((Object)(object)_canvas != (Object)null && ((Component)_canvas).gameObject.activeSelf)
{
((Component)_canvas).gameObject.SetActive(false);
}
return;
}
if ((Object)(object)_canvas == (Object)null || (Object)(object)_image == (Object)null || (Object)(object)_gui != (Object)(object)gui)
{
Initialize(gui);
}
if ((Object)(object)_canvas != (Object)null && !((Component)_canvas).gameObject.activeSelf)
{
((Component)_canvas).gameObject.SetActive(true);
}
}
public void Dispose()
{
if ((Object)(object)_canvas != (Object)null)
{
Object.Destroy((Object)(object)((Component)_canvas).gameObject);
}
_canvas = null;
_image = null;
_gui = null;
}
private void Initialize(GUIManager gui)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Expected O, but got Unknown
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: 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_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
Dispose();
Image reticleDefaultImage = gui.reticleDefaultImage;
if (!((Object)(object)reticleDefaultImage == (Object)null) && !((Object)(object)reticleDefaultImage.sprite == (Object)null))
{
GameObject val = new GameObject("Canvas_EnhancedPingGhostReticle", new Type[2]
{
typeof(Canvas),
typeof(CanvasScaler)
});
val.transform.SetParent(((Component)gui).transform, false);
val.layer = LayerMask.NameToLayer("UI");
_canvas = val.GetComponent<Canvas>();
_canvas.renderMode = (RenderMode)0;
_canvas.sortingOrder = 101;
CanvasScaler component = val.GetComponent<CanvasScaler>();
component.uiScaleMode = (ScaleMode)1;
component.referenceResolution = new Vector2(1920f, 1080f);
component.screenMatchMode = (ScreenMatchMode)1;
GameObject val2 = new GameObject("EnhancedPingGhostReticle", new Type[3]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image)
});
val2.transform.SetParent(((Component)_canvas).transform, false);
RectTransform rectTransform = ((Graphic)reticleDefaultImage).rectTransform;
RectTransform component2 = val2.GetComponent<RectTransform>();
component2.anchorMin = new Vector2(0.5f, 0.5f);
component2.anchorMax = new Vector2(0.5f, 0.5f);
component2.pivot = rectTransform.pivot;
component2.anchoredPosition = Vector2.zero;
Rect rect = rectTransform.rect;
component2.sizeDelta = ((Rect)(ref rect)).size;
((Transform)component2).localScale = ((Transform)rectTransform).localScale;
_image = val2.GetComponent<Image>();
_image.sprite = reticleDefaultImage.sprite;
((Graphic)_image).material = ((Graphic)reticleDefaultImage).material;
((Graphic)_image).color = ((Graphic)reticleDefaultImage).color;
_image.type = reticleDefaultImage.type;
_image.preserveAspect = reticleDefaultImage.preserveAspect;
((Graphic)_image).raycastTarget = false;
_gui = gui;
}
}
}
internal sealed class ModConfig
{
private const int DefaultMaximumPingPoints = 10;
private const float DefaultMinimumCaptureAngle = 0.5f;
private const float DefaultMinimumPathAngle = 1.5f;
private const float DefaultPreferredPointDuration = 0.2f;
private const float DefaultMaximumSequenceDuration = 2f;
private const int DefaultFontSize = 24;
public ConfigEntry<bool> Enabled { get; }
public ConfigEntry<bool> DistanceEnabled { get; }
public ConfigEntry<int> DistanceDecimalPlaces { get; }
public ConfigEntry<int> DistanceFontSize { get; }
public ConfigEntry<bool> GhostEnabled { get; }
public ConfigEntry<bool> ShowReticleWhenDead { get; }
public ConfigEntry<bool> PathEnabled { get; }
public ConfigEntry<int> MaximumPingPoints { get; }
public ConfigEntry<float> MinimumCaptureAngleDegrees { get; }
public ConfigEntry<float> MinimumPathAngleDegrees { get; }
public ConfigEntry<float> PreferredPointDurationSeconds { get; }
public ConfigEntry<float> MaximumSequenceDurationSeconds { get; }
public ConfigEntry<bool> ShowPathPreview { get; }
public int SafeDistanceDecimals => Mathf.Clamp(DistanceDecimalPlaces.Value, 0, 1);
public int SafeDistanceFontSize => Mathf.Clamp(DistanceFontSize.Value, 10, 72);
public int SafeMaximumPingPoints => Mathf.Clamp(MaximumPingPoints.Value, 2, 20);
public float SafeMinimumCaptureAngle => SafeRange(MinimumCaptureAngleDegrees.Value, 0.05f, 5f, 0.5f);
public float SafeMinimumPathAngle => SafeRange(MinimumPathAngleDegrees.Value, 0.1f, 30f, 1.5f);
public float SafePreferredPointDuration => SafeRange(PreferredPointDurationSeconds.Value, 0.05f, 1f, 0.2f);
public float SafeMaximumSequenceDuration => SafeRange(MaximumSequenceDurationSeconds.Value, 1f, 10f, 2f);
public ModConfig(ConfigFile config)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Expected O, but got Unknown
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Expected O, but got Unknown
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
//IL_018b: Expected O, but got Unknown
//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
//IL_01c4: Expected O, but got Unknown
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_01fd: Expected O, but got Unknown
Enabled = config.Bind<bool>("General", "Enabled", true, "Enable EnhancedPing features.");
DistanceEnabled = config.Bind<bool>("Distance", "Enabled", true, "Show distance on visible ping markers.");
DistanceDecimalPlaces = config.Bind<int>("Distance", "DecimalPlaces", 0, new ConfigDescription("Number of decimal places used by distance labels.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1), Array.Empty<object>()));
DistanceFontSize = config.Bind<int>("Distance", "FontSize", 24, new ConfigDescription("Distance label font size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 72), Array.Empty<object>()));
GhostEnabled = config.Bind<bool>("Ghost", "Enabled", true, "Allow ping input while the local scout is dead.");
ShowReticleWhenDead = config.Bind<bool>("Ghost", "ShowReticleWhenDead", true, "Show PEAK's default center reticle while the local scout is dead.");
PathEnabled = config.Bind<bool>("Path", "Enabled", true, "Hold the rebound Ping action and move the aim to draw a path.");
MaximumPingPoints = config.Bind<int>("Path", "MaximumPingPoints", 10, new ConfigDescription("Maximum transmitted points, including the start and end.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 20), Array.Empty<object>()));
MinimumCaptureAngleDegrees = config.Bind<float>("Path", "MinimumCaptureAngleDegrees", 0.5f, new ConfigDescription("Minimum angular movement between captured aim rays.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
MinimumPathAngleDegrees = config.Bind<float>("Path", "MinimumPathAngleDegrees", 1.5f, new ConfigDescription("Minimum cumulative angular movement required to classify a held Ping as a path.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
PreferredPointDurationSeconds = config.Bind<float>("Path", "PreferredPointDurationSeconds", 0.2f, new ConfigDescription("Preferred lifetime of each intermediate ping before the next replaces it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
MaximumSequenceDurationSeconds = config.Bind<float>("Path", "MaximumSequenceDurationSeconds", 2f, new ConfigDescription("Maximum time from the first path ping until the endpoint appears.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
ShowPathPreview = config.Bind<bool>("Path", "ShowPreview", true, "Show a local line while drawing a path.");
}
private static float SafeRange(float value, float minimum, float maximum, float fallback)
{
if (float.IsNaN(value) || float.IsInfinity(value))
{
return fallback;
}
return Mathf.Clamp(value, minimum, maximum);
}
}
internal readonly struct PatchCapabilities
{
public bool Input { get; }
public bool Distance { get; }
public bool DeadReticle { get; }
public PatchCapabilities(bool input, bool distance, bool deadReticle)
{
Input = input;
Distance = distance;
DeadReticle = deadReticle;
}
}
internal static class PatchInstaller
{
public static PatchCapabilities Install(Harmony harmony, ManualLogSource logger)
{
bool input = TryPatch(harmony, AccessTools.Method(typeof(PointPinger), "Update", (Type[])null, (Type[])null), AccessTools.Method(typeof(PatchCallbacks), "PointPingerUpdatePrefix", (Type[])null, (Type[])null), null, "PointPinger.Update", logger);
bool distance = TryPatch(harmony, AccessTools.Method(typeof(PointPinger), "ReceivePoint_Rpc", (Type[])null, (Type[])null), AccessTools.Method(typeof(PatchCallbacks), "ReceivePointPrefix", (Type[])null, (Type[])null), AccessTools.Method(typeof(PatchCallbacks), "ReceivePointPostfix", (Type[])null, (Type[])null), "PointPinger.ReceivePoint_Rpc", logger);
TryPatch(harmony, AccessTools.Method(typeof(GUIManager), "Start", (Type[])null, (Type[])null), null, AccessTools.Method(typeof(PatchCallbacks), "GUIManagerStartPostfix", (Type[])null, (Type[])null), "GUIManager.Start", logger);
TryPatch(harmony, AccessTools.Method(typeof(GUIManager), "OnDestroy", (Type[])null, (Type[])null), AccessTools.Method(typeof(PatchCallbacks), "GUIManagerOnDestroyPrefix", (Type[])null, (Type[])null), null, "GUIManager.OnDestroy", logger);
bool deadReticle = TryPatch(harmony, AccessTools.Method(typeof(GUIManager), "LateUpdate", (Type[])null, (Type[])null), null, AccessTools.Method(typeof(PatchCallbacks), "GUIManagerLateUpdatePostfix", (Type[])null, (Type[])null), "GUIManager.LateUpdate", logger);
return new PatchCapabilities(input, distance, deadReticle);
}
private static bool TryPatch(Harmony harmony, MethodInfo? original, MethodInfo? prefix = null, MethodInfo? postfix = null, string? description = null, ManualLogSource? logger = null)
{
//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_0063: 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)
if (original == null || (prefix == null && postfix == null))
{
if (logger != null)
{
logger.LogError((object)("Required patch target is missing: " + description + "."));
}
return false;
}
try
{
harmony.Patch((MethodBase)original, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix)
{
priority = 800
}, (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix)
{
priority = 0
}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
return true;
}
catch (Exception arg)
{
if (logger != null)
{
logger.LogError((object)$"Failed to patch {description}: {arg}");
}
return false;
}
}
}
internal static class PatchCallbacks
{
public static bool PointPingerUpdatePrefix(PointPinger __instance, ref float ____timeLastPinged)
{
return (Plugin.Instance?.Controller)?.BeforePointPingerUpdate(__instance, ref ____timeLastPinged) ?? true;
}
public static void ReceivePointPrefix(ref GameObject ___pingInstance, out GameObject __state)
{
__state = ___pingInstance;
}
public static void ReceivePointPostfix(PointPinger __instance, GameObject __state, ref GameObject ___pingInstance)
{
Plugin.Instance?.Controller.ShowDistanceLabel(__instance, __state, ___pingInstance);
}
public static void GUIManagerStartPostfix(GUIManager __instance)
{
Plugin.Instance?.Controller.InitializeDistanceOverlay(__instance);
}
public static void GUIManagerOnDestroyPrefix(GUIManager __instance)
{
Plugin.Instance?.Controller.DestroyDistanceOverlay();
}
public static void GUIManagerLateUpdatePostfix(GUIManager __instance)
{
Plugin.Instance?.Controller.UpdateDeadReticle(__instance);
}
}
internal readonly struct PathDrawingResult
{
public IReadOnlyList<RuntimePingSample> Samples { get; }
public float TotalAngleDegrees { get; }
public PathDrawingResult(IReadOnlyList<RuntimePingSample> samples, float totalAngleDegrees)
{
Samples = samples;
TotalAngleDegrees = totalAngleDegrees;
}
}
internal sealed class PathDrawingSession
{
private readonly List<RuntimePingSample> _accepted = new List<RuntimePingSample>();
private RuntimePingSample _latest;
private bool _hasLatest;
public IReadOnlyList<RuntimePingSample> PreviewSamples
{
get
{
//IL_0037: 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)
if (!_hasLatest || _accepted.Count == 0)
{
return _accepted;
}
if (Angle(_accepted[_accepted.Count - 1].Direction, _latest.Direction) <= 0.0001f)
{
return _accepted;
}
List<RuntimePingSample> list = new List<RuntimePingSample>(_accepted.Count + 1);
list.AddRange(_accepted);
list.Add(_latest);
return list;
}
}
public void Capture(RuntimePingSample sample, float minimumAngleDegrees)
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
_latest = sample;
_hasLatest = true;
if (_accepted.Count == 0 || Angle(_accepted[_accepted.Count - 1].Direction, sample.Direction) >= minimumAngleDegrees)
{
_accepted.Add(sample);
}
}
public PathDrawingResult Finish(int maximumPoints)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
if (_hasLatest && (_accepted.Count == 0 || Angle(_accepted[_accepted.Count - 1].Direction, _latest.Direction) > 0.0001f))
{
_accepted.Add(_latest);
}
List<SphericalPathSample> list = new List<SphericalPathSample>(_accepted.Count);
foreach (RuntimePingSample item in _accepted)
{
list.Add(item.ToCore());
}
float totalAngleDegrees;
IReadOnlyList<SphericalPathSample> readOnlyList = SphericalPathSelector.Select(list, maximumPoints, out totalAngleDegrees);
List<RuntimePingSample> list2 = new List<RuntimePingSample>(readOnlyList.Count);
foreach (SphericalPathSample item2 in readOnlyList)
{
list2.Add(RuntimePingSample.FromCore(item2));
}
return new PathDrawingResult(list2, totalAngleDegrees);
}
private static float Angle(Vector3 left, Vector3 right)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if (((Vector3)(ref left)).sqrMagnitude <= 1E-08f || ((Vector3)(ref right)).sqrMagnitude <= 1E-08f)
{
return float.NaN;
}
return Vector3.Angle(left, right);
}
}
internal sealed class PathPreview
{
private GameObject? _gameObject;
private LineRenderer? _line;
private Material? _material;
public void Initialize(Color color)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
//IL_00b8: 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)
Dispose();
Shader val = Shader.Find("Sprites/Default");
if (!((Object)(object)val == (Object)null))
{
_gameObject = new GameObject("EnhancedPing.PathPreview");
((Object)_gameObject).hideFlags = (HideFlags)61;
_line = _gameObject.AddComponent<LineRenderer>();
_material = new Material(val);
((Renderer)_line).material = _material;
_line.useWorldSpace = true;
_line.alignment = (LineAlignment)0;
_line.widthMultiplier = 0.045f;
_line.numCapVertices = 4;
_line.numCornerVertices = 2;
color.a = 0.9f;
_line.startColor = color;
_line.endColor = color;
_line.positionCount = 0;
}
}
public void Update(IReadOnlyList<RuntimePingSample> samples)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: 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_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_line == (Object)null)
{
return;
}
_line.positionCount = samples.Count;
for (int i = 0; i < samples.Count; i++)
{
Vector3 normal = samples[i].Normal;
Vector3 val;
if (!(((Vector3)(ref normal)).sqrMagnitude > 1E-08f))
{
val = Vector3.up;
}
else
{
normal = samples[i].Normal;
val = ((Vector3)(ref normal)).normalized;
}
Vector3 val2 = val;
_line.SetPosition(i, samples[i].Point + val2 * 0.035f);
}
}
public void Dispose()
{
if ((Object)(object)_gameObject != (Object)null)
{
Object.Destroy((Object)(object)_gameObject);
}
if ((Object)(object)_material != (Object)null)
{
Object.Destroy((Object)(object)_material);
}
_gameObject = null;
_line = null;
_material = null;
}
}
internal sealed class PingDistanceOverlay
{
private readonly ModConfig _config;
private readonly ManualLogSource _logger;
private readonly Dictionary<Character, GameObject> _instances = new Dictionary<Character, GameObject>();
private Canvas? _canvas;
private GameObject? _template;
public PingDistanceOverlay(ModConfig config, ManualLogSource logger)
{
_config = config;
_logger = logger;
}
public void Initialize(GUIManager gui)
{
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Expected O, but got Unknown
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Expected O, but got Unknown
if ((Object)(object)_canvas != (Object)null && (Object)(object)_template != (Object)null && (Object)(object)((Component)_canvas).transform.parent == (Object)(object)((Component)gui).transform)
{
return;
}
Dispose();
TextMeshProUGUI interactNameText = gui.interactNameText;
if ((Object)(object)interactNameText == (Object)null || (Object)(object)((TMP_Text)interactNameText).font == (Object)null || (Object)(object)((TMP_Text)interactNameText).fontSharedMaterial == (Object)null)
{
_logger.LogError((object)"Could not initialize distance labels from GUIManager.interactNameText.");
return;
}
try
{
GameObject val = new GameObject("Canvas_EnhancedPingDistance", new Type[2]
{
typeof(Canvas),
typeof(CanvasScaler)
});
val.transform.SetParent(((Component)gui).transform, false);
val.layer = LayerMask.NameToLayer("UI");
_canvas = val.GetComponent<Canvas>();
_canvas.renderMode = (RenderMode)0;
_canvas.sortingOrder = 100;
CanvasScaler component = val.GetComponent<CanvasScaler>();
component.uiScaleMode = (ScaleMode)1;
component.referenceResolution = new Vector2(1920f, 1080f);
component.screenMatchMode = (ScreenMatchMode)1;
_template = new GameObject("EnhancedPingDistanceIndicator", new Type[3]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(PingDistanceLabel)
});
_template.transform.SetParent(((Component)_canvas).transform, false);
CreateText(_template.transform, ((TMP_Text)interactNameText).font, ((TMP_Text)interactNameText).fontSharedMaterial);
_template.SetActive(false);
_logger.LogInfo((object)"Distance label overlay initialized from GUIManager.interactNameText.");
}
catch (Exception arg)
{
_logger.LogWarning((object)$"Could not initialize the ping distance overlay: {arg}");
Dispose();
}
}
public void Show(Character character, GameObject marker)
{
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
if (!_config.Enabled.Value || !_config.DistanceEnabled.Value || (Object)(object)character == (Object)null || (Object)(object)marker == (Object)null)
{
return;
}
if ((Object)(object)_canvas == (Object)null || (Object)(object)_template == (Object)null)
{
GUIManager instance = GUIManager.instance;
if ((Object)(object)instance != (Object)null)
{
Initialize(instance);
}
}
if ((Object)(object)_canvas == (Object)null || (Object)(object)_template == (Object)null)
{
return;
}
if (_instances.TryGetValue(character, out GameObject value) && (Object)(object)value != (Object)null)
{
Object.Destroy((Object)(object)value);
}
try
{
PointPing component = marker.GetComponent<PointPing>();
Vector3 normal = (((Object)(object)component != (Object)null && ((Vector3)(ref component.hitNormal)).sqrMagnitude > 1E-08f) ? ((Vector3)(ref component.hitNormal)).normalized : Vector3.up);
GameObject val = Object.Instantiate<GameObject>(_template, ((Component)_canvas).transform);
val.GetComponent<PingDistanceLabel>().Initialize(marker, normal, GetPlayerColor(character), _config);
val.SetActive(true);
_instances[character] = val;
}
catch (Exception arg)
{
_logger.LogWarning((object)$"Could not create a ping distance label: {arg}");
}
}
public void Dispose()
{
if ((Object)(object)_canvas != (Object)null)
{
Object.Destroy((Object)(object)((Component)_canvas).gameObject);
}
_canvas = null;
_template = null;
_instances.Clear();
}
private static void CreateText(Transform parent, TMP_FontAsset font, Material material)
{
//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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: 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_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("DistanceText", new Type[4]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(TextMeshProUGUI),
typeof(Shadow)
});
val.transform.SetParent(parent, false);
RectTransform component = val.GetComponent<RectTransform>();
component.anchorMin = new Vector2(0.5f, 0.5f);
component.anchorMax = new Vector2(0.5f, 0.5f);
component.pivot = new Vector2(0.5f, 0.5f);
component.sizeDelta = new Vector2(160f, 50f);
TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>();
((TMP_Text)component2).font = font;
((TMP_Text)component2).fontMaterial = material;
((Graphic)component2).color = Color.white;
((TMP_Text)component2).alignment = (TextAlignmentOptions)514;
((TMP_Text)component2).enableAutoSizing = false;
((Graphic)component2).raycastTarget = false;
((TMP_Text)component2).textWrappingMode = (TextWrappingModes)0;
((TMP_Text)component2).outlineWidth = 0.1f;
((TMP_Text)component2).outlineColor = Color32.op_Implicit(Color.black);
Shadow component3 = val.GetComponent<Shadow>();
component3.effectColor = new Color(0f, 0f, 0f, 0.95f);
component3.effectDistance = new Vector2(2f, -2f);
}
private static Color GetPlayerColor(Character character)
{
//IL_000b: 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_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
try
{
return character.refs.customization.PlayerColor;
}
catch
{
return Color.white;
}
}
}
internal sealed class PingDistanceLabel : MonoBehaviour
{
private GameObject? _marker;
private Vector3 _normal;
private Color _color;
private ModConfig? _config;
private TextMeshProUGUI? _text;
public void Initialize(GameObject marker, Vector3 normal, Color color, ModConfig config)
{
//IL_0008: 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_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)
_marker = marker;
_normal = normal;
_color = color;
_config = config;
_text = ((Component)this).GetComponentInChildren<TextMeshProUGUI>(true);
}
private void LateUpdate()
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: 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_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_marker == (Object)null)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
Camera main = Camera.main;
if (_config == null || !_config.Enabled.Value || !_config.DistanceEnabled.Value || (Object)(object)main == (Object)null || (Object)(object)_text == (Object)null)
{
SetTextVisible(visible: false);
return;
}
Vector3 position = _marker.transform.position;
Vector3 val = main.WorldToScreenPoint(position + _normal);
if (val.z <= 0f)
{
SetTextVisible(visible: false);
return;
}
float num = Vector3.Distance(position, ((Component)main).transform.position);
float num2 = Mathf.Clamp(20f / Mathf.Max(num, 0.01f), 0.5f, 1.5f);
((Component)this).transform.position = val;
((Component)this).transform.localScale = new Vector3(num2, num2, num2);
int safeDistanceDecimals = _config.SafeDistanceDecimals;
((TMP_Text)_text).fontSize = _config.SafeDistanceFontSize;
((Graphic)_text).color = _color;
((TMP_Text)_text).text = num.ToString((safeDistanceDecimals == 0) ? "0" : "0.0", CultureInfo.InvariantCulture) + "m";
SetTextVisible(visible: true);
}
private void SetTextVisible(bool visible)
{
if ((Object)(object)_text != (Object)null && ((Component)_text).gameObject.activeSelf != visible)
{
((Component)_text).gameObject.SetActive(visible);
}
}
}
[BepInPlugin("com.github.lllei.EnhancedPing", "EnhancedPing", "1.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "com.github.lllei.EnhancedPing";
public const string PluginName = "EnhancedPing";
private Harmony? _harmony;
internal static Plugin? Instance { get; private set; }
internal EnhancedPingController Controller { get; private set; }
private void Awake()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
Instance = this;
ModConfig config = new ModConfig(((BaseUnityPlugin)this).Config);
Controller = new EnhancedPingController(this, config, ((BaseUnityPlugin)this).Logger);
_harmony = new Harmony("com.github.lllei.EnhancedPing");
PatchCapabilities capabilities = PatchInstaller.Install(_harmony, ((BaseUnityPlugin)this).Logger);
Controller.SetCapabilities(capabilities);
((BaseUnityPlugin)this).Logger.LogInfo((object)("EnhancedPing 1.0.0 loaded for PEAK 2.0.a baseline. " + $"Input: {capabilities.Input}; distance: {capabilities.Distance}; " + $"dead reticle: {capabilities.DeadReticle}."));
}
private void Update()
{
Controller?.TickLifecycle();
}
private void OnDestroy()
{
Controller?.Reset("plugin destroyed");
Harmony? harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
Instance = null;
}
}
internal readonly struct RuntimePingSample
{
public Vector3 Direction { get; }
public Vector3 Point { get; }
public Vector3 Normal { get; }
public RuntimePingSample(Vector3 direction, Vector3 point, Vector3 normal)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: 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_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)
Direction = direction;
Point = point;
Normal = normal;
}
public SphericalPathSample ToCore()
{
//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)
return new SphericalPathSample(ToCore(Direction), ToCore(Point), ToCore(Normal));
}
public static RuntimePingSample FromCore(SphericalPathSample sample)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
return new RuntimePingSample(ToUnity(sample.Direction), ToUnity(sample.Point), ToUnity(sample.Normal));
}
private static Vector3 ToCore(Vector3 value)
{
//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)
return new Vector3(value.x, value.y, value.z);
}
private static Vector3 ToUnity(Vector3 value)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(value.X, value.Y, value.Z);
}
}
internal static class BuildInfo
{
internal const string Version = "1.0.0";
}
}
namespace EnhancedPing.Core
{
public static class SequenceTiming
{
public static float EffectivePointDuration(int pointCount, float preferredPointDurationSeconds, float maximumSequenceDurationSeconds)
{
if (pointCount <= 0)
{
throw new ArgumentOutOfRangeException("pointCount");
}
if (!IsFinite(preferredPointDurationSeconds) || preferredPointDurationSeconds <= 0f)
{
throw new ArgumentOutOfRangeException("preferredPointDurationSeconds");
}
if (!IsFinite(maximumSequenceDurationSeconds) || maximumSequenceDurationSeconds <= 0f)
{
throw new ArgumentOutOfRangeException("maximumSequenceDurationSeconds");
}
return MathF.Min(preferredPointDurationSeconds, maximumSequenceDurationSeconds / (float)pointCount);
}
private static bool IsFinite(float value)
{
if (!float.IsNaN(value))
{
return !float.IsInfinity(value);
}
return false;
}
}
public readonly struct SphericalPathSample
{
public Vector3 Direction { get; }
public Vector3 Point { get; }
public Vector3 Normal { get; }
public SphericalPathSample(Vector3 direction, Vector3 point, Vector3 normal)
{
Direction = direction;
Point = point;
Normal = normal;
}
}
public static class SphericalPathSelector
{
private const float DirectionEpsilonSquared = 1E-10f;
private const float DuplicateAngleDegrees = 0.0001f;
private const float RadToDeg = 180f / MathF.PI;
public static float AngleDegrees(Vector3 left, Vector3 right)
{
if (!TryNormalize(left, out var normalized) || !TryNormalize(right, out var normalized2))
{
return float.NaN;
}
return MathF.Acos(MathF.Max(-1f, MathF.Min(1f, Vector3.Dot(normalized, normalized2)))) * (180f / MathF.PI);
}
public static IReadOnlyList<SphericalPathSample> Select(IReadOnlyList<SphericalPathSample> samples, int maximumPoints)
{
float totalAngleDegrees;
return Select(samples, maximumPoints, out totalAngleDegrees);
}
public static IReadOnlyList<SphericalPathSample> Select(IReadOnlyList<SphericalPathSample> samples, int maximumPoints, out float totalAngleDegrees)
{
if (samples == null)
{
throw new ArgumentNullException("samples");
}
if (maximumPoints < 2)
{
throw new ArgumentOutOfRangeException("maximumPoints");
}
List<SphericalPathSample> list = Sanitize(samples);
float[] array = BuildCumulativeAngles(list);
totalAngleDegrees = ((array.Length == 0) ? 0f : array[^1]);
if (list.Count <= maximumPoints)
{
return list;
}
if (totalAngleDegrees <= 0.0001f)
{
return new SphericalPathSample[1] { list[0] };
}
int num = Math.Min(list.Count, maximumPoints);
List<SphericalPathSample> list2 = new List<SphericalPathSample>(num) { list[0] };
int num2 = 0;
for (int i = 1; i < num - 1; i++)
{
float num3 = totalAngleDegrees * (float)i / (float)(num - 1);
int num4 = num2 + 1;
int num5 = list.Count - (num - i);
int num6 = num4;
float num7 = MathF.Abs(array[num6] - num3);
for (int j = num4 + 1; j <= num5; j++)
{
float num8 = MathF.Abs(array[j] - num3);
if (num8 < num7)
{
num7 = num8;
num6 = j;
}
}
list2.Add(list[num6]);
num2 = num6;
}
list2.Add(list[list.Count - 1]);
return list2;
}
private static float[] BuildCumulativeAngles(IReadOnlyList<SphericalPathSample> samples)
{
float[] array = new float[samples.Count];
for (int i = 1; i < samples.Count; i++)
{
float num = AngleDegrees(samples[i - 1].Direction, samples[i].Direction);
array[i] = array[i - 1] + (IsFinite(num) ? num : 0f);
}
return array;
}
private static List<SphericalPathSample> Sanitize(IReadOnlyList<SphericalPathSample> samples)
{
List<SphericalPathSample> list = new List<SphericalPathSample>(samples.Count);
foreach (SphericalPathSample sample in samples)
{
if (TryNormalize(sample.Direction, out var normalized) && IsFinite(sample.Point) && IsFinite(sample.Normal))
{
Vector3 normalized2;
Vector3 normal = (TryNormalize(sample.Normal, out normalized2) ? normalized2 : Vector3.UnitY);
SphericalPathSample item = new SphericalPathSample(normalized, sample.Point, normal);
if (list.Count <= 0 || !(AngleDegrees(list[list.Count - 1].Direction, normalized) <= 0.0001f))
{
list.Add(item);
}
}
}
return list;
}
private static bool TryNormalize(Vector3 value, out Vector3 normalized)
{
float num = value.LengthSquared();
if (!IsFinite(num) || num <= 1E-10f)
{
normalized = Vector3.Zero;
return false;
}
normalized = value / MathF.Sqrt(num);
return IsFinite(normalized);
}
private static bool IsFinite(Vector3 value)
{
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;
}
}
}