Decompiled source of BounceIndicatorPlus v1.0.2

BepInEx/plugins/BounceIndicatorPlus.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Math;
using Pigeon.Movement;
using Unity.Netcode;
using UnityEngine;

[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("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("BounceIndicatorPlus")]
[assembly: AssemblyTitle("BounceIndicatorPlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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;
		}
	}
}
internal static class AllBounceIndicators
{
	private const string SourceMaterialName = "BounceIndicatorPlus_Source";

	private static readonly FieldInfo BounceLinePrefabField = AccessTools.Field(typeof(BounceShotgun), "bounceLinePrefab");

	private static readonly string[] FallbackShaderNames = new string[5] { "Sprites/Default", "Universal Render Pipeline/Unlit", "Unlit/Color", "UI/Default", "Legacy Shaders/Particles/Alpha Blended Premultiply" };

	internal static readonly Dictionary<Gun, List<LineRenderer>> BounceLines = new Dictionary<Gun, List<LineRenderer>>();

	internal static LineRenderer BounceLinePrefab;

	private static Material _sourceMaterial;

	private static bool _loggedMissingMaterial;

	private static bool _loggedMissingShader;

	internal static LineRenderer CreateBounceLinePrefab()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		EnsureSourceMaterial();
		GameObject val = new GameObject("BounceIndicatorPrefab");
		Object.DontDestroyOnLoad((Object)(object)val);
		LineRenderer obj = val.AddComponent<LineRenderer>();
		obj.positionCount = 2;
		obj.useWorldSpace = true;
		obj.startWidth = 0.01f;
		obj.endWidth = 0.01f;
		((Renderer)obj).sharedMaterial = CreateLineMaterial();
		ApplyColorToLine(obj, ConfigManager.GetSelectedColor());
		val.SetActive(false);
		return obj;
	}

	internal static void HideAll()
	{
		foreach (KeyValuePair<Gun, List<LineRenderer>> bounceLine in BounceLines)
		{
			List<LineRenderer> value = bounceLine.Value;
			for (int i = 0; i < value.Count; i++)
			{
				if ((Object)(object)value[i] != (Object)null && (Object)(object)((Component)value[i]).gameObject != (Object)null && ((Component)value[i]).gameObject.activeSelf)
				{
					((Component)value[i]).gameObject.SetActive(false);
				}
			}
		}
	}

	internal static void ApplyColor(Color color)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<Gun, List<LineRenderer>> bounceLine in BounceLines)
		{
			List<LineRenderer> value = bounceLine.Value;
			for (int i = 0; i < value.Count; i++)
			{
				if ((Object)(object)value[i] != (Object)null)
				{
					ApplyColorToLine(value[i], color);
				}
			}
		}
		if ((Object)(object)BounceLinePrefab != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)BounceLinePrefab).gameObject);
			BounceLinePrefab = null;
		}
	}

	internal static void ApplyColorToLine(LineRenderer line, Color color)
	{
		//IL_0011: 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)
		//IL_0042: 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_0074: 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_00ae: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)line == (Object)null)
		{
			return;
		}
		EnsureLineHasValidMaterial(line);
		line.startColor = color;
		line.endColor = color;
		Material sharedMaterial = ((Renderer)line).sharedMaterial;
		if (!((Object)(object)sharedMaterial == (Object)null))
		{
			if (sharedMaterial.HasProperty(Global._BaseColor))
			{
				sharedMaterial.SetColor(Global._BaseColor, color);
			}
			if (sharedMaterial.HasProperty(Global._Color))
			{
				sharedMaterial.SetColor(Global._Color, color);
			}
			if (sharedMaterial.HasProperty(Global._MainColor))
			{
				sharedMaterial.SetColor(Global._MainColor, color);
			}
			if (sharedMaterial.HasProperty("_TintColor"))
			{
				sharedMaterial.SetColor("_TintColor", color);
			}
			if (sharedMaterial.HasProperty(Global._Color) || sharedMaterial.HasProperty("_Color"))
			{
				sharedMaterial.color = color;
			}
			if (sharedMaterial.HasProperty("_EmissionColor"))
			{
				Color val = color * 0.5f;
				val.a = 1f;
				sharedMaterial.SetColor("_EmissionColor", val);
			}
		}
	}

	internal static void CleanupGun(Gun gun)
	{
		if (!BounceLines.TryGetValue(gun, out var value))
		{
			return;
		}
		for (int i = 0; i < value.Count; i++)
		{
			if ((Object)(object)value[i] != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)value[i]).gameObject);
			}
		}
		BounceLines.Remove(gun);
	}

	internal static void HideGun(Gun gun)
	{
		if (!BounceLines.TryGetValue(gun, out var value))
		{
			return;
		}
		for (int i = 0; i < value.Count; i++)
		{
			if ((Object)(object)value[i] != (Object)null && ((Component)value[i]).gameObject.activeSelf)
			{
				((Component)value[i]).gameObject.SetActive(false);
			}
		}
	}

	internal static void TryCaptureMaterialFromGun(Gun gun)
	{
		//IL_0078: 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_008d: Expected O, but got Unknown
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_sourceMaterial != (Object)null || (Object)(object)gun == (Object)null)
		{
			return;
		}
		BounceShotgun val = (BounceShotgun)(object)((gun is BounceShotgun) ? gun : null);
		if (val == null || BounceLinePrefabField == null)
		{
			return;
		}
		object? value = BounceLinePrefabField.GetValue(val);
		LineRenderer val2 = (LineRenderer)((value is LineRenderer) ? value : null);
		if (!((Object)(object)val2 == (Object)null))
		{
			Material sharedMaterial = ((Renderer)val2).sharedMaterial;
			if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null) && !IsErrorShader(sharedMaterial.shader))
			{
				_sourceMaterial = new Material(sharedMaterial)
				{
					name = "BounceIndicatorPlus_Source"
				};
				Object.DontDestroyOnLoad((Object)(object)_sourceMaterial);
				BounceIndicatorPlusPlugin.Logger.LogInfo((object)("Captured bounce line material from BounceShotgun (shader: " + ((Object)sharedMaterial.shader).name + ")."));
				ApplyColor(ConfigManager.GetSelectedColor());
			}
		}
	}

	internal static Material CreateUniqueLineMaterial()
	{
		return CreateLineMaterial();
	}

	private static void EnsureSourceMaterial()
	{
		if ((Object)(object)_sourceMaterial != (Object)null)
		{
			return;
		}
		BounceShotgun[] array = Object.FindObjectsOfType<BounceShotgun>(true);
		for (int i = 0; i < array.Length; i++)
		{
			TryCaptureMaterialFromGun((Gun)(object)array[i]);
			if ((Object)(object)_sourceMaterial != (Object)null)
			{
				break;
			}
		}
	}

	private static Material CreateLineMaterial()
	{
		//IL_0012: 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_0023: Expected O, but got Unknown
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		if ((Object)(object)_sourceMaterial != (Object)null)
		{
			return new Material(_sourceMaterial)
			{
				name = "BounceIndicatorPlus_Source"
			};
		}
		Shader val = FindFallbackShader();
		if ((Object)(object)val != (Object)null)
		{
			return new Material(val)
			{
				name = "BounceIndicatorPlus_Fallback"
			};
		}
		if (!_loggedMissingMaterial)
		{
			_loggedMissingMaterial = true;
			BounceIndicatorPlusPlugin.Logger.LogError((object)"Could not resolve a bounce line material/shader. Lines may render magenta.");
		}
		Shader val2 = Shader.Find("Hidden/InternalErrorShader");
		if (!((Object)(object)val2 != (Object)null))
		{
			return null;
		}
		return new Material(val2)
		{
			name = "BounceIndicatorPlus_Error"
		};
	}

	private static void EnsureLineHasValidMaterial(LineRenderer line)
	{
		Material sharedMaterial = ((Renderer)line).sharedMaterial;
		bool flag = (Object)(object)sharedMaterial == (Object)null || (Object)(object)sharedMaterial.shader == (Object)null || IsErrorShader(sharedMaterial.shader);
		bool flag2 = (Object)(object)_sourceMaterial != (Object)null && !IsFromSource(sharedMaterial) && (flag || IsLikelyFallback(sharedMaterial));
		if (flag || flag2)
		{
			((Renderer)line).sharedMaterial = CreateLineMaterial();
		}
	}

	private static bool IsFromSource(Material mat)
	{
		if ((Object)(object)mat == (Object)null || ((Object)mat).name == null)
		{
			return false;
		}
		return ((Object)mat).name.StartsWith("BounceIndicatorPlus_Source");
	}

	private static bool IsLikelyFallback(Material mat)
	{
		if ((Object)(object)mat == (Object)null || (Object)(object)mat.shader == (Object)null)
		{
			return true;
		}
		string name = ((Object)mat.shader).name;
		for (int i = 0; i < FallbackShaderNames.Length; i++)
		{
			if (name == FallbackShaderNames[i])
			{
				return true;
			}
		}
		if (((Object)mat).name != null && (((Object)mat).name.StartsWith("BounceIndicatorPlus_Fallback") || ((Object)mat).name.StartsWith("BounceIndicatorPlus_Error")))
		{
			return true;
		}
		return false;
	}

	private static bool IsErrorShader(Shader shader)
	{
		if ((Object)(object)shader == (Object)null)
		{
			return true;
		}
		string name = ((Object)shader).name;
		if (!(name == "Hidden/InternalErrorShader"))
		{
			return name.Contains("InternalError");
		}
		return true;
	}

	private static Shader FindFallbackShader()
	{
		for (int i = 0; i < FallbackShaderNames.Length; i++)
		{
			Shader val = Shader.Find(FallbackShaderNames[i]);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		if (!_loggedMissingShader)
		{
			_loggedMissingShader = true;
			BounceIndicatorPlusPlugin.Logger.LogWarning((object)"No fallback line shader found via Shader.Find. Waiting for BounceShotgun material.");
		}
		return null;
	}
}
public enum BounceIndicatorColor
{
	[Description("Standard orange color (highest priority, default)")]
	Orange,
	[Description("Clean white color")]
	White,
	[Description("Bright green color")]
	Green,
	[Description("Deep blue color")]
	Blue,
	[Description("Vibrant red color")]
	Red,
	[Description("Sunny yellow color")]
	Yellow,
	[Description("Royal purple color")]
	Purple,
	[Description("Aqua cyan color")]
	Cyan,
	[Description("Use a custom color specified by hex code")]
	Custom
}
public static class ConfigManager
{
	private const float DebounceSeconds = 0.25f;

