Decompiled source of Super Battle Shock v1.0.0

plugins/com.github.addzeey.SbgShock.dll

Decompiled 21 hours ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("GameAssembly")]
[assembly: IgnoresAccessChecksTo("SharedAssembly")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.addzeey.SbgShock")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("com.github.addzeey.SbgShock")]
[assembly: AssemblyTitle("Super Battle Shock")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 SbgShock
{
	internal interface IShockController : IDisposable
	{
		void EnqueueShock(int intensity, int duration, string? code = null);
	}
	internal static class NotificationOverlay
	{
		private readonly struct OverlayEntry
		{
			internal SbgNotification Notification { get; }

			internal float ExpiresAt { get; }

			internal OverlayEntry(SbgNotification notification, float expiresAt)
			{
				Notification = notification;
				ExpiresAt = expiresAt;
			}
		}

		private const int MaximumVisibleNotifications = 5;

		private const float CardWidth = 400f;

		private const float CardHeight = 48f;

		private const float CardGap = 7f;

		private const float ScreenMargin = 24f;

		private const float FadeDuration = 0.35f;

		private static readonly List<OverlayEntry> Entries = new List<OverlayEntry>();

		private static GUIStyle? _cardStyle;

		private static GUIStyle? _messageStyle;

		private static Texture2D? _cardTexture;

		private static Texture2D? _lightningTexture;

		internal static void Enqueue(SbgNotification notification)
		{
			float num = Mathf.Clamp(Plugin.NotificationDurationSeconds.Value, 1f, 15f);
			Entries.Add(new OverlayEntry(notification, Time.realtimeSinceStartup + num));
			if (Entries.Count > 5)
			{
				Entries.RemoveAt(0);
			}
		}

		internal static void Draw()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			//IL_00ec: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.NotificationDisplay == null || Plugin.NotificationDisplay.Value != Plugin.NotificationDisplayMode.Overlay || Entries.Count == 0)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			for (int num = Entries.Count - 1; num >= 0; num--)
			{
				if (Entries[num].ExpiresAt <= realtimeSinceStartup)
				{
					Entries.RemoveAt(num);
				}
			}
			if (Entries.Count != 0 && (int)Event.current.type == 7)
			{
				EnsureResources();
				float num2 = Mathf.Min(400f, (float)Screen.width - 48f);
				float num3 = (float)Entries.Count * 48f + (float)(Entries.Count - 1) * 7f;
				float num4 = (float)Screen.width - num2 - 24f;
				float num5 = Mathf.Max(24f, ((float)Screen.height - num3) * 0.5f);
				Color color = GUI.color;
				Color contentColor = GUI.contentColor;
				for (int num6 = Entries.Count - 1; num6 >= 0; num6--)
				{
					OverlayEntry overlayEntry = Entries[num6];
					float alpha = Mathf.Clamp01((overlayEntry.ExpiresAt - realtimeSinceStartup) / 0.35f);
					DrawCard(new Rect(num4, num5, num2, 48f), overlayEntry.Notification, alpha);
					num5 += 55f;
				}
				GUI.color = color;
				GUI.contentColor = contentColor;
			}
		}

		internal static void Dispose()
		{
			Entries.Clear();
			DestroyTexture(ref _cardTexture);
			DestroyTexture(ref _lightningTexture);
			_cardStyle = null;
			_messageStyle = null;
		}

		private static void DrawCard(Rect rect, SbgNotification notification, float alpha)
		{
			//IL_0016: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_00d4: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			GUI.color = new Color(0f, 0f, 0f, 0.28f * alpha);
			GUI.Box(new Rect(((Rect)(ref rect)).x + 2f, ((Rect)(ref rect)).y + 3f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), GUIContent.none, _cardStyle);
			GUI.color = new Color(1f, 1f, 1f, alpha);
			GUI.Box(rect, GUIContent.none, _cardStyle);
			Color accentColor = GetAccentColor(notification.Kind);
			GUI.color = new Color(accentColor.r, accentColor.g, accentColor.b, alpha);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 17f, ((Rect)(ref rect)).y + 12f, 17f, 24f), (Texture)(object)_lightningTexture, (ScaleMode)2, true);
			GUI.contentColor = new Color(1f, 1f, 1f, alpha);
			GUI.Label(new Rect(((Rect)(ref rect)).x + 47f, ((Rect)(ref rect)).y + 6f, ((Rect)(ref rect)).width - 63f, ((Rect)(ref rect)).height - 12f), notification.Message, _messageStyle);
		}

		private static void EnsureResources()
		{
			//IL_0035: 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_004a: 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_005d: Expected O, but got Unknown
			//IL_0062: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0086: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//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_00b7: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_cardTexture == (Object)null)
			{
				_cardTexture = CreateRoundedCardTexture();
			}
			if ((Object)(object)_lightningTexture == (Object)null)
			{
				_lightningTexture = CreateLightningTexture();
			}
			if (_cardStyle == null)
			{
				GUIStyle val = new GUIStyle();
				val.normal.background = _cardTexture;
				val.border = new RectOffset(15, 15, 15, 15);
				_cardStyle = val;
			}
			if (_messageStyle == null)
			{
				_messageStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)3,
					clipping = (TextClipping)1,
					fontSize = 15,
					fontStyle = (FontStyle)1,
					padding = new RectOffset(0, 0, 0, 0),
					richText = false,
					wordWrap = false
				};
				_messageStyle.normal.textColor = Color.white;
			}
		}

		private static Texture2D CreateRoundedCardTexture()
		{
			//IL_0067: 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_00bb: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(0.22f, 0.2f, 0.23f, 0.9f);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.11f, 0.1f, 0.12f, 0.86f);
			Color[] array = (Color[])(object)new Color[2048];
			Vector2 point = default(Vector2);
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					((Vector2)(ref point))..ctor((float)j + 0.5f, (float)i + 0.5f);
					if (IsInsideRoundedRect(point, 0f, 0f, 64f, 32f, 14f))
					{
						bool flag = IsInsideRoundedRect(point, 2f, 2f, 60f, 28f, 12f);
						array[i * 64 + j] = (flag ? val2 : val);
					}
				}
			}
			Texture2D val3 = CreateTexture(64, 32, (FilterMode)1);
			val3.SetPixels(array);
			val3.Apply(false, true);
			return val3;
		}

		private static Texture2D CreateLightningTexture()
		{
			//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_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_003e: 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_0054: 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_006a: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			Vector2[] polygon = (Vector2[])(object)new Vector2[7]
			{
				new Vector2(10f, 27f),
				new Vector2(18f, 27f),
				new Vector2(13f, 17f),
				new Vector2(19f, 17f),
				new Vector2(5f, 0f),
				new Vector2(9f, 12f),
				new Vector2(2f, 12f)
			};
			Color[] array = (Color[])(object)new Color[560];
			for (int i = 0; i < 28; i++)
			{
				for (int j = 0; j < 20; j++)
				{
					if (IsPointInPolygon(new Vector2((float)j + 0.5f, (float)i + 0.5f), polygon))
					{
						array[i * 20 + j] = Color.white;
					}
				}
			}
			Texture2D val = CreateTexture(20, 28, (FilterMode)0);
			val.SetPixels(array);
			val.Apply(false, true);
			return val;
		}

		private static Texture2D CreateTexture(int width, int height, FilterMode filterMode)
		{
			//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_000a: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			return new Texture2D(width, height, (TextureFormat)4, false)
			{
				filterMode = filterMode,
				hideFlags = (HideFlags)61,
				wrapMode = (TextureWrapMode)1
			};
		}

		private static bool IsInsideRoundedRect(Vector2 point, float x, float y, float width, float height, float radius)
		{
			//IL_0000: 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_002d: 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)
			float num = Mathf.Clamp(point.x, x + radius, x + width - radius);
			float num2 = Mathf.Clamp(point.y, y + radius, y + height - radius);
			float num3 = point.x - num;
			float num4 = point.y - num2;
			return num3 * num3 + num4 * num4 <= radius * radius;
		}

		private static bool IsPointInPolygon(Vector2 point, IReadOnlyList<Vector2> polygon)
		{
			//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_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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: 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_0045: 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_0053: 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_0061: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			int num = 0;
			int index = polygon.Count - 1;
			while (num < polygon.Count)
			{
				Vector2 val = polygon[num];
				Vector2 val2 = polygon[index];
				if (val.y > point.y != val2.y > point.y && point.x < (val2.x - val.x) * (point.y - val.y) / (val2.y - val.y) + val.x)
				{
					flag = !flag;
				}
				index = num++;
			}
			return flag;
		}

		private static Color GetAccentColor(NotificationKind kind)
		{
			//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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0047: 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)
			return (Color)(kind switch
			{
				NotificationKind.Warning => new Color(1f, 0.72f, 0.25f), 
				NotificationKind.Error => new Color(1f, 0.55f, 0.62f), 
				_ => new Color(0.82f, 0.9f, 0.25f), 
			});
		}

		private static void DestroyTexture(ref Texture2D? texture)
		{
			if ((Object)(object)texture != (Object)null)
			{
				Object.Destroy((Object)(object)texture);
			}
			texture = null;
		}
	}
	internal enum NotificationKind
	{
		Info,
		Warning,
		Error
	}
	internal readonly struct SbgNotification
	{
		internal string Message { get; }

		internal NotificationKind Kind { get; }

		internal SbgNotification(string message, NotificationKind kind)
		{
			Message = message;
			Kind = kind;
		}
	}
	internal static class NotificationService
	{
		private const int MaximumPendingMessages = 20;

		private static readonly ConcurrentQueue<SbgNotification> PendingMessages = new ConcurrentQueue<SbgNotification>();

		private static readonly object QueueGate = new object();

		private static int _pendingCount;

		internal static void Publish(string message, bool showInGame, string? displayMessage = null)
		{
			Publish(message, NotificationKind.Info, showInGame, displayMessage);
		}

		internal static void PublishWarning(string message, bool showInGame, string? displayMessage = null)
		{
			Publish(message, NotificationKind.Warning, showInGame, displayMessage);
		}

		internal static void PublishError(string message, string displayMessage = "Shock failed. Check LogOutput.log.")
		{
			Publish(message, NotificationKind.Error, showInGame: true, displayMessage);
		}

		internal static void FlushToGame()
		{
			if (Plugin.NotificationDisplay == null || Plugin.NotificationDisplay.Value == Plugin.NotificationDisplayMode.Disabled)
			{
				ClearPendingMessages();
			}
			else if (Plugin.NotificationDisplay.Value == Plugin.NotificationDisplayMode.ChatFeed)
			{
				if (SingletonBehaviour<TextChatUi>.HasInstance)
				{
					SbgNotification notification;
					while (TryDequeue(out notification))
					{
						TextChatUi.ShowMessage("[Super Battle Shock] " + GameManager.RichTextNoParse(notification.Message));
					}
				}
			}
			else
			{
				SbgNotification notification2;
				while (TryDequeue(out notification2))
				{
					NotificationOverlay.Enqueue(notification2);
				}
			}
		}

		internal static void Clear()
		{
			ClearPendingMessages();
		}

		private static void Publish(string message, NotificationKind kind, bool showInGame, string? displayMessage)
		{
			string text = "[Super Battle Shock] " + message;
			switch (kind)
			{
			case NotificationKind.Warning:
				Plugin.Log.LogWarning((object)text);
				break;
			case NotificationKind.Error:
				Plugin.Log.LogError((object)text);
				break;
			default:
				Plugin.Log.LogInfo((object)text);
				break;
			}
			if (!showInGame || Plugin.NotificationDisplay == null || Plugin.NotificationDisplay.Value == Plugin.NotificationDisplayMode.Disabled)
			{
				return;
			}
			lock (QueueGate)
			{
				PendingMessages.Enqueue(new SbgNotification(displayMessage ?? message, kind));
				_pendingCount++;
				if (_pendingCount > 20 && PendingMessages.TryDequeue(out var _))
				{
					_pendingCount--;
				}
			}
		}

		private static void ClearPendingMessages()
		{
			SbgNotification notification;
			while (TryDequeue(out notification))
			{
			}
		}

		private static bool TryDequeue(out SbgNotification notification)
		{
			lock (QueueGate)
			{
				if (!PendingMessages.TryDequeue(out notification))
				{
					return false;
				}
				_pendingCount--;
				return true;
			}
		}
	}
	internal sealed class OpenShockController : ShockControllerBase
	{
		public override void EnqueueShock(int intensity, int duration, string? code = null)
		{
			intensity = ShockControllerBase.ClampIntensity(intensity);
			duration = ShockControllerBase.ClampDuration(duration);
			string apiUrl = Plugin.OpenShockApiUrl.Value.TrimEnd('/');
			string apiKey = Plugin.OpenShockApiKey.Value;
			string deviceId = (string.IsNullOrWhiteSpace(code) ? Plugin.OpenShockDeviceId.Value : code);
			if (string.IsNullOrWhiteSpace(apiUrl) || string.IsNullOrWhiteSpace(apiKey) || string.IsNullOrWhiteSpace(deviceId))
			{
				NotificationService.PublishWarning($"Dry run: would send OpenShock intensity={intensity}, duration={duration}s. Configure ApiUrl, ApiKey, and DeviceId.", showInGame: true, "Dry run: " + ShockControllerBase.FormatShockSummary(intensity, duration));
				return;
			}
			EnqueueRequest("OpenShock", intensity, duration, (CancellationToken cancellationToken) => SendShockAsync(apiUrl, apiKey, deviceId, intensity, duration, cancellationToken));
		}

		private async Task SendShockAsync(string apiUrl, string apiKey, string deviceId, int intensity, int duration, CancellationToken cancellationToken)
		{
			int duration2 = duration * 1000;
			var anon = new
			{
				Shocks = new[]
				{
					new
					{
						Id = deviceId,
						Type = 1,
						Intensity = intensity,
						Duration = duration2
					}
				},
				CustomName = "Integrations.SuperBattleShock"
			};
			try
			{
				using StringContent content = new StringContent(JsonConvert.SerializeObject((object)anon), Encoding.UTF8, "application/json");
				using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, apiUrl + "/2/shockers/control")
				{
					Content = content
				};
				request.Headers.Add("OpenShockToken", apiKey);
				request.Headers.Add("User-Agent", "SuperBattleShock/1.0.0");
				using HttpResponseMessage response = await base.Client.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken);
				if (response.IsSuccessStatusCode)
				{
					NotificationService.Publish($"OpenShock accepted intensity={intensity}, duration={duration}s.", showInGame: true, ShockControllerBase.FormatShockSummary(intensity, duration) + " sent.");
					return;
				}
				string responseBody = await response.Content.ReadAsStringAsync();
				NotificationService.PublishError($"OpenShock rejected shock: {(int)response.StatusCode} {response.StatusCode}. " + "Response: " + ShockControllerBase.FormatResponseBody(responseBody));
			}
			catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
			{
			}
			catch (Exception ex2)
			{
				NotificationService.PublishError("OpenShock request failed: " + ex2.Message);
				Plugin.Log.LogError((object)ex2);
			}
		}
	}
	internal sealed class PiShockController : ShockControllerBase
	{
		private const string PiShockIdLookupUrl = "https://pishock-lookup.addzeey.com/";

		private const string PiShockV3DocsUrl = "https://docs.pishock.com/pishock/pishock-v3-documentation.html";

		public override void EnqueueShock(int intensity, int duration, string? code = null)
		{
			intensity = ShockControllerBase.ClampIntensity(intensity);
			duration = ShockControllerBase.ClampDuration(duration);
			string apiUrl = Plugin.PiShockApiUrl.Value.TrimEnd('/');
			string apiKey = Plugin.PiShockApiKey.Value;
			string shockerId = (string.IsNullOrWhiteSpace(code) ? Plugin.PiShockShockerId.Value : code);
			if (string.IsNullOrWhiteSpace(apiUrl) || string.IsNullOrWhiteSpace(apiKey) || string.IsNullOrWhiteSpace(shockerId))
			{
				NotificationService.PublishWarning(string.Format("Dry run: would send PiShock intensity={0}, duration={1}s. Configure ApiKey and ShockerId; lookup: {2}", intensity, duration, "https://pishock-lookup.addzeey.com/"), showInGame: true, "Dry run: " + ShockControllerBase.FormatShockSummary(intensity, duration));
				return;
			}
			EnqueueRequest("PiShock", intensity, duration, (CancellationToken cancellationToken) => SendShockAsync(apiUrl, apiKey, shockerId, intensity, duration, cancellationToken));
		}

		private async Task SendShockAsync(string apiUrl, string apiKey, string shockerId, int intensity, int duration, CancellationToken cancellationToken)
		{
			string content = JsonConvert.SerializeObject((object)new
			{
				AgentName = "Super Battle Shock Mod",
				Intensity = intensity,
				Duration = duration * 1000,
				Operation = 0
			});
			try
			{
				using StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json");
				using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, apiUrl + "/Shockers/" + Uri.EscapeDataString(shockerId))
				{
					Content = content2
				};
				request.Headers.Add("X-PiShock-Api-Key", apiKey);
				request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
				using HttpResponseMessage response = await base.Client.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken);
				if (response.IsSuccessStatusCode)
				{
					NotificationService.Publish($"PiShock accepted intensity={intensity}, duration={duration}s.", showInGame: true, ShockControllerBase.FormatShockSummary(intensity, duration) + " sent.");
					return;
				}
				string responseBody = await response.Content.ReadAsStringAsync();
				NotificationService.PublishError($"PiShock rejected shock: {(int)response.StatusCode} {response.StatusCode}. " + GetStatusExplanation(response.StatusCode) + " Response: " + ShockControllerBase.FormatResponseBody(responseBody));
			}
			catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
			{
			}
			catch (Exception ex2)
			{
				NotificationService.PublishError("PiShock request failed: " + ex2.Message);
				Plugin.Log.LogError((object)ex2);
			}
		}

		private static string GetStatusExplanation(HttpStatusCode statusCode)
		{
			return statusCode switch
			{
				HttpStatusCode.Unauthorized => "Verify the API key.", 
				HttpStatusCode.Forbidden => "Account access was rejected.", 
				HttpStatusCode.NotFound => "Verify the shocker ID with https://pishock-lookup.addzeey.com/", 
				HttpStatusCode.MethodNotAllowed => "This share does not permit shocks.", 
				HttpStatusCode.NotAcceptable => "Device must use PiShock V3 firmware: https://docs.pishock.com/pishock/pishock-v3-documentation.html", 
				HttpStatusCode.Gone => "The share is locked.", 
				HttpStatusCode.PreconditionFailed => "Intensity is outside share limits.", 
				HttpStatusCode.RequestedRangeNotSatisfiable => "Duration exceeds PiShock limits.", 
				HttpStatusCode.ServiceUnavailable => "The share or shocker is paused.", 
				_ => "Check PiShock status and configuration.", 
			};
		}
	}
	[BepInPlugin("com.github.addzeey.SbgShock", "Super Battle Shock", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public enum ShockProvider
		{
			PiShock,
			OpenShock
		}

		public enum HitTriggerMode
		{
			Disabled,
			AnyHit,
			KnockoutOnly
		}

		public enum NotificationDisplayMode
		{
			Disabled,
			Overlay,
			ChatFeed
		}

		public const string PluginGuid = "com.github.addzeey.SbgShock";

		public const string PluginName = "Super Battle Shock";

		public const string PluginVersion = "1.0.0";

		private static readonly object ShockControllerGate = new object();

		private static IShockController? _shockController;

		private Harmony? _harmony;

		internal static ManualLogSource Log { get; private set; } = null;

		internal static ConfigFile CFG { get; private set; } = null;

		internal static ConfigEntry<ShockProvider> ShockProviderType { get; private set; } = null;

		internal static ConfigEntry<float> ShockCooldownSeconds { get; private set; } = null;

		internal static ConfigEntry<bool> EnableShocksInLobby { get; private set; } = null;

		internal static ConfigEntry<string> PiShockApiUrl { get; private set; } = null;

		internal static ConfigEntry<string> PiShockApiKey { get; private set; } = null;

		internal static ConfigEntry<string> PiShockShockerId { get; private set; } = null;

		internal static ConfigEntry<string> OpenShockApiUrl { get; private set; } = null;

		internal static ConfigEntry<string> OpenShockDeviceId { get; private set; } = null;

		internal static ConfigEntry<string> OpenShockApiKey { get; private set; } = null;

		internal static ConfigEntry<bool> EnableFailedHoleShock { get; private set; } = null;

		internal static ConfigEntry<int> FailedHoleIntensity { get; private set; } = null;

		internal static ConfigEntry<int> FailedHoleDuration { get; private set; } = null;

		internal static ConfigEntry<bool> EnableWaterDeathShock { get; private set; } = null;

		internal static ConfigEntry<int> WaterDeathIntensity { get; private set; } = null;

		internal static ConfigEntry<int> WaterDeathDuration { get; private set; } = null;

		internal static ConfigEntry<bool> EnableFogDeathShock { get; private set; } = null;

		internal static ConfigEntry<int> FogDeathIntensity { get; private set; } = null;

		internal static ConfigEntry<int> FogDeathDuration { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> ClubHitMode { get; private set; } = null;

		internal static ConfigEntry<int> ClubHitIntensity { get; private set; } = null;

		internal static ConfigEntry<int> ClubHitDuration { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> GolfBallHitMode { get; private set; } = null;

		internal static ConfigEntry<int> GolfBallHitIntensity { get; private set; } = null;

		internal static ConfigEntry<int> GolfBallHitDuration { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> DuelingPistolHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> ElephantGunHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> RailgunHitMode { get; private set; } = null;

		internal static ConfigEntry<int> WeaponHitIntensity { get; private set; } = null;

		internal static ConfigEntry<int> WeaponHitDuration { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> RocketHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> RocketBackBlastHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> LandmineHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> OrbitalLaserHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> ThunderstormHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> ElectromagnetExplosionHitMode { get; private set; } = null;

		internal static ConfigEntry<int> ExplosiveHitIntensity { get; private set; } = null;

		internal static ConfigEntry<int> ExplosiveHitDuration { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> GolfCartHitMode { get; private set; } = null;

		internal static ConfigEntry<int> GolfCartIntensity { get; private set; } = null;

		internal static ConfigEntry<int> GolfCartDuration { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> RocketDriverHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> JumboBurgerHitMode { get; private set; } = null;

		internal static ConfigEntry<HitTriggerMode> TrafficVehicleHitMode { get; private set; } = null;

		internal static ConfigEntry<bool> EnableUnmappedKnockoutShock { get; private set; } = null;

		internal static ConfigEntry<int> UnmappedKnockoutIntensity { get; private set; } = null;

		internal static ConfigEntry<int> UnmappedKnockoutDuration { get; private set; } = null;

		internal static ConfigEntry<NotificationDisplayMode> NotificationDisplay { get; private set; } = null;

		internal static ConfigEntry<bool> ShowSkippedNotifications { get; private set; } = null;

		internal static ConfigEntry<float> NotificationDurationSeconds { get; private set; } = null;

		private void Awake()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			CFG = ((BaseUnityPlugin)this).Config;
			BindConfig();
			InitializeShockController();
			ShockProviderType.SettingChanged += OnShockProviderChanged;
			_harmony = new Harmony("com.github.addzeey.SbgShock");
			try
			{
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
			}
			catch (Exception arg)
			{
				_harmony.UnpatchSelf();
				Log.LogError((object)$"[Super Battle Shock] Failed to apply gameplay hooks: {arg}");
				NotificationService.Publish("Hook setup failed; check LogOutput.log.", showInGame: true);
				return;
			}
			Log.LogInfo((object)"Plugin Super Battle Shock is loaded!");
			NotificationService.Publish("Loaded v1.0.0. Event logging is active.", showInGame: true);
		}

		private void Update()
		{
			NotificationService.FlushToGame();
		}

		private void OnGUI()
		{
			NotificationOverlay.Draw();
		}

		private void OnDestroy()
		{
			ShockProviderType.SettingChanged -= OnShockProviderChanged;
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			DisposeShockController();
			ShockControllerBase.ResetCooldown();
			EliminationShockHandler.ClearPending();
			NotificationService.Clear();
			NotificationOverlay.Dispose();
			ShockDispatcher.Reset();
		}

		private static void BindConfig()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_053c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0546: Expected O, but got Unknown
			ShockProviderType = CFG.Bind<ShockProvider>("Shock", "Provider", ShockProvider.PiShock, "Choose PiShock or OpenShock.");
			ShockCooldownSeconds = CFG.Bind<float>("Shock", "ShockCooldownSeconds", 2f, new ConfigDescription("Minimum seconds between outgoing requests.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			EnableShocksInLobby = CFG.Bind<bool>("Shock", "EnableShocksInLobby", false, "Allow shocks in the multiplayer Driving Range lobby. Disabled by default.");
			PiShockApiUrl = CFG.Bind<string>("PiShock", "ApiUrl", "https://api.pishock.com", "PiShock API URL.");
			PiShockApiKey = CFG.Bind<string>("PiShock", "ApiKey", string.Empty, "Your PiShock API key.");
			PiShockShockerId = CFG.Bind<string>("PiShock", "ShockerId", string.Empty, "Your PiShock V3 shocker ID.");
			OpenShockApiUrl = CFG.Bind<string>("OpenShock", "ApiUrl", "https://api.openshock.app", "OpenShock API URL.");
			OpenShockDeviceId = CFG.Bind<string>("OpenShock", "DeviceId", string.Empty, "OpenShock device ID or share ID.");
			OpenShockApiKey = CFG.Bind<string>("OpenShock", "ApiKey", string.Empty, "OpenShock API key.");
			EnableFailedHoleShock = CFG.Bind<bool>("Events", "EnableFailedHoleShock", true, "Shock when the local player times out instead of finishing the hole.");
			FailedHoleIntensity = BindIntensity("Events", "FailedHoleIntensity", 55, "Intensity for a failed hole timeout shock.");
			FailedHoleDuration = BindDuration("Events", "FailedHoleDuration", 2, "Duration for a failed hole timeout shock.");
			EnableWaterDeathShock = CFG.Bind<bool>("Deaths", "EnableWaterDeathShock", true, "Shock when the local player falls into water and starts waiting to respawn.");
			WaterDeathIntensity = BindIntensity("Deaths", "WaterDeathIntensity", 10, "Intensity for falling into water.");
			WaterDeathDuration = BindDuration("Deaths", "WaterDeathDuration", 1, "Duration for falling into water.");
			EnableFogDeathShock = CFG.Bind<bool>("Deaths", "EnableFogDeathShock", true, "Shock when the local player falls into fog and starts waiting to respawn.");
			FogDeathIntensity = BindIntensity("Deaths", "FogDeathIntensity", 10, "Intensity for falling into fog.");
			FogDeathDuration = BindDuration("Deaths", "FogDeathDuration", 1, "Duration for falling into fog.");
			ClubHitMode = BindHitMode("ClubHitMode", "club swings");
			ClubHitIntensity = BindIntensity("Events", "ClubHitIntensity", 25, "Intensity for club hit shocks.");
			ClubHitDuration = BindDuration("Events", "ClubHitDuration", 1, "Duration for club hit shocks.");
			GolfBallHitMode = BindHitMode("GolfBallHitMode", "club-launched or reflected golf balls");
			GolfBallHitIntensity = BindIntensity("Events", "GolfBallHitIntensity", 25, "Intensity for golf ball hit shocks.");
			GolfBallHitDuration = BindDuration("Events", "GolfBallHitDuration", 1, "Duration for golf ball hit shocks.");
			DuelingPistolHitMode = BindHitMode("DuelingPistolHitMode", "dueling pistol hits");
			ElephantGunHitMode = BindHitMode("ElephantGunHitMode", "elephant gun hits");
			RailgunHitMode = BindHitMode("RailgunHitMode", "railgun hits");
			WeaponHitIntensity = BindIntensity("Events", "WeaponHitIntensity", 35, "Intensity for direct weapon hit shocks.");
			WeaponHitDuration = BindDuration("Events", "WeaponHitDuration", 1, "Duration for direct weapon hit shocks.");
			RocketHitMode = BindHitMode("RocketHitMode", "rocket hits");
			RocketBackBlastHitMode = BindHitMode("RocketBackBlastHitMode", "rocket backblast hits");
			LandmineHitMode = BindHitMode("LandmineHitMode", "landmine hits");
			OrbitalLaserHitMode = BindHitMode("OrbitalLaserHitMode", "orbital laser hits");
			ThunderstormHitMode = BindHitMode("ThunderstormHitMode", "thunderstorm hits");
			ElectromagnetExplosionHitMode = BindHitMode("ElectromagnetExplosionHitMode", "electromagnet shield explosions");
			ExplosiveHitIntensity = BindIntensity("Events", "ExplosiveHitIntensity", 50, "Intensity for explosive hit shocks.");
			ExplosiveHitDuration = BindDuration("Events", "ExplosiveHitDuration", 2, "Duration for explosive hit shocks.");
			GolfCartHitMode = BindHitMode("GolfCartHitMode", "golf cart hits");
			GolfCartIntensity = BindIntensity("Events", "GolfCartIntensity", 45, "Intensity for golf cart shocks.");
			GolfCartDuration = BindDuration("Events", "GolfCartDuration", 2, "Duration for golf cart shocks.");
			RocketDriverHitMode = BindHitMode("RocketDriverHitMode", "Rocket Driver hits");
			JumboBurgerHitMode = BindHitMode("JumboBurgerHitMode", "Jumbo Burger giant hits");
			TrafficVehicleHitMode = BindHitMode("TrafficVehicleHitMode", "traffic vehicle hits");
			EnableUnmappedKnockoutShock = CFG.Bind<bool>("Events", "EnableUnmappedKnockoutShock", false, "Optional shock for new knockout causes without a dedicated hit setting.");
			UnmappedKnockoutIntensity = BindIntensity("Events", "UnmappedKnockoutIntensity", 30, "Intensity for unmapped knockout shocks.");
			UnmappedKnockoutDuration = BindDuration("Events", "UnmappedKnockoutDuration", 1, "Duration for unmapped knockout shocks.");
			NotificationDisplay = CFG.Bind<NotificationDisplayMode>("Notifications", "DisplayMode", NotificationDisplayMode.Overlay, "Where local Super Battle Shock status messages appear: Disabled, Overlay, or ChatFeed.");
			ShowSkippedNotifications = CFG.Bind<bool>("Notifications", "ShowSkippedNotifications", false, "Show cooldown and disabled-event skips in game. All skips are still logged.");
			NotificationDurationSeconds = CFG.Bind<float>("Notifications", "DurationSeconds", 4f, new ConfigDescription("How long overlay notifications remain visible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>()));
			static ConfigEntry<int> BindDuration(string section, string key, int defaultValue, string description)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				return CFG.Bind<int>(section, key, defaultValue, new ConfigDescription(description + " Range: 1-15 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 15), Array.Empty<object>()));
			}
			static ConfigEntry<HitTriggerMode> BindHitMode(string key, string cause)
			{
				return CFG.Bind<HitTriggerMode>("Events", key, HitTriggerMode.KnockoutOnly, "When " + cause + " trigger a shock: Disabled, AnyHit, or KnockoutOnly.");
			}
			static ConfigEntry<int> BindIntensity(string section, string key, int defaultValue, string description)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				return CFG.Bind<int>(section, key, defaultValue, new ConfigDescription(description + " Range: 1-100.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			}
		}

		private static void InitializeShockController()
		{
			IShockController shockController2;
			if (ShockProviderType.Value != ShockProvider.PiShock)
			{
				IShockController shockController = new OpenShockController();
				shockController2 = shockController;
			}
			else
			{
				IShockController shockController = new PiShockController();
				shockController2 = shockController;
			}
			IShockController shockController3 = shockController2;
			IShockController shockController4;
			lock (ShockControllerGate)
			{
				shockController4 = _shockController;
				_shockController = null;
			}
			shockController4?.Dispose();
			lock (ShockControllerGate)
			{
				_shockController = shockController3;
			}
			Log.LogInfo((object)$"[Super Battle Shock] Initialized {ShockProviderType.Value} controller.");
		}

		internal static bool EnqueueShock(int intensity, int duration)
		{
			lock (ShockControllerGate)
			{
				if (_shockController == null)
				{
					return false;
				}
				_shockController.EnqueueShock(intensity, duration);
				return true;
			}
		}

		private static void DisposeShockController()
		{
			IShockController shockController;
			lock (ShockControllerGate)
			{
				shockController = _shockController;
				_shockController = null;
			}
			shockController?.Dispose();
		}

		private static void OnShockProviderChanged(object sender, EventArgs args)
		{
			InitializeShockController();
			NotificationService.Publish($"Provider changed to {ShockProviderType.Value}.", showInGame: true);
		}
	}
	internal abstract class ShockControllerBase : IShockController, IDisposable
	{
		private const int MaximumResponseBodyLength = 512;

		private const int MaximumResponseBufferLength = 4096;

		private static readonly TimeSpan RequestTimeout = TimeSpan.FromSeconds(10.0);

		private static readonly object CooldownGate = new object();

		private static double _lastRequestTime = double.NegativeInfinity;

		private readonly ShockRequestQueue _queue = new ShockRequestQueue();

		protected HttpClient Client { get; } = new HttpClient();

		protected ShockControllerBase()
		{
			Client.Timeout = RequestTimeout;
			Client.MaxResponseContentBufferSize = 4096L;
		}

		public abstract void EnqueueShock(int intensity, int duration, string? code = null);

		protected void EnqueueRequest(string providerName, int intensity, int duration, Func<CancellationToken, Task> sendRequest)
		{
			if (_queue.TryEnqueue(async delegate(CancellationToken cancellationToken)
			{
				if (!TryReserveCooldown(out var remainingSeconds))
				{
					NotificationService.Publish($"{providerName} request skipped by cooldown ({remainingSeconds:0.0}s remaining).", Plugin.ShowSkippedNotifications.Value, "Shock skipped: cooldown active.");
				}
				else
				{
					await sendRequest(cancellationToken);
				}
			}))
			{
				NotificationService.Publish($"{providerName} request queued: intensity={intensity}, duration={duration}s.", showInGame: false);
			}
			else
			{
				NotificationService.PublishWarning(providerName + " request skipped because another request is already in progress.", Plugin.ShowSkippedNotifications.Value, "Shock skipped: request already in progress.");
			}
		}

		protected static int ClampIntensity(int intensity)
		{
			return Math.Clamp(intensity, 1, 100);
		}

		protected static int ClampDuration(int duration)
		{
			return Math.Clamp(duration, 1, 15);
		}

		protected static string FormatShockSummary(int intensity, int duration)
		{
			return $"{duration} second shock at {intensity}%";
		}

		protected static string FormatResponseBody(string responseBody)
		{
			if (string.IsNullOrWhiteSpace(responseBody))
			{
				return "<empty>";
			}
			int num = Math.Min(responseBody.Length, 512);
			StringBuilder stringBuilder = new StringBuilder(num + 3);
			for (int i = 0; i < num; i++)
			{
				char c = responseBody[i];
				stringBuilder.Append((char.IsControl(c) && !char.IsWhiteSpace(c)) ? '?' : c);
			}
			if (responseBody.Length > num)
			{
				stringBuilder.Append("...");
			}
			return stringBuilder.ToString();
		}

		internal static void ResetCooldown()
		{
			lock (CooldownGate)
			{
				_lastRequestTime = double.NegativeInfinity;
			}
		}

		private bool TryReserveCooldown(out double remainingSeconds)
		{
			lock (CooldownGate)
			{
				double num = (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency;
				double num2 = Plugin.ShockCooldownSeconds.Value;
				double num3 = num - _lastRequestTime;
				if (num3 < num2)
				{
					remainingSeconds = num2 - num3;
					return false;
				}
				_lastRequestTime = num;
				remainingSeconds = 0.0;
				return true;
			}
		}

		public void Dispose()
		{
			_queue.Dispose();
			Client.Dispose();
		}
	}
	internal static class ShockDispatcher
	{
		private const double LocalDedupWindowSeconds = 0.75;

		private static readonly Dictionary<string, double> RecentEvents = new Dictionary<string, double>();

		private static readonly Dictionary<string, double> RecentDuplicateLogs = new Dictionary<string, double>();

		private static readonly object Gate = new object();

		internal static void Trigger(string eventKey, int intensity, int duration, string reason)
		{
			if (!Plugin.EnableShocksInLobby.Value && SingletonBehaviour<DrivingRangeManager>.HasInstance)
			{
				NotificationService.Publish("Ignored " + reason + ": shocks are disabled in the Driving Range lobby.", Plugin.ShowSkippedNotifications.Value, "Shock skipped: disabled in lobby.");
				return;
			}
			intensity = Math.Clamp(intensity, 1, 100);
			duration = Math.Clamp(duration, 1, 15);
			double num = (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency;
			bool flag = false;
			bool flag2;
			lock (Gate)
			{
				flag2 = RecentEvents.TryGetValue(eventKey, out var value) && num - value < 0.75;
				RecentEvents[eventKey] = num;
				if (flag2 && (!RecentDuplicateLogs.TryGetValue(eventKey, out var value2) || num - value2 >= 0.75))
				{
					RecentDuplicateLogs[eventKey] = num;
					flag = true;
				}
			}
			if (flag2)
			{
				if (flag)
				{
					NotificationService.Publish($"Ignored repeated {reason} within {750.0:0}ms.", Plugin.ShowSkippedNotifications.Value, "Shock skipped: repeated event.");
				}
			}
			else
			{
				NotificationService.Publish($"Detected {reason}: intensity={intensity}, duration={duration}s.", showInGame: false);
				Plugin.EnqueueShock(intensity, duration);
			}
		}

		internal static void Reset()
		{
			lock (Gate)
			{
				RecentEvents.Clear();
				RecentDuplicateLogs.Clear();
			}
		}
	}
	[HarmonyPatch]
	internal static class ShockHooks
	{
		[HarmonyPatch(typeof(PlayerMovement), "TryKnockOut")]
		[HarmonyPostfix]
		private static void TryKnockOutPostfix(PlayerMovement __instance, KnockoutType knockoutType, bool __result, bool isNewKnockout)
		{
			//IL_0009: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			if (LocalPlayerGuard.IsLocal(__instance))
			{
				if (ShockHitHandler.TryGetSettings(knockoutType, out var settings))
				{
					ShockHitHandler.Handle(settings, __result, isNewKnockout);
				}
				else if (__result && isNewKnockout && Plugin.EnableUnmappedKnockoutShock.Value)
				{
					ShockDispatcher.Trigger($"ragdoll-{knockoutType}", Plugin.UnmappedKnockoutIntensity.Value, Plugin.UnmappedKnockoutDuration.Value, $"unmapped knockout via {knockoutType}");
				}
			}
		}

		[HarmonyPatch(typeof(PlayerMovement), "OnLocalPlayerWillApplyItemHitPhysics")]
		[HarmonyPostfix]
		private static void OnLocalPlayerWillApplyItemHitPhysicsPostfix(PlayerMovement __instance, ItemType itemType, float distance)
		{
			//IL_0009: 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)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if (!LocalPlayerGuard.IsLocal(__instance))
			{
				return;
			}
			HitSettings settings;
			if ((int)itemType != 10)
			{
				if ((int)itemType != 15)
				{
					if ((int)itemType != 16)
					{
						return;
					}
					settings = ShockHitHandler.GetRailgunSettings();
				}
				else
				{
					if (!(distance <= GameManager.ItemSettings.ThunderstormLightningStrikeVaporizationRadius))
					{
						return;
					}
					settings = ShockHitHandler.GetThunderstormSettings();
				}
			}
			else
			{
				if (!(distance <= GameManager.ItemSettings.OrbitalLaserExplosionCenterRadius))
				{
					return;
				}
				settings = ShockHitHandler.GetOrbitalLaserSettings();
			}
			ShockHitHandler.HandleAnyHit(settings);
		}

		[HarmonyPatch(typeof(PlayerGolfer), "OnLocalPlayerWillBeEliminated")]
		[HarmonyPostfix]
		private static void OnLocalPlayerWillBeEliminatedPostfix(PlayerGolfer __instance, EliminationReason immediateEliminationReason)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (!LocalPlayerGuard.IsLocal(__instance))
			{
				return;
			}
			EliminationShockHandler.ClearPending();
			HitSettings settings;
			if ((int)immediateEliminationReason == 7)
			{
				if (Plugin.EnableFailedHoleShock.Value)
				{
					ShockDispatcher.Trigger("timed-out", Plugin.FailedHoleIntensity.Value, Plugin.FailedHoleDuration.Value, "timed out before finishing hole");
				}
				else
				{
					ShockHitHandler.LogSkipped("hole timeout", "disabled");
				}
			}
			else if (ShockHitHandler.TryGetInstantEliminationSettings(immediateEliminationReason, out settings))
			{
				if (settings.Mode == Plugin.HitTriggerMode.KnockoutOnly)
				{
					ShockDispatcher.Trigger(settings.EventKey, settings.Intensity, settings.Duration, settings.Reason + " elimination");
				}
			}
			else
			{
				EliminationShockHandler.HandleElimination(__instance.PlayerInfo, immediateEliminationReason);
			}
		}

		[HarmonyPatch(typeof(PlayerMovement), "OnRespawnStateChanged")]
		[HarmonyPostfix]
		private static void OnRespawnStateChangedPostfix(PlayerMovement __instance, RespawnState previousState, RespawnState currentState)
		{
			//IL_0009: 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_000e: Invalid comparison between Unknown and I4
			if (LocalPlayerGuard.IsLocal(__instance) && (int)previousState == 0 && (int)currentState == 1)
			{
				EliminationShockHandler.HandleRespawnStarted(__instance.PlayerInfo);
			}
		}

		[HarmonyPatch(typeof(PlayerMovement), "LocalPlayerBeginRespawn")]
		[HarmonyPrefix]
		private static void LocalPlayerBeginRespawnPrefix(PlayerMovement __instance, bool isRestart)
		{
			if (isRestart && LocalPlayerGuard.IsLocal(__instance))
			{
				EliminationShockHandler.ClearPending();
			}
		}
	}
	internal static class EliminationShockHandler
	{
		private static PlayerInfo? _pendingPlayer;

		private static EliminationReason _pendingReason;

		internal static void HandleElimination(PlayerInfo player, EliminationReason reason)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0032: 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)
			if ((int)reason == 6 || (int)reason == 23)
			{
				EliminationSettings settings = GetSettings(reason);
				if (!settings.Enabled)
				{
					ShockHitHandler.LogSkipped(settings.Reason, "death shock disabled");
					return;
				}
				_pendingPlayer = player;
				_pendingReason = reason;
				NotificationService.Publish("Detected " + settings.Reason + "; waiting for confirmed local respawn.", Plugin.ShowSkippedNotifications.Value, "Waiting for respawn to start.");
			}
		}

		internal static void HandleRespawnStarted(PlayerInfo player)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_pendingPlayer == (Object)null || player != _pendingPlayer)
			{
				ClearPending();
				return;
			}
			EliminationSettings settings = GetSettings(_pendingReason);
			ClearPending();
			if (settings.Enabled)
			{
				ShockDispatcher.Trigger(settings.EventKey, settings.Intensity, settings.Duration, settings.Reason + " (respawn started)");
			}
		}

		internal static void ClearPending()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			_pendingPlayer = null;
			_pendingReason = (EliminationReason)0;
		}

		private static EliminationSettings GetSettings(EliminationReason reason)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if ((int)reason != 6)
			{
				if ((int)reason == 23)
				{
					return new EliminationSettings("fog-death", "fell into fog", Plugin.EnableFogDeathShock.Value, Plugin.FogDeathIntensity.Value, Plugin.FogDeathDuration.Value);
				}
				throw new ArgumentOutOfRangeException("reason", reason, "Unsupported elimination reason.");
			}
			return new EliminationSettings("water-death", "fell into water", Plugin.EnableWaterDeathShock.Value, Plugin.WaterDeathIntensity.Value, Plugin.WaterDeathDuration.Value);
		}
	}
	internal static class LocalPlayerGuard
	{
		internal static bool IsLocal(PlayerMovement movement)
		{
			if ((Object)(object)movement != (Object)null && ((NetworkBehaviour)movement).isLocalPlayer && (Object)(object)GameManager.LocalPlayerInfo != (Object)null)
			{
				return movement.PlayerInfo == GameManager.LocalPlayerInfo;
			}
			return false;
		}

		internal static bool IsLocal(PlayerGolfer golfer)
		{
			if ((Object)(object)golfer != (Object)null && ((NetworkBehaviour)golfer).isLocalPlayer && (Object)(object)GameManager.LocalPlayerInfo != (Object)null)
			{
				return golfer.PlayerInfo == GameManager.LocalPlayerInfo;
			}
			return false;
		}
	}
	internal readonly struct EliminationSettings
	{
		internal string EventKey { get; }

		internal string Reason { get; }

		internal bool Enabled { get; }

		internal int Intensity { get; }

		internal int Duration { get; }

		internal EliminationSettings(string eventKey, string reason, bool enabled, int intensity, int duration)
		{
			EventKey = eventKey;
			Reason = reason;
			Enabled = enabled;
			Intensity = intensity;
			Duration = duration;
		}
	}
	internal static class ShockHitHandler
	{
		internal static void HandleAnyHit(HitSettings settings)
		{
			if (settings.Mode == Plugin.HitTriggerMode.AnyHit)
			{
				Handle(settings, wasApplied: false, isNewKnockout: false);
			}
			else if (settings.Mode == Plugin.HitTriggerMode.Disabled)
			{
				LogSkipped(settings.Reason, "disabled");
			}
		}

		internal static void Handle(HitSettings settings, bool wasApplied, bool isNewKnockout)
		{
			if (settings.Mode == Plugin.HitTriggerMode.Disabled)
			{
				LogSkipped(settings.Reason, "disabled");
				return;
			}
			if (settings.Mode == Plugin.HitTriggerMode.KnockoutOnly && (!wasApplied || !isNewKnockout))
			{
				LogSkipped(settings.Reason, "no new knockout");
				return;
			}
			int intensity = Mathf.Clamp(settings.Intensity, 1, 100);
			string text = ((wasApplied && isNewKnockout) ? "new knockout" : "hit without new knockout");
			ShockDispatcher.Trigger(settings.EventKey, intensity, settings.Duration, settings.Reason + " (" + text + ")");
		}

		internal static bool TryGetSettings(KnockoutType knockoutType, out HitSettings settings)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected I4, but got Unknown
			switch ((int)knockoutType)
			{
			case 0:
				settings = new HitSettings("club-hit", "club hit", Plugin.ClubHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 1:
			case 13:
				settings = new HitSettings("golf-ball-hit", "golf ball hit", Plugin.GolfBallHitMode.Value, Plugin.GolfBallHitIntensity.Value, Plugin.GolfBallHitDuration.Value);
				return true;
			case 4:
			case 15:
				settings = new HitSettings("dueling-pistol", "dueling pistol hit", Plugin.DuelingPistolHitMode.Value, Plugin.WeaponHitIntensity.Value, Plugin.WeaponHitDuration.Value);
				return true;
			case 5:
			case 16:
				settings = new HitSettings("elephant-gun", "elephant gun hit", Plugin.ElephantGunHitMode.Value, Plugin.WeaponHitIntensity.Value, Plugin.WeaponHitDuration.Value);
				return true;
			case 26:
			case 28:
			case 37:
				settings = GetRailgunSettings();
				return true;
			case 7:
			case 14:
				settings = new HitSettings("rocket", "rocket hit", Plugin.RocketHitMode.Value, Plugin.ExplosiveHitIntensity.Value, Plugin.ExplosiveHitDuration.Value);
				return true;
			case 8:
				settings = new HitSettings("rocket-backblast", "rocket backblast hit", Plugin.RocketBackBlastHitMode.Value, Plugin.ExplosiveHitIntensity.Value, Plugin.ExplosiveHitDuration.Value);
				return true;
			case 12:
				settings = new HitSettings("landmine", "landmine hit", Plugin.LandmineHitMode.Value, Plugin.ExplosiveHitIntensity.Value, Plugin.ExplosiveHitDuration.Value);
				return true;
			case 17:
			case 25:
			case 32:
			case 35:
				settings = GetOrbitalLaserSettings();
				return true;
			case 23:
			case 24:
			case 33:
			case 36:
				settings = GetThunderstormSettings();
				return true;
			case 34:
				settings = new HitSettings("electromagnet-explosion", "electromagnet shield explosion", Plugin.ElectromagnetExplosionHitMode.Value, Plugin.ExplosiveHitIntensity.Value, Plugin.ExplosiveHitDuration.Value);
				return true;
			case 6:
				settings = new HitSettings("golf-cart", "golf cart hit", Plugin.GolfCartHitMode.Value, Plugin.GolfCartIntensity.Value, Plugin.GolfCartDuration.Value);
				return true;
			case 18:
				settings = new HitSettings("rocket-driver-swing", "Rocket Driver swing", Plugin.RocketDriverHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 19:
				settings = new HitSettings("rocket-driver-spin", "Rocket Driver spin hit", Plugin.RocketDriverHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 20:
				settings = new HitSettings("rocket-driver-projectile", "Rocket Driver projectile hit", Plugin.RocketDriverHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 29:
				settings = new HitSettings("jumbo-burger-swing", "Jumbo Burger giant swing", Plugin.JumboBurgerHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 30:
				settings = new HitSettings("jumbo-burger-projectile", "Jumbo Burger giant projectile hit", Plugin.JumboBurgerHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 31:
				settings = new HitSettings("jumbo-burger-collision", "Jumbo Burger giant collision", Plugin.JumboBurgerHitMode.Value, Plugin.ClubHitIntensity.Value, Plugin.ClubHitDuration.Value);
				return true;
			case 27:
				settings = new HitSettings("traffic-vehicle", "traffic vehicle hit", Plugin.TrafficVehicleHitMode.Value, Plugin.GolfCartIntensity.Value, Plugin.GolfCartDuration.Value);
				return true;
			default:
				settings = default(HitSettings);
				return false;
			}
		}

		internal static bool TryGetInstantEliminationSettings(EliminationReason reason, out HitSettings settings)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if ((int)reason != 24)
			{
				if ((int)reason != 32)
				{
					if ((int)reason == 34)
					{
						settings = GetRailgunSettings();
						return true;
					}
					settings = default(HitSettings);
					return false;
				}
				settings = GetThunderstormSettings();
				return true;
			}
			settings = GetOrbitalLaserSettings();
			return true;
		}

		internal static HitSettings GetOrbitalLaserSettings()
		{
			return new HitSettings("orbital-laser", "orbital laser hit", Plugin.OrbitalLaserHitMode.Value, Plugin.ExplosiveHitIntensity.Value, Plugin.ExplosiveHitDuration.Value);
		}

		internal static HitSettings GetThunderstormSettings()
		{
			return new HitSettings("thunderstorm", "thunderstorm hit", Plugin.ThunderstormHitMode.Value, Plugin.ExplosiveHitIntensity.Value, Plugin.ExplosiveHitDuration.Value);
		}

		internal static HitSettings GetRailgunSettings()
		{
			return new HitSettings("railgun", "railgun hit", Plugin.RailgunHitMode.Value, Plugin.WeaponHitIntensity.Value, Plugin.WeaponHitDuration.Value);
		}

		internal static void LogSkipped(string reason, string explanation)
		{
			NotificationService.Publish("Ignored " + reason + ": " + explanation + ".", Plugin.ShowSkippedNotifications.Value, "Shock skipped: " + explanation + ".");
		}
	}
	internal readonly struct HitSettings
	{
		internal string EventKey { get; }

		internal string Reason { get; }

		internal Plugin.HitTriggerMode Mode { get; }

		internal int Intensity { get; }

		internal int Duration { get; }

		internal HitSettings(string eventKey, string reason, Plugin.HitTriggerMode mode, int intensity, int duration)
		{
			EventKey = eventKey;
			Reason = reason;
			Mode = mode;
			Intensity = intensity;
			Duration = duration;
		}
	}
	internal sealed class ShockRequestQueue : IDisposable
	{
		private const int MaximumPendingRequests = 1;

		private readonly CancellationTokenSource _cancellation = new CancellationTokenSource();

		private readonly object _gate = new object();

		private readonly SemaphoreSlim _signal = new SemaphoreSlim(0);

		private readonly ConcurrentQueue<Func<CancellationToken, Task>> _tasks = new ConcurrentQueue<Func<CancellationToken, Task>>();

		private readonly Task _worker;

		private int _pendingCount;

		private bool _stopping;

		internal ShockRequestQueue()
		{
			_worker = Task.Run((Func<Task?>)ProcessQueueAsync);
		}

		internal bool TryEnqueue(Func<CancellationToken, Task> task)
		{
			lock (_gate)
			{
				if (_stopping || _pendingCount >= 1)
				{
					return false;
				}
				_tasks.Enqueue(task);
				_pendingCount++;
				_signal.Release();
				return true;
			}
		}

		private async Task ProcessQueueAsync()
		{
			_ = 1;
			try
			{
				while (true)
				{
					await _signal.WaitAsync(_cancellation.Token);
					if (!_tasks.TryDequeue(out Func<CancellationToken, Task> result))
					{
						continue;
					}
					try
					{
						await result(_cancellation.Token);
					}
					catch (OperationCanceledException) when (_cancellation.IsCancellationRequested)
					{
						break;
					}
					catch (Exception ex2)
					{
						NotificationService.PublishError("Queued shock request failed: " + ex2.Message);
						Plugin.Log.LogError((object)ex2);
					}
					finally
					{
						lock (_gate)
						{
							_pendingCount--;
						}
					}
				}
			}
			catch (OperationCanceledException) when (_cancellation.IsCancellationRequested)
			{
			}
		}

		public void Dispose()
		{
			lock (_gate)
			{
				if (_stopping)
				{
					return;
				}
				_stopping = true;
				_cancellation.Cancel();
			}
			try
			{
				_worker.GetAwaiter().GetResult();
			}
			catch (OperationCanceledException)
			{
			}
			finally
			{
				_cancellation.Dispose();
				_signal.Dispose();
				Func<CancellationToken, Task> result;
				while (_tasks.TryDequeue(out result))
				{
				}
			}
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ConstantExpectedAttribute : Attribute
	{
		public object? Min { get; set; }

		public object? Max { get; set; }
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class OverloadResolutionPriorityAttribute : Attribute
	{
		public int Priority { get; }

		public OverloadResolutionPriorityAttribute(int priority)
		{
			Priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}