Decompiled source of Pro Golf Plus v0.1.23

BepInEx\plugins\ProGolfMod.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Steamworks;
using Steamworks.Data;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[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("ProGolfMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ProGolfMod")]
[assembly: AssemblyTitle("ProGolfMod")]
[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 ProGolfMod
{
	[BepInPlugin("codex.superbattlegolf.progolfplus", "Pro Golf Plus", "0.1.23")]
	public sealed class ProGolfPlugin : BaseUnityPlugin
	{
		private sealed class DriveCandidate
		{
			public PlayerInfo Player;

			public ulong PlayerGuid;

			public Vector3 StartPosition;
		}

		private sealed class FirstDriveResult
		{
			public string PlayerName;

			public float Distance;

			public bool IsValid;
		}

		private sealed class ClosestToPinResult
		{
			public string PlayerName;

			public float Distance;
		}

		private sealed class CartFlipState
		{
			public WheelCollider[] Wheels = Array.Empty<WheelCollider>();

			public bool WasUprightOnWheels;

			public bool FlipInProgress;

			public int CurrentFlipStreak;

			public float AccumulatedFlipRadians;

			public float LastFlipPollTime = -1f;

			public float SettledSince = -1f;

			public ulong ResponsiblePlayerGuid;

			public string ResponsiblePlayerName;
		}

		[HarmonyPatch(typeof(CourseManager), "BeginCountdownToMatchEnd")]
		private static class SkipFirstFinishCountdownPatch
		{
			private static bool Prefix(CourseManager __instance)
			{
				if (!IsActiveProGolf() || (Object)(object)__instance == (Object)null)
				{
					return true;
				}
				if (AllActivePlayersResolved(__instance))
				{
					TryAnnounceClosestToPinIfReady();
					TryAnnounceHoleStatsIfReady();
					return true;
				}
				ProGolfPlugin instance = ProGolfPlugin.instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogInfo((object)"Skipped Pro Golf end-of-hole countdown because active players are still playing.");
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(CourseManager), "OnPlayerStatesChanged")]
		private static class AnnounceHoleStatsOnPlayerStateChangedPatch
		{
			private static void Postfix(CourseManager __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && NetworkServer.active && IsProGolfScoringActive() && AllActivePlayersResolved(__instance))
				{
					TryAnnounceClosestToPinIfReady();
					TryAnnounceHoleStatsIfReady();
				}
			}
		}

		[HarmonyPatch(typeof(PlayerState), "CompareTo")]
		private static class ProGolfStrokeFirstPlayerStateSortPatch
		{
			private static bool Prefix(PlayerState __instance, PlayerState other, ref int __result)
			{
				//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)
				return !TryCompareProGolfPlayerStates(__instance, other, ref __result);
			}
		}

		[HarmonyPatch(typeof(ScoreboardEntry), "PopulateWith")]
		private static class ProGolfScoreboardEntryStatsPatch
		{
			private static void Postfix(ScoreboardEntry __instance, PlayerState playerState)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				UpdateScoreboardEntryProGolfStats(__instance, playerState);
			}
		}

		[HarmonyPatch(typeof(Scoreboard), "Refresh")]
		private static class ProGolfScoreboardStatCardPatch
		{
			private static void Postfix(Scoreboard __instance)
			{
				UpdateScoreboardProGolfStatCard(__instance);
			}
		}

		[HarmonyPatch(typeof(CourseManager), "RegisterActivePlayerOnGreen")]
		private static class CaptureClosestToPinOnGreenPatch
		{
			private static void Postfix(PlayerGolfer player)
			{
				CaptureClosestToPinOnFirstGreen(player);
			}
		}

		[HarmonyPatch(typeof(CourseManager), "TryPlayHoleMusic")]
		private static class ForceNormalHoleMusicPatch
		{
			private static void Prefix(ref bool hurryUpInstantly)
			{
				if (IsActiveProGolf())
				{
					hurryUpInstantly = false;
				}
			}
		}

		[HarmonyPatch(typeof(CourseManager), "HurryUpHoleMusic")]
		private static class PreventHurryUpMusicPatch
		{
			private static bool Prefix()
			{
				return !IsActiveProGolf();
			}
		}

		[HarmonyPatch(typeof(GolfBall), "OnWillApplyGolfSwingHitPhysics")]
		private static class BeginLongestDriveTrackingPatch
		{
			private static void Prefix(GolfBall __instance)
			{
				BeginDriveTracking(__instance);
			}
		}

		[HarmonyPatch(typeof(PlayerGolfer), "OnPlayerHitOwnBall")]
		private static class TrackPerfectShotPatch
		{
			private static void Postfix(PlayerGolfer __instance)
			{
				TrackPerfectShot(__instance);
			}
		}

		[HarmonyPatch(typeof(GolfBall), "set_IsStationary")]
		private static class CompleteLongestDriveTrackingPatch
		{
			private static void Postfix(GolfBall __instance, bool value)
			{
				if (value)
				{
					TryCompleteDriveTracking(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(CourseManager), "AddPenaltyStroke")]
		private static class InvalidatePenaltyDrivePatch
		{
			private static void Prefix(PlayerGolfer penalizedPlayer)
			{
				InvalidateFirstDrive((penalizedPlayer != null) ? penalizedPlayer.PlayerInfo : null);
			}
		}

		[HarmonyPatch(typeof(PlayerGolfer), "ServerEliminate")]
		private static class HazardEliminationRespawnPatch
		{
			private static void Prefix(PlayerGolfer __instance, EliminationReason immediateEliminationReason)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				MarkBallRespawnForHazardElimination(__instance, immediateEliminationReason);
			}
		}

		[HarmonyPatch(typeof(PlayerMovement), "TryBeginRespawn")]
		private static class BeginRespawnAtBallPatch
		{
			private static void Prefix(PlayerMovement __instance, ref RespawnTarget respawnTarget)
			{
				RedirectHazardRespawnToBall(__instance, ref respawnTarget);
			}
		}

		[HarmonyPatch(typeof(Checkpoint), "Awake")]
		private static class HideCheckpointOnAwakePatch
		{
			private static void Postfix(Checkpoint __instance)
			{
				if (IsActiveProGolf())
				{
					SuppressCheckpointVisuals(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerInventorySettings), "get_MaxItems")]
		private static class MinimumProGolfInventoryPatch
		{
			private static void Postfix(ref int __result)
			{
				if (IsActiveProGolf())
				{
					__result = 3;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "OnStartServer")]
		private static class ServerStartLoadoutPatch
		{
			private static void Postfix(PlayerInventory __instance)
			{
				EnsureProGolfLoadout(__instance);
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "OnStartLocalPlayer")]
		private static class LocalStartLoadoutPatch
		{
			private static void Postfix(PlayerInventory __instance)
			{
				EnsureProGolfLoadout(__instance);
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "OnBUpdate")]
		private static class InventoryUpdateLoadoutPatch
		{
			private static void Postfix(PlayerInventory __instance)
			{
				EnsureProGolfLoadout(__instance);
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "ServerTryAddItem")]
		private static class ProGolfItemGrantPatch
		{
			private static bool Prefix(PlayerInventory __instance, ItemType itemToAdd, ref bool __result)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Invalid comparison between Unknown and I4
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Invalid comparison between Unknown and I4
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Invalid comparison between Unknown and I4
				if (!IsActiveProGolf() || !NetworkServer.active)
				{
					return true;
				}
				EnsureProGolfLoadout(__instance);
				if ((int)itemToAdd == 6 || (int)itemToAdd == 1 || (int)itemToAdd == 5)
				{
					__result = true;
					return false;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(ItemPool), "GetWeightedRandomItem")]
		private static class RemovePermanentItemsFromItemPoolsPatch
		{
			private static bool Prefix(ItemPool __instance, ref ItemType __result)
			{
				if (!IsActiveProGolf())
				{
					return true;
				}
				return !TryGetWeightedRandomAllowedPickupItem(__instance, out __result);
			}
		}

		[HarmonyPatch(typeof(ItemSpawner), "OnStartServer")]
		private static class HideInitialItemSpawnersPatch
		{
			private static void Postfix(ItemSpawner __instance)
			{
				if (IsActiveProGolf() && (Object)(object)__instance != (Object)null)
				{
					SuppressItemSpawner(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(ItemSpawner), "OnBUpdate")]
		private static class KeepItemSpawnersHiddenPatch
		{
			private static void Postfix(ItemSpawner __instance)
			{
				if (IsActiveProGolf())
				{
					SuppressItemSpawner(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(ItemSpawner), "ServerSpawnItemBox")]
		private static class PreventItemSpawnerRespawnsPatch
		{
			private static bool Prefix(ItemSpawner __instance)
			{
				if (!IsActiveProGolf())
				{
					return true;
				}
				if ((Object)(object)__instance != (Object)null)
				{
					SuppressItemSpawner(__instance);
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "DecrementUseFromSlotAt")]
		private static class KeepPermanentItemsLoadedPatch
		{
			private static bool Prefix(PlayerInventory __instance, int index)
			{
				return !IsReservedPermanentSlot(__instance, index);
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "RemoveIfOutOfUses")]
		private static class PreventPermanentItemsRemovalPatch
		{
			private static bool Prefix(PlayerInventory __instance, int index)
			{
				return !IsReservedPermanentSlot(__instance, index);
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "DropItem")]
		private static class PreventDroppingPermanentItemsPatch
		{
			private static bool Prefix(PlayerInventory __instance)
			{
				return !IsReservedPermanentSlot(__instance, __instance.EquippedItemIndex);
			}
		}

		private const string PluginGuid = "codex.superbattlegolf.progolfplus";

		private const string PluginName = "Pro Golf Plus";

		private const string PluginVersion = "0.1.23";

		private const string LobbyMemberVersionKey = "codex_progolfplus_member_version";

		private const string LobbyRequiredVersionKey = "codex_progolfplus_required_version";

		private const string LobbyActiveStateKey = "codex_progolfplus_active";

		private const string LobbyActiveVersionKey = "codex_progolfplus_active_version";

		private const string LobbyAnnouncementTextKey = "codex_progolfplus_announcement_text";

		private const string LobbyAnnouncementVersionKey = "codex_progolfplus_announcement_version";

		private const string LobbyHoleStatsPayloadKey = "codex_progolfplus_hole_stats_payload";

		private const string LobbyHoleStatsVersionKey = "codex_progolfplus_hole_stats_version";

		private const int ReservedCartSlotIndex = 0;

		private const int ReservedCoffeeSlotIndex = 1;

		private const int ReservedSpringBootsSlotIndex = 2;

		private const int TotalInventorySlots = 3;

		private const float CartFlipPollInterval = 0.15f;

		private const float CartUprightDotThreshold = 0.65f;

		private const float CartMovingSpeedThreshold = 0.35f;

		private const float CartMovingAngularThreshold = 0.35f;

		private const float CartFlipStartAngularThreshold = 1f;

		private const float CartFlipFullRotationRadians = (float)Math.PI * 2f;

		private const float CartSettledSeconds = 0.5f;

		private static ProGolfPlugin instance;

		private static FieldInfo inventorySlotsField;

		private static FieldInfo itemPoolSpawnChancesField;

		private static FieldInfo itemSpawnerVisualsField;

		private static FieldInfo itemSpawnerPickupColliderField;

		private static FieldInfo itemSpawnerVisualsFillingObjectField;

		private static FieldInfo itemSpawnerVisualsIdleObjectField;

		private static FieldInfo itemSpawnerVisualsFillRendererField;

		private static FieldInfo itemSpawnerVisualsAnimatorField;

		private static FieldInfo checkpointVisualCenterField;

		private static FieldInfo checkpointBaseMeshField;

		private static FieldInfo checkpointScreenMeshField;

		private static FieldInfo checkpointAnimatorField;

		private static FieldInfo scoreboardEntryStatsBackgroundField;

		private static FieldInfo scoreboardEntryNameField;

		private static FieldInfo scoreboardItemPickupsStatField;

		private static FieldInfo scoreboardKnockoutRatioStatField;

		private static FieldInfo scoreboardStatLabelField;

		private static MethodInfo scoreboardMarkDirtyMethod;

		private static bool allLobbyMembersCompatible = true;

		private static string incompatibleLobbyMembers = string.Empty;

		private static float nextLobbyPollTime;

		private static float nextCompatibilityWarningTime;

		private static bool lastPublishedActiveState;

		private static string lastObservedActiveVersion = string.Empty;

		private static string lastObservedHoleStatsVersion = string.Empty;

		private static readonly Dictionary<GolfBall, DriveCandidate> activeDrives = new Dictionary<GolfBall, DriveCandidate>();

		private static readonly Dictionary<ulong, FirstDriveResult> firstDriveResults = new Dictionary<ulong, FirstDriveResult>();

		private static readonly Dictionary<ulong, ClosestToPinResult> closestToPinResults = new Dictionary<ulong, ClosestToPinResult>();

		private static readonly Dictionary<ulong, int> perfectShotCounts = new Dictionary<ulong, int>();

		private static readonly Dictionary<ulong, int> cartBestFlipStreaks = new Dictionary<ulong, int>();

		private static readonly Dictionary<GolfCartMovement, CartFlipState> cartFlipStates = new Dictionary<GolfCartMovement, CartFlipState>();

		private static readonly HashSet<PlayerMovement> forceNextRespawnAtBall = new HashSet<PlayerMovement>();

		private static int longestDriveHoleIndex = int.MinValue;

		private static bool longestDriveAnnounced;

		private static bool closestToPinAnnounced;

		private static bool holeStatsAnnounced;

		private static string lastObservedAnnouncementVersion = string.Empty;

		private static string topAnnouncementText = string.Empty;

		private static string topAnnouncementDetailText = string.Empty;

		private static float topAnnouncementVisibleUntil;

		private static float nextCartFlipPollTime;

		private static GUIStyle topAnnouncementBoxStyle;

		private static GUIStyle topAnnouncementTextStyle;

		private static GUIStyle topAnnouncementDetailStyle;

		private static Texture2D topAnnouncementBoxTexture;

		private static readonly Dictionary<ScoreboardEntry, TextMeshProUGUI> scoreboardEntryStatLabels = new Dictionary<ScoreboardEntry, TextMeshProUGUI>();

		private Harmony harmony;

		private ConfigEntry<bool> enabledConfig;

		private ConfigEntry<float> grantCheckIntervalConfig;

		private ConfigEntry<float> longestDriveMinimumMetersConfig;

		private float nextGrantCheckTime;

		private void Awake()
		{
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			instance = this;
			enabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Pro Golf Plus.");
			grantCheckIntervalConfig = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GrantCheckIntervalSeconds", 0.5f, "How often the host checks whether every Pro Golf player needs a cart.");
			longestDriveMinimumMetersConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Longest Drive", "MinimumDistanceMeters", 15f, "Minimum drive distance required before a Longest Drive popup can appear.");
			inventorySlotsField = AccessTools.Field(typeof(PlayerInventory), "slots");
			itemPoolSpawnChancesField = AccessTools.Field(typeof(ItemPool), "spawnChances");
			itemSpawnerVisualsField = AccessTools.Field(typeof(ItemSpawner), "visuals");
			itemSpawnerPickupColliderField = AccessTools.Field(typeof(ItemSpawner), "pickUpCollider");
			itemSpawnerVisualsFillingObjectField = AccessTools.Field(typeof(ItemSpawnerVisuals), "fillingObj");
			itemSpawnerVisualsIdleObjectField = AccessTools.Field(typeof(ItemSpawnerVisuals), "idleObj");
			itemSpawnerVisualsFillRendererField = AccessTools.Field(typeof(ItemSpawnerVisuals), "fillMeshRenderer");
			itemSpawnerVisualsAnimatorField = AccessTools.Field(typeof(ItemSpawnerVisuals), "animator");
			checkpointVisualCenterField = AccessTools.Field(typeof(Checkpoint), "visualCenter");
			checkpointBaseMeshField = AccessTools.Field(typeof(Checkpoint), "baseMesh");
			checkpointScreenMeshField = AccessTools.Field(typeof(Checkpoint), "screenMesh");
			checkpointAnimatorField = AccessTools.Field(typeof(Checkpoint), "animator");
			scoreboardEntryStatsBackgroundField = AccessTools.Field(typeof(ScoreboardEntry), "statsBackground");
			scoreboardEntryNameField = AccessTools.Field(typeof(ScoreboardEntry), "name");
			scoreboardItemPickupsStatField = AccessTools.Field(typeof(Scoreboard), "itemPickups");
			scoreboardKnockoutRatioStatField = AccessTools.Field(typeof(Scoreboard), "knockoutRatio");
			scoreboardStatLabelField = AccessTools.Field(typeof(ScoreboardStat), "label");
			scoreboardMarkDirtyMethod = AccessTools.Method(typeof(Scoreboard), "MarkDirty", (Type[])null, (Type[])null);
			harmony = new Harmony("codex.superbattlegolf.progolfplus");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Pro Golf Plus 0.1.23 loaded.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			DestroyTopAnnouncementStyles();
			if (instance == this)
			{
				instance = null;
			}
		}

		private void OnGUI()
		{
			DrawTopAnnouncement();
		}

		private void Update()
		{
			PollLobbyCompatibility();
			PollCartFlipStats();
			if (IsActiveProGolf() && !(Time.unscaledTime < nextGrantCheckTime))
			{
				nextGrantCheckTime = Time.unscaledTime + Mathf.Max(0.25f, grantCheckIntervalConfig.Value);
				TryEnsureAllPlayersHaveProGolfLoadout();
				TrySuppressAllItemSpawners();
				TrySuppressCheckpoints();
			}
		}

		private static bool IsActiveProGolf()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			if ((Object)(object)instance == (Object)null || !instance.enabledConfig.Value)
			{
				return false;
			}
			if (NetworkServer.active && !allLobbyMembersCompatible)
			{
				return false;
			}
			MatchSetupRules val = FindMatchSetupRules();
			if ((Object)(object)val != (Object)null && (int)val.CurrentPreset == 1)
			{
				return IsMatchUnderway();
			}
			return false;
		}

		private static bool IsMatchUnderway()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			MatchState matchState = CourseManager.MatchState;
			if ((int)matchState >= 1)
			{
				return (int)matchState < 6;
			}
			return false;
		}

		private static bool IsProGolfScoringActive()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			if ((Object)(object)instance == (Object)null || !instance.enabledConfig.Value)
			{
				return false;
			}
			if (NetworkServer.active && !allLobbyMembersCompatible)
			{
				return false;
			}
			MatchSetupRules val = FindMatchSetupRules();
			if ((Object)(object)val != (Object)null && (int)val.CurrentPreset == 1)
			{
				return (int)CourseManager.MatchState >= 1;
			}
			return false;
		}

		private static void ResetLongestDriveIfHoleChanged()
		{
			int currentHoleGlobalIndex = CourseManager.CurrentHoleGlobalIndex;
			if (currentHoleGlobalIndex != longestDriveHoleIndex)
			{
				longestDriveHoleIndex = currentHoleGlobalIndex;
				longestDriveAnnounced = false;
				closestToPinAnnounced = false;
				holeStatsAnnounced = false;
				activeDrives.Clear();
				firstDriveResults.Clear();
				closestToPinResults.Clear();
				perfectShotCounts.Clear();
				cartBestFlipStreaks.Clear();
				cartFlipStates.Clear();
			}
		}

		private static void PollLobbyCompatibility()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0064: 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)
			if (Time.unscaledTime < nextLobbyPollTime)
			{
				return;
			}
			nextLobbyPollTime = Time.unscaledTime + 0.5f;
			Lobby lobby = default(Lobby);
			if (!BNetworkManager.TryGetSteamLobby(ref lobby))
			{
				if (!NetworkServer.active && !NetworkClient.active)
				{
					allLobbyMembersCompatible = true;
					incompatibleLobbyMembers = string.Empty;
				}
				return;
			}
			PublishLocalMemberVersion(lobby);
			PollActiveState(lobby);
			PollProGolfAnnouncement(lobby);
			PollProGolfHoleStats(lobby);
			if (NetworkServer.active)
			{
				UpdateLobbyCompatibility(lobby);
				PublishActiveState(lobby, IsActiveProGolf());
			}
		}

		private static void PollProGolfHoleStats(Lobby lobby)
		{
			string data = ((Lobby)(ref lobby)).GetData("codex_progolfplus_hole_stats_version");
			if (!string.IsNullOrEmpty(data) && !(data == lastObservedHoleStatsVersion))
			{
				lastObservedHoleStatsVersion = data;
				ApplyHoleStatsPayload(((Lobby)(ref lobby)).GetData("codex_progolfplus_hole_stats_payload"));
				MarkScoreboardsDirty();
			}
		}

		private static void PublishActiveState(Lobby lobby, bool active)
		{
			if (active != lastPublishedActiveState || string.IsNullOrEmpty(((Lobby)(ref lobby)).GetData("codex_progolfplus_active")))
			{
				lastPublishedActiveState = active;
				((Lobby)(ref lobby)).SetData("codex_progolfplus_active", active ? "1" : "0");
				((Lobby)(ref lobby)).SetData("codex_progolfplus_active_version", Time.unscaledTime.ToString("R"));
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)$"Published Pro Golf Plus active lobby state: {active}.");
				}
			}
		}

		private static void PollActiveState(Lobby lobby)
		{
			string data = ((Lobby)(ref lobby)).GetData("codex_progolfplus_active_version");
			if (!string.IsNullOrEmpty(data) && !(data == lastObservedActiveVersion))
			{
				bool flag = ((Lobby)(ref lobby)).GetData("codex_progolfplus_active") == "1";
				lastObservedActiveVersion = data;
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)$"Observed Pro Golf Plus active lobby state: {flag}.");
				}
			}
		}

		private static void PollProGolfAnnouncement(Lobby lobby)
		{
			string data = ((Lobby)(ref lobby)).GetData("codex_progolfplus_announcement_version");
			if (!string.IsNullOrEmpty(data) && !(data == lastObservedAnnouncementVersion))
			{
				lastObservedAnnouncementVersion = data;
				string data2 = ((Lobby)(ref lobby)).GetData("codex_progolfplus_announcement_text");
				if (!string.IsNullOrEmpty(data2))
				{
					ShowTopAnnouncement(data2);
				}
			}
		}

		private static void PublishLocalMemberVersion(Lobby lobby)
		{
			if (SteamClient.IsValid)
			{
				((Lobby)(ref lobby)).SetMemberData("codex_progolfplus_member_version", "0.1.23");
			}
		}

		private static void UpdateLobbyCompatibility(Lobby lobby)
		{
			//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_0030: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			((Lobby)(ref lobby)).SetData("codex_progolfplus_required_version", "0.1.23");
			List<string> list = new List<string>();
			foreach (Friend member in ((Lobby)(ref lobby)).Members)
			{
				Friend current = member;
				string memberData = ((Lobby)(ref lobby)).GetMemberData(current, "codex_progolfplus_member_version");
				if (!string.Equals(memberData, "0.1.23", StringComparison.Ordinal))
				{
					string? text;
					if (!string.IsNullOrEmpty(((Friend)(ref current)).Name))
					{
						text = ((Friend)(ref current)).Name;
					}
					else
					{
						SteamId id = current.Id;
						text = ((object)(SteamId)(ref id)).ToString();
					}
					string text2 = text;
					list.Add(string.IsNullOrEmpty(memberData) ? (text2 + " (missing Pro Golf Plus 0.1.23)") : (text2 + " (Pro Golf Plus " + memberData + ", needs 0.1.23)"));
				}
			}
			allLobbyMembersCompatible = list.Count == 0;
			incompatibleLobbyMembers = string.Join(", ", list);
			if (!allLobbyMembersCompatible && Time.unscaledTime >= nextCompatibilityWarningTime)
			{
				nextCompatibilityWarningTime = Time.unscaledTime + 10f;
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogWarning((object)("Pro Golf Plus disabled until every lobby member is running Pro Golf Plus 0.1.23: " + incompatibleLobbyMembers));
				}
			}
		}

		private static MatchSetupRules FindMatchSetupRules()
		{
			if (SingletonNetworkBehaviour<MatchSetupRules>.HasInstance)
			{
				return SingletonNetworkBehaviour<MatchSetupRules>.Instance;
			}
			if (SingletonBehaviour<MatchSetupRules>.HasInstance)
			{
				return SingletonBehaviour<MatchSetupRules>.Instance;
			}
			return Object.FindFirstObjectByType<MatchSetupRules>((FindObjectsInactive)1);
		}

		private void TryEnsureAllPlayersHaveProGolfLoadout()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			PlayerInventory[] array = Object.FindObjectsByType<PlayerInventory>((FindObjectsSortMode)0);
			foreach (PlayerInventory val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					num++;
					if (EnsureProGolfLoadout(val))
					{
						num2++;
					}
				}
			}
			if (num2 > 0)
			{
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)$"Ensured Pro Golf loadout for {num2}/{num} player inventories.");
				}
			}
		}

		private static void TrySuppressAllItemSpawners()
		{
			if (!IsActiveProGolf())
			{
				return;
			}
			ItemSpawner[] array = Object.FindObjectsByType<ItemSpawner>((FindObjectsSortMode)0);
			foreach (ItemSpawner val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					SuppressItemSpawner(val);
				}
			}
		}

		private static void SuppressItemSpawner(ItemSpawner spawner)
		{
			if (!((Object)(object)spawner == (Object)null))
			{
				if (NetworkServer.active)
				{
					spawner.NetworkhasItemBox = false;
					spawner.NetworkvisualsFill = 0f;
				}
				object? obj = itemSpawnerPickupColliderField?.GetValue(spawner);
				Collider val = (Collider)((obj is Collider) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					val.enabled = false;
				}
				object obj2 = itemSpawnerVisualsField?.GetValue(spawner);
				object? obj3 = itemSpawnerVisualsFillingObjectField?.GetValue(obj2);
				SetSpawnerVisualObjectActive((GameObject)((obj3 is GameObject) ? obj3 : null), active: false);
				object? obj4 = itemSpawnerVisualsIdleObjectField?.GetValue(obj2);
				SetSpawnerVisualObjectActive((GameObject)((obj4 is GameObject) ? obj4 : null), active: false);
				object? obj5 = itemSpawnerVisualsFillRendererField?.GetValue(obj2);
				MeshRenderer val2 = (MeshRenderer)((obj5 is MeshRenderer) ? obj5 : null);
				if ((Object)(object)val2 != (Object)null)
				{
					((Renderer)val2).enabled = false;
				}
				object? obj6 = itemSpawnerVisualsAnimatorField?.GetValue(obj2);
				Behaviour val3 = (Behaviour)((obj6 is Behaviour) ? obj6 : null);
				if ((Object)(object)val3 != (Object)null)
				{
					val3.enabled = false;
				}
				Renderer[] componentsInChildren = ((Component)spawner).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = false;
				}
			}
		}

		private static void SetSpawnerVisualObjectActive(GameObject gameObject, bool active)
		{
			if ((Object)(object)gameObject != (Object)null && gameObject.activeSelf != active)
			{
				gameObject.SetActive(active);
			}
		}

		private static void ShowTopAnnouncement(string text)
		{
			SplitAnnouncementText(text, out topAnnouncementText, out topAnnouncementDetailText);
			topAnnouncementVisibleUntil = Time.unscaledTime + (text.StartsWith("Hole Stats:", StringComparison.Ordinal) ? 8f : 6f);
		}

		private static void DrawTopAnnouncement()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(topAnnouncementText) && !(Time.unscaledTime >= topAnnouncementVisibleUntil))
			{
				EnsureTopAnnouncementStyles();
				float num = Mathf.Clamp((float)Screen.width * 0.78f, 620f, 1060f);
				int num2 = ((!string.IsNullOrEmpty(topAnnouncementDetailText)) ? topAnnouncementDetailText.Split(new char[1] { '\n' }).Length : 0);
				float num3 = (string.IsNullOrEmpty(topAnnouncementDetailText) ? 104f : (100f + Mathf.Max(42f, (float)num2 * 34f)));
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, Mathf.Max(64f, (float)Screen.height * 0.28f), num, num3);
				GUI.Box(val, GUIContent.none, topAnnouncementBoxStyle);
				GUI.Label(new Rect(((Rect)(ref val)).x + 26f, ((Rect)(ref val)).y + 20f, ((Rect)(ref val)).width - 52f, 64f), topAnnouncementText, topAnnouncementTextStyle);
				if (!string.IsNullOrEmpty(topAnnouncementDetailText))
				{
					GUI.Label(new Rect(((Rect)(ref val)).x + 26f, ((Rect)(ref val)).y + 82f, ((Rect)(ref val)).width - 52f, ((Rect)(ref val)).height - 92f), topAnnouncementDetailText, topAnnouncementDetailStyle);
				}
			}
		}

		private static void EnsureTopAnnouncementStyles()
		{
			//IL_001c: 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_004e: 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_0063: 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: Expected O, but got Unknown
			//IL_0076: 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_0089: Expected O, but got Unknown
			//IL_008e: Expected O, but got Unknown
			//IL_0098: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//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)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			if (topAnnouncementBoxStyle == null)
			{
				topAnnouncementBoxTexture = CreateStripedGuiTexture(new Color(0.05f, 0.16f, 0.27f, 0.82f), new Color(0.12f, 0.3f, 0.47f, 0.82f));
				GUIStyle val = new GUIStyle(GUI.skin.box);
				val.normal.background = topAnnouncementBoxTexture;
				val.border = new RectOffset(14, 14, 14, 14);
				val.padding = new RectOffset(22, 22, 18, 18);
				topAnnouncementBoxStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 46,
					fontStyle = (FontStyle)1
				};
				val2.normal.textColor = Color.white;
				val2.wordWrap = false;
				val2.clipping = (TextClipping)1;
				topAnnouncementTextStyle = val2;
				GUIStyle val3 = new GUIStyle(topAnnouncementTextStyle)
				{
					fontSize = 34,
					wordWrap = true
				};
				val3.normal.textColor = new Color(0.82f, 0.86f, 0.9f, 1f);
				topAnnouncementDetailStyle = val3;
			}
		}

		private static void SplitAnnouncementText(string text, out string title, out string detail)
		{
			title = text;
			detail = string.Empty;
			int num = text.IndexOf(':');
			if (num >= 0 && num < text.Length - 1)
			{
				title = text.Substring(0, num + 1).Trim();
				detail = text.Substring(num + 1).Trim();
			}
		}

		private static Texture2D CreateGuiTexture(Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, color);
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private static Texture2D CreateStripedGuiTexture(Color baseColor, Color stripeColor)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64);
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					bool flag = (j + i) / 8 % 2 == 0;
					val.SetPixel(j, i, flag ? stripeColor : baseColor);
				}
			}
			((Texture)val).wrapMode = (TextureWrapMode)0;
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private static void DestroyTopAnnouncementStyles()
		{
			if ((Object)(object)topAnnouncementBoxTexture != (Object)null)
			{
				Object.Destroy((Object)(object)topAnnouncementBoxTexture);
				topAnnouncementBoxTexture = null;
			}
			topAnnouncementBoxStyle = null;
			topAnnouncementTextStyle = null;
			topAnnouncementDetailStyle = null;
		}

		private static void TrySuppressCheckpoints()
		{
			if (IsActiveProGolf())
			{
				Checkpoint[] array = Object.FindObjectsByType<Checkpoint>((FindObjectsSortMode)0);
				for (int i = 0; i < array.Length; i++)
				{
					SuppressCheckpointVisuals(array[i]);
				}
			}
		}

		private static void SuppressCheckpointVisuals(Checkpoint checkpoint)
		{
			if ((Object)(object)checkpoint == (Object)null)
			{
				return;
			}
			object? obj = checkpointBaseMeshField?.GetValue(checkpoint);
			MeshRenderer val = (MeshRenderer)((obj is MeshRenderer) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				((Renderer)val).enabled = false;
			}
			object? obj2 = checkpointScreenMeshField?.GetValue(checkpoint);
			MeshRenderer val2 = (MeshRenderer)((obj2 is MeshRenderer) ? obj2 : null);
			if ((Object)(object)val2 != (Object)null)
			{
				((Renderer)val2).enabled = false;
			}
			object? obj3 = checkpointAnimatorField?.GetValue(checkpoint);
			Behaviour val3 = (Behaviour)((obj3 is Behaviour) ? obj3 : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.enabled = false;
			}
			object? obj4 = checkpointVisualCenterField?.GetValue(checkpoint);
			Transform val4 = (Transform)((obj4 is Transform) ? obj4 : null);
			if ((Object)(object)val4 != (Object)null)
			{
				Renderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = false;
				}
				Collider[] componentsInChildren2 = ((Component)val4).GetComponentsInChildren<Collider>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].enabled = false;
				}
			}
			else
			{
				Renderer[] componentsInChildren = ((Component)checkpoint).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = false;
				}
			}
		}

		private static SyncList<InventorySlot> GetSlots(PlayerInventory inventory)
		{
			return inventorySlotsField?.GetValue(inventory) as SyncList<InventorySlot>;
		}

		private static void EnsureSlotCount(PlayerInventory inventory)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			SyncList<InventorySlot> slots = GetSlots(inventory);
			if (slots != null)
			{
				while (slots.Count < 3)
				{
					slots.Add(InventorySlot.Empty);
				}
				while (slots.Count > 3)
				{
					slots.RemoveAt(slots.Count - 1);
				}
			}
		}

		private static bool IsCart(InventorySlot slot)
		{
			//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_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((int)slot.itemType == 6)
			{
				return slot.remainingUses > 0;
			}
			return false;
		}

		private static bool IsCoffee(InventorySlot slot)
		{
			//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_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((int)slot.itemType == 1)
			{
				return slot.remainingUses > 0;
			}
			return false;
		}

		private static bool IsSpringBoots(InventorySlot slot)
		{
			//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_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((int)slot.itemType == 5)
			{
				return slot.remainingUses > 0;
			}
			return false;
		}

		private static bool IsPistol(InventorySlot slot)
		{
			//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_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((int)slot.itemType == 2)
			{
				return slot.remainingUses > 0;
			}
			return false;
		}

		private static bool IsEmpty(InventorySlot slot)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			if ((int)slot.itemType != 0)
			{
				return slot.remainingUses <= 0;
			}
			return true;
		}

		private static bool IsReservedPermanentSlot(PlayerInventory inventory, int index)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActiveProGolf() || !TryGetSlot(inventory, index, out var slot))
			{
				return false;
			}
			if ((index != 0 || !IsCart(slot)) && (index != 1 || !IsCoffee(slot)))
			{
				if (index == 2)
				{
					return IsSpringBoots(slot);
				}
				return false;
			}
			return true;
		}

		private static bool TryGetSlot(PlayerInventory inventory, int index, out InventorySlot slot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			slot = InventorySlot.Empty;
			SyncList<InventorySlot> slots = GetSlots(inventory);
			if (slots == null || index < 0 || index >= slots.Count)
			{
				return false;
			}
			slot = slots[index];
			return true;
		}

		private static bool EnsureProGolfLoadout(PlayerInventory inventory)
		{
			if (!IsActiveProGolf() || !NetworkServer.active)
			{
				return false;
			}
			SyncList<InventorySlot> slots = GetSlots(inventory);
			if (slots == null)
			{
				return false;
			}
			EnsureSlotCount(inventory);
			return false | SetSlotIfDifferent(slots, 0, (ItemType)6) | SetSlotIfDifferent(slots, 1, (ItemType)1) | SetSlotIfDifferent(slots, 2, (ItemType)5) | ClearNonPermanentItems(slots);
		}

		private static bool SetSlotIfDifferent(SyncList<InventorySlot> slots, int index, ItemType itemType)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			InventorySlot val = slots[index];
			if (val.itemType == itemType && val.remainingUses > 0)
			{
				return false;
			}
			slots[index] = new InventorySlot(itemType, 1);
			return true;
		}

		private static bool ClearNonPermanentItems(SyncList<InventorySlot> slots)
		{
			//IL_0010: 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)
			bool result = false;
			for (int i = 0; i < slots.Count; i++)
			{
				if (!IsPermanentLoadoutSlot(i) && !IsEmpty(slots[i]))
				{
					slots[i] = InventorySlot.Empty;
					result = true;
				}
			}
			return result;
		}

		private static bool IsPermanentLoadoutSlot(int index)
		{
			if (index != 0 && index != 1)
			{
				return index == 2;
			}
			return true;
		}

		private static bool IsBlockedProGolfPickupItem(ItemType itemType)
		{
			//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_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000c: 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_0012: Invalid comparison between Unknown and I4
			if ((int)itemType != 6 && (int)itemType != 1 && (int)itemType != 5 && (int)itemType != 2)
			{
				return (int)itemType == 0;
			}
			return true;
		}

		private static void MarkBallRespawnForHazardElimination(PlayerGolfer golfer, EliminationReason immediateEliminationReason)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (IsActiveProGolf() && !((Object)(object)golfer == (Object)null) && IsHazardElimination(immediateEliminationReason))
			{
				PlayerInfo playerInfo = golfer.PlayerInfo;
				PlayerMovement val = ((playerInfo != null) ? playerInfo.Movement : null);
				GolfBall ownBall = golfer.OwnBall;
				if (!((Object)(object)val == (Object)null) && !((Object)(object)ownBall == (Object)null))
				{
					forceNextRespawnAtBall.Add(val);
				}
			}
		}

		private static bool IsHazardElimination(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_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if ((int)reason != 5 && (int)reason != 6)
			{
				return (int)reason == 23;
			}
			return true;
		}

		private static void RedirectHazardRespawnToBall(PlayerMovement movement, ref RespawnTarget respawnTarget)
		{
			if (IsActiveProGolf() && !((Object)(object)movement == (Object)null) && (int)respawnTarget == 0 && forceNextRespawnAtBall.Remove(movement))
			{
				respawnTarget = (RespawnTarget)1;
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)"Redirected Pro Golf Plus hazard respawn to player's ball.");
				}
			}
		}

		private static bool AllActivePlayersResolved(CourseManager courseManager)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0033: 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_003b: Invalid comparison between Unknown and I4
			//IL_0041: 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)
			SyncList<PlayerState> playerStates = CourseManager.PlayerStates;
			if (playerStates == null)
			{
				return false;
			}
			int num = 0;
			int num2 = 0;
			Enumerator<PlayerState> enumerator = playerStates.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					PlayerState current = enumerator.Current;
					if (current.isConnected && !current.isSpectator && (int)current.matchResolution != -1)
					{
						num++;
						if ((int)current.matchResolution != 0)
						{
							num2++;
						}
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			if (num > 0)
			{
				return num == num2;
			}
			return false;
		}

		private static bool TryCompareProGolfPlayerStates(PlayerState self, PlayerState other, ref int result)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if (!IsProGolfScoringActive())
			{
				return false;
			}
			if (self.courseStrokes != other.courseStrokes)
			{
				result = self.courseStrokes.CompareTo(other.courseStrokes);
				return true;
			}
			if (self.courseScore != other.courseScore)
			{
				result = other.courseScore.CompareTo(self.courseScore);
				return true;
			}
			if (self.wins != other.wins)
			{
				result = other.wins.CompareTo(self.wins);
				return true;
			}
			if (self.finishes != other.finishes)
			{
				result = other.finishes.CompareTo(self.finishes);
				return true;
			}
			if (self.courseKnockouts != other.courseKnockouts)
			{
				result = other.courseKnockouts.CompareTo(self.courseKnockouts);
				return true;
			}
			if (self.losses != other.losses)
			{
				result = self.losses.CompareTo(other.losses);
				return true;
			}
			if (!self.scoreTimestamp.Equals(other.scoreTimestamp))
			{
				result = self.scoreTimestamp.CompareTo(other.scoreTimestamp);
				return true;
			}
			result = self.joinIndex.CompareTo(other.joinIndex);
			return true;
		}

		private static bool TryGetWeightedRandomAllowedPickupItem(ItemPool pool, out ItemType item)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected I4, but got Unknown
			item = (ItemType)0;
			if (!(itemPoolSpawnChancesField?.GetValue(pool) is Array array) || array.Length == 0)
			{
				return false;
			}
			float num = 0f;
			foreach (object item2 in array)
			{
				ItemType itemType = (ItemType)AccessTools.Field(item2.GetType(), "item").GetValue(item2);
				float num2 = (float)AccessTools.Field(item2.GetType(), "spawnChanceWeight").GetValue(item2);
				if (!IsBlockedProGolfPickupItem(itemType) && num2 > 0f)
				{
					num += num2;
				}
			}
			if (num <= 0f)
			{
				item = (ItemType)3;
				return true;
			}
			float num3 = Random.value * num;
			foreach (object item3 in array)
			{
				ItemType val = (ItemType)AccessTools.Field(item3.GetType(), "item").GetValue(item3);
				float num4 = (float)AccessTools.Field(item3.GetType(), "spawnChanceWeight").GetValue(item3);
				if (!IsBlockedProGolfPickupItem(val) && !(num4 <= 0f))
				{
					num3 -= num4;
					if (num3 <= 0f)
					{
						item = (ItemType)(int)val;
						return true;
					}
				}
			}
			item = (ItemType)3;
			return true;
		}

		private static void BeginDriveTracking(GolfBall ball)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active && IsActiveProGolf() && !((Object)(object)ball == (Object)null) && !((Object)(object)ball.Owner == (Object)null) && !((Object)(object)ball.Owner.PlayerInfo == (Object)null) && !((Object)(object)ball.Owner.PlayerInfo.PlayerId == (Object)null))
			{
				ResetLongestDriveIfHoleChanged();
				ulong guid = ball.Owner.PlayerInfo.PlayerId.Guid;
				if (!firstDriveResults.ContainsKey(guid) && !HasActiveDriveForPlayer(guid))
				{
					activeDrives[ball] = new DriveCandidate
					{
						Player = ball.Owner.PlayerInfo,
						PlayerGuid = guid,
						StartPosition = ((Component)ball).transform.position
					};
				}
			}
		}

		private static void TryCompleteDriveTracking(GolfBall ball)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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)
			if (NetworkServer.active && IsActiveProGolf() && !((Object)(object)ball == (Object)null) && ball.IsStationary && activeDrives.TryGetValue(ball, out var value))
			{
				activeDrives.Remove(ball);
				if (!((Object)(object)value.Player == (Object)null) && !((Object)(object)value.Player.PlayerId == (Object)null) && !firstDriveResults.ContainsKey(value.PlayerGuid))
				{
					Vector3 val = ((Component)ball).transform.position - value.StartPosition;
					val.y = 0f;
					float magnitude = ((Vector3)(ref val)).magnitude;
					float num = Mathf.Max(0f, instance?.longestDriveMinimumMetersConfig.Value ?? 0f);
					firstDriveResults[value.PlayerGuid] = new FirstDriveResult
					{
						PlayerName = GetPlayerName(value.Player, value.PlayerGuid),
						Distance = magnitude,
						IsValid = (magnitude >= num)
					};
					TryAnnounceLongestDriveIfReady();
				}
			}
		}

		private static void CaptureClosestToPinOnFirstGreen(PlayerGolfer player)
		{
			if (!NetworkServer.active || !IsActiveProGolf())
			{
				return;
			}
			object obj;
			if (player == null)
			{
				obj = null;
			}
			else
			{
				PlayerInfo playerInfo = player.PlayerInfo;
				obj = ((playerInfo != null) ? playerInfo.PlayerId : null);
			}
			if ((Object)obj == (Object)null)
			{
				return;
			}
			ResetLongestDriveIfHoleChanged();
			ulong guid = player.PlayerInfo.PlayerId.Guid;
			if (!closestToPinResults.ContainsKey(guid) && TryGetDistanceToPinOnGreen(player.OwnBall, out var distanceToPin))
			{
				closestToPinResults[guid] = new ClosestToPinResult
				{
					PlayerName = GetPlayerName(player.PlayerInfo, guid),
					Distance = distanceToPin
				};
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)("Captured Closest to Pin first green distance: " + GetPlayerName(player.PlayerInfo, guid) + " " + FormatDistance(distanceToPin) + "."));
				}
				TryAnnounceClosestToPinIfReady();
			}
		}

		private static void TrackPerfectShot(PlayerGolfer player)
		{
			if (!NetworkServer.active || !IsActiveProGolf())
			{
				return;
			}
			object obj;
			if (player == null)
			{
				obj = null;
			}
			else
			{
				PlayerInfo playerInfo = player.PlayerInfo;
				obj = ((playerInfo != null) ? playerInfo.PlayerId : null);
			}
			if ((Object)obj == (Object)null)
			{
				return;
			}
			ResetLongestDriveIfHoleChanged();
			float swingNormalizedCharge = player.SwingNormalizedCharge;
			if (!(swingNormalizedCharge <= 0.99f) && !(swingNormalizedCharge > 1f))
			{
				ulong guid = player.PlayerInfo.PlayerId.Guid;
				perfectShotCounts.TryGetValue(guid, out var value);
				perfectShotCounts[guid] = value + 1;
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)$"Tracked Pro Golf perfect shot: {GetPlayerName(player.PlayerInfo, guid)} ({value + 1}).");
				}
			}
		}

		private static void PollCartFlipStats()
		{
			if (!NetworkServer.active || !IsActiveProGolf())
			{
				cartFlipStates.Clear();
			}
			else
			{
				if (Time.unscaledTime < nextCartFlipPollTime)
				{
					return;
				}
				nextCartFlipPollTime = Time.unscaledTime + 0.15f;
				ResetLongestDriveIfHoleChanged();
				HashSet<GolfCartMovement> hashSet = new HashSet<GolfCartMovement>();
				GolfCartMovement[] array = Object.FindObjectsByType<GolfCartMovement>((FindObjectsSortMode)0);
				foreach (GolfCartMovement val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						hashSet.Add(val);
						if (!cartFlipStates.TryGetValue(val, out var value))
						{
							value = new CartFlipState
							{
								Wheels = ((Component)val).GetComponentsInChildren<WheelCollider>(true)
							};
							cartFlipStates[val] = value;
						}
						UpdateCartFlipState(val, value);
					}
				}
				List<GolfCartMovement> list = new List<GolfCartMovement>();
				foreach (GolfCartMovement key in cartFlipStates.Keys)
				{
					if ((Object)(object)key == (Object)null || !hashSet.Contains(key))
					{
						list.Add(key);
					}
				}
				foreach (GolfCartMovement item in list)
				{
					cartFlipStates.Remove(item);
				}
			}
		}

		private static void UpdateCartFlipState(GolfCartMovement cart, CartFlipState state)
		{
			//IL_0006: 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)
			float num = Vector3.Dot(((Component)cart).transform.up, Vector3.up);
			bool flag = AreAllCartWheelsGrounded(cart, state);
			bool flag2 = IsCartMoving(cart);
			float cartTumbleAngularSpeed = GetCartTumbleAngularSpeed(cart);
			float unscaledTime = Time.unscaledTime;
			if (!state.FlipInProgress)
			{
				if (num >= 0.65f)
				{
					state.WasUprightOnWheels = true;
				}
				bool flag3 = !flag || num < 0.65f;
				if (!state.WasUprightOnWheels || !flag3 || !flag2 || cartTumbleAngularSpeed < 1f)
				{
					return;
				}
				state.FlipInProgress = true;
				state.CurrentFlipStreak = 0;
				state.AccumulatedFlipRadians = 0f;
				state.LastFlipPollTime = unscaledTime;
				state.SettledSince = -1f;
				CaptureCartResponsiblePlayer(cart, state);
			}
			CaptureCartResponsiblePlayer(cart, state);
			AccumulateCartFlipRotation(state, cartTumbleAngularSpeed, unscaledTime);
			if (flag && num >= 0.65f)
			{
				CreditCartFlipStreak(state);
				ResetCartFlipSession(state, keepUprightReady: true);
			}
			else if (flag2)
			{
				state.SettledSince = -1f;
			}
			else if (state.SettledSince < 0f)
			{
				state.SettledSince = Time.unscaledTime;
			}
			else if (!(Time.unscaledTime - state.SettledSince < 0.5f))
			{
				CreditCartFlipStreak(state);
				ResetCartFlipSession(state, keepUprightReady: false);
			}
		}

		private static void ResetCartFlipSession(CartFlipState state, bool keepUprightReady)
		{
			state.FlipInProgress = false;
			state.WasUprightOnWheels = keepUprightReady;
			state.CurrentFlipStreak = 0;
			state.AccumulatedFlipRadians = 0f;
			state.LastFlipPollTime = -1f;
			state.SettledSince = -1f;
			state.ResponsiblePlayerGuid = 0uL;
			state.ResponsiblePlayerName = null;
		}

		private static void AccumulateCartFlipRotation(CartFlipState state, float tumbleAngularSpeed, float now)
		{
			if (state.LastFlipPollTime < 0f)
			{
				state.LastFlipPollTime = now;
				return;
			}
			float num = Mathf.Clamp(now - state.LastFlipPollTime, 0f, 0.5f);
			state.LastFlipPollTime = now;
			if (!(num <= 0f))
			{
				state.AccumulatedFlipRadians += tumbleAngularSpeed * num;
				state.CurrentFlipStreak = Mathf.FloorToInt(state.AccumulatedFlipRadians / ((float)Math.PI * 2f));
			}
		}

		private static bool AreAllCartWheelsGrounded(GolfCartMovement cart, CartFlipState state)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			WheelCollider[] array = state.Wheels;
			if (array == null || array.Length < 4)
			{
				array = ((Component)cart).GetComponentsInChildren<WheelCollider>(true);
				state.Wheels = array ?? Array.Empty<WheelCollider>();
			}
			if (array != null && array.Length >= 4)
			{
				int num = 0;
				WheelCollider[] array2 = array;
				foreach (WheelCollider val in array2)
				{
					if ((Object)(object)val != (Object)null && val.isGrounded)
					{
						num++;
					}
				}
				return num >= 4;
			}
			return Vector3.Dot(((Component)cart).transform.up, Vector3.up) >= 0.65f;
		}

		private static bool IsCartMoving(GolfCartMovement cart)
		{
			//IL_0013: 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_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)
			Rigidbody component = ((Component)cart).GetComponent<Rigidbody>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			Vector3 val = component.linearVelocity;
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.122499995f))
			{
				val = component.angularVelocity;
				return ((Vector3)(ref val)).sqrMagnitude > 0.122499995f;
			}
			return true;
		}

		private static float GetCartTumbleAngularSpeed(GolfCartMovement cart)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//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)
			Rigidbody component = ((Component)cart).GetComponent<Rigidbody>();
			if ((Object)(object)component == (Object)null)
			{
				return 0f;
			}
			Vector3 val = Vector3.ProjectOnPlane(component.angularVelocity, Vector3.up);
			return ((Vector3)(ref val)).magnitude;
		}

		private static void CaptureCartResponsiblePlayer(GolfCartMovement cart, CartFlipState state)
		{
			if (TryGetCartResponsiblePlayer(cart, out var player) && !((Object)(object)((player != null) ? player.PlayerId : null) == (Object)null))
			{
				state.ResponsiblePlayerGuid = player.PlayerId.Guid;
				state.ResponsiblePlayerName = GetPlayerName(player, state.ResponsiblePlayerGuid);
			}
		}

		private static bool TryGetCartResponsiblePlayer(GolfCartMovement cart, out PlayerInfo player)
		{
			player = null;
			GolfCartInfo val = ((cart != null) ? cart.GolfCartInfo : null);
			if ((Object)(object)val == (Object)null && (Object)(object)cart != (Object)null)
			{
				val = ((Component)cart).GetComponent<GolfCartInfo>() ?? ((Component)cart).GetComponentInParent<GolfCartInfo>();
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			try
			{
				if (val.TryGetDriver(ref player) && (Object)(object)player != (Object)null)
				{
					return true;
				}
			}
			catch (Exception ex)
			{
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogDebug((object)("Could not read golf cart driver for flip stats: " + ex.Message));
				}
			}
			player = val.ResponsiblePlayer;
			return (Object)(object)player != (Object)null;
		}

		private static void CreditCartFlipStreak(CartFlipState state)
		{
			if (state.ResponsiblePlayerGuid == 0L || state.CurrentFlipStreak <= 0)
			{
				return;
			}
			cartBestFlipStreaks.TryGetValue(state.ResponsiblePlayerGuid, out var value);
			if (state.CurrentFlipStreak > value)
			{
				cartBestFlipStreaks[state.ResponsiblePlayerGuid] = state.CurrentFlipStreak;
				string arg = (string.IsNullOrEmpty(state.ResponsiblePlayerName) ? GetPlayerName(null, state.ResponsiblePlayerGuid) : state.ResponsiblePlayerName);
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)$"Tracked Pro Golf best cart flip streak: {arg} ({state.CurrentFlipStreak}).");
				}
			}
		}

		private static bool TryGetDistanceToPinOnGreen(GolfBall ball, out float distanceToPin)
		{
			//IL_0026: 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_0045: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			distanceToPin = 0f;
			GolfHole val = FindMainHole();
			if ((Object)(object)val == (Object)null || (Object)(object)ball == (Object)null || !val.IsPointInGreenTrigger(((Component)ball).transform.position))
			{
				return false;
			}
			Vector3 val2 = ((Component)ball).transform.position - ((Component)val).transform.position;
			val2.y = 0f;
			distanceToPin = ((Vector3)(ref val2)).magnitude;
			return true;
		}

		private static GolfHole FindMainHole()
		{
			if ((Object)(object)GolfHoleManager.MainHole != (Object)null)
			{
				return GolfHoleManager.MainHole;
			}
			GolfHole[] array = Object.FindObjectsByType<GolfHole>((FindObjectsSortMode)0);
			GolfHole[] array2 = array;
			foreach (GolfHole val in array2)
			{
				if ((Object)(object)val != (Object)null && val.IsMainHole)
				{
					return val;
				}
			}
			if (array.Length == 0)
			{
				return null;
			}
			return array[0];
		}

		private static bool HasActiveDriveForPlayer(ulong playerGuid)
		{
			foreach (DriveCandidate value in activeDrives.Values)
			{
				if (value.PlayerGuid == playerGuid)
				{
					return true;
				}
			}
			return false;
		}

		private static void InvalidateFirstDrive(PlayerInfo player)
		{
			if (!NetworkServer.active || !IsActiveProGolf() || (Object)(object)((player != null) ? player.PlayerId : null) == (Object)null)
			{
				return;
			}
			ResetLongestDriveIfHoleChanged();
			ulong guid = player.PlayerId.Guid;
			bool flag = false;
			List<GolfBall> list = new List<GolfBall>();
			foreach (KeyValuePair<GolfBall, DriveCandidate> activeDrife in activeDrives)
			{
				if (activeDrife.Value.PlayerGuid == guid)
				{
					list.Add(activeDrife.Key);
					flag = true;
				}
			}
			foreach (GolfBall item in list)
			{
				activeDrives.Remove(item);
			}
			if (!firstDriveResults.ContainsKey(guid) && flag)
			{
				firstDriveResults[guid] = new FirstDriveResult
				{
					PlayerName = GetPlayerName(player, guid),
					Distance = 0f,
					IsValid = false
				};
				TryAnnounceLongestDriveIfReady();
			}
		}

		private static void TryAnnounceLongestDriveIfReady()
		{
			if (longestDriveAnnounced)
			{
				return;
			}
			List<ulong> activePlayerGuids = GetActivePlayerGuids();
			if (activePlayerGuids.Count == 0)
			{
				return;
			}
			foreach (ulong item in activePlayerGuids)
			{
				if (!firstDriveResults.ContainsKey(item))
				{
					return;
				}
			}
			FirstDriveResult firstDriveResult = null;
			foreach (ulong item2 in activePlayerGuids)
			{
				FirstDriveResult firstDriveResult2 = firstDriveResults[item2];
				if (firstDriveResult2.IsValid && (firstDriveResult == null || firstDriveResult2.Distance > firstDriveResult.Distance))
				{
					firstDriveResult = firstDriveResult2;
				}
			}
			longestDriveAnnounced = true;
			if (firstDriveResult != null)
			{
				string text = $"Longest Drive: {firstDriveResult.PlayerName} {Mathf.RoundToInt(firstDriveResult.Distance)}m";
				PublishProGolfAnnouncement(text);
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)text);
				}
			}
		}

		private static void TryAnnounceClosestToPinIfReady()
		{
			if (closestToPinAnnounced || !NetworkServer.active || !IsActiveProGolf())
			{
				return;
			}
			List<ulong> activePlayerGuids = GetActivePlayerGuids();
			if (activePlayerGuids.Count == 0)
			{
				return;
			}
			foreach (ulong item in activePlayerGuids)
			{
				if (!closestToPinResults.ContainsKey(item))
				{
					return;
				}
			}
			ClosestToPinResult closestToPinResult = null;
			foreach (ulong item2 in activePlayerGuids)
			{
				ClosestToPinResult closestToPinResult2 = closestToPinResults[item2];
				if (closestToPinResult == null || closestToPinResult2.Distance < closestToPinResult.Distance)
				{
					closestToPinResult = closestToPinResult2;
				}
			}
			closestToPinAnnounced = true;
			if (closestToPinResult != null)
			{
				string text = "Closest to Pin: " + closestToPinResult.PlayerName + " " + FormatDistance(closestToPinResult.Distance);
				PublishProGolfAnnouncement(text);
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)text);
				}
			}
		}

		private static void TryAnnounceHoleStatsIfReady()
		{
			if (holeStatsAnnounced || !NetworkServer.active || !IsProGolfScoringActive())
			{
				return;
			}
			List<ulong> activePlayerGuids = GetActivePlayerGuids();
			if (activePlayerGuids.Count != 0)
			{
				holeStatsAnnounced = true;
				PublishProGolfHoleStats(activePlayerGuids);
				MarkScoreboardsDirty();
				ProGolfPlugin proGolfPlugin = instance;
				if (proGolfPlugin != null)
				{
					((BaseUnityPlugin)proGolfPlugin).Logger.LogInfo((object)"Published Pro Golf Plus hole stats for scoreboard rows.");
				}
			}
		}

		private static void PublishProGolfHoleStats(List<ulong> activePlayers)
		{
			string text = BuildHoleStatsPayload(activePlayers);
			ApplyHoleStatsPayload(text);
			Lobby val = default(Lobby);
			if (BNetworkManager.TryGetSteamLobby(ref val))
			{
				string text2 = (lastObservedHoleStatsVersion = $"{CourseManager.CurrentHoleGlobalIndex}:{Time.unscaledTime:R}");
				((Lobby)(ref val)).SetData("codex_progolfplus_hole_stats_payload", text);
				((Lobby)(ref val)).SetData("codex_progolfplus_hole_stats_version", text2);
			}
		}

		private static string BuildHoleStatsPayload(List<ulong> activePlayers)
		{
			List<string> list = new List<string>();
			foreach (ulong activePlayer in activePlayers)
			{
				perfectShotCounts.TryGetValue(activePlayer, out var value);
				cartBestFlipStreaks.TryGetValue(activePlayer, out var value2);
				list.Add($"{activePlayer},{value},{value2}");
			}
			return string.Join(";", list);
		}

		private static void ApplyHoleStatsPayload(string payload)
		{
			if (string.IsNullOrEmpty(payload))
			{
				return;
			}
			string[] array = payload.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ',' });
				if (array2.Length == 3 && ulong.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && int.TryParse(array2[2], out var result3))
				{
					perfectShotCounts[result] = result2;
					cartBestFlipStreaks[result] = result3;
				}
			}
		}

		private static void MarkScoreboardsDirty()
		{
			Scoreboard[] array = Object.FindObjectsByType<Scoreboard>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (Scoreboard val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					scoreboardMarkDirtyMethod?.Invoke(val, null);
				}
			}
		}

		private static string FormatDistance(float meters)
		{
			if (meters < 10f)
			{
				return $"{meters:0.0}m";
			}
			return $"{Mathf.RoundToInt(meters)}m";
		}

		private static List<ulong> GetActivePlayerGuids()
		{
			//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_001c: 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_0022: 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_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)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			List<ulong> list = new List<ulong>();
			SyncList<PlayerState> playerStates = CourseManager.PlayerStates;
			if (playerStates == null)
			{
				return list;
			}
			Enumerator<PlayerState> enumerator = playerStates.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					PlayerState current = enumerator.Current;
					if (current.isConnected && !current.isSpectator && (int)current.matchResolution != -1)
					{
						list.Add(current.playerGuid);
					}
				}
				return list;
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
		}

		private static void UpdateScoreboardEntryProGolfStats(ScoreboardEntry entry, PlayerState playerState)
		{
			//IL_0022: 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_0044: 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)
			if ((Object)(object)entry == (Object)null)
			{
				return;
			}
			TextMeshProUGUI orCreateScoreboardEntryStatsLabel = GetOrCreateScoreboardEntryStatsLabel(entry);
			if (!((Object)(object)orCreateScoreboardEntryStatsLabel == (Object)null))
			{
				if (!IsProGolfScoringActive() || playerState.isSpectator || playerState.playerGuid == 0L)
				{
					((Component)orCreateScoreboardEntryStatsLabel).gameObject.SetActive(false);
					return;
				}
				perfectShotCounts.TryGetValue(playerState.playerGuid, out var value);
				cartBestFlipStreaks.TryGetValue(playerState.playerGuid, out var value2);
				((TMP_Text)orCreateScoreboardEntryStatsLabel).text = $"Perfect {value}  |  Flip Streak {value2}";
				((Component)orCreateScoreboardEntryStatsLabel).gameObject.SetActive(true);
			}
		}

		private static TextMeshProUGUI GetOrCreateScoreboardEntryStatsLabel(ScoreboardEntry entry)
		{
			//IL_004f: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			if (scoreboardEntryStatLabels.TryGetValue(entry, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			object? obj = scoreboardEntryStatsBackgroundField?.GetValue(entry);
			Image val = (Image)((obj is Image) ? obj : null);
			Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : ((Component)entry).transform);
			GameObject val3 = new GameObject("ProGolfPlusStats");
			val3.transform.SetParent(val2, false);
			RectTransform obj2 = val3.AddComponent<RectTransform>();
			obj2.anchorMin = new Vector2(0.04f, 0.02f);
			obj2.anchorMax = new Vector2(0.96f, 0.34f);
			obj2.offsetMin = Vector2.zero;
			obj2.offsetMax = Vector2.zero;
			TextMeshProUGUI val4 = val3.AddComponent<TextMeshProUGUI>();
			object? obj3 = scoreboardEntryNameField?.GetValue(entry);
			TextMeshProUGUI val5 = (TextMeshProUGUI)((obj3 is TextMeshProUGUI) ? obj3 : null);
			if ((Object)(object)val5 != (Object)null)
			{
				((TMP_Text)val4).font = ((TMP_Text)val5).font;
				((TMP_Text)val4).fontSharedMaterial = ((TMP_Text)val5).fontSharedMaterial;
			}
			((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val4).enableAutoSizing = true;
			((TMP_Text)val4).fontSizeMin = 10f;
			((TMP_Text)val4).fontSizeMax = 17f;
			((Graphic)val4).color = new Color(0.82f, 0.88f, 1f, 1f);
			((Graphic)val4).raycastTarget = false;
			((TMP_Text)val4).text = string.Empty;
			scoreboardEntryStatLabels[entry] = val4;
			return val4;
		}

		private static void UpdateScoreboardProGolfStatCard(Scoreboard scoreboard)
		{
			//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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)scoreboard == (Object)null) && IsProGolfScoringActive())
			{
				PlayerState localPlayerState = CourseManager.GetLocalPlayerState();
				if (localPlayerState.playerGuid != 0L && !localPlayerState.isSpectator)
				{
					perfectShotCounts.TryGetValue(localPlayerState.playerGuid, out var value);
					cartBestFlipStreaks.TryGetValue(localPlayerState.playerGuid, out var value2);
					object? obj = scoreboardItemPickupsStatField?.GetValue(scoreboard);
					ScoreboardStat stat = (ScoreboardStat)((obj is ScoreboardStat) ? obj : null);
					object? obj2 = scoreboardKnockoutRatioStatField?.GetValue(scoreboard);
					object? stat2 = ((obj2 is ScoreboardStat) ? obj2 : null);
					UpdateScoreboardStat(stat, "Item Pickups", "Perfect Shots", value.ToString());
					UpdateScoreboardStat((ScoreboardStat)stat2, "Knockout Ratio", "Best Cart Flip Streak", value2.ToString());
				}
			}
		}

		private static void UpdateScoreboardStat(ScoreboardStat stat, string oldTitle, string newTitle, string value)
		{
			if (!((Object)(object)stat == (Object)null))
			{
				stat.Initialize(value, (Sprite)null);
				TryReplaceScoreboardStatTitle(stat, oldTitle, newTitle);
			}
		}

		private static void TryReplaceScoreboardStatTitle(ScoreboardStat stat, string oldTitle, string newTitle)
		{
			object? obj = scoreboardStatLabelField?.GetValue(stat);
			TextMeshProUGUI val = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null);
			Transform val2 = (((Object)(object)((Component)stat).transform.parent != (Object)null) ? ((Component)stat).transform.parent : ((Component)stat).transform);
			int num = 0;
			while (num < 3 && (Object)(object)val2 != (Object)null)
			{
				TMP_Text[] componentsInChildren = ((Component)val2).GetComponentsInChildren<TMP_Text>(true);
				foreach (TMP_Text val3 in componentsInChildren)
				{
					if ((Object)(object)val3 == (Object)null || val3 == val)
					{
						continue;
					}
					string text = (val3.text ?? string.Empty).Trim();
					if (!text.Equals(oldTitle, StringComparison.OrdinalIgnoreCase) && !text.Equals(newTitle, StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					Behaviour[] components = ((Component)val3).GetComponents<Behaviour>();
					foreach (Behaviour val4 in components)
					{
						if ((Object)(object)val4 != (Object)null && ((object)val4).GetType().Name == "LocalizeStringEvent")
						{
							val4.enabled = false;
						}
					}
					val3.text = newTitle;
					return;
				}
				num++;
				val2 = val2.parent;
			}
		}

		private static void PublishProGolfAnnouncement(string text)
		{
			string text2 = (lastObservedAnnouncementVersion = $"{CourseManager.CurrentHoleGlobalIndex}:{Time.unscaledTime:R}");
			ShowTopAnnouncement(text);
			Lobby val = default(Lobby);
			if (BNetworkManager.TryGetSteamLobby(ref val))
			{
				((Lobby)(ref val)).SetData("codex_progolfplus_announcement_text", text);
				((Lobby)(ref val)).SetData("codex_progolfplus_announcement_version", text2);
			}
		}

		private static string GetPlayerName(PlayerInfo player, ulong playerGuid)
		{
			string text = null;
			if ((Object)(object)((player != null) ? player.PlayerId : null) != (Object)null)
			{
				text = CourseManager.GetPlayerName(player.PlayerId);
			}
			if (string.IsNullOrEmpty(text) && playerGuid != 0L)
			{
				text = CourseManager.GetPlayerName(playerGuid);
			}
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return "Player";
		}
	}
}