	private static ConfigFile config;

	private static ManualLogSource logger;

	private static FileSystemWatcher configWatcher;

	private static volatile bool reloadPending;

	private static float lastReloadTime;

	public static ConfigEntry<bool> EnableAllBounceIndicators { get; private set; }

	public static ConfigEntry<BounceIndicatorColor> LineColor { get; private set; }

	public static ConfigEntry<string> LineCustomColor { get; private set; }

	public static void Initialize(ConfigFile configFile, ManualLogSource log)
	{
		config = configFile;
		logger = log;
		EnableAllBounceIndicators = config.Bind<bool>("Bounce Indicators", "Enable Bounce Lines", true, "Show bounce/ricochet prediction lines for all weapons with bounces >= 1.");
		LineColor = config.Bind<BounceIndicatorColor>("Bounce Indicators", "Line Color", BounceIndicatorColor.Orange, "Select the color for bounce/ricochet prediction lines");
		LineCustomColor = config.Bind<string>("Bounce Indicators", "Line Custom Color", "#FF8000", "Hex color code when 'Custom' is selected (format: #RRGGBB or RRGGBB)");
		EnableAllBounceIndicators.SettingChanged += OnEnableChanged;
		LineColor.SettingChanged += OnColorChanged;
		LineCustomColor.SettingChanged += OnCustomColorChanged;
		try
		{
			SetupFileWatcher();
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error setting up config file watcher: " + ex.Message));
		}
	}

