using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("EventChatNotifications")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EventChatNotifications")]
[assembly: AssemblyTitle("EventChatNotifications")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 EventChatNotifications
{
[BepInPlugin("sbg.eventchatnotifications", "EventChatNotifications", "0.4.1")]
public sealed class Plugin : BaseUnityPlugin
{
public const string ModGuid = "sbg.eventchatnotifications";
public const string ModName = "EventChatNotifications";
public const string ModVersion = "0.4.1";
internal static ManualLogSource Log;
private void Awake()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
new Harmony("sbg.eventchatnotifications").PatchAll();
FirstPlaceTracker.Hook();
Log.LogInfo((object)"EventChatNotifications v0.4.1 loaded.");
}
private void OnDestroy()
{
FirstPlaceTracker.Unhook();
}
}
internal static class FirstPlaceTracker
{
private enum Metric
{
BestHoleScore,
LongestChipIn,
AvgFinishTime,
ItemPickups,
KORatio
}
private static readonly Metric[] AllMetrics = new Metric[5]
{
Metric.BestHoleScore,
Metric.LongestChipIn,
Metric.AvgFinishTime,
Metric.ItemPickups,
Metric.KORatio
};
private static readonly Dictionary<Metric, ulong> CurrentLeader = new Dictionary<Metric, ulong>();
private static bool subscribed;
internal static void Hook()
{
if (!subscribed)
{
CourseManager.PlayerStatesChanged += OnPlayerStatesChanged;
subscribed = true;
}
}
internal static void Unhook()
{
if (subscribed)
{
CourseManager.PlayerStatesChanged -= OnPlayerStatesChanged;
CurrentLeader.Clear();
subscribed = false;
}
}
private static void OnPlayerStatesChanged(Operation<PlayerState> op, int index, PlayerState changed)
{
//IL_0012: 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)
SyncList<PlayerState> playerStates = CourseManager.PlayerStates;
if (playerStates == null)
{
return;
}
int num = 0;
for (int i = 0; i < playerStates.Count; i++)
{
if (!playerStates[i].isSpectator && playerStates[i].isConnected)
{
num++;
}
}
if (num >= 2)
{
Metric[] allMetrics = AllMetrics;
foreach (Metric metric in allMetrics)
{
Reconcile(playerStates, metric);
}
}
}
private static void Reconcile(SyncList<PlayerState> states, Metric metric)
{
if (TryComputeLeader(states, metric, out var leaderGuid, out var valueLabel))
{
ulong value;
bool flag = CurrentLeader.TryGetValue(metric, out value);
if (!flag || value != leaderGuid)
{
CurrentLeader[metric] = leaderGuid;
string text = Narrator.PlayerNameFromGuid(leaderGuid);
string text2 = MetricLabel(metric);
Narrator.Post(flag ? (text + " took first on " + text2 + " from " + Narrator.PlayerNameFromGuid(value) + " — " + valueLabel + ".") : (text + " took first on " + text2 + " — " + valueLabel + "."));
}
}
}
private static bool TryComputeLeader(SyncList<PlayerState> states, Metric metric, out ulong leaderGuid, out string valueLabel)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: 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_0039: 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_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
leaderGuid = 0uL;
valueLabel = null;
bool flag = false;
ulong num = 0uL;
int num2 = int.MaxValue;
float num3 = 0f;
int num4 = 0;
for (int i = 0; i < states.Count; i++)
{
PlayerState val = states[i];
if (val.isSpectator || !val.isConnected || !IsEligible(val, metric))
{
continue;
}
bool flag2;
if (!flag)
{
flag2 = true;
}
else if (UsesIntComparison(metric))
{
int num5 = ReadInt(val, metric);
flag2 = (LowerIsBetter(metric) ? (num5 < num4) : (num5 > num4));
}
else
{
float num6 = ReadFloat(val, metric);
flag2 = (LowerIsBetter(metric) ? (num6 < num3) : (num6 > num3));
}
if (flag2)
{
num = val.playerGuid;
num2 = val.joinIndex;
flag = true;
if (UsesIntComparison(metric))
{
num4 = ReadInt(val, metric);
}
else
{
num3 = ReadFloat(val, metric);
}
}
else if (HasTie(val, metric, num4, num3) && val.joinIndex < num2)
{
num = val.playerGuid;
num2 = val.joinIndex;
}
}
if (!flag)
{
return false;
}
leaderGuid = num;
valueLabel = FormatValue(states, num, metric, num4, num3);
return true;
}
private static bool IsEligible(PlayerState s, Metric metric)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Invalid comparison between Unknown and I4
//IL_0026: 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_004d: 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_0041: Unknown result type (might be due to invalid IL or missing references)
switch (metric)
{
case Metric.BestHoleScore:
return (int)s.bestHoleScore > 0;
case Metric.LongestChipIn:
return s.longestChipIn > float.MinValue;
case Metric.AvgFinishTime:
if (s.avgFinishTime > 0f)
{
return s.finishes > 0;
}
return false;
case Metric.ItemPickups:
return s.itemPickups > 0;
case Metric.KORatio:
return s.matchKnockouts > 0;
default:
return false;
}
}
private static bool UsesIntComparison(Metric m)
{
if (m != 0)
{
return m == Metric.ItemPickups;
}
return true;
}
private static bool LowerIsBetter(Metric m)
{
return m == Metric.AvgFinishTime;
}
private static int ReadInt(PlayerState s, Metric m)
{
//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: Expected I4, but got Unknown
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
return m switch
{
Metric.BestHoleScore => (int)s.bestHoleScore,
Metric.ItemPickups => s.itemPickups,
_ => 0,
};
}
private static float ReadFloat(PlayerState s, Metric m)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
return m switch
{
Metric.LongestChipIn => s.longestChipIn,
Metric.AvgFinishTime => s.avgFinishTime,
Metric.KORatio => ComputeKORatio(s),
_ => 0f,
};
}
private static float ComputeKORatio(PlayerState s)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
int num = Mathf.Max(1, s.matchKnockedOut);
return (float)s.matchKnockouts / (float)num;
}
private static bool HasTie(PlayerState s, Metric metric, int bestInt, float bestFloat)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
if (UsesIntComparison(metric))
{
return ReadInt(s, metric) == bestInt;
}
return Mathf.Approximately(ReadFloat(s, metric), bestFloat);
}
private static string FormatValue(SyncList<PlayerState> states, ulong leaderGuid, Metric metric, int bestInt, float bestFloat)
{
//IL_005d: 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_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: 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)
switch (metric)
{
case Metric.BestHoleScore:
return DescribeStrokesUnderPar((StrokesUnderParType)bestInt);
case Metric.LongestChipIn:
return $"{Mathf.RoundToInt(bestFloat)}m";
case Metric.AvgFinishTime:
return $"{bestFloat:0.0}s";
case Metric.ItemPickups:
return bestInt.ToString();
case Metric.KORatio:
{
for (int i = 0; i < states.Count; i++)
{
if (states[i].playerGuid == leaderGuid)
{
PlayerState val = states[i];
return $"{bestFloat:0.00} ({val.matchKnockouts}/{val.matchKnockedOut})";
}
}
return bestFloat.ToString("0.00");
}
default:
return string.Empty;
}
}
private static string MetricLabel(Metric m)
{
return m switch
{
Metric.BestHoleScore => "best hole",
Metric.LongestChipIn => "longest chip-in",
Metric.AvgFinishTime => "average finish time",
Metric.ItemPickups => "item pickups",
Metric.KORatio => "K/O ratio",
_ => "stat",
};
}
private static string DescribeStrokesUnderPar(StrokesUnderParType type)
{
//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_0020: Expected I4, but got Unknown
return (type - 1) switch
{
5 => "Hole in One",
4 => "Condor",
3 => "Albatross",
2 => "Eagle",
1 => "Birdie",
0 => "Par",
_ => "—",
};
}
}
internal static class Narrator
{
private const string Prefix = "<color=#9aa6ff><b>[Match]</b></color> ";
internal static void Post(string message)
{
if (string.IsNullOrEmpty(message))
{
return;
}
try
{
TextChatUi.ShowMessage("<color=#9aa6ff><b>[Match]</b></color> " + message);
}
catch
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)("[chat-fallback] " + message));
}
}
}
internal static string PlayerNameFromGuid(ulong guid)
{
PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo;
if ((Object)(object)localPlayerInfo != (Object)null && (Object)(object)localPlayerInfo.PlayerId != (Object)null && localPlayerInfo.PlayerId.Guid == guid)
{
return localPlayerInfo.PlayerId.PlayerNameNoRichText;
}
if (GameManager.RemotePlayers != null)
{
foreach (PlayerInfo remotePlayer in GameManager.RemotePlayers)
{
if (!((Object)(object)remotePlayer == (Object)null) && !((Object)(object)remotePlayer.PlayerId == (Object)null) && remotePlayer.PlayerId.Guid == guid)
{
return remotePlayer.PlayerId.PlayerNameNoRichText;
}
}
}
return "Someone";
}
internal static string DescribeStrokesUnderPar(StrokesUnderParType type)
{
//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_001c: Expected I4, but got Unknown
return (type - 2) switch
{
4 => "scored a hole in one!",
2 => "landed an albatross!",
1 => "landed an eagle!",
0 => "landed a birdie!",
3 => "pulled off a condor!",
_ => null,
};
}
}
[HarmonyPatch(typeof(InfoFeed), "UserCode_RpcShowMessage__StrokesMessageData")]
internal static class Patch_StrokesMessage
{
private static void Postfix(StrokesMessageData messageData)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: 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)
string text = Narrator.DescribeStrokesUnderPar(messageData.strokesUnderParType);
if (text != null)
{
Narrator.Post(Narrator.PlayerNameFromGuid(messageData.playerGuid) + " " + text);
}
}
}
[HarmonyPatch(typeof(InfoFeed), "UserCode_RpcShowMessage__SpeedrunMessageData")]
internal static class Patch_SpeedrunMessage
{
private static void Postfix(SpeedrunMessageData messageData)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
Narrator.Post(Narrator.PlayerNameFromGuid(messageData.playerGuid) + " sprinted through the hole — that was fast!");
}
}
}