using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
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.Bootstrap;
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.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("com.github.addzeey.SbgShock")]
[assembly: AssemblyTitle("Super Battle Shock")]
[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.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, bool isTeamShock = false);
}
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_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: 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)
return (Color)(kind switch
{
NotificationKind.Team => new Color(0.25f, 0.78f, 1f),
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,
Team,
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 PublishTeam(string message, bool showInGame, string? displayMessage = null)
{
Publish(message, NotificationKind.Team, 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, bool isTeamShock = false)
{
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))
{
string message = $"Dry run: would send OpenShock intensity={intensity}, duration={duration}s. Configure ApiUrl, ApiKey, and DeviceId.";
if (isTeamShock)
{
NotificationService.PublishTeam(message, showInGame: true, "TEAM SHOCK dry run: " + ShockControllerBase.FormatShockSummary(intensity, duration));
}
else
{
NotificationService.PublishWarning(message, showInGame: true, "Dry run: " + ShockControllerBase.FormatShockSummary(intensity, duration));
}
}
else
{
EnqueueRequest("OpenShock", intensity, duration, isTeamShock, (CancellationToken cancellationToken) => SendShockAsync(apiUrl, apiKey, deviceId, intensity, duration, isTeamShock, cancellationToken));
}
}
private async Task SendShockAsync(string apiUrl, string apiKey, string deviceId, int intensity, int duration, bool isTeamShock, 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.2");
using HttpResponseMessage response = await base.Client.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken);
if (response.IsSuccessStatusCode)
{
string message = $"OpenShock accepted intensity={intensity}, duration={duration}s.";
if (isTeamShock)
{
NotificationService.PublishTeam(message, showInGame: true, "TEAM SHOCK: " + ShockControllerBase.FormatShockSummary(intensity, duration) + " sent.");
}
else
{
NotificationService.Publish(message, 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), isTeamShock ? "TEAM SHOCK failed. Check LogOutput.log." : "Shock failed. Check LogOutput.log.");
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
}
catch (Exception ex2)
{
NotificationService.PublishError("OpenShock request failed: " + ex2.Message, isTeamShock ? "TEAM SHOCK failed. Check LogOutput.log." : "Shock failed. Check LogOutput.log.");
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, bool isTeamShock = false)
{
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))
{
string message = 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/");
if (isTeamShock)
{
NotificationService.PublishTeam(message, showInGame: true, "TEAM SHOCK dry run: " + ShockControllerBase.FormatShockSummary(intensity, duration));
}
else
{
NotificationService.PublishWarning(message, showInGame: true, "Dry run: " + ShockControllerBase.FormatShockSummary(intensity, duration));
}
}
else
{
EnqueueRequest("PiShock", intensity, duration, isTeamShock, (CancellationToken cancellationToken) => SendShockAsync(apiUrl, apiKey, shockerId, intensity, duration, isTeamShock, cancellationToken));
}
}
private async Task SendShockAsync(string apiUrl, string apiKey, string shockerId, int intensity, int duration, bool isTeamShock, 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/OperateById/" + 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)
{
string message = $"PiShock accepted intensity={intensity}, duration={duration}s.";
if (isTeamShock)
{
NotificationService.PublishTeam(message, showInGame: true, "TEAM SHOCK: " + ShockControllerBase.FormatShockSummary(intensity, duration) + " sent.");
}
else
{
NotificationService.Publish(message, 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), isTeamShock ? "TEAM SHOCK failed. Check LogOutput.log." : "Shock failed. Check LogOutput.log.");
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
}
catch (Exception ex2)
{
NotificationService.PublishError("PiShock request failed: " + ex2.Message, isTeamShock ? "TEAM SHOCK failed. Check LogOutput.log." : "Shock failed. Check LogOutput.log.");
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.2")]
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.2";
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<bool> EnableTeamShock { get; private set; } = null;
internal static ConfigEntry<HitTriggerMode> TeamShockTriggerMode { get; private set; } = null;
internal static ConfigEntry<int> TeamShockIntensity { get; private set; } = null;
internal static ConfigEntry<int> TeamShockDuration { 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_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
CFG = ((BaseUnityPlugin)this).Config;
BindConfig();
InitializeShockController();
TeamShockNetworking.Initialize();
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.2. Event logging is active.", showInGame: true);
}
private void Update()
{
TeamShockNetworking.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();
TeamShockNetworking.Shutdown();
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_05af: Unknown result type (might be due to invalid IL or missing references)
//IL_05b9: 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.");
EnableTeamShock = CFG.Bind<bool>("TeamShock", "Enabled", false, "Shock locally when another player on your native or Team_Mode team is hit. Each teammate controls their own device and settings.");
TeamShockTriggerMode = CFG.Bind<HitTriggerMode>("TeamShock", "TriggerMode", HitTriggerMode.KnockoutOnly, "When teammate events trigger your local shock: Disabled, AnyHit, or KnockoutOnly.");
TeamShockIntensity = BindIntensity("TeamShock", "Intensity", 20, "Intensity for teammate hit shocks.");
TeamShockDuration = BindDuration("TeamShock", "Duration", 1, "Duration for teammate hit 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, bool isTeamShock = false)
{
lock (ShockControllerGate)
{
if (_shockController == null)
{
return false;
}
_shockController.EnqueueShock(intensity, duration, null, isTeamShock);
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, bool isTeamShock = false);
protected void EnqueueRequest(string providerName, int intensity, int duration, bool isTeamShock, Func<CancellationToken, Task> sendRequest)
{
if (_queue.TryEnqueue(async delegate(CancellationToken cancellationToken)
{
if (!TryReserveCooldown(out var remainingSeconds))
{
string message2 = $"{providerName} request skipped by cooldown ({remainingSeconds:0.0}s remaining).";
if (isTeamShock)
{
NotificationService.PublishTeam(message2, Plugin.ShowSkippedNotifications.Value, "TEAM SHOCK: cooldown active.");
}
else
{
NotificationService.Publish(message2, Plugin.ShowSkippedNotifications.Value, "Shock skipped: cooldown active.");
}
}
else
{
await sendRequest(cancellationToken);
}
}))
{
NotificationService.Publish($"{providerName} request queued: intensity={intensity}, duration={duration}s.", showInGame: false);
return;
}
string message = providerName + " request skipped because another request is already in progress.";
if (isTeamShock)
{
NotificationService.PublishTeam(message, Plugin.ShowSkippedNotifications.Value, "TEAM SHOCK: request already in progress.");
}
else
{
NotificationService.PublishWarning(message, 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, bool isTeamShock = false)
{
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, isTeamShock);
}
}
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_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
if (LocalPlayerGuard.IsLocal(__instance))
{
if (ShockHitHandler.TryGetSettings(knockoutType, out var settings))
{
TeamShockService.ReportLocalHit(__result && isNewKnockout);
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();
}
TeamShockService.ReportLocalHit(isKnockout: false);
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_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
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))
{
TeamShockService.ReportLocalHit(isKnockout: true);
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();
}
}
}
[HarmonyPatch(typeof(InfoFeed), "ShowMessage")]
internal static class TeamShockInfoFeedPatch
{
[HarmonyPostfix]
private static void ShowMessagePostfix(IMessageData messageData)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: 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_004f: 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_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: 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_005c: 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)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: 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_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
if (!(messageData is KnockoutMessageData val))
{
if (!(messageData is SelfKnockoutMessageData val2))
{
if (!(messageData is EliminationMessaqeData val3))
{
if (messageData is SelfEliminationMessageData val4 && TeamShockService.IsSupportedCombatIcon(val4.icon))
{
TeamShockService.HandleTeamEvent(val4.playerGuid, isKnockout: true);
}
}
else if (TeamShockService.IsSupportedCombatIcon(val3.icon))
{
TeamShockService.HandleTeamEvent(val3.knockedOutPlayer, isKnockout: true);
}
}
else if (TeamShockService.IsSupportedCombatIcon(val2.icon))
{
TeamShockService.HandleTeamEvent(val2.playerGuid, isKnockout: true);
}
}
else if (TeamShockService.IsSupportedCombatIcon(val.icon))
{
TeamShockService.HandleTeamEvent(val.knockedOutPlayer, isKnockout: true);
}
}
}
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))
{
}
}
}
}
internal static class TeamModeIntegration
{
private const string PluginGuid = "Team_Mode";
private const int MaxPlayers = 64;
private static readonly Dictionary<ulong, int> RemoteTeams = new Dictionary<ulong, int>();
private static FieldInfo? _enabledField;
private static FieldInfo? _teamCountField;
private static FieldInfo? _playerTeamsField;
private static bool _reflectionInitialized;
private static bool _hasRemoteSnapshot;
private static bool _remoteEnabled;
private static int _remoteTeamCount;
internal static bool IsInstalled => Chainloader.PluginInfos.ContainsKey("Team_Mode");
internal static bool TryCaptureSnapshot(out TeamModeSnapshotMessage snapshot)
{
snapshot = default(TeamModeSnapshotMessage);
if (!NetworkServer.active || !TryInitializeReflection())
{
return false;
}
object obj = _enabledField?.GetValue(null);
bool enabled = obj is bool && (bool)obj;
int num = ((_teamCountField?.GetValue(null) is int num2) ? num2 : 0);
if (!(_playerTeamsField?.GetValue(null) is IDictionary dictionary))
{
return false;
}
List<KeyValuePair<ulong, int>> list = new List<KeyValuePair<ulong, int>>();
foreach (DictionaryEntry item in dictionary)
{
if (item.Key is ulong num3 && item.Value is int num4 && num3 != 0L && num4 >= 0 && num4 < num)
{
list.Add(new KeyValuePair<ulong, int>(num3, num4));
}
}
list.Sort((KeyValuePair<ulong, int> left, KeyValuePair<ulong, int> right) => left.Key.CompareTo(right.Key));
int num5 = Math.Min(list.Count, 64);
ulong[] array = new ulong[num5];
int[] array2 = new int[num5];
for (int num6 = 0; num6 < num5; num6++)
{
array[num6] = list[num6].Key;
array2[num6] = list[num6].Value;
}
snapshot = new TeamModeSnapshotMessage(enabled, num, array, array2);
return true;
}
internal static void ApplySnapshot(TeamModeSnapshotMessage snapshot)
{
RemoteTeams.Clear();
ulong[] playerGuids = snapshot.PlayerGuids;
int val = ((playerGuids != null) ? playerGuids.Length : 0);
int[] teamIds = snapshot.TeamIds;
int num = Math.Min(Math.Min(val, (teamIds != null) ? teamIds.Length : 0), 64);
for (int i = 0; i < num; i++)
{
ulong num2 = snapshot.PlayerGuids[i];
int num3 = snapshot.TeamIds[i];
if (num2 != 0L && num3 >= 0 && num3 < snapshot.TeamCount)
{
RemoteTeams[num2] = num3;
}
}
_remoteEnabled = snapshot.Enabled;
_remoteTeamCount = snapshot.TeamCount;
_hasRemoteSnapshot = true;
}
internal static bool TryAreTeammates(ulong firstGuid, ulong secondGuid, out bool customModeEnabled)
{
customModeEnabled = false;
if (!IsInstalled)
{
return false;
}
if (NetworkServer.active && TryCaptureSnapshot(out var snapshot))
{
customModeEnabled = snapshot.Enabled && snapshot.TeamCount > 1;
if (customModeEnabled)
{
return TryFindSameTeam(snapshot, firstGuid, secondGuid);
}
return false;
}
if (!_hasRemoteSnapshot)
{
return false;
}
customModeEnabled = _remoteEnabled && _remoteTeamCount > 1;
if (customModeEnabled && RemoteTeams.TryGetValue(firstGuid, out var value) && RemoteTeams.TryGetValue(secondGuid, out var value2))
{
return value == value2;
}
return false;
}
internal static void ClearRemoteSnapshot()
{
RemoteTeams.Clear();
_hasRemoteSnapshot = false;
_remoteEnabled = false;
_remoteTeamCount = 0;
}
private static bool TryInitializeReflection()
{
if (_reflectionInitialized)
{
if (_enabledField != null && _teamCountField != null)
{
return _playerTeamsField != null;
}
return false;
}
_reflectionInitialized = true;
if (!Chainloader.PluginInfos.TryGetValue("Team_Mode", out var value))
{
return false;
}
Type type = ((object)value.Instance).GetType();
_enabledField = type.GetField("Enabled", BindingFlags.Static | BindingFlags.Public);
_teamCountField = type.GetField("TeamCount", BindingFlags.Static | BindingFlags.Public);
_playerTeamsField = type.GetField("PlayerTeams", BindingFlags.Static | BindingFlags.Public);
if (_enabledField == null || _teamCountField == null || _playerTeamsField == null)
{
Plugin.Log.LogWarning((object)"[Super Battle Shock] Team_Mode detected, but its public team fields were not found. Custom team shocks are disabled.");
return false;
}
Plugin.Log.LogInfo((object)"[Super Battle Shock] Team_Mode compatibility enabled.");
return true;
}
private static bool TryFindSameTeam(TeamModeSnapshotMessage snapshot, ulong firstGuid, ulong secondGuid)
{
int? num = null;
int? num2 = null;
int num3 = Math.Min(snapshot.PlayerGuids.Length, snapshot.TeamIds.Length);
for (int i = 0; i < num3; i++)
{
if (snapshot.PlayerGuids[i] == firstGuid)
{
num = snapshot.TeamIds[i];
}
if (snapshot.PlayerGuids[i] == secondGuid)
{
num2 = snapshot.TeamIds[i];
}
}
if (num.HasValue && num2.HasValue)
{
return num.Value == num2.Value;
}
return false;
}
}
internal static class TeamShockNetworking
{
private const int ProtocolVersion = 1;
private const float SnapshotIntervalSeconds = 1f;
private static readonly HashSet<int> ModdedConnections = new HashSet<int>();
private static bool _serverRegistered;
private static bool _clientRegistered;
private static bool _helloSent;
private static float _nextSnapshotTime;
private static TeamModeSnapshotMessage _lastSnapshot;
private static bool _hasLastSnapshot;
internal static void Initialize()
{
Writer<TeamShockHelloMessage>.write = WriteHello;
Reader<TeamShockHelloMessage>.read = ReadHello;
Writer<TeamShockHitMessage>.write = WriteHit;
Reader<TeamShockHitMessage>.read = ReadHit;
Writer<TeamModeSnapshotMessage>.write = WriteSnapshot;
Reader<TeamModeSnapshotMessage>.read = ReadSnapshot;
}
internal static void Update()
{
UpdateServerRegistration();
UpdateClientRegistration();
if (_serverRegistered && TeamModeIntegration.IsInstalled && !(Time.unscaledTime < _nextSnapshotTime))
{
_nextSnapshotTime = Time.unscaledTime + 1f;
if (TeamModeIntegration.TryCaptureSnapshot(out var snapshot) && (!_hasLastSnapshot || !SnapshotEquals(_lastSnapshot, snapshot)))
{
_lastSnapshot = snapshot;
_hasLastSnapshot = true;
SendSnapshotToModdedClients(snapshot);
}
}
}
internal static void SendHitEvent(ulong victimGuid, bool isKnockout)
{
if (_helloSent && NetworkClient.isConnected)
{
NetworkClient.Send<TeamShockHitMessage>(new TeamShockHitMessage(victimGuid, isKnockout), 0);
}
}
internal static void Shutdown()
{
if (_serverRegistered && NetworkServer.active)
{
NetworkServer.UnregisterHandler<TeamShockHelloMessage>();
NetworkServer.UnregisterHandler<TeamShockHitMessage>();
NetworkServer.OnDisconnectedEvent = (Action<NetworkConnectionToClient>)Delegate.Remove(NetworkServer.OnDisconnectedEvent, new Action<NetworkConnectionToClient>(OnServerDisconnected));
}
if (_clientRegistered && NetworkClient.active)
{
NetworkClient.UnregisterHandler<TeamShockHitMessage>();
NetworkClient.UnregisterHandler<TeamModeSnapshotMessage>();
}
ResetState();
}
private static void UpdateServerRegistration()
{
if (NetworkServer.active && !_serverRegistered)
{
NetworkServer.RegisterHandler<TeamShockHelloMessage>((Action<NetworkConnectionToClient, TeamShockHelloMessage>)OnServerHello, true);
NetworkServer.RegisterHandler<TeamShockHitMessage>((Action<NetworkConnectionToClient, TeamShockHitMessage>)OnServerHit, true);
NetworkServer.OnDisconnectedEvent = (Action<NetworkConnectionToClient>)Delegate.Combine(NetworkServer.OnDisconnectedEvent, new Action<NetworkConnectionToClient>(OnServerDisconnected));
_serverRegistered = true;
_nextSnapshotTime = 0f;
}
else if (!NetworkServer.active && _serverRegistered)
{
_serverRegistered = false;
ModdedConnections.Clear();
_hasLastSnapshot = false;
}
}
private static void UpdateClientRegistration()
{
if (!NetworkClient.active || !NetworkClient.isConnected)
{
if (_clientRegistered || _helloSent)
{
_clientRegistered = false;
_helloSent = false;
TeamModeIntegration.ClearRemoteSnapshot();
TeamShockService.Reset();
}
}
else if (NetworkClient.ready && TeamShockService.NeedsCustomNetworking)
{
if (!_clientRegistered)
{
NetworkClient.RegisterHandler<TeamShockHitMessage>((Action<TeamShockHitMessage>)OnClientHit, true);
NetworkClient.RegisterHandler<TeamModeSnapshotMessage>((Action<TeamModeSnapshotMessage>)TeamModeIntegration.ApplySnapshot, true);
_clientRegistered = true;
}
if (!_helloSent)
{
NetworkClient.Send<TeamShockHelloMessage>(new TeamShockHelloMessage(1), 0);
_helloSent = true;
}
}
}
private static void OnServerHello(NetworkConnectionToClient connection, TeamShockHelloMessage message)
{
if (message.ProtocolVersion == 1)
{
ModdedConnections.Add(connection.connectionId);
if (TeamModeIntegration.TryCaptureSnapshot(out var snapshot))
{
((NetworkConnection)connection).Send<TeamModeSnapshotMessage>(snapshot, 0);
}
}
}
private static void OnServerHit(NetworkConnectionToClient connection, TeamShockHitMessage message)
{
if (!ModdedConnections.Contains(connection.connectionId) || message.VictimGuid == 0L)
{
return;
}
NetworkIdentity identity = ((NetworkConnection)connection).identity;
PlayerInfo val = ((identity != null) ? ((Component)identity).GetComponent<PlayerInfo>() : null);
if ((Object)(object)val == (Object)null || val.PlayerId.Guid != message.VictimGuid)
{
Plugin.Log.LogWarning((object)$"[Super Battle Shock] Rejected team event with mismatched sender identity from connection {connection.connectionId}.");
return;
}
foreach (int moddedConnection in ModdedConnections)
{
if (NetworkServer.connections.TryGetValue(moddedConnection, out var value) && ((NetworkConnection)value).isReady)
{
((NetworkConnection)value).Send<TeamShockHitMessage>(message, 0);
}
}
}
private static void OnServerDisconnected(NetworkConnectionToClient connection)
{
ModdedConnections.Remove(connection.connectionId);
}
private static void OnClientHit(TeamShockHitMessage message)
{
TeamShockService.HandleTeamEvent(message.VictimGuid, message.IsKnockout);
}
private static void SendSnapshotToModdedClients(TeamModeSnapshotMessage snapshot)
{
foreach (int moddedConnection in ModdedConnections)
{
if (NetworkServer.connections.TryGetValue(moddedConnection, out var value) && ((NetworkConnection)value).isReady)
{
((NetworkConnection)value).Send<TeamModeSnapshotMessage>(snapshot, 0);
}
}
}
private static bool SnapshotEquals(TeamModeSnapshotMessage left, TeamModeSnapshotMessage right)
{
if (left.Enabled != right.Enabled || left.TeamCount != right.TeamCount || left.PlayerGuids.Length != right.PlayerGuids.Length)
{
return false;
}
for (int i = 0; i < left.PlayerGuids.Length; i++)
{
if (left.PlayerGuids[i] != right.PlayerGuids[i] || left.TeamIds[i] != right.TeamIds[i])
{
return false;
}
}
return true;
}
private static void ResetState()
{
_serverRegistered = false;
_clientRegistered = false;
_helloSent = false;
_hasLastSnapshot = false;
_nextSnapshotTime = 0f;
ModdedConnections.Clear();
TeamModeIntegration.ClearRemoteSnapshot();
TeamShockService.Reset();
}
private static void WriteHello(NetworkWriter writer, TeamShockHelloMessage message)
{
NetworkWriterExtensions.WriteInt(writer, message.ProtocolVersion);
}
private static TeamShockHelloMessage ReadHello(NetworkReader reader)
{
return new TeamShockHelloMessage(NetworkReaderExtensions.ReadInt(reader));
}
private static void WriteHit(NetworkWriter writer, TeamShockHitMessage message)
{
NetworkWriterExtensions.WriteULong(writer, message.VictimGuid);
NetworkWriterExtensions.WriteBool(writer, message.IsKnockout);
}
private static TeamShockHitMessage ReadHit(NetworkReader reader)
{
return new TeamShockHitMessage(NetworkReaderExtensions.ReadULong(reader), NetworkReaderExtensions.ReadBool(reader));
}
private static void WriteSnapshot(NetworkWriter writer, TeamModeSnapshotMessage message)
{
NetworkWriterExtensions.WriteBool(writer, message.Enabled);
NetworkWriterExtensions.WriteInt(writer, message.TeamCount);
int num = Math.Min(message.PlayerGuids.Length, message.TeamIds.Length);
NetworkWriterExtensions.WriteInt(writer, num);
for (int i = 0; i < num; i++)
{
NetworkWriterExtensions.WriteULong(writer, message.PlayerGuids[i]);
NetworkWriterExtensions.WriteInt(writer, message.TeamIds[i]);
}
}
private static TeamModeSnapshotMessage ReadSnapshot(NetworkReader reader)
{
bool enabled = NetworkReaderExtensions.ReadBool(reader);
int teamCount = NetworkReaderExtensions.ReadInt(reader);
int num = NetworkReaderExtensions.ReadInt(reader);
if (num < 0 || num > 64)
{
throw new InvalidDataException($"Invalid Team_Mode snapshot player count: {num}.");
}
ulong[] array = new ulong[num];
int[] array2 = new int[num];
for (int i = 0; i < num; i++)
{
array[i] = NetworkReaderExtensions.ReadULong(reader);
array2[i] = NetworkReaderExtensions.ReadInt(reader);
}
return new TeamModeSnapshotMessage(enabled, teamCount, array, array2);
}
}
internal readonly struct TeamShockHelloMessage : NetworkMessage
{
internal int ProtocolVersion { get; }
internal TeamShockHelloMessage(int protocolVersion)
{
ProtocolVersion = protocolVersion;
}
}
internal readonly struct TeamShockHitMessage : NetworkMessage
{
internal ulong VictimGuid { get; }
internal bool IsKnockout { get; }
internal TeamShockHitMessage(ulong victimGuid, bool isKnockout)
{
VictimGuid = victimGuid;
IsKnockout = isKnockout;
}
}
internal readonly struct TeamModeSnapshotMessage : NetworkMessage
{
internal bool Enabled { get; }
internal int TeamCount { get; }
internal ulong[] PlayerGuids { get; }
internal int[] TeamIds { get; }
internal TeamModeSnapshotMessage(bool enabled, int teamCount, ulong[] playerGuids, int[] teamIds)
{
Enabled = enabled;
TeamCount = teamCount;
PlayerGuids = playerGuids;
TeamIds = teamIds;
}
}
internal static class TeamShockService
{
private const double ReportDedupSeconds = 0.25;
private static double _lastRegularReport;
private static double _lastKnockoutReport;
internal static bool NeedsCustomNetworking
{
get
{
if (Plugin.EnableTeamShock.Value && Plugin.TeamShockTriggerMode.Value != Plugin.HitTriggerMode.Disabled)
{
if (Plugin.TeamShockTriggerMode.Value != Plugin.HitTriggerMode.AnyHit)
{
return TeamModeIntegration.IsInstalled;
}
return true;
}
return false;
}
}
internal static void ReportLocalHit(bool isKnockout)
{
if (!Plugin.EnableTeamShock.Value || Plugin.TeamShockTriggerMode.Value == Plugin.HitTriggerMode.Disabled)
{
return;
}
PlayerId localPlayerId = GameManager.LocalPlayerId;
ulong num = ((localPlayerId != null) ? localPlayerId.Guid : 0);
if (num != 0L)
{
double num2 = (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency;
ref double reference = ref isKnockout ? ref _lastKnockoutReport : ref _lastRegularReport;
if (!(num2 - reference < 0.25))
{
reference = num2;
TeamShockNetworking.SendHitEvent(num, isKnockout);
}
}
}
internal static void HandleTeamEvent(ulong victimGuid, bool isKnockout)
{
if (!Plugin.EnableTeamShock.Value || victimGuid == 0L)
{
return;
}
switch (Plugin.TeamShockTriggerMode.Value)
{
case Plugin.HitTriggerMode.KnockoutOnly:
if (!isKnockout)
{
return;
}
break;
case Plugin.HitTriggerMode.Disabled:
return;
}
PlayerId localPlayerId = GameManager.LocalPlayerId;
ulong num = ((localPlayerId != null) ? localPlayerId.Guid : 0);
if (num != 0L && num != victimGuid && AreTeammates(num, victimGuid))
{
string text = (isKnockout ? "knockout" : "hit");
ShockDispatcher.Trigger($"team-{victimGuid}", Plugin.TeamShockIntensity.Value, Plugin.TeamShockDuration.Value, "teammate " + text, isTeamShock: true);
}
}
internal static bool IsSupportedCombatIcon(InfoFeedIconType icon)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Expected I4, but got Unknown
switch (icon - 2)
{
case 0:
case 1:
case 8:
case 10:
case 11:
case 12:
case 13:
case 17:
case 18:
case 19:
case 20:
case 21:
case 23:
case 24:
case 26:
case 27:
case 29:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
return true;
default:
return false;
}
}
internal static void Reset()
{
_lastRegularReport = 0.0;
_lastKnockoutReport = 0.0;
}
private static bool AreTeammates(ulong localGuid, ulong victimGuid)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Invalid comparison between Unknown and I4
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (TeamModeIntegration.TryAreTeammates(localGuid, victimGuid, out var customModeEnabled))
{
return true;
}
if (customModeEnabled || (int)MatchSetupMenu.CurrentGameMode != 1)
{
return false;
}
PlayerState val = default(PlayerState);
PlayerState val2 = default(PlayerState);
if (CourseManager.TryGetPlayerState(localGuid, ref val) && CourseManager.TryGetPlayerState(victimGuid, ref val2) && val.isConnected && val2.isConnected && !val.isInSpectatorMode && !val2.isInSpectatorMode && (int)val.team != 0)
{
return val.team == val2.team;
}
return false;
}
}
}
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
{
}
}