	public static void Tick()
	{
		if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f)
		{
			return;
		}
		reloadPending = false;
		lastReloadTime = Time.unscaledTime;
		try
		{
			config.Reload();
			logger.LogInfo((object)"Config reloaded from disk.");
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error reloading config: " + ex.Message));
		}
	}

	public static void Dispose()
	{
		if (EnableAllBounceIndicators != null)
		{
			EnableAllBounceIndicators.SettingChanged -= OnEnableChanged;
		}
		if (LineColor != null)
		{
			LineColor.SettingChanged -= OnColorChanged;
		}
		if (LineCustomColor != null)
		{
			LineCustomColor.SettingChanged -= OnCustomColorChanged;
		}
		if (configWatcher != null)
		{
			configWatcher.EnableRaisingEvents = false;
			configWatcher.Changed -= OnConfigFileChanged;
			configWatcher.Created -= OnConfigFileChanged;
			configWatcher.Renamed -= OnConfigFileChanged;
			configWatcher.Dispose();
			configWatcher = null;
		}
	}

	public static Color GetSelectedColor()
	{
		//IL_0049: 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_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: 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_00c7: 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_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		switch (LineColor.Value)
		{
		case BounceIndicatorColor.Orange:
			return new Color(1f, 0.5f, 0f);
		case BounceIndicatorColor.White:
			return new Color(1f, 1f, 1f);
		case BounceIndicatorColor.Green:
			return new Color(0f, 1f, 0f);
		case BounceIndicatorColor.Blue:
			return new Color(0f, 0f, 1f);
		case BounceIndicatorColor.Red:
			return new Color(1f, 0f, 0f);
		case BounceIndicatorColor.Yellow:
			return new Color(1f, 1f, 0f);
		case BounceIndicatorColor.Purple:
			return new Color(0.6f, 0.2f, 0.85f);
		case BounceIndicatorColor.Cyan:
			return new Color(0f, 1f, 1f);
		case BounceIndicatorColor.Custom:
		{
			string text = LineCustomColor.Value;
			if (!text.StartsWith("#"))
			{
				text = "#" + text;
			}
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(text, ref result))
			{
				return result;
			}
			return new Color(1f, 0f, 0f);
		}
		default:
			return new Color(1f, 0f, 0f);
		}
	}

	private static void SetupFileWatcher()
	{
		configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.bounceindicatorplus.cfg");
		configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
		configWatcher.Changed += OnConfigFileChanged;
		configWatcher.Created += OnConfigFileChanged;
		configWatcher.Renamed += OnConfigFileChanged;
		configWatcher.EnableRaisingEvents = true;
	}

	private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		reloadPending = true;
	}

	private static void OnEnableChanged(object sender, EventArgs e)
	{
		if (!EnableAllBounceIndicators.Value)
		{
			AllBounceIndicators.HideAll();
		}
	}

	private static void OnColorChanged(object sender, EventArgs e)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		AllBounceIndicators.ApplyColor(GetSelectedColor());
	}

	private static void OnCustomColorChanged(object sender, EventArgs e)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		if (LineColor.Value == BounceIndicatorColor.Custom)
		{
			AllBounceIndicators.ApplyColor(GetSelectedColor());
		}
	}
}
[HarmonyPatch]
public static class GunBouncePatches
{
	private static readonly FieldInfo FireDataField = AccessTools.Field(typeof(Gun), "fireData");

	private static readonly FieldInfo ShotsFiredField = AccessTools.Field(typeof(Gun), "shotsFiredSinceStartedFiring");

	private static readonly Vector3[] PositionsBuffer = (Vector3[])(object)new Vector3[2];

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Gun), "Update")]
	public static void Update_Postfix(Gun __instance)
	{
		try
		{
			if (((NetworkBehaviour)__instance).IsOwner && __instance.Active)
			{
				HandleBounceIndicators(__instance);
			}
		}
		catch (Exception ex)
		{
			BounceIndicatorPlusPlugin.Logger.LogError((object)("Update postfix failed: " + ex.Message));
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Gun), "Disable")]
	public static void Disable_Postfix(Gun __instance)
	{
		AllBounceIndicators.HideGun(__instance);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Gun), "OnDestroy")]
	public static void OnDestroy_Postfix(Gun __instance)
	{
		AllBounceIndicators.CleanupGun(__instance);
	}

	private static void HandleBounceIndicators(Gun gun)
	{
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		if (!ConfigManager.EnableAllBounceIndicators.Value)
		{
			return;
		}
		AllBounceIndicators.TryCaptureMaterialFromGun(gun);
		ref GunData gunData = ref gun.GunData;
		int maxBounces = gunData.maxBounces;
		if (maxBounces >= 1)
		{
			if (!AllBounceIndicators.BounceLines.TryGetValue(gun, out var value))
			{
				value = new List<LineRenderer>();
				AllBounceIndicators.BounceLines[gun] = value;
			}
			if ((Object)(object)AllBounceIndicators.BounceLinePrefab == (Object)null)
			{
				AllBounceIndicators.BounceLinePrefab = AllBounceIndicators.CreateBounceLinePrefab();
			}
			int num = Mathf.Max(1, gunData.bulletsPerShot);
			int num2 = num * maxBounces;
			while (value.Count < num2)
			{
				LineRenderer val = Object.Instantiate<LineRenderer>(AllBounceIndicators.BounceLinePrefab);
				((Renderer)val).sharedMaterial = AllBounceIndicators.CreateUniqueLineMaterial();
				AllBounceIndicators.ApplyColorToLine(val, ConfigManager.GetSelectedColor());
				value.Add(val);
			}
			Player player = gun.Player;
			if ((Object)(object)player != (Object)null && (player.IsSprinting || player.IsFireLocked))
			{
				AllBounceIndicators.HideGun(gun);
			}
			else
			{
				UpdateBounceLines(gun, value, maxBounces, num);
			}
		}
	}

	private static void UpdateBounceLines(Gun gun, List<LineRenderer> bounceLines, int maxBounces, int bulletsPerShot)
	{
		//IL_020b: 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_0028: 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_0097: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: 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_00f6: 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_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: 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)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: 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_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: 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_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: 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)
		//IL_016b: 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_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			gun.PrepareFireData();
			if (FireDataField == null)
			{
				return;
			}
			FireData fireData = (FireData)FireDataField.GetValue(gun);
			ref GunData gunData = ref gun.GunData;
			bool isFirstShot = ShotsFiredField == null || (int)ShotsFiredField.GetValue(gun) == 0;
			float num = gunData.rangeData.maxDamageRange;
			if (num <= 0f)
			{
				num = 50f;
			}
			float num2 = gunData.rangeData.falloffStartDistance;
			if (num2 <= 0f)
			{
				num2 = 15f;
			}
			int num3 = LayerMask.op_Implicit(gunData.surfaceCollisionMask) | LayerMask.op_Implicit(gunData.targetCollisionMask);
			int i = 0;
			Random saved = SpreadDirectionHelper.CaptureSpreadRandom(gun);
			try
			{
				RaycastHit val = default(RaycastHit);
				RaycastHit val3 = default(RaycastHit);
				for (int j = 0; j < bulletsPerShot; j++)
				{
					if (i >= bounceLines.Count)
					{
						break;
					}
					Vector3 firePosition = fireData.firePosition;
					Vector3 direction = SpreadDirectionHelper.GetDirection(gun, in fireData, j, isFirstShot);
					if (!IBullet.RaycastForBullet(firePosition, direction, num, num3, 0f, ref val))
					{
						continue;
					}
					firePosition = ((RaycastHit)(ref val)).point;
					direction = Vector3.Reflect(direction, ((RaycastHit)(ref val)).normal);
					for (int k = 0; k < maxBounces; k++)
					{
						if (i >= bounceLines.Count)
						{
							break;
						}
						Vector3 val2 = firePosition;
						if (IBullet.RaycastForBullet(firePosition, direction, num, num3, 0f, ref val3))
						{
							PositionsBuffer[0] = val2;
							PositionsBuffer[1] = ((RaycastHit)(ref val3)).point;
							bounceLines[i].SetPositions(PositionsBuffer);
							((Component)bounceLines[i]).gameObject.SetActive(true);
							firePosition = ((RaycastHit)(ref val3)).point;
							direction = Vector3.Reflect(direction, ((RaycastHit)(ref val3)).normal);
							i++;
							continue;
						}
						PositionsBuffer[0] = val2;
						PositionsBuffer[1] = firePosition + direction * num2;
						bounceLines[i].SetPositions(PositionsBuffer);
						((Component)bounceLines[i]).gameObject.SetActive(true);
						i++;
						break;
					}
				}
			}
			finally
			{
				SpreadDirectionHelper.RestoreSpreadRandom(gun, saved);
			}
			for (; i < bounceLines.Count; i++)
			{
				if (((Component)bounceLines[i]).gameObject.activeSelf)
				{
					((Component)bounceLines[i]).gameObject.SetActive(false);
				}
			}
		}
		catch (Exception ex)
		{
			BounceIndicatorPlusPlugin.Logger.LogError((object)("UpdateBounceLines failed: " + ex.Message));
		}
	}
}
[BepInPlugin("sparroh.bounceindicatorplus", "BounceIndicatorPlus", "1.0.2")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class BounceIndicatorPlusPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.bounceindicatorplus";

	public const string PluginName = "BounceIndicatorPlus";

	public const string PluginVersion = "1.0.2";

	internal static ManualLogSource Logger;

	private Harmony harmony;

	private void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger);
		harmony = new Harmony("sparroh.bounceindicatorplus");
		try
		{
			harmony.PatchAll(typeof(GunBouncePatches));
			Logger.LogInfo((object)"Harmony patches applied.");
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error applying patches: " + ex.Message));
		}
		Logger.LogInfo((object)"BounceIndicatorPlus v1.0.2 loaded successfully.");
	}

	private void Update()
	{
		ConfigManager.Tick();
	}

	private void OnDestroy()
	{
		ConfigManager.Dispose();
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}
}
internal static class SpreadDirectionHelper
{
	public static Random CaptureSpreadRandom(Gun gun)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		return gun.GunData.spreadData.spreadRandom;
	}

	public static void RestoreSpreadRandom(Gun gun, Random saved)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		gun.GunData.spreadData.spreadRandom = saved;
	}

	public static Vector3 GetDirection(Gun gun, in FireData fireData, int shotIndex, bool isFirstShot)
	{
		//IL_0008: 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_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: 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)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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_0050: 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_0056: 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_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_002d: Unknown result type (might be due to invalid IL or missing references)
		ref GunData gunData = ref gun.GunData;
		Quaternion bulletRotation = fireData.bulletRotation;
		Vector3 eulerAngles = ((Quaternion)(ref bulletRotation)).eulerAngles;
		Vector2 val = gun.GetSpread(shotIndex);
		if (isFirstShot)
		{
			val *= gunData.firstShotSpreadMultiplier;
		}
		eulerAngles.y += val.x;
		eulerAngles.x += val.y;
		return Quaternion.Euler(eulerAngles) * Vector3.forward;
	}
}
namespace BounceIndicatorPlus
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BounceIndicatorPlus";

		public const string PLUGIN_NAME = "BounceIndicatorPlus";

		public const string PLUGIN_VERSION = "1.0.2";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}