Decompiled source of MultiGoals v1.8.1

BepInEx/plugins/SBGMultiGoals/SBGMultiGoals.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Mirror;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace SBGMultiGoalsMod;

[BepInPlugin("com.user.sbg.multigoals", "SBG Multi Goals", "1.8.0")]
public class MultiGoalsPlugin : BaseUnityPlugin
{
	private struct MultiGoalsClientHelloMessage : NetworkMessage
	{
		public int ProtocolVersion;

		public ulong PlayerGuid;
	}

	private struct MultiGoalsStateMessage : NetworkMessage
	{
		public int ProtocolVersion;

		public int RequiredGoals;

		public int TeamCount;

		public int GameMode;

		public int HoleIndex;

		public string TeamAssignmentsPayload;

		public string PlayerGoalsPayload;

		public string TeamGoalsPayload;
	}

	private enum GameMode
	{
		FreeForAll,
		TeamChaos,
		TeamCompetitive
	}

	private enum CompetitiveScoringMode
	{
		SimpleDecrement
	}

	[HarmonyPatch(typeof(GameManager), "RegisterPlayer")]
	private static class GameManager_RegisterPlayer_Patch
	{
		private static void Prefix(GameManager __instance, PlayerInfo playerInfo)
		{
			CleanupDuplicateRemotePlayerEntries(__instance, playerInfo);
		}
	}

	[HarmonyPatch(typeof(NetworkServer), "OnTransportDisconnected")]
	private static class NetworkServer_OnTransportDisconnected_Patch
	{
		private static void Prefix(int connectionId)
		{
			ModdedClientConnectionIds.Remove(connectionId);
		}
	}

	[HarmonyPatch(typeof(MatchSetupMenu), "OnStartClient")]
	private static class MatchSetupMenu_OnStartClient_Patch
	{
		private static void Postfix(MatchSetupMenu __instance)
		{
			TryCreateGoalsTab(__instance);
		}
	}

	[HarmonyPatch(typeof(MatchSetupMenu), "SetEnabled")]
	private static class MatchSetupMenu_SetEnabled_Patch
	{
		private static void Postfix(MatchSetupMenu __instance, bool enabled)
		{
			if (enabled)
			{
				TryCreateGoalsTab(__instance);
				SliderOption value = null;
				if (GoalsSliderByMenu.TryGetValue(__instance, out value) && (Object)(object)value != (Object)null)
				{
					UpdateGoalsSliderVisual(value);
				}
				DropdownOption value2 = null;
				if (ScoreEachGoalOptionByMenu.TryGetValue(__instance, out value2) && (Object)(object)value2 != (Object)null)
				{
					UpdateScoreEachGoalVisual(value2);
				}
				SliderOption value3 = null;
				if (ScoreEachGoalPointsSliderByMenu.TryGetValue(__instance, out value3) && (Object)(object)value3 != (Object)null)
				{
					UpdateScoreEachGoalPointsVisual(value3);
				}
				DropdownOption value4 = null;
				if (GameModeOptionByMenu.TryGetValue(__instance, out value4) && (Object)(object)value4 != (Object)null)
				{
					UpdateGameModeVisual(value4);
				}
				DropdownOption value5 = null;
				if (CompetitiveScoringModeOptionByMenu.TryGetValue(__instance, out value5) && (Object)(object)value5 != (Object)null)
				{
					UpdateCompetitiveScoringModeVisual(value5);
				}
				SliderOption value6 = null;
				if (TeamCountSliderByMenu.TryGetValue(__instance, out value6) && (Object)(object)value6 != (Object)null)
				{
					UpdateTeamCountVisual(value6);
				}
				MatchSetupRules rules = (MatchSetupRules)((MatchSetupMenuRulesField != null) ? /*isinst with value type is only supported in some contexts*/: null);
				Transform value7 = null;
				GoalsTabRootByMenu.TryGetValue(__instance, out value7);
				List<DropdownOption> teamOptions = RebuildTeamAssignmentOptions(__instance, rules, value7);
				PositionGoalsTabControls(value, value2, value3, value4, value5, value6, teamOptions);
			}
		}
	}

	[HarmonyPatch(typeof(MatchSetupMenu), "OnPlayersUpdated")]
	private static class MatchSetupMenu_OnPlayersUpdated_Patch
	{
		private static void Postfix(MatchSetupMenu __instance)
		{
			MatchSetupRules rules = (MatchSetupRules)((MatchSetupMenuRulesField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			Transform value = null;
			GoalsTabRootByMenu.TryGetValue(__instance, out value);
			List<DropdownOption> teamOptions = RebuildTeamAssignmentOptions(__instance, rules, value);
			SliderOption value2 = null;
			DropdownOption value3 = null;
			SliderOption value4 = null;
			DropdownOption value5 = null;
			DropdownOption value6 = null;
			SliderOption value7 = null;
			GoalsSliderByMenu.TryGetValue(__instance, out value2);
			ScoreEachGoalOptionByMenu.TryGetValue(__instance, out value3);
			ScoreEachGoalPointsSliderByMenu.TryGetValue(__instance, out value4);
			GameModeOptionByMenu.TryGetValue(__instance, out value5);
			CompetitiveScoringModeOptionByMenu.TryGetValue(__instance, out value6);
			TeamCountSliderByMenu.TryGetValue(__instance, out value7);
			PositionGoalsTabControls(value2, value3, value4, value5, value6, value7, teamOptions);
		}
	}

	[HarmonyPatch(typeof(MatchSetupMenu), "OnDestroy")]
	private static class MatchSetupMenu_OnDestroy_Patch
	{
		private static void Prefix(MatchSetupMenu __instance)
		{
			if (GoalsSliderByMenu.ContainsKey(__instance))
			{
				GoalsSliderByMenu.Remove(__instance);
			}
			if (ScoreEachGoalOptionByMenu.ContainsKey(__instance))
			{
				ScoreEachGoalOptionByMenu.Remove(__instance);
			}
			if (ScoreEachGoalPointsSliderByMenu.ContainsKey(__instance))
			{
				ScoreEachGoalPointsSliderByMenu.Remove(__instance);
			}
			if (GameModeOptionByMenu.ContainsKey(__instance))
			{
				GameModeOptionByMenu.Remove(__instance);
			}
			if (CompetitiveScoringModeOptionByMenu.ContainsKey(__instance))
			{
				CompetitiveScoringModeOptionByMenu.Remove(__instance);
			}
			if (TeamCountSliderByMenu.ContainsKey(__instance))
			{
				TeamCountSliderByMenu.Remove(__instance);
			}
			if (GoalsTabRootByMenu.ContainsKey(__instance))
			{
				GoalsTabRootByMenu.Remove(__instance);
			}
			if (TeamAssignmentSignatureByMenu.ContainsKey(__instance))
			{
				TeamAssignmentSignatureByMenu.Remove(__instance);
			}
			List<DropdownOption> value = null;
			if (!TeamAssignmentOptionsByMenu.TryGetValue(__instance, out value))
			{
				return;
			}
			if (value != null)
			{
				for (int i = 0; i < value.Count; i++)
				{
					DropdownOption val = value[i];
					if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
			}
			TeamAssignmentOptionsByMenu.Remove(__instance);
		}
	}

	[HarmonyPatch(typeof(CourseManager), "StartCourseInternal")]
	private static class CourseManager_StartCourseInternal_Patch
	{
		private static void Prefix()
		{
			EnsureTeamAssignmentsForConnectedPlayers();
			ClearScoringProgress();
		}
	}

	[HarmonyPatch(typeof(CourseManager), "OnCurrentHoleGlobalIndexChanged")]
	private static class CourseManager_OnCurrentHoleGlobalIndexChanged_Patch
	{
		private static void Postfix()
		{
			EnsureTeamAssignmentsForConnectedPlayers();
			ClearScoringProgress();
		}
	}

	[HarmonyPatch(typeof(CourseManager), "OnMatchStateChanged")]
	private static class CourseManager_OnMatchStateChanged_Patch
	{
		private static void Postfix(MatchState previousState, MatchState currentState)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (IsTeamChaosActive())
			{
				SyncTeamChaosSharedScores();
			}
			if (IsTeamCompetitiveActive() && ((int)currentState == 4 || (int)currentState == 6))
			{
				EnforceTeamCompetitiveRoundScores();
			}
		}
	}

	[HarmonyPatch(typeof(ScoreboardEntry), "PopulateWith")]
	private static class ScoreboardEntry_PopulateWith_Patch
	{
		private static void Postfix(ScoreboardEntry __instance, object __0)
		{
			UpdateScoreboardEntryGoals(__instance, __0);
		}
	}

	[HarmonyPatch(typeof(NameTagUi), "LateUpdate")]
	private static class NameTagUi_LateUpdate_Patch
	{
		private static void Postfix(NameTagUi __instance)
		{
			UpdateWorldNameTagColor(__instance);
		}
	}

	[HarmonyPatch(typeof(GolfBall), "OnEnteredHole")]
	private static class GolfBall_OnEnteredHole_Patch
	{
		private static bool Prefix(GolfBall __instance, GolfHole hole)
		{
			if (!NetworkServer.active)
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)null || (Object)(object)hole == (Object)null || !hole.IsMainHole)
			{
				return true;
			}
			PlayerGolfer networkowner = __instance.Networkowner;
			if ((Object)(object)networkowner == (Object)null)
			{
				return true;
			}
			if (IsTeamCompetitiveActive())
			{
				EnsureTeamAssignmentsForConnectedPlayers();
				string key = BuildScoreKey(networkowner);
				int value = 0;
				ScoredGoalsByPlayerAndHole.TryGetValue(key, out value);
				if (value >= _requiredGoals)
				{
					return false;
				}
				value++;
				if (value >= _requiredGoals)
				{
					ScoredGoalsByPlayerAndHole[key] = _requiredGoals;
					RequestScoreboardRefresh();
					if ((Object)(object)networkowner.PlayerInfo != (Object)null)
					{
						AwardTeamCompetitiveFinishScore(GetPlayerGuid(networkowner.PlayerInfo));
					}
					EnforceTeamCompetitiveRoundScores();
					return true;
				}
				ScoredGoalsByPlayerAndHole[key] = value;
				RequestScoreboardRefresh();
				if ((Object)(object)networkowner.PlayerInfo != (Object)null)
				{
					AwardTeamCompetitiveIntermediateGoalScore(GetPlayerGuid(networkowner.PlayerInfo));
				}
				EnforceTeamCompetitiveRoundScores();
				TriggerNativeRestart(networkowner);
				if (Log != null)
				{
					string playerDisplayName = GetPlayerDisplayName(networkowner.PlayerInfo);
					int teamId = ((!((Object)(object)networkowner.PlayerInfo != (Object)null)) ? 1 : GetTeamForPlayerGuid(GetPlayerGuid(networkowner.PlayerInfo)));
					Log.LogInfo((object)(playerDisplayName + " scored for " + GetTeamLabel(teamId) + " (competitive): " + value + "/" + _requiredGoals + "."));
				}
				return false;
			}
			if (IsTeamChaosActive())
			{
				EnsureTeamAssignmentsForConnectedPlayers();
				int teamForPlayerGuid = GetTeamForPlayerGuid(GetPlayerGuid(networkowner.PlayerInfo));
				string key2 = BuildTeamScoreKey(teamForPlayerGuid);
				int value2 = 0;
				TeamGoalsByHoleAndTeam.TryGetValue(key2, out value2);
				if (value2 >= _requiredGoals)
				{
					return false;
				}
				value2++;
				if (value2 >= _requiredGoals)
				{
					TeamGoalsByHoleAndTeam[key2] = _requiredGoals;
					RequestScoreboardRefresh();
					TriggerStandardTeamWinFlow();
					if (Log != null)
					{
						string playerDisplayName2 = GetPlayerDisplayName(networkowner.PlayerInfo);
						Log.LogInfo((object)(playerDisplayName2 + " scored final goal for " + GetTeamLabel(teamForPlayerGuid) + " (" + _requiredGoals + "/" + _requiredGoals + ")."));
					}
					return true;
				}
				TeamGoalsByHoleAndTeam[key2] = value2;
				RequestScoreboardRefresh();
				int num = AwardIntermediateGoalScore(networkowner);
				if (num > 0 && (Object)(object)networkowner.PlayerInfo != (Object)null)
				{
					MirrorKnownTeamScoreDelta(GetPlayerGuid(networkowner.PlayerInfo), num);
				}
				SyncTeamChaosSharedScores();
				TriggerNativeRestart(networkowner);
				if (Log != null)
				{
					string playerDisplayName3 = GetPlayerDisplayName(networkowner.PlayerInfo);
					Log.LogInfo((object)(playerDisplayName3 + " scored for " + GetTeamLabel(teamForPlayerGuid) + ": " + value2 + "/" + _requiredGoals + "."));
				}
				return false;
			}
			if (_requiredGoals <= 1)
			{
				return true;
			}
			string key3 = BuildScoreKey(networkowner);
			int value3 = 0;
			ScoredGoalsByPlayerAndHole.TryGetValue(key3, out value3);
			value3++;
			if (value3 >= _requiredGoals)
			{
				ScoredGoalsByPlayerAndHole[key3] = _requiredGoals;
				RequestScoreboardRefresh();
				return true;
			}
			ScoredGoalsByPlayerAndHole[key3] = value3;
			RequestScoreboardRefresh();
			AwardIntermediateGoalScore(networkowner);
			TriggerNativeRestart(networkowner);
			if (Log != null)
			{
				string playerDisplayName4 = GetPlayerDisplayName(networkowner.PlayerInfo);
				Log.LogInfo((object)(playerDisplayName4 + " scored " + value3 + "/" + _requiredGoals + " goals on current hole."));
			}
			return false;
		}
	}

	private const int MinGoals = 1;

	private const int MaxGoals = 100;

	private const int MinTeams = 2;

	private const int MaxTeams = 4;

	private const int MinScorePerGoal = 1;

	private const int MaxScorePerGoal = 100;

	private const int DefaultScorePerGoal = 50;

	private const string GoalsOptionLabel = "Goals Required";

	private const string GoalsTabLabel = "MultiGoal";

	private const string ScoreEachGoalLabel = "Score for each goal";

	private const string ScoreEachGoalPointsLabel = "Points per goal";

	private const string GameModeLabel = "Game Mode";

	private const string CompetitiveScoringModeLabel = "Competitive scoring mode";

	private const string TeamCountLabel = "Teams Count";

	private const string OptionOffLabel = "Off";

	private const string OptionOnLabel = "On";

	private const string ModeFreeForAllLabel = "Standard";

	private const string ModeTeamChaosLabel = "Team Chaos";

	private const string ModeTeamCompetitiveLabel = "Team Competitive";

	private const string CompetitiveScoringSimpleDecrementLabel = "Simple (Decrement)";

	private const int NetworkSyncProtocolVersion = 1;

	private const float HostStateSyncIntervalSeconds = 0.35f;

	private const float ClientHelloIntervalSeconds = 2f;

	private static readonly Color TeamDefaultDisplayColor = Color.white;

	private static readonly Color[] TeamDisplayColors = (Color[])(object)new Color[4]
	{
		Color32.op_Implicit(new Color32((byte)221, (byte)161, (byte)161, byte.MaxValue)),
		Color32.op_Implicit(new Color32((byte)119, (byte)143, (byte)169, byte.MaxValue)),
		Color32.op_Implicit(new Color32((byte)175, (byte)152, (byte)196, byte.MaxValue)),
		Color32.op_Implicit(new Color32((byte)125, (byte)182, (byte)163, byte.MaxValue))
	};

	private static readonly int[] TeamPlacementScores = new int[4] { 100, 90, 80, 70 };

	private static readonly Dictionary<string, int> ScoredGoalsByPlayerAndHole = new Dictionary<string, int>();

	private static readonly Dictionary<string, int> TeamGoalsByHoleAndTeam = new Dictionary<string, int>();

	private static readonly HashSet<int> TeamScoresAppliedHoles = new HashSet<int>();

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

	private static readonly Dictionary<MatchSetupMenu, SliderOption> GoalsSliderByMenu = new Dictionary<MatchSetupMenu, SliderOption>();

	private static readonly Dictionary<MatchSetupMenu, DropdownOption> ScoreEachGoalOptionByMenu = new Dictionary<MatchSetupMenu, DropdownOption>();

	private static readonly Dictionary<MatchSetupMenu, SliderOption> ScoreEachGoalPointsSliderByMenu = new Dictionary<MatchSetupMenu, SliderOption>();

	private static readonly Dictionary<MatchSetupMenu, DropdownOption> GameModeOptionByMenu = new Dictionary<MatchSetupMenu, DropdownOption>();

	private static readonly Dictionary<MatchSetupMenu, DropdownOption> CompetitiveScoringModeOptionByMenu = new Dictionary<MatchSetupMenu, DropdownOption>();

	private static readonly Dictionary<MatchSetupMenu, SliderOption> TeamCountSliderByMenu = new Dictionary<MatchSetupMenu, SliderOption>();

	private static readonly Dictionary<MatchSetupMenu, List<DropdownOption>> TeamAssignmentOptionsByMenu = new Dictionary<MatchSetupMenu, List<DropdownOption>>();

	private static readonly Dictionary<MatchSetupMenu, string> TeamAssignmentSignatureByMenu = new Dictionary<MatchSetupMenu, string>();

	private static readonly Dictionary<MatchSetupMenu, Transform> GoalsTabRootByMenu = new Dictionary<MatchSetupMenu, Transform>();

	private static readonly FieldInfo CountdownField = AccessTools.Field(typeof(MatchSetupRules), "countdown");

	private static readonly FieldInfo ScoreOptionTemplateField = AccessTools.Field(typeof(MatchSetupRules), "hitOtherPlayers");

	private static readonly FieldInfo MatchSetupMenuRulesField = AccessTools.Field(typeof(MatchSetupMenu), "rules");

	private static readonly FieldInfo MatchSetupMenuPlayersField = AccessTools.Field(typeof(MatchSetupMenu), "players");

	private static readonly FieldInfo MenuTabsButtonsField = AccessTools.Field(typeof(MenuTabs), "tabButtons");

	private static readonly FieldInfo MenuTabsTabsField = AccessTools.Field(typeof(MenuTabs), "tabs");

	private static readonly FieldInfo MenuTabsTextColorsField = AccessTools.Field(typeof(MenuTabs), "textColors");

	private static readonly FieldInfo SliderLabelField = AccessTools.Field(typeof(SliderOption), "sliderLabel");

	private static readonly FieldInfo DropdownField = AccessTools.Field(typeof(DropdownOption), "dropdown");

	private static readonly FieldInfo ScoreboardEntryNameField = AccessTools.Field(typeof(ScoreboardEntry), "name");

	private static readonly FieldInfo ScoreboardEntryMatchScoreField = AccessTools.Field(typeof(ScoreboardEntry), "matchScore");

	private static readonly FieldInfo ScoreboardEntryCourseScoreField = AccessTools.Field(typeof(ScoreboardEntry), "courseScore");

	private static readonly FieldInfo NameTagUiTagField = AccessTools.Field(typeof(NameTagUi), "tag");

	private static readonly FieldInfo NameTagUiPlayerInfoField = AccessTools.Field(typeof(NameTagUi), "playerInfo");

	private static readonly FieldInfo MatchSetupPlayerNicknameField = AccessTools.Field(typeof(MatchSetupPlayer), "playerNickname");

	private static readonly FieldInfo GameManagerRemotePlayersField = AccessTools.Field(typeof(GameManager), "remotePlayers");

	private static readonly FieldInfo GameManagerRemotePlayerPerConnectionIdField = AccessTools.Field(typeof(GameManager), "remotePlayerPerconnectionId");

	private static readonly FieldInfo NetworkServerHandlersField = AccessTools.Field(typeof(NetworkServer), "handlers");

	private static readonly FieldInfo NetworkClientHandlersField = AccessTools.Field(typeof(NetworkClient), "handlers");

	private static readonly MethodInfo ServerReturnBallToPlayerMethod = AccessTools.Method(typeof(PlayerGolfer), "ServerReturnBallToPlayer", (Type[])null, (Type[])null);

	private static readonly MethodInfo ScoreboardMarkDirtyMethod = AccessTools.Method(typeof(Scoreboard), "MarkDirty", (Type[])null, (Type[])null);

	private static readonly MethodInfo CourseManagerBeginCountdownMethod = AccessTools.Method(typeof(CourseManager), "BeginCountdownToMatchEnd", (Type[])null, (Type[])null);

	private static readonly PropertyInfo CourseManagerPlayerStatesProperty = AccessTools.Property(typeof(CourseManager), "PlayerStates");

	private static readonly Type PlayerStateType = AccessTools.Inner(typeof(CourseManager), "PlayerState");

	private static readonly FieldInfo PlayerStateGuidField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "playerGuid") : null);

	private static readonly FieldInfo PlayerStateNameField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "name") : null);

	private static readonly FieldInfo PlayerStateConnectedField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "isConnected") : null);

	private static readonly FieldInfo PlayerStateSpectatorField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "isSpectator") : null);

	private static readonly FieldInfo PlayerStateCourseScoreField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "courseScore") : null);

	private static readonly FieldInfo PlayerStateMatchScoreField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "matchScore") : null);

	private static readonly FieldInfo PlayerStateScoreTimestampField = ((PlayerStateType != null) ? AccessTools.Field(PlayerStateType, "scoreTimestamp") : null);

	private static readonly PropertyInfo PlayerInfoGuidProperty = AccessTools.Property(typeof(PlayerInfo), "Guid");

	private static readonly PropertyInfo PlayerInfoNameProperty = AccessTools.Property(typeof(PlayerInfo), "Name");

	private static readonly PropertyInfo PlayerInfoSteamIdProperty = AccessTools.Property(typeof(PlayerInfo), "SteamId");

	private static readonly PropertyInfo PlayerInfoPlayerIdProperty = AccessTools.Property(typeof(PlayerInfo), "PlayerId");

	private static readonly Type PlayerIdType = ((PlayerInfoPlayerIdProperty != null) ? PlayerInfoPlayerIdProperty.PropertyType : AccessTools.TypeByName("PlayerId"));

	private static readonly PropertyInfo PlayerIdGuidProperty = ((PlayerIdType != null) ? AccessTools.Property(PlayerIdType, "Guid") : null);

	private static readonly PropertyInfo PlayerIdPlayerNameProperty = ((PlayerIdType != null) ? AccessTools.Property(PlayerIdType, "PlayerName") : null);

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

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

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

	private static readonly Dictionary<string, int> TeamCompetitivePlacementByPlayerAndHole = new Dictionary<string, int>();

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

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

	private static readonly Dictionary<string, int> TeamCompetitiveScriptScoreByHoleAndTeam = new Dictionary<string, int>();

	private static readonly HashSet<int> ModdedClientConnectionIds = new HashSet<int>();

	private static ConfigEntry<int> _goalsConfig;

	private static ConfigEntry<bool> _scoreEachGoalConfig;

	private static ConfigEntry<int> _scoreEachGoalPointsConfig;

	private static ConfigEntry<int> _gameModeConfig;

	private static ConfigEntry<int> _competitiveScoringModeConfig;

	private static ConfigEntry<int> _teamCountConfig;

	private static ConfigEntry<string> _teamAssignmentsConfig;

	private static int _requiredGoals = 1;

	private static bool _scoreEachGoal;

	private static int _scoreEachGoalPoints = 50;

	private static GameMode _gameMode = GameMode.FreeForAll;

	private static CompetitiveScoringMode _competitiveScoringMode = CompetitiveScoringMode.SimpleDecrement;

	private static int _teamCount = 2;

	private static bool _updatingSlider;

	private static bool _updatingScoreOption;

	private static bool _updatingScorePointsSlider;

	private static bool _updatingGameModeOption;

	private static bool _updatingCompetitiveScoringModeOption;

	private static bool _updatingTeamCountSlider;

	private static bool _updatingTeamAssignmentOption;

	private static bool _networkSyncInitialized;

	private static float _nextHostStateSyncTime;

	private static float _nextNetworkHandlersCheckTime;

	internal static ManualLogSource Log;

	private Harmony _harmony;

	private float _nextTeamScoreSyncTime;

	private float _nextClientHelloTime;

	private void Awake()
	{
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_goalsConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "GoalsPerHole", 1, "How many successful hole entries are required before a player finishes the current hole.");
		_scoreEachGoalConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ScoreEachGoal", false, "If enabled, each non-final goal grants bonus score.");
		_scoreEachGoalPointsConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ScoreEachGoalPoints", 50, "How many points to award for each non-final goal.");
		_gameModeConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "GameMode", 0, "0 = Standard, 1 = Team Chaos, 2 = Team Competitive");
		_competitiveScoringModeConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CompetitiveScoringMode", 0, "0 = Simple (Decrement)");
		_teamCountConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "TeamCount", 2, "How many teams to use in Team Chaos mode.");
		_teamAssignmentsConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "TeamAssignments", string.Empty, "Persisted team assignment map in format guid=team;guid=team");
		_requiredGoals = ClampGoals(_goalsConfig.Value);
		if (_requiredGoals != _goalsConfig.Value)
		{
			_goalsConfig.Value = _requiredGoals;
		}
		_scoreEachGoal = _scoreEachGoalConfig.Value;
		_scoreEachGoalPoints = ClampScorePerGoal(_scoreEachGoalPointsConfig.Value);
		if (_scoreEachGoalPoints != _scoreEachGoalPointsConfig.Value)
		{
			_scoreEachGoalPointsConfig.Value = _scoreEachGoalPoints;
		}
		_teamCount = ClampTeamCount(_teamCountConfig.Value);
		if (_teamCount != _teamCountConfig.Value)
		{
			_teamCountConfig.Value = _teamCount;
		}
		_gameMode = ParseGameMode(_gameModeConfig.Value);
		if (_gameMode != (GameMode)_gameModeConfig.Value)
		{
			_gameModeConfig.Value = (int)_gameMode;
		}
		_competitiveScoringMode = ParseCompetitiveScoringMode(_competitiveScoringModeConfig.Value);
		if (_competitiveScoringMode != (CompetitiveScoringMode)_competitiveScoringModeConfig.Value)
		{
			_competitiveScoringModeConfig.Value = (int)_competitiveScoringMode;
		}
		LoadTeamAssignments();
		EnsureNetworkSyncInitialized();
		_harmony = new Harmony("com.user.sbg.multigoals");
		_harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("SBG Multi Goals loaded. Required goals per hole: ", _requiredGoals, ", score each goal: ", _scoreEachGoal, ", points per goal: ", _scoreEachGoalPoints, ", mode: ", _gameMode, ", competitive scoring: ", _competitiveScoringMode, ", teams: ", _teamCount));
	}

	private void Update()
	{
		EnsureRuntimeNetworkHandlers();
		TrySendClientHello();
		SyncStateToModdedClients(force: false);
		if (!(Time.unscaledTime < _nextTeamScoreSyncTime))
		{
			_nextTeamScoreSyncTime = Time.unscaledTime + 0.15f;
			SyncTeamChaosSharedScores();
			EnforceTeamCompetitiveRoundScores();
		}
	}

	private static int ClampGoals(int value)
	{
		return Mathf.Clamp(value, 1, 100);
	}

	private static int ClampTeamCount(int value)
	{
		return Mathf.Clamp(value, 2, 4);
	}

	private static int ClampScorePerGoal(int value)
	{
		return Mathf.Clamp(value, 1, 100);
	}

	private static GameMode ParseGameMode(int value)
	{
		return value switch
		{
			1 => GameMode.TeamChaos, 
			2 => GameMode.TeamCompetitive, 
			_ => GameMode.FreeForAll, 
		};
	}

	private static CompetitiveScoringMode ParseCompetitiveScoringMode(int value)
	{
		return CompetitiveScoringMode.SimpleDecrement;
	}

	private static void ClearScoringProgress()
	{
		ScoredGoalsByPlayerAndHole.Clear();
		TeamGoalsByHoleAndTeam.Clear();
		TeamScoresAppliedHoles.Clear();
		TeamChaosRoundScoreByPlayer.Clear();
		ObservedMatchScoreByPlayer.Clear();
		PendingMirroredScoreDeltaByPlayer.Clear();
		TeamCompetitivePlacementByPlayerAndHole.Clear();
		TeamCompetitiveNextPlacementByHole.Clear();
		TeamCompetitiveTotalPlayersByHole.Clear();
		TeamCompetitiveScriptScoreByHoleAndTeam.Clear();
		RequestScoreboardRefresh();
	}

	private static bool IsTeamChaosActive()
	{
		return _gameMode == GameMode.TeamChaos;
	}

	private static bool IsTeamCompetitiveActive()
	{
		return _gameMode == GameMode.TeamCompetitive;
	}

	private static void LoadTeamAssignments()
	{
		TeamByPlayerGuid.Clear();
		if (_teamAssignmentsConfig == null || string.IsNullOrWhiteSpace(_teamAssignmentsConfig.Value))
		{
			return;
		}
		string[] array = _teamAssignmentsConfig.Value.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 == 2 && ulong.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2))
			{
				result2 = ClampTeam(result2);
				TeamByPlayerGuid[result] = result2;
			}
		}
	}

	private static void SaveTeamAssignments()
	{
		if (_teamAssignmentsConfig == null)
		{
			return;
		}
		List<string> list = new List<string>(TeamByPlayerGuid.Count);
		foreach (KeyValuePair<ulong, int> item in TeamByPlayerGuid)
		{
			if (item.Key != 0)
			{
				list.Add(item.Key + "=" + ClampTeam(item.Value));
			}
		}
		_teamAssignmentsConfig.Value = string.Join(";", list.ToArray());
	}

	private static object GetPlayerIdObject(PlayerInfo playerInfo)
	{
		if ((Object)(object)playerInfo == (Object)null || PlayerInfoPlayerIdProperty == null)
		{
			return null;
		}
		try
		{
			return PlayerInfoPlayerIdProperty.GetValue(playerInfo, null);
		}
		catch
		{
			return null;
		}
	}

	private static ulong GetPlayerGuid(PlayerInfo playerInfo)
	{
		if ((Object)(object)playerInfo == (Object)null)
		{
			return 0uL;
		}
		if (PlayerInfoGuidProperty != null)
		{
			try
			{
				object value = PlayerInfoGuidProperty.GetValue(playerInfo, null);
				if (value is ulong)
				{
					return (ulong)value;
				}
			}
			catch
			{
			}
		}
		if (PlayerIdGuidProperty != null)
		{
			object playerIdObject = GetPlayerIdObject(playerInfo);
			if (playerIdObject != null)
			{
				try
				{
					object value2 = PlayerIdGuidProperty.GetValue(playerIdObject, null);
					if (value2 is ulong)
					{
						return (ulong)value2;
					}
				}
				catch
				{
				}
			}
		}
		return 0uL;
	}

	private static ulong GetPlayerSteamId(PlayerInfo playerInfo)
	{
		if ((Object)(object)playerInfo == (Object)null || PlayerInfoSteamIdProperty == null)
		{
			return 0uL;
		}
		try
		{
			object value = PlayerInfoSteamIdProperty.GetValue(playerInfo, null);
			if (value is ulong)
			{
				return (ulong)value;
			}
		}
		catch
		{
		}
		return 0uL;
	}

	private static string GetPlayerDisplayName(PlayerInfo playerInfo)
	{
		if ((Object)(object)playerInfo == (Object)null)
		{
			return "Unknown";
		}
		if (PlayerInfoNameProperty != null)
		{
			try
			{
				string text = PlayerInfoNameProperty.GetValue(playerInfo, null) as string;
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch
			{
			}
		}
		if (PlayerIdPlayerNameProperty != null)
		{
			object playerIdObject = GetPlayerIdObject(playerInfo);
			if (playerIdObject != null)
			{
				try
				{
					string text2 = PlayerIdPlayerNameProperty.GetValue(playerIdObject, null) as string;
					if (!string.IsNullOrEmpty(text2))
					{
						return text2;
					}
				}
				catch
				{
				}
			}
		}
		return "Unknown";
	}

	private static void EnsureNetworkSyncInitialized()
	{
		if (_networkSyncInitialized)
		{
			return;
		}
		try
		{
			Writer<MultiGoalsClientHelloMessage>.write = WriteClientHelloMessage;
			Reader<MultiGoalsClientHelloMessage>.read = ReadClientHelloMessage;
			Writer<MultiGoalsStateMessage>.write = WriteStateMessage;
			Reader<MultiGoalsStateMessage>.read = ReadStateMessage;
			NetworkServer.RegisterHandler<MultiGoalsClientHelloMessage>((Action<NetworkConnectionToClient, MultiGoalsClientHelloMessage>)OnClientHelloMessage, false);
			NetworkClient.RegisterHandler<MultiGoalsStateMessage>((Action<MultiGoalsStateMessage>)OnStateMessage, false);
			_networkSyncInitialized = true;
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogError((object)("Failed to initialize network sync handlers: " + ex));
			}
		}
	}

	private static bool IsServerHelloHandlerRegistered()
	{
		ushort id = NetworkMessageId<MultiGoalsClientHelloMessage>.Id;
		return ((NetworkServerHandlersField != null) ? (NetworkServerHandlersField.GetValue(null) as IDictionary) : null)?.Contains(id) ?? false;
	}

	private static bool IsClientStateHandlerRegistered()
	{
		IDictionary dictionary = ((NetworkClientHandlersField != null) ? (NetworkClientHandlersField.GetValue(null) as IDictionary) : null);
		if (dictionary == null)
		{
			return false;
		}
		ushort id = NetworkMessageId<MultiGoalsStateMessage>.Id;
		return dictionary.Contains(id);
	}

	private void EnsureRuntimeNetworkHandlers()
	{
		EnsureNetworkSyncInitialized();
		if (Time.unscaledTime < _nextNetworkHandlersCheckTime)
		{
			return;
		}
		_nextNetworkHandlersCheckTime = Time.unscaledTime + 0.5f;
		try
		{
			if (NetworkServer.active && !IsServerHelloHandlerRegistered())
			{
				NetworkServer.RegisterHandler<MultiGoalsClientHelloMessage>((Action<NetworkConnectionToClient, MultiGoalsClientHelloMessage>)OnClientHelloMessage, false);
			}
			if (NetworkClient.active && !IsClientStateHandlerRegistered())
			{
				NetworkClient.RegisterHandler<MultiGoalsStateMessage>((Action<MultiGoalsStateMessage>)OnStateMessage, false);
			}
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogError((object)("Failed to refresh runtime network handlers: " + ex));
			}
		}
	}

	private static void WriteClientHelloMessage(NetworkWriter writer, MultiGoalsClientHelloMessage message)
	{
		NetworkWriterExtensions.WriteInt(writer, message.ProtocolVersion);
		NetworkWriterExtensions.WriteULong(writer, message.PlayerGuid);
	}

	private static MultiGoalsClientHelloMessage ReadClientHelloMessage(NetworkReader reader)
	{
		MultiGoalsClientHelloMessage result = default(MultiGoalsClientHelloMessage);
		result.ProtocolVersion = NetworkReaderExtensions.ReadInt(reader);
		result.PlayerGuid = NetworkReaderExtensions.ReadULong(reader);
		return result;
	}

	private static void WriteStateMessage(NetworkWriter writer, MultiGoalsStateMessage message)
	{
		NetworkWriterExtensions.WriteInt(writer, message.ProtocolVersion);
		NetworkWriterExtensions.WriteInt(writer, message.RequiredGoals);
		NetworkWriterExtensions.WriteInt(writer, message.TeamCount);
		NetworkWriterExtensions.WriteInt(writer, message.GameMode);
		NetworkWriterExtensions.WriteInt(writer, message.HoleIndex);
		NetworkWriterExtensions.WriteString(writer, message.TeamAssignmentsPayload ?? string.Empty);
		NetworkWriterExtensions.WriteString(writer, message.PlayerGoalsPayload ?? string.Empty);
		NetworkWriterExtensions.WriteString(writer, message.TeamGoalsPayload ?? string.Empty);
	}

	private static MultiGoalsStateMessage ReadStateMessage(NetworkReader reader)
	{
		MultiGoalsStateMessage result = default(MultiGoalsStateMessage);
		result.ProtocolVersion = NetworkReaderExtensions.ReadInt(reader);
		result.RequiredGoals = NetworkReaderExtensions.ReadInt(reader);
		result.TeamCount = NetworkReaderExtensions.ReadInt(reader);
		result.GameMode = NetworkReaderExtensions.ReadInt(reader);
		result.HoleIndex = NetworkReaderExtensions.ReadInt(reader);
		result.TeamAssignmentsPayload = NetworkReaderExtensions.ReadString(reader);
		result.PlayerGoalsPayload = NetworkReaderExtensions.ReadString(reader);
		result.TeamGoalsPayload = NetworkReaderExtensions.ReadString(reader);
		return result;
	}

	private static void OnClientHelloMessage(NetworkConnectionToClient connection, MultiGoalsClientHelloMessage message)
	{
		if (connection != null && message.ProtocolVersion == 1)
		{
			ModdedClientConnectionIds.Add(connection.connectionId);
			SendStateToConnection(connection);
		}
	}

	private static void OnStateMessage(MultiGoalsStateMessage message)
	{
		if (!NetworkServer.active && message.ProtocolVersion == 1)
		{
			_requiredGoals = ClampGoals(message.RequiredGoals);
			_teamCount = ClampTeamCount(message.TeamCount);
			_gameMode = ParseGameMode(message.GameMode);
			ApplyTeamAssignmentsPayload(message.TeamAssignmentsPayload);
			ApplyPlayerGoalsPayload(message.HoleIndex, message.PlayerGoalsPayload);
			ApplyTeamGoalsPayload(message.HoleIndex, message.TeamGoalsPayload);
			RequestScoreboardRefresh();
		}
	}

	private void TrySendClientHello()
	{
		EnsureNetworkSyncInitialized();
		if (NetworkServer.active || !NetworkClient.active || !NetworkClient.isConnected)
		{
			_nextClientHelloTime = 0f;
		}
		else
		{
			if (Time.unscaledTime < _nextClientHelloTime)
			{
				return;
			}
			_nextClientHelloTime = Time.unscaledTime + 2f;
			try
			{
				MultiGoalsClientHelloMessage multiGoalsClientHelloMessage = default(MultiGoalsClientHelloMessage);
				multiGoalsClientHelloMessage.ProtocolVersion = 1;
				multiGoalsClientHelloMessage.PlayerGuid = GetLocalPlayerGuidForHello();
				NetworkClient.Send<MultiGoalsClientHelloMessage>(multiGoalsClientHelloMessage, 0);
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogError((object)("Failed to send client hello: " + ex));
				}
			}
		}
	}

	private static ulong GetLocalPlayerGuidForHello()
	{
		try
		{
			NetworkConnectionToServer connection = NetworkClient.connection;
			if (connection != null && (Object)(object)((NetworkConnection)connection).identity != (Object)null)
			{
				PlayerInfo component = ((Component)((NetworkConnection)connection).identity).GetComponent<PlayerInfo>();
				if ((Object)(object)component != (Object)null)
				{
					return GetPlayerGuid(component);
				}
			}
		}
		catch
		{
		}
		return 0uL;
	}

	private static void SyncStateToModdedClients(bool force)
	{
		EnsureNetworkSyncInitialized();
		if (!NetworkServer.active || (!force && Time.unscaledTime < _nextHostStateSyncTime))
		{
			return;
		}
		_nextHostStateSyncTime = Time.unscaledTime + 0.35f;
		if (ModdedClientConnectionIds.Count == 0)
		{
			return;
		}
		List<int> list = null;
		MultiGoalsStateMessage multiGoalsStateMessage = BuildStateSnapshotMessage();
		foreach (int moddedClientConnectionId in ModdedClientConnectionIds)
		{
			if (!NetworkServer.connections.TryGetValue(moddedClientConnectionId, out var value) || value == null || !((NetworkConnection)value).isAuthenticated)
			{
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(moddedClientConnectionId);
				continue;
			}
			try
			{
				((NetworkConnection)value).Send<MultiGoalsStateMessage>(multiGoalsStateMessage, 0);
			}
			catch
			{
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(moddedClientConnectionId);
			}
		}
		if (list != null)
		{
			for (int i = 0; i < list.Count; i++)
			{
				ModdedClientConnectionIds.Remove(list[i]);
			}
		}
	}

	private static void SendStateToConnection(NetworkConnectionToClient connection)
	{
		if (connection == null || !((NetworkConnection)connection).isAuthenticated)
		{
			return;
		}
		try
		{
			((NetworkConnection)connection).Send<MultiGoalsStateMessage>(BuildStateSnapshotMessage(), 0);
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogError((object)("Failed to send state snapshot to connection " + connection.connectionId + ": " + ex));
			}
		}
	}

	private static MultiGoalsStateMessage BuildStateSnapshotMessage()
	{
		EnsureTeamAssignmentsForConnectedPlayers();
		int currentHoleGlobalIndex = CourseManager.CurrentHoleGlobalIndex;
		MultiGoalsStateMessage result = default(MultiGoalsStateMessage);
		result.ProtocolVersion = 1;
		result.RequiredGoals = _requiredGoals;
		result.TeamCount = _teamCount;
		result.GameMode = (int)_gameMode;
		result.HoleIndex = currentHoleGlobalIndex;
		result.TeamAssignmentsPayload = BuildTeamAssignmentsPayload();
		result.PlayerGoalsPayload = BuildPlayerGoalsPayload(currentHoleGlobalIndex);
		result.TeamGoalsPayload = BuildTeamGoalsPayload(currentHoleGlobalIndex);
		return result;
	}

	private static string BuildTeamAssignmentsPayload()
	{
		List<ulong> list = new List<ulong>(TeamByPlayerGuid.Keys);
		list.Sort();
		List<string> list2 = new List<string>(list.Count);
		for (int i = 0; i < list.Count; i++)
		{
			ulong num = list[i];
			if (num != 0 && TeamByPlayerGuid.TryGetValue(num, out var value))
			{
				list2.Add(num + "=" + ClampTeam(value));
			}
		}
		return string.Join(";", list2.ToArray());
	}

	private static string BuildPlayerGoalsPayload(int holeIndex)
	{
		List<ulong> knownParticipantGuids = GetKnownParticipantGuids();
		knownParticipantGuids.Sort();
		List<string> list = new List<string>(knownParticipantGuids.Count);
		for (int i = 0; i < knownParticipantGuids.Count; i++)
		{
			ulong num = knownParticipantGuids[i];
			if (num != 0)
			{
				int value = 0;
				ScoredGoalsByPlayerAndHole.TryGetValue(BuildScoreKey(holeIndex, num), out value);
				list.Add(num + "=" + Mathf.Max(value, 0));
			}
		}
		return string.Join(";", list.ToArray());
	}

	private static string BuildTeamGoalsPayload(int holeIndex)
	{
		List<string> list = new List<string>(_teamCount);
		for (int i = 1; i <= _teamCount; i++)
		{
			int value = 0;
			TeamGoalsByHoleAndTeam.TryGetValue(BuildTeamScoreKey(holeIndex, i), out value);
			list.Add(i + "=" + Mathf.Max(value, 0));
		}
		return string.Join(";", list.ToArray());
	}

	private static void ApplyTeamAssignmentsPayload(string payload)
	{
		TeamByPlayerGuid.Clear();
		if (string.IsNullOrWhiteSpace(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 == 2 && ulong.TryParse(array2[0], out var result) && result != 0 && int.TryParse(array2[1], out var result2))
			{
				TeamByPlayerGuid[result] = ClampTeam(result2);
			}
		}
	}

	private static void ApplyPlayerGoalsPayload(int holeIndex, string payload)
	{
		string value = holeIndex + ":";
		List<string> list = new List<string>(ScoredGoalsByPlayerAndHole.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			string text = list[i];
			if (text != null && text.StartsWith(value, StringComparison.Ordinal))
			{
				ScoredGoalsByPlayerAndHole.Remove(text);
			}
		}
		if (string.IsNullOrWhiteSpace(payload))
		{
			return;
		}
		string[] array = payload.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
		for (int j = 0; j < array.Length; j++)
		{
			string[] array2 = array[j].Split(new char[1] { '=' });
			if (array2.Length == 2 && ulong.TryParse(array2[0], out var result) && result != 0 && int.TryParse(array2[1], out var result2))
			{
				ScoredGoalsByPlayerAndHole[BuildScoreKey(holeIndex, result)] = Mathf.Max(result2, 0);
			}
		}
	}

	private static void ApplyTeamGoalsPayload(int holeIndex, string payload)
	{
		string value = holeIndex + ":T";
		List<string> list = new List<string>(TeamGoalsByHoleAndTeam.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			string text = list[i];
			if (text != null && text.StartsWith(value, StringComparison.Ordinal))
			{
				TeamGoalsByHoleAndTeam.Remove(text);
			}
		}
		if (string.IsNullOrWhiteSpace(payload))
		{
			return;
		}
		string[] array = payload.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
		for (int j = 0; j < array.Length; j++)
		{
			string[] array2 = array[j].Split(new char[1] { '=' });
			if (array2.Length == 2 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2))
			{
				TeamGoalsByHoleAndTeam[BuildTeamScoreKey(holeIndex, ClampTeam(result))] = Mathf.Max(result2, 0);
			}
		}
	}

	private static string BuildScoreKey(PlayerGolfer owner)
	{
		ulong playerGuid = 0uL;
		if ((Object)(object)owner != (Object)null && (Object)(object)owner.PlayerInfo != (Object)null)
		{
			playerGuid = GetPlayerGuid(owner.PlayerInfo);
		}
		return BuildScoreKey(playerGuid);
	}

	private static string BuildScoreKey(ulong playerGuid)
	{
		int currentHoleGlobalIndex = CourseManager.CurrentHoleGlobalIndex;
		return BuildScoreKey(currentHoleGlobalIndex, playerGuid);
	}

	private static string BuildScoreKey(int holeIndex, ulong playerGuid)
	{
		return holeIndex + ":" + playerGuid;
	}

	private static int GetCurrentGoalsForPlayer(ulong playerGuid)
	{
		int value = 0;
		ScoredGoalsByPlayerAndHole.TryGetValue(BuildScoreKey(playerGuid), out value);
		return Mathf.Clamp(value, 0, _requiredGoals);
	}

	private static string BuildTeamScoreKey(int teamId)
	{
		int currentHoleGlobalIndex = CourseManager.CurrentHoleGlobalIndex;
		return BuildTeamScoreKey(currentHoleGlobalIndex, teamId);
	}

	private static string BuildTeamScoreKey(int holeIndex, int teamId)
	{
		return holeIndex + ":T" + teamId;
	}

	private static int ClampTeam(int teamId)
	{
		return Mathf.Clamp(teamId, 1, _teamCount);
	}

	private static int GetCurrentGoalsForTeam(int teamId)
	{
		int value = 0;
		TeamGoalsByHoleAndTeam.TryGetValue(BuildTeamScoreKey(teamId), out value);
		return Mathf.Clamp(value, 0, _requiredGoals);
	}

	private static bool IsConnectedParticipantState(object boxedState)
	{
		if (boxedState == null)
		{
			return false;
		}
		if (PlayerStateConnectedField == null || PlayerStateSpectatorField == null)
		{
			return true;
		}
		bool flag = (bool)PlayerStateConnectedField.GetValue(boxedState);
		bool flag2 = (bool)PlayerStateSpectatorField.GetValue(boxedState);
		if (flag)
		{
			return !flag2;
		}
		return false;
	}

	private static List<ulong> GetConnectedParticipantGuids()
	{
		List<ulong> list = new List<ulong>();
		if (CourseManagerPlayerStatesProperty == null || PlayerStateGuidField == null)
		{
			return list;
		}
		object value = CourseManagerPlayerStatesProperty.GetValue(null, null);
		if (value == null)
		{
			return list;
		}
		if (value is IList list2)
		{
			for (int i = 0; i < list2.Count; i++)
			{
				object obj = list2[i];
				if (IsConnectedParticipantState(obj))
				{
					ulong num = (ulong)PlayerStateGuidField.GetValue(obj);
					if (num != 0)
					{
						list.Add(num);
					}
				}
			}
			return list;
		}
		Type type = value.GetType();
		PropertyInfo propertyInfo = AccessTools.Property(type, "Count");
		PropertyInfo propertyInfo2 = AccessTools.Property(type, "Item");
		if (propertyInfo == null || propertyInfo2 == null || !propertyInfo2.CanRead)
		{
			return list;
		}
		int num2 = (int)propertyInfo.GetValue(value, null);
		object[] array = new object[1];
		for (int j = 0; j < num2; j++)
		{
			array[0] = j;
			object value2 = propertyInfo2.GetValue(value, array);
			if (IsConnectedParticipantState(value2))
			{
				ulong num3 = (ulong)PlayerStateGuidField.GetValue(value2);
				if (num3 != 0)
				{
					list.Add(num3);
				}
			}
		}
		return list;
	}

	private static List<ulong> GetKnownParticipantGuids()
	{
		List<ulong> connectedParticipantGuids = GetConnectedParticipantGuids();
		if (connectedParticipantGuids.Count > 0)
		{
			return connectedParticipantGuids;
		}
		foreach (KeyValuePair<ulong, int> item in TeamByPlayerGuid)
		{
			if (item.Key != 0 && !connectedParticipantGuids.Contains(item.Key))
			{
				connectedParticipantGuids.Add(item.Key);
			}
		}
		return connectedParticipantGuids;
	}

	private static void EnsureTeamAssignmentsForConnectedPlayers()
	{
		if (!NetworkServer.active)
		{
			return;
		}
		List<ulong> knownParticipantGuids = GetKnownParticipantGuids();
		if (knownParticipantGuids.Count == 0)
		{
			return;
		}
		knownParticipantGuids.Sort();
		bool flag = false;
		int num = 1;
		for (int i = 0; i < knownParticipantGuids.Count; i++)
		{
			ulong key = knownParticipantGuids[i];
			int value = 0;
			if (TeamByPlayerGuid.TryGetValue(key, out value))
			{
				int num2 = ClampTeam(value);
				if (num2 != value)
				{
					TeamByPlayerGuid[key] = num2;
					flag = true;
				}
			}
			else
			{
				TeamByPlayerGuid[key] = num;
				flag = true;
			}
			num++;
			if (num > _teamCount)
			{
				num = 1;
			}
		}
		if (flag)
		{
			SaveTeamAssignments();
		}
	}

	private static int GetTeamForPlayerGuid(ulong playerGuid)
	{
		if (playerGuid == 0)
		{
			return 1;
		}
		int value = 0;
		if (TeamByPlayerGuid.TryGetValue(playerGuid, out value))
		{
			return ClampTeam(value);
		}
		if (!NetworkServer.active)
		{
			return 1;
		}
		EnsureTeamAssignmentsForConnectedPlayers();
		if (TeamByPlayerGuid.TryGetValue(playerGuid, out value))
		{
			return ClampTeam(value);
		}
		int teamId = TeamByPlayerGuid.Count % _teamCount + 1;
		TeamByPlayerGuid[playerGuid] = ClampTeam(teamId);
		SaveTeamAssignments();
		return TeamByPlayerGuid[playerGuid];
	}

	private static string GetTeamLabel(int teamId)
	{
		return "Team " + ClampTeam(teamId);
	}

	private static Color GetTeamDisplayColor(int teamId)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.Clamp(teamId, 1, TeamDisplayColors.Length);
		return TeamDisplayColors[num - 1];
	}

	private static List<string> BuildTeamOptions()
	{
		List<string> list = new List<string>(_teamCount);
		for (int i = 1; i <= _teamCount; i++)
		{
			list.Add(GetTeamLabel(i));
		}
		return list;
	}

	private static string BuildTeamAssignmentSignature(MatchSetupMenu menu)
	{
		List<MatchSetupPlayer> menuPlayers = GetMenuPlayers(menu);
		List<ulong> list = new List<ulong>(menuPlayers.Count);
		for (int i = 0; i < menuPlayers.Count; i++)
		{
			MatchSetupPlayer val = menuPlayers[i];
			if (!((Object)(object)val == (Object)null) && val.Guid != 0)
			{
				list.Add(val.Guid);
			}
		}
		list.Sort();
		string[] array = new string[list.Count];
		for (int j = 0; j < list.Count; j++)
		{
			array[j] = list[j].ToString();
		}
		return _teamCount + "|" + string.Join(",", array);
	}

	private static bool IsSameRemoteIdentity(PlayerInfo candidate, ulong guid, ulong steamId)
	{
		if ((Object)(object)candidate == (Object)null)
		{
			return false;
		}
		ulong playerGuid = GetPlayerGuid(candidate);
		if (guid != 0 && playerGuid == guid)
		{
			return true;
		}
		ulong playerSteamId = GetPlayerSteamId(candidate);
		if (steamId != 0 && playerSteamId == steamId)
		{
			return true;
		}
		return false;
	}

	private static void AddStalePlayer(List<PlayerInfo> stalePlayers, PlayerInfo player)
	{
		if (stalePlayers == null || (Object)(object)player == (Object)null)
		{
			return;
		}
		for (int i = 0; i < stalePlayers.Count; i++)
		{
			if (object.ReferenceEquals(stalePlayers[i], player))
			{
				return;
			}
		}
		stalePlayers.Add(player);
	}

	private static void CleanupDuplicateRemotePlayerEntries(GameManager gameManager, PlayerInfo incomingPlayer)
	{
		if ((Object)(object)gameManager == (Object)null || (Object)(object)incomingPlayer == (Object)null || ((NetworkBehaviour)incomingPlayer).isLocalPlayer)
		{
			return;
		}
		try
		{
			ulong playerGuid = GetPlayerGuid(incomingPlayer);
			ulong playerSteamId = GetPlayerSteamId(incomingPlayer);
			List<PlayerInfo> list = new List<PlayerInfo>();
			IList list2 = ((GameManagerRemotePlayersField != null) ? (GameManagerRemotePlayersField.GetValue(gameManager) as IList) : null);
			if (list2 != null)
			{
				for (int i = 0; i < list2.Count; i++)
				{
					object? obj = list2[i];
					PlayerInfo val = (PlayerInfo)((obj is PlayerInfo) ? obj : null);
					if (!((Object)(object)val == (Object)null) && !object.ReferenceEquals(val, incomingPlayer) && IsSameRemoteIdentity(val, playerGuid, playerSteamId))
					{
						AddStalePlayer(list, val);
					}
				}
			}
			IDictionary dictionary = ((GameManagerRemotePlayerPerConnectionIdField != null) ? (GameManagerRemotePlayerPerConnectionIdField.GetValue(gameManager) as IDictionary) : null);
			List<object> list3 = new List<object>();
			if (dictionary != null)
			{
				foreach (DictionaryEntry item in dictionary)
				{
					object? value = item.Value;
					PlayerInfo val2 = (PlayerInfo)((value is PlayerInfo) ? value : null);
					if ((Object)(object)val2 == (Object)null)
					{
						list3.Add(item.Key);
					}
					else if (!object.ReferenceEquals(val2, incomingPlayer) && IsSameRemoteIdentity(val2, playerGuid, playerSteamId))
					{
						AddStalePlayer(list, val2);
					}
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				PlayerInfo val3 = list[j];
				if (!((Object)(object)val3 == (Object)null))
				{
					GameManager.DeregisterPlayer(val3);
					if (Log != null)
					{
						Log.LogInfo((object)("Removed stale remote player before register. guid=" + GetPlayerGuid(val3) + ", steamId=" + GetPlayerSteamId(val3) + "."));
					}
				}
			}
			if (dictionary == null || list3.Count <= 0)
			{
				return;
			}
			for (int k = 0; k < list3.Count; k++)
			{
				object key = list3[k];
				if (dictionary.Contains(key))
				{
					dictionary.Remove(key);
				}
			}
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogError((object)("Failed duplicate remote-player cleanup before register: " + ex));
			}
		}
	}

	private static void RequestScoreboardRefresh()
	{
		if (ScoreboardMarkDirtyMethod == null)
		{
			return;
		}
		try
		{
			Scoreboard val = Object.FindObjectOfType<Scoreboard>();
			if ((Object)(object)val != (Object)null)
			{
				ScoreboardMarkDirtyMethod.Invoke(val, null);
			}
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogError((object)("Failed to refresh scoreboard: " + ex));
			}
		}
	}

	private static SliderOption CreateGoalsSliderFromTemplate(MatchSetupRules rules, Transform parent)
	{
		if ((Object)(object)rules == (Object)null || CountdownField == null || (Object)(object)parent == (Object)null)
		{
			return null;
		}
		object? value = CountdownField.GetValue(rules);
		SliderOption val = (SliderOption)((value is SliderOption) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
		{
			return null;
		}
		GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject);
		if ((Object)(object)val2 == (Object)null)
		{
			return null;
		}
		((Object)val2).name = "Mod_GoalsPerHole";
		val2.transform.SetParent(parent, false);
		val2.transform.SetAsLastSibling();
		SliderOption goalsSlider = val2.GetComponent<SliderOption>();
		if ((Object)(object)goalsSlider == (Object)null)
		{
			goalsSlider = val2.GetComponentInChildren<SliderOption>(true);
		}
		if ((Object)(object)goalsSlider == (Object)null)
		{
			Object.Destroy((Object)(object)val2);
			return null;
		}
		SetSliderTitleText(((Component)goalsSlider).gameObject, goalsSlider, "Goals Required");
		goalsSlider.SetLimits(1f, 100f);
		goalsSlider.Initialize((Action)delegate
		{
			OnGoalsSliderChanged(goalsSlider);
		}, (float)_requiredGoals);
		UpdateGoalsSliderVisual(goalsSlider);
		return goalsSlider;
	}

	private static DropdownOption CreateScoreEachGoalOptionFromTemplate(MatchSetupRules rules, Transform parent)
	{
		DropdownOption option = CreateDropdownOptionClone(rules, parent, "Mod_ScoreEachGoal");
		if ((Object)(object)option == (Object)null)
		{
			return null;
		}
		option.SetOptions(new List<string> { "Off", "On" });
		option.Initialize((Action)delegate
		{
			OnScoreEachGoalChanged(option);
		}, _scoreEachGoal ? 1 : 0);
		UpdateScoreEachGoalVisual(option);
		return option;
	}

	private static SliderOption CreateScoreEachGoalPointsSliderFromTemplate(MatchSetupRules rules, Transform parent)
	{
		if ((Object)(object)rules == (Object)null || CountdownField == null || (Object)(object)parent == (Object)null)
		{
			return null;
		}
		object? value = CountdownField.GetValue(rules);
		SliderOption val = (SliderOption)((value is SliderOption) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
		{
			return null;
		}
		GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject);
		if ((Object)(object)val2 == (Object)null)
		{
			return null;
		}
		((Object)val2).name = "Mod_ScoreEachGoalPoints";
		val2.transform.SetParent(parent, false);
		val2.transform.SetAsLastSibling();
		SliderOption slider = val2.GetComponent<SliderOption>();
		if ((Object)(object)slider == (Object)null)
		{
			slider = val2.GetComponentInChildren<SliderOption>(true);
		}
		if ((Object)(object)slider == (Object)null)
		{
			Object.Destroy((Object)(object)val2);
			return null;
		}
		SetSliderTitleText(((Component)slider).gameObject, slider, "Points per goal");
		slider.SetLimits(1f, 100f);
		slider.Initialize((Action)delegate
		{
			OnScoreEachGoalPointsChanged(slider);
		}, (float)_scoreEachGoalPoints);
		UpdateScoreEachGoalPointsVisual(slider);
		return slider;
	}

	private static DropdownOption CreateGameModeOptionFromTemplate(MatchSetupRules rules, Transform parent)
	{
		DropdownOption option = CreateDropdownOptionClone(rules, parent, "Mod_GameMode");
		if ((Object)(object)option == (Object)null)
		{
			return null;
		}
		RemoveLocalizationComponents(((Component)option).gameObject);
		option.SetOptions(new List<string> { "Standard", "Team Chaos", "Team Competitive" });
		_updatingGameModeOption = true;
		try
		{
			option.Initialize((Action)delegate
			{
				OnGameModeChanged(option);
			}, (int)_gameMode);
		}
		finally
		{
			_updatingGameModeOption = false;
		}
		UpdateGameModeVisual(option);
		return option;
	}

	private static DropdownOption CreateCompetitiveScoringModeOptionFromTemplate(MatchSetupRules rules, Transform parent)
	{
		DropdownOption option = CreateDropdownOptionClone(rules, parent, "Mod_CompetitiveScoringMode");
		if ((Object)(object)option == (Object)null)
		{
			return null;
		}
		RemoveLocalizationComponents(((Component)option).gameObject);
		option.SetOptions(new List<string> { "Simple (Decrement)" });
		_updatingCompetitiveScoringModeOption = true;
		try
		{
			option.Initialize((Action)delegate
			{
				OnCompetitiveScoringModeChanged(option);
			}, (int)_competitiveScoringMode);
		}
		finally
		{
			_updatingCompetitiveScoringModeOption = false;
		}
		UpdateCompetitiveScoringModeVisual(option);
		return option;
	}

	private static SliderOption CreateTeamCountSliderFromTemplate(MatchSetupRules rules, Transform parent)
	{
		if ((Object)(object)rules == (Object)null || CountdownField == null || (Object)(object)parent == (Object)null)
		{
			return null;
		}
		object? value = CountdownField.GetValue(rules);
		SliderOption val = (SliderOption)((value is SliderOption) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
		{
			return null;
		}
		GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject);
		if ((Object)(object)val2 == (Object)null)
		{
			return null;
		}
		((Object)val2).name = "Mod_TeamCount";
		val2.transform.SetParent(parent, false);
		val2.transform.SetAsLastSibling();
		SliderOption slider = val2.GetComponent<SliderOption>();
		if ((Object)(object)slider == (Object)null)
		{
			slider = val2.GetComponentInChildren<SliderOption>(true);
		}
		if ((Object)(object)slider == (Object)null)
		{
			Object.Destroy((Object)(object)val2);
			return null;
		}
		SetSliderTitleText(((Component)slider).gameObject, slider, "Teams Count");
		slider.SetLimits(2f, 4f);
		slider.Initialize((Action)delegate
		{
			OnTeamCountSliderChanged(slider);
		}, (float)_teamCount);
		UpdateTeamCountVisual(slider);
		return slider;
	}

	private static DropdownOption CreateDropdownOptionClone(MatchSetupRules rules, Transform parent, string cloneName)
	{
		if ((Object)(object)rules == (Object)null || (Object)(object)parent == (Object)null || ScoreOptionTemplateField == null)
		{
			return null;
		}
		object? value = ScoreOptionTemplateField.GetValue(rules);
		DropdownOption val = (DropdownOption)((value is DropdownOption) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
		{
			return null;
		}
		GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject);
		if ((Object)(object)val2 == (Object)null)
		{
			return null;
		}
		((Object)val2).name = cloneName;
		val2.transform.SetParent(parent, false);
		val2.transform.SetAsLastSibling();
		DropdownOption val3 = val2.GetComponent<DropdownOption>();
		if ((Object)(object)val3 == (Object)null)
		{
			val3 = val2.GetComponentInChildren<DropdownOption>(true);
		}
		if ((Object)(object)val3 == (Object)null)
		{
			Object.Destroy((Object)(object)val2);
			return null;
		}
		return val3;
	}

	private static List<MatchSetupPlayer> GetMenuPlayers(MatchSetupMenu menu)
	{
		List<MatchSetupPlayer> list = new List<MatchSetupPlayer>();
		if ((Object)(object)menu == (Object)null || MatchSetupMenuPlayersField == null)
		{
			return list;
		}
		object value = MatchSetupMenuPlayersField.GetValue(menu);
		if (value is List<MatchSetupPlayer> list2)
		{
			for (int i = 0; i < list2.Count; i++)
			{
				MatchSetupPlayer val = list2[i];
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val);
				}
			}
			return list;
		}
		if (value is IList list3)
		{
			for (int j = 0; j < list3.Count; j++)
			{
				object? obj = list3[j];
				MatchSetupPlayer val2 = (MatchSetupPlayer)((obj is MatchSetupPlayer) ? obj : null);
				if ((Object)(object)val2 != (Object)null)
				{
					list.Add(val2);
				}
			}
		}
		return list;
	}

	private static string GetPlayerNameByGuid(ulong playerGuid)
	{
		if (playerGuid == 0 || CourseManagerPlayerStatesProperty == null || PlayerStateGuidField == null || PlayerStateNameField == null)
		{
			return "Player";
		}
		object value = CourseManagerPlayerStatesProperty.GetValue(null, null);
		if (!(value is IList list))
		{
			return "Player";
		}
		for (int i = 0; i < list.Count; i++)
		{
			object obj = list[i];
			if (obj == null)
			{
				continue;
			}
			ulong num = (ulong)PlayerStateGuidField.GetValue(obj);
			if (num == playerGuid)
			{
				string text = PlayerStateNameField.GetValue(obj) as string;
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
				return "Player";
			}
		}
		return "Player";
	}

	private static string GetMatchSetupPlayerName(MatchSetupPlayer player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return "Player";
		}
		TMP_Text val = (TMP_Text)((MatchSetupPlayerNicknameField != null) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val != (Object)null && !string.IsNullOrWhiteSpace(val.text))
		{
			return val.text;
		}
		return GetPlayerNameByGuid(player.Guid);
	}

	private static List<DropdownOption> RebuildTeamAssignmentOptions(MatchSetupMenu menu, MatchSetupRules rules, Transform tabRoot, bool forceRebuild = false)
	{
		if (!TeamAssignmentOptionsByMenu.TryGetValue(menu, out var value) || value == null)
		{
			value = new List<DropdownOption>();
			TeamAssignmentOptionsByMenu[menu] = value;
		}
		if ((Object)(object)rules == (Object)null || (Object)(object)tabRoot == (Object)null)
		{
			return value;
		}
		string text = BuildTeamAssignmentSignature(menu);
		if (!forceRebuild && TeamAssignmentSignatureByMenu.TryGetValue(menu, out var value2) && string.Equals(text, value2, StringComparison.Ordinal) && value.Count > 0)
		{
			return value;
		}
		for (int i = 0; i < value.Count; i++)
		{
			DropdownOption val = value[i];
			if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}
		value.Clear();
		EnsureTeamAssignmentsForConnectedPlayers();
		List<MatchSetupPlayer> menuPlayers = GetMenuPlayers(menu);
		for (int j = 0; j < menuPlayers.Count; j++)
		{
			MatchSetupPlayer val2 = menuPlayers[j];
			if ((Object)(object)val2 == (Object)null || val2.Guid == 0)
			{
				continue;
			}
			ulong guid = val2.Guid;
			string matchSetupPlayerName = GetMatchSetupPlayerName(val2);
			DropdownOption option = CreateDropdownOptionClone(rules, tabRoot, "Mod_Team_" + guid);
			if ((Object)(object)option == (Object)null)
			{
				continue;
			}
			int teamForPlayerGuid = GetTeamForPlayerGuid(guid);
			int num = Mathf.Clamp(teamForPlayerGuid - 1, 0, _teamCount - 1);
			_updatingTeamAssignmentOption = true;
			try
			{
				option.Initialize((Action)delegate
				{
					OnPlayerTeamChanged(option, guid);
				}, num);
			}
			finally
			{
				_updatingTeamAssignmentOption = false;
			}
			option.SetOptions(BuildTeamOptions());
			option.valueWithoutNotify = num;
			SetDropdownTitleText(((Component)option).gameObject, option, matchSetupPlayerName + " team");
			value.Add(option);
		}
		TeamAssignmentSignatureByMenu[menu] = text;
		return value;
	}

	private static void TryCreateGoalsTab(MatchSetupMenu menu)
	{
		//IL_035d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0369: Unknown result type (might be due to invalid IL or missing references)
		//IL_0375: Unknown result type (might be due to invalid IL or missing references)
		//IL_0381: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d2: Expected O, but got Unknown
		//IL_0583: Unknown result type (might be due to invalid IL or missing references)
		//IL_0588: Unknown result type (might be due to invalid IL or missing references)
		//IL_0556: Unknown result type (might be due to invalid IL or missing references)
		//IL_055b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)menu == (Object)null || MatchSetupMenuRulesField == null || MenuTabsButtonsField == null || MenuTabsTabsField == null)
		{
			return;
		}
		SliderOption value;
		bool flag = GoalsSliderByMenu.TryGetValue(menu, out value) && (Object)(object)value != (Object)null;
		DropdownOption value2;
		bool flag2 = ScoreEachGoalOptionByMenu.TryGetValue(menu, out value2) && (Object)(object)value2 != (Object)null;
		SliderOption value3;
		bool flag3 = ScoreEachGoalPointsSliderByMenu.TryGetValue(menu, out value3) && (Object)(object)value3 != (Object)null;
		DropdownOption value4;
		bool flag4 = GameModeOptionByMenu.TryGetValue(menu, out value4) && (Object)(object)value4 != (Object)null;
		DropdownOption value5;
		bool flag5 = CompetitiveScoringModeOptionByMenu.TryGetValue(menu, out value5) && (Object)(object)value5 != (Object)null;
		SliderOption value6;
		bool flag6 = TeamCountSliderByMenu.TryGetValue(menu, out value6) && (Object)(object)value6 != (Object)null;
		Transform value7;
		bool flag7 = GoalsTabRootByMenu.TryGetValue(menu, out value7) && (Object)(object)value7 != (Object)null;
		object? value8 = MatchSetupMenuRulesField.GetValue(menu);
		MatchSetupRules val = (MatchSetupRules)((value8 is MatchSetupRules) ? value8 : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		if (flag && flag2 && flag3 && flag4 && flag5 && flag6 && flag7)
		{
			List<DropdownOption> teamOptions = RebuildTeamAssignmentOptions(menu, val, value7);
			PositionGoalsTabControls(value, value2, value3, value4, value5, value6, teamOptions);
			return;
		}
		MenuTabs menuTabs = ((Component)menu).GetComponentInChildren<MenuTabs>(true);
		if ((Object)(object)menuTabs == (Object)null)
		{
			return;
		}
		Button[] array = MenuTabsButtonsField.GetValue(menuTabs) as Button[];
		GameObject[] array2 = MenuTabsTabsField.GetValue(menuTabs) as GameObject[];
		if (array == null || array2 == null || array.Length == 0 || array2.Length == 0 || array.Length != array2.Length)
		{
			return;
		}
		int num = array2.Length - 1;
		Button val2 = array[num];
		GameObject val3 = array2[num];
		if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
		{
			return;
		}
		GameObject val4 = Object.Instantiate<GameObject>(((Component)val2).gameObject);
		if ((Object)(object)val4 == (Object)null)
		{
			return;
		}
		((Object)val4).name = "Mod_GoalsTabButton";
		val4.transform.SetParent(((Component)val2).transform.parent, false);
		val4.transform.SetAsLastSibling();
		RemoveLocalizationComponents(val4);
		Button component = val4.GetComponent<Button>();
		if ((Object)(object)component == (Object)null)
		{
			Object.Destroy((Object)(object)val4);
			return;
		}
		TMP_Text[] componentsInChildren = val4.GetComponentsInChildren<TMP_Text>(true);
		foreach (TMP_Text val5 in componentsInChildren)
		{
			if ((Object)(object)val5 != (Object)null)
			{
				val5.text = "MultiGoal";
			}
		}
		GameObject val6 = Object.Instantiate<GameObject>(val3);
		if ((Object)(object)val6 == (Object)null)
		{
			Object.Destroy((Object)(object)val4);
			return;
		}
		((Object)val6).name = "Mod_GoalsTab";
		val6.transform.SetParent(val3.transform.parent, false);
		val6.transform.SetAsLastSibling();
		for (int num2 = val6.transform.childCount - 1; num2 >= 0; num2--)
		{
			Object.Destroy((Object)(object)((Component)val6.transform.GetChild(num2)).gameObject);
		}
		LayoutGroup component2 = val6.GetComponent<LayoutGroup>();
		if ((Object)(object)component2 != (Object)null)
		{
			((Behaviour)component2).enabled = false;
		}
		ContentSizeFitter component3 = val6.GetComponent<ContentSizeFitter>();
		if ((Object)(object)component3 != (Object)null)
		{
			((Behaviour)component3).enabled = false;
		}
		Transform transform = val6.transform;
		RectTransform val7 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
		if ((Object)(object)val7 != (Object)null)
		{
			val7.anchorMin = Vector2.zero;
			val7.anchorMax = Vector2.one;
			val7.offsetMin = Vector2.zero;
			val7.offsetMax = Vector2.zero;
		}
		SliderOption val8 = CreateGoalsSliderFromTemplate(val, val6.transform);
		DropdownOption val9 = CreateScoreEachGoalOptionFromTemplate(val, val6.transform);
		SliderOption val10 = CreateScoreEachGoalPointsSliderFromTemplate(val, val6.transform);
		DropdownOption val11 = CreateGameModeOptionFromTemplate(val, val6.transform);
		DropdownOption val12 = CreateCompetitiveScoringModeOptionFromTemplate(val, val6.transform);
		SliderOption val13 = CreateTeamCountSliderFromTemplate(val, val6.transform);
		if ((Object)(object)val8 == (Object)null || (Object)(object)val9 == (Object)null || (Object)(object)val10 == (Object)null || (Object)(object)val11 == (Object)null || (Object)(object)val12 == (Object)null || (Object)(object)val13 == (Object)null)
		{
			Object.Destroy((Object)(object)val6);
			Object.Destroy((Object)(object)val4);
			return;
		}
		GoalsTabRootByMenu[menu] = val6.transform;
		List<DropdownOption> teamOptions2 = RebuildTeamAssignmentOptions(menu, val, val6.transform);
		PositionGoalsTabControls(val8, val9, val10, val11, val12, val13, teamOptions2);
		val6.SetActive(false);
		Button[] array3 = (Button[])(object)new Button[array.Length + 1];
		Array.Copy(array, array3, array.Length);
		array3[^1] = component;
		MenuTabsButtonsField.SetValue(menuTabs, array3);
		GameObject[] array4 = (GameObject[])(object)new GameObject[array2.Length + 1];
		Array.Copy(array2, array4, array2.Length);
		array4[^1] = val6;
		MenuTabsTabsField.SetValue(menuTabs, array4);
		if (MenuTabsTextColorsField != null)
		{
			Color[] array5 = MenuTabsTextColorsField.GetValue(menuTabs) as Color[];
			Color[] array6 = (Color[])(object)new Color[array3.Length];
			if (array5 != null)
			{
				Array.Copy(array5, array6, Mathf.Min(array5.Length, array6.Length));
			}
			if (componentsInChildren.Length > 0 && (Object)(object)componentsInChildren[0] != (Object)null)
			{
				ref Color reference = ref array6[^1];
				reference = ((Graphic)componentsInChildren[0]).color;
			}
			else if (array6.Length > 1)
			{
				ref Color reference2 = ref array6[^1];
				reference2 = array6[^2];
			}
			MenuTabsTextColorsField.SetValue(menuTabs, array6);
		}
		int goalsTabIndex = array3.Length - 1;
		((UnityEventBase)component.onClick).RemoveAllListeners();
		((UnityEvent)component.onClick).AddListener((UnityAction)delegate
		{
			menuTabs.SelectTab(goalsTabIndex);
		});
		GoalsSliderByMenu[menu] = val8;
		ScoreEachGoalOptionByMenu[menu] = val9;
		ScoreEachGoalPointsSliderByMenu[menu] = val10;
		GameModeOptionByMenu[menu] = val11;
		CompetitiveScoringModeOptionByMenu[menu] = val12;
		TeamCountSliderByMenu[menu] = val13;
		Canvas.ForceUpdateCanvases();
		if ((Object)(object)val7 != (Object)null)
		{
			LayoutRebuilder.ForceRebuildLayoutImmediate(val7);
		}
		if (Log != null)
		{
			Log.LogInfo((object)"Added tab: MultiGoal");
		}
	}

	private static void RemoveLocalizationComponents(GameObject root)
	{
		if ((Object)(object)root == (Object)null)
		{
			return;
		}
		Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
		foreach (Component val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null))
			{
				Type type = ((object)val).GetType();
				if (!(type == null) && type.FullName != null && (type.FullName == "UnityEngine.Localization.Components.LocalizeStringEvent" || type.FullName == "UnityEngine.Localization.Components.LocalizeSpriteEvent" || type.Name == "LocalizeDropdown"))
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}
	}

	private static void SetSliderTitleText(GameObject sliderRoot, SliderOption slider, string title)
	{
		if ((Object)(object)sliderRoot == (Object)null || (Object)(object)slider == (Object)null || string.IsNullOrEmpty(title))
		{
			return;
		}
		RemoveLocalizationComponents(sliderRoot);
		TextMeshProUGUI objB = null;
		if (SliderLabelField != null)
		{
			object? value = SliderLabelField.GetValue(slider);
			objB = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
		}
		TextMeshProUGUI[] componentsInChildren = sliderRoot.GetComponentsInChildren<TextMeshProUGUI>(true);
		foreach (TextMeshProUGUI val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && !object.ReferenceEquals(val, objB))
			{
				((TMP_Text)val).text = title;
				break;
			}
		}
	}

	private static void SetDropdownTitleText(GameObject optionRoot, DropdownOption option, string title)
	{
		if ((Object)(object)optionRoot == (Object)null || (Object)(object)option == (Object)null || string.IsNullOrEmpty(title))
		{
			return;
		}
		RemoveLocalizationComponents(optionRoot);
		TMP_Dropdown val = null;
		if (DropdownField != null)
		{
			object? value = DropdownField.GetValue(option);
			val = (TMP_Dropdown)((value is TMP_Dropdown) ? value : null);
		}
		TMP_Text objB = (((Object)(object)val != (Object)null) ? val.captionText : null);
		TMP_Text objB2 = (((Object)(object)val != (Object)null) ? val.itemText : null);
		TextMeshProUGUI[] componentsInChildren = optionRoot.GetComponentsInChildren<TextMeshProUGUI>(true);
		foreach (TextMeshProUGUI val2 in componentsInChildren)
		{
			if (!((Object)(object)val2 == (Object)null) && !object.ReferenceEquals(val2, objB) && !object.ReferenceEquals(val2, objB2))
			{
				((TMP_Text)val2).text = title;
				break;
			}
		}
	}

	private static void PositionGoalsTabControls(SliderOption goalsSlider, DropdownOption scoreOption, SliderOption scorePointsSlider, DropdownOption gameModeOption, DropdownOption competitiveScoringModeOption, SliderOption teamCountSlider, List<DropdownOption> teamOptions)
	{
		float num = -34f;
		PositionControlRect((RectTransform)(((Object)(object)goalsSlider != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
		num -= 72f;
		PositionControlRect((RectTransform)(((Object)(object)scoreOption != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
		num -= 72f;
		PositionControlRect((RectTransform)(((Object)(object)scorePointsSlider != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
		num -= 72f;
		PositionControlRect((RectTransform)(((Object)(object)gameModeOption != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
		num -= 72f;
		PositionControlRect((RectTransform)(((Object)(object)competitiveScoringModeOption != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
		num -= 72f;
		PositionControlRect((RectTransform)(((Object)(object)teamCountSlider != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
		num -= 72f;
		if (teamOptions != null)
		{
			for (int i = 0; i < teamOptions.Count; i++)
			{
				DropdownOption val = teamOptions[i];
				PositionControlRect((RectTransform)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), num);
				num -= 66f;
			}
		}
	}

	private static void PositionControlRect(RectTransform rect, float yOffset)
	{
		PositionControlRect(rect, yOffset, 0f);
	}

	private static void PositionControlRect(RectTransform rect, float yOffset, float xOffset)
	{
		//IL_0038: 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_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)rect == (Object)null))
		{
			LayoutElement val = ((Component)rect).GetComponent<LayoutElement>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)rect).gameObject.AddComponent<LayoutElement>();
			}
			val.ignoreLayout = true;
			rect.anchorMin = new Vector2(0.5f, 1f);
			rect.anchorMax = new Vector2(0.5f, 1f);
			rect.pivot = new Vector2(0.5f, 1f);
			rect.anchoredPosition = new Vector2(xOffset, yOffset);
		}
	}

	private static void UpdateGoalsSliderVisual(SliderOption slider)
	{
		if (!((Object)(object)slider == (Object)null))
		{
			SetSliderTitleText(((Component)slider).gameObject, slider, "Goals Required");
			slider.valueWithoutNotify = _requiredGoals;
			slider.SetValueText(_requiredGoals.ToString());
		}
	}

	private static void UpdateScoreEachGoalVisual(DropdownOption option)
	{
		if (!((Object)(object)option == (Object)null))
		{
			option.SetOptions(new List<string> { "Off", "On" });
			SetDropdownTitleText(((Component)option).gameObject, option, "Score for each goal");
			option.valueWithoutNotify = (_scoreEachGoal ? 1 : 0);
		}
	}

	private static void UpdateScoreEachGoalPointsVisual(SliderOption slider)
	{
		if (!((Object)(object)slider == (Object)null))
		{
			SetSliderTitleText(((Component)slider).gameObject, slider, "Points per goal");
			slider.valueWithoutNotify = _scoreEachGoalPoints;
			slider.SetValueText(_scoreEachGoalPoints.ToString());
		}
	}

	private static void UpdateGameModeVisual(DropdownOption option)
	{
		if (!((Object)(object)option == (Object)null))
		{
			option.SetOptions(new List<string> { "Standard", "Team Chaos", "Team Competitive" });
			SetDropdownTitleText(((Component)option).gameObject, option, "Game Mode");
			option.valueWithoutNotify = (int)_gameMode;
		}
	}

	private static void UpdateCompetitiveScoringModeVisual(DropdownOption option)
	{
		if (!((Object)(object)option == (Object)null))
		{
			option.SetOptions(new List<string> { "Simple (Decrement)" });
			SetDropdownTitleText(((Component)option).gameObject, option, "Competitive scoring mode");
			option.valueWithoutNotify = (int)_competitiveScoringMode;
		}
	}

	private static void UpdateTeamCountVisual(SliderOption slider)
	{
		if (!((Object)(object)slider == (Object)null))
		{
			SetSliderTitleText(((Component)slider).gameObject, slider, "Teams Count");
			slider.valueWithoutNotify = _teamCount;
			slider.SetValueText(_teamCount.ToString());
		}
	}

	private static void RebuildAllTeamAssignmentOptions()
	{
		List<MatchSetupMenu> list = new List<MatchSetupMenu>(GoalsTabRootByMenu.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			MatchSetupMenu val = list[i];
			if (!((Object)(object)val == (Object)null))
			{
				MatchSetupRules val2 = (MatchSetupRules)((MatchSetupMenuRulesField != null) ? /*isinst with value type is only supported in some contexts*/: null);
				Transform value = null;
				GoalsTabRootByMenu.TryGetValue(val, out value);
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)value == (Object)null))
				{
					List<DropdownOption> teamOptions = RebuildTeamAssignmentOptions(val, val2, value, forceRebuild: true);
					SliderOption value2 = null;
					DropdownOption value3 = null;
					SliderOption value4 = null;
					DropdownOption value5 = null;
					DropdownOption value6 = null;
					SliderOption value7 = null;
					GoalsSliderByMenu.TryGetValue(val, out value2);
					ScoreEachGoalOptionByMenu.TryGetValue(val, out value3);
					ScoreEachGoalPointsSliderByMenu.TryGetValue(val, out value4);
					GameModeOptionByMenu.TryGetValue(val, out value5);
					CompetitiveScoringModeOptionByMenu.TryGetValue(val, out value6);
					TeamCountSliderByMenu.TryGetValue(val, out value7);
					PositionGoalsTabControls(value2, value3, value4, value5, value6, value7, teamOptions);
				}
			}
		}
	}

	private static void OnGoalsSliderChanged(SliderOption slider)
	{
		if ((Object)(object)slider == (Object)null || _updatingSlider)
		{
			return;
		}
		_updatingSlider = true;
		try
		{
			int num = (_requiredGoals = ClampGoals(Mathf.RoundToInt(slider.value)));
			if (_goalsConfig != null)
			{
				_goalsConfig.Value = num;
			}
			slider.valueWithoutNotify = num;
			slider.SetValueText(num.ToString());
			RequestScoreboardRefresh();
			if (Log != null)
			{
				Log.LogInfo((object)("Updated Goals Required: " + num));
			}
		}
		finally
		{
			_updatingSlider = false;
		}
	}

	private static void OnScoreEachGoalChanged(DropdownOption option)
	{
		if ((Object)(object)option == (Object)null || _updatingScoreOption)
		{
			return;
		}
		_updatingScoreOption = true;
		try
		{
			bool flag = (_scoreEachGoal = option.value > 0);
			if (_scoreEachGoalConfig != null)
			{
				_scoreEachGoalConfig.Value = flag;
			}
			option.valueWithoutNotify = (flag ? 1 : 0);
			if (Log != null)
			{
				Log.LogInfo((object)("Updated Score for each goal: " + flag));
			}
		}
		finally
		{
			_updatingScoreOption = false;
		}
	}

	private static void OnScoreEachGoalPointsChanged(SliderOption slider)
	{
		if ((Object)(object)slider == (Object)null || _updatingScorePointsSlider)
		{
			return;
		}
		_updatingScorePointsSlider = true;
		try
		{
			int num = (_scoreEachGoalPoints = ClampScorePerGoal(Mathf.RoundToInt(slider.value)));
			if (_scoreEachGoalPointsConfig != null)
			{
				_scoreEachGoalPointsConfig.Value = num;
			}
			slider.valueWithoutNotify = num;
			slider.SetValueText(num.ToString());
			if (Log != null)
			{
				Log.LogInfo((object)("Updated Points per goal: " + num));
			}
		}
		finally
		{
			_updatingScorePointsSlider = false;
		}
	}

	private static void OnGameModeChanged(DropdownOption option)
	{
		if ((Object)(object)option == (Object)null || _updatingGameModeOption)
		{
			return;
		}
		_updatingGameModeOption = true;
		try
		{
			_gameMode = ParseGameMode(option.value);
			if (_gameModeConfig != null)
			{
				_gameModeConfig.Value = (int)_gameMode;
			}
			option.valueWithoutNotify = (int)_gameMode;
			ClearScoringProgress();
			RebuildAllTeamAssignmentOptions();
			RequestScoreboardRefresh();
			if (Log != null)
			{
				Log.LogInfo((object)("Updated Game Mode: " + _gameMode));
			}
		}
		finally
		{
			_updatingGameModeOption = false;
		}
	}

	private static void OnCompetitiveScoringModeChanged(DropdownOption option)
	{
		if ((Object)(object)option == (Object)null || _updatingCompetitiveScoringModeOption)
		{
			return;
		}
		_updatingCompetitiveScoringModeOption = true;
		try
		{
			_competitiveScoringMode = ParseCompetitiveScoringMode(option.value);
			if (_competitiveScoringModeConfig != null)
			{
				_competitiveScoringModeConfig.Value = (int)_competitiveScoringMode;
			}
			option.valueWithoutNotify = (int)_competitiveScoringMode;
			if (Log != null)
			{
				Log.LogInfo((object)("Updated Competitive scoring mode: " + _competitiveScoringMode));
			}
		}
		finally
		{
			_updatingCompetitiveScoringModeOption = false;
		}
	}

	private static void OnTeamCountSliderChanged(SliderOption slider)
	{
		if ((Object)(object)slider == (Object)null || _updatingTeamCountSlider)
		{
			return;
		}
		_updatingTeamCountSlider = true;
		try
		{
			int num = (_teamCount = ClampTeamCount(Mathf.RoundToInt(slider.value)));
			if (_teamCountConfig != null)
			{
				_teamCountConfig.Value = num;
			}
			slider.valueWithoutNotify = num;
			slider.SetValueText(num.ToString());
			List<ulong> list = new List<ulong>(TeamByPlayerGuid.Keys);
			for (int i = 0; i < list.Count; i++)
			{
				ulong key = list[i];
				TeamByPlayerGuid[key] = ClampTeam(TeamByPlayerGuid[key]);
			}
			SaveTeamAssignments();
			RebuildAllTeamAssignmentOptions();
			RequestScoreboardRefresh();
			if (Log != null)
			{
				Log.LogInfo((object)("Updated Teams Count: " + num));
			}
		}
		finally
		{
			_updatingTeamCountSlider = false;
		}
	}

	private static void OnPlayerTeamChanged(DropdownOption option, ulong playerGuid)
	{
		if ((Object)(object)option == (Object)null || _updatingTeamAssignmentOption || playerGuid == 0)
		{
			return;
		}
		_updatingTeamAssignmentOption = true;
		try
		{
			int num = ClampTeam(option.value + 1);
			TeamByPlayerGuid[playerGuid] = num;
			SaveTeamAssignments();
			option.valueWithoutNotify = num - 1;
			RequestScoreboardRefresh();
		}
		finally
		{
			_updatingTeamAssignmentOption = false;
		}
	}

	private static int AwardIntermediateGoalScore(PlayerGolfer owner)
	{
		if (!_scoreEachGoal || (Object)(object)owner == (Object)null || (Object)(object)owner.PlayerInfo == (Object)null)
		{
			return 0;
		}
		try
		{
			int num = ClampScorePerGoal(_scoreEachGoalPoints);
			bool flag = TryAdjustPlayerScore(GetPlayerGuid(owner.PlayerInfo), num);
			if (flag && Log != null)
			{
				string playerDisplayName = GetPlayerDisplayName(owner.PlayerInfo);
				Log.LogInfo((object)("Awarded +" + num + " score for intermediate goal to " + playerDisplayName + "."));
			}
			return flag ? num : 0;
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogError((object)("Failed to award intermediate goal score: " + ex));
			}
		}
		return 0;
	}

	private static bool TryAdjustPlayerScore(ulong playerGuid, int scoreDelta)
	{
		if (scoreDelta == 0 || CourseManagerPlayerStatesProperty == null || PlayerStateGuidField == null || PlayerStateCourseScoreField == null || PlayerStateMatchScoreField == null)
		{
			return false;
		}
		object value = CourseManagerPlayerStatesProperty.GetValue(null, null);
		if (value == null)
		{
			return false;
		}
		if (!(value is IList list))
		{
			Type type = value.GetType();
			PropertyInfo propertyInfo = AccessTools.Property(type, "Count");
			PropertyInfo propertyInfo2 = AccessTools.Property(type, "Item");
			if (propertyInfo == null || propertyInfo2 == null || !propertyInfo2.CanRead || !propertyInfo2.CanWrite)
			{
				return false;
			}
			int num = (int)propertyInfo.GetValue(value, null);
			object[] array = new object[1];
			for (int i = 0; i < num; i++)
			{
				array[0] = i;
				object value2 = propertyInfo2.GetValue(value, array);
				if (value2 == null)
				{
					continue;
				}
				ulong num2 = (ulong)PlayerStateGuidField.GetValue(value2);
				if (num2 == playerGuid)
				{
					int num3 = (int)PlayerStateCourseScoreField.GetValue(value2);
					int num4 = (int)PlayerStateMatchScoreField.GetValue(value2);
					PlayerStateCourseScoreField.SetValue(value2, num3 + scoreDelta);
					PlayerStateMatchScoreField.SetValue(value2, num4 + scoreDelta);
					if (PlayerStateScoreTimestampField != null)
					{
						PlayerStateScoreTimestampField.SetValue(value2, NetworkTime.time);
					}
					propertyInfo2.SetValue(value, value2, array);
					return true;
				}
			}
			return false;
		}
		for (int j = 0; j < list.Count; j++)
		{
			object obj = list[j];
			if (obj == null)
			{
				continue;
			}
			ulong num5 = (ulong)PlayerStateGuidField.GetValue(obj);
			if (num5 == playerGuid)
			{
				int num6 = (int)PlayerStateCourseScoreField.GetValue(obj);
				int num7 = (int)PlayerStateMatchScoreField.GetValue(obj);
				PlayerStateCourseScoreField.SetValue(obj, num6 + scoreDelta);
				PlayerStateMatchScoreField.SetValue(obj, num7 + scoreDelta);
				if (PlayerStateScoreTimestampField != null)
				{
					PlayerStateScoreTimestampField.SetValue(obj, NetworkTime.time);
				}
				list[j] = obj;
				return true;
			}
		}
		return false;
	}

	private static bool TrySetPlayerRoundScore(ulong playerGuid, int roundScore)
	{
		if (CourseManagerPlayerStatesProperty == null || PlayerStateGuidField == null || PlayerStateCourseScoreField == null || PlayerStateMatchScoreField == null)
		{
			return false;
		}
		object value = CourseManagerPlayerStatesProperty.GetValue(null, null);
		if (value == null)
		{
			return false;
		}
		if (!(value is IList list))
		{
			Type type = value.GetType();
			PropertyInfo propertyInfo = AccessTools.Property(type, "Count");
			PropertyInfo propertyInfo2 = AccessTools.Property(type, "Item");
			if (propertyInfo == null || propertyInfo2 == null || !propertyInfo2.CanRead || !propertyInfo2.CanWrite)
			{
				return false;
			}
			int num = (int)propertyInfo.GetValue(value, null);
			object[] array = new object[1];
			for (int i = 0; i < num; i++)
			{
				array[0] = i;
				object value2 = propertyInfo2.GetValue(value, array);
				if (value2 == null)
				{
					continue;
				}
				ulong num2 = (ulong)PlayerStateGuidField.GetValue(value2);
				if (num2 == playerGuid)
				{
					int num3 = (int)PlayerStateMatchScoreField.GetValue(value2);
					int num4 = (int)PlayerStateCourseScoreField.GetValue(value2);
					int num5 = roundScore - num3;
					PlayerStateMatchScoreField.SetValue(value2, roundScore);
					PlayerStateCourseScoreField.SetValue(value2, num4 + num5);
					if (PlayerStateScoreTimestampField != null)
					{
						PlayerStateScoreTimestampField.SetValue(value2, NetworkTime.time);
					}
					propertyInfo2.SetValue(value, value2, array);
					return true;
				}
			}
			return false;
		}
		for (int j = 0; j < list.Count; j++)
		{
			object obj = list[j];
			if (obj == null)
			{
				continue;
			}
			ulong num6 = (ulong)PlayerStateGuidField.GetValue(obj);
			if (num6 == playerGuid)
			{
				int num7 = (int)PlayerStateMatchScoreField.GetValue(obj);
				int num8 = (int)PlayerStateCourseScoreField.GetValue(obj);
				int num9 = roundScore - num7;
				PlayerStateMatchScoreField.SetValue(obj, roundScore);
				PlayerStateCourseScoreField.SetValue(obj, num8 + num9);
				if (PlayerStateScoreTimestampField != null)
				{
					PlayerStateScoreTimestampField.SetValue(obj, NetworkTime.time);
				}
				list[j] = obj;
				return true;
			}
		}
		return false;
	}

	private static bool TryGetAllPlayerMatchScores(Dictionary<ulong, int> scoresByPlayerGuid)
	{
		if (scoresByPlayerGuid == null || CourseManagerPlayerStatesProperty == null || PlayerStateGuidField == null || PlayerStateMatchScoreField == null)
		{
			return false;
		}
		scoresByPlayerGuid.Clear();
		object value = CourseManagerPlayerStatesProperty.GetValue(null, null);
		if (value == null)
		{
			return false;
		}
		if (value is IList list)
		{
			for (int i = 0; i < list.Count; i++)
			{
				object obj = list[i];
				if (obj != null)
				{
					ulong num = (ulong)PlayerStateGuidField.GetValue(obj);
					if (num != 0)
					{
						int value2 = (int)PlayerStateMatchScoreField.GetValue(obj);
						scoresByPlayerGuid[num] = value2;
					}
				}
			}
			return scoresByPlayerGuid.Count > 0;
		}
		Type type = value.GetType();
		PropertyInfo propertyInfo = AccessTools.Property(type, "Count");
		PropertyInfo propertyInfo2 = AccessTools.Property(type, "Item");
		if (propertyInfo == null || propertyInfo2 == null || !propertyInfo2.CanRead)
		{
			return false;
		}
		int num2 = (int)propertyInfo.GetValue(value, null);
		object[] array = new object[1];
		for (int j = 0; j < num2; j++)
		{
			array[0] = j;
			object value3 = propertyInfo2.GetValue(value, array);
			if (value3 != null)
			{
				ulong num3 = (ulong)PlayerStateGuidField.GetValue(value3);
				if (num3 != 0)
				{
					int value4 = (int)PlayerStateMatchScoreField.GetValue(value3);
					scoresByPlayerGuid[num3] = value4;
				}
			}
		}
		return scoresByPlayerGuid.Count > 0;
	}

	private static void AddPendingMirroredDelta(ulong playerGuid, int delta)
	{
		if (playerGuid != 0 && delta > 0)
		{
			int value = 0;
			PendingMirroredScoreDeltaByPlayer.TryGetValue(playerGuid, out value);
			PendingMirroredScoreDeltaByPlayer[playerGuid] = value + delta;
		}
	}

	private static void MirrorScoreDeltaToTeam(ulong scoringPlayerGuid, int scoreDelta, Dictionary<ulong, int> snapshot)
	{
		if (scoringPlayerGuid == 0 || scoreDelta <= 0 || snapshot == null)
		{
			return;
		}
		int teamForPlayerGuid = GetTeamForPlayerGuid(scoringPlayerGuid);
		bool flag = false;
		foreach (KeyValuePair<ulong, int> item in snapshot)
		{
			ulong key = item.Key;
			if (key != 0 && key != scoringPlayerGuid && GetTeamForPlayerGuid(key) == teamForPlayerGuid && TryAdjustPlayerScore(key, scoreDelta))
			{
				AddPendingMirroredDelta(key, scoreDelta);
				flag = true;
			}
		}
		if (flag)
		{
			RequestScoreboardRefresh();
			if (Log != null)
			{
				string playerNameByGuid = GetPlayerNameByGuid(scoringPlayerGuid);
				Log.LogInfo((object)("Mirrored +" + scoreDelta + " score from " + playerNameByGuid + " to teammates in " + GetTeamLabel(teamForPlayerGuid) + "."));
			}
		}
	}

	private static void MirrorKnownTeamScoreDelta(ulong scoringPlayerGuid, int scoreDelta)
	{
		if (NetworkServer.active && IsTeamChaosActive() && scoringPlayerGuid != 0 && scoreDelta > 0)
		{
			Dictionary<ulong, int> dictionary = new Dictionary<ulong, int>();
			if (TryGetAllPlayerMatchScores(dictionary))
			{
				AddPendingMirroredDelta(scoringPlayerGuid, scoreDelta);
				MirrorScoreDeltaToTeam(scoringPlayerGuid, scoreDelta, dictionary);
			}
		}
	}

	private static void SyncTeamChaosSharedScores()
	{
		if (!NetworkServer.active || !IsTeamChaosActive())
		{
			return;
		}
		Dictionary<ulong, int> dictionary = new Dictionary<ulong, int>();
		if (!TryGetAllPlayerMatchScores(dictionary))
		{
			return;
		}
		EnsureTeamAssignmentsForConnectedPlayers();
		HashSet<ulong> hashSet = new HashSet<ulong>(dictionary.Keys);
		foreach (KeyValuePair<ulong, int> item in dictionary)
		{
			ulong key = item.Key;
			int value = item.Value;
			int value2 = 0;
			if (!ObservedMatchScoreByPlayer.TryGetValue(key, out value2))
			{
				ObservedMatchScoreByPlayer[key] = value;
				continue;
			}
			int num = value - value2;
			if (num > 0)
			{
				int value3 = 0;
				PendingMirroredScoreDeltaByPlayer.TryGetValue(key, out value3);
				if (value3 > 0)
				{
					int num2 = Mathf.Min(num, value3);
					num -= num2;
					value3 -= num2;
					if (value3 > 0)
					{
						PendingMirroredScoreDeltaByPlayer[key] = value3;
					}
					else
					{
						PendingMirroredScoreDeltaByPlayer.Remove(key);
					}
				}
				if (num > 0)
				{
					MirrorScoreDeltaToTeam(key, num, dictionary);
				}
			}
			ObservedMatchScoreByPlayer[key] = value;
		}
		List<ulong> list = new List<ulong>(ObservedMatchScoreByPlayer.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			ulong num3 = list[i];
			if (!hashSet.Contains(num3))
			{
				ObservedMatchScoreByPlayer.Remove(num3);
			}
		}
		List<ulong> list2 = new List<ulong>(PendingMirroredScoreDeltaByPlayer.Keys);
		for (int j = 0; j < list2.Count; j++)
		{
			ulong num4 = list2[j];
			if (!hashSet.Contains(num4))
			{
				PendingMirroredScoreDeltaByPlayer.Remove(num4);
			}
		}
	}

	private static int GetTeamPlacementScore(int placementIndex)
	{
		if (placementIndex < 0)
		{
			return 0;
		}
		if (placementIndex < TeamPlacementScores.Length)
		{
			return TeamPlacementScores[placementIndex];
		}
		return TeamPlacementScores[TeamPlacementScores.Length - 1];
	}

	private static Dictionary<int, List<ulong>> BuildConnectedTeamRoster()
	{
		Dictionary<int, List<ulong>> dictionary = new Dictionary<int, List<ulong>>();
		List<ulong> knownParticipantGuids = GetKnownParticipantGuids();
		for (int i = 0; i < knownParticipantGuids.Count; i++)
		{
			ulong num = knownParticipantGuids[i];
			int teamForPlayerGuid = GetTeamForPlayerGuid(num);
			if (!dictionary.TryGetValue(teamForPlayerGuid, out var value))
			{
				value = (dictionary[teamForPlayerGuid] = new List<ulong>());
			}
			value.Add(num);
		}
		return dictionary;
	}

	private static void EnsureTeamChaosRoundScoreEntries(Dictionary<int, List<ulong>> roster)
	{
		HashSet<ulong> hashSet = new HashSet<ulong>();
		if (roster != null)
		{
			foreach (KeyValuePair<int, List<ulong>> item in roster)
			{
				List<ulong> value = item.Value;
				if (value == null)
				{
					continue;
				}
				for (int i = 0; i < value.Count; i++)
				{
					ulong num = value[i];
					if (num != 0)
					{
						hashSet.Add(num);
						if (!TeamChaosRoundScoreByPlayer.ContainsKey(num))
						{
							TeamChaosRoundScoreByPlayer[num] = 0;
						}
					}
				}
			}
		}
		List<ulong> list = new List<ulong>(TeamChaosRoundScoreByPlayer.Keys);
		for (int j = 0; j < list.Count; j++)
		{
			ulong num2 = list[j];
			if (!hashSet.Contains(num2))
			{
				TeamChaosRoundScoreByPlayer.Remove(num2);
			}
		}
	}

	private static bool ApplyTeamRoundScoreDelta(Dictionary<int, List<ulong>> roster, int teamId, int scoreDelta)
	{
		if (scoreDelta == 0 || roster == null)
		{
			return false;
		}
		List<ulong> value = null;
		if (!roster.TryGetValue(teamId, out value) || value == null || value.Count == 0)
		{
			return false;
		}
		bool result = false;
		for (int i = 0; i < value.Count; i++)
		{
			ulong num = value[i];
			int value2 = 0;
			TeamChaosRoundScoreByPlayer.TryGetValue(num, out value2);
			int num2 = value2 + scoreDelta;
			TeamChaosRoundScoreByPlayer[num] = num2;
			if (TrySetPlayerRoundScore(num, num2))
			{
				result = true;
			}
		}
		return result;
	}

	private static void AwardTeamIntermediateGoalScore(int teamId)
	{
		if (!_scoreEachGoal || !NetworkServer.active || !IsTeamChaosActive())
		{
			return;
		}
		int num = ClampScorePerGoal(_scoreEachGoalPoints);
		if (num <= 0)
		{
			return;
		}
		Dictionary<int, List<ulong>> dictionary = BuildConnectedTeamRoster();
		if (dictionary.Count == 0)
		{
			return;
		}
		EnsureTeamChaosRoundScoreEntries(dictionary);
		if (ApplyTeamRoundScoreDelta(dictionary, teamId, num))
		{
			RequestScoreboardRefresh();
			if (Log != null)
			{
				Log.LogInfo((object)("Awarded +" + num + " score to all players in " + GetTeamLabel(teamId) + " for an intermediate goal."));
			}
		}
	}

	private static void ApplyTeamPlacementScoresForCurrentHole()
	{
		if (!NetworkServer.active || !IsTeamChaosActive())
		{
			return;
		}
		int currentHoleGlobalIndex = CourseManager.CurrentHoleGlobalIndex;
		if (TeamScoresAppliedHoles.Contains(currentHoleGlobalIndex))
		{
			return;
		}
		EnsureTeamAssignmentsForConnectedPlayers();
		Dictionary<int, List<ulong>> dictionary = BuildConnectedTeamRoster();
		if (dictionary.Count == 0)
		{
			return;
		}
		EnsureTeamChaosRoundScoreEntries(dictionary);
		List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>();
		foreach (KeyValuePair<int, List<ulong>> item in dictionary)
		{
			int currentGoalsForTeam = GetCurrentGoalsForTeam(item.Key);
			list.Add(new KeyValuePair<int, int>(item.Key, currentGoalsForTeam));
		}
		list.Sort(delegate(KeyValuePair<int, int> a, KeyValuePair<int, int> b)
		{
			int num = b.Value.CompareTo(a.Value);
			return (num != 0) ? num : a.Key.CompareTo(b.Key);
		});
		for (int i = 0; i < list.Count; i++)
		{
			int key = list[i].Key;
			int teamPlacementScore = GetTeamPlacementScore(i);
			ApplyTeamRoundScoreDelta(dictionary, key, teamPlacementScore);
			if (Log != null)
			{
				Log.LogInfo((object)("Awarded +" + teamPlacementScore + " placement score to " + GetTeamLabel(key) + " (" + (i + 1) + " place)."));
			}
		}
		TeamScoresAppliedHoles.Add(currentHoleGlobalIndex);
		RequestScoreboardRefresh();
	}

	private static string BuildTeamCompetitivePlacementKey(ulong playerGuid)
	{
		return CourseManager.CurrentHoleGlobalIndex + ":C:" + playerGuid;
	}

	private static string BuildTeamCompetitiveScoreKey(int teamId)
	{
		return CourseManager.CurrentHoleGlobalIndex + ":CS:T" + teamId;
	}

	private static int GetTeamCompetitiveScriptScore(int teamId)
	{
		int value = 0;
		TeamCompetitiveScriptScoreByHoleAndTeam.TryGetValue(BuildTeamCompetitiveScoreKey(teamId), out value);
		return value;
	}

	private static int AddTeamCompetitiveScriptScore(int teamId, int scoreDelta)
	{
		if (scoreDelta == 0)
		{
			return GetTeamCompetitiveScriptScore(teamId);
		}
		string key = BuildTeamCompetitiveScoreKey(teamId);
		int value = 0;
		TeamCompetitiveScriptScoreByHoleAndTeam.TryGetValue(key, out value);
		int num = value + scoreDelta;
		TeamCompetitiveScriptScoreByHoleAndTeam[key] = num;
		return num;
	}

	private static bool SyncTeamCompetitiveScoreForTeam(Dictionary<int, List<ulong>> roster, int teamId)
	{
		if (roster == null)
		{
			return false;
		}
		List<ulong> value = null;
		if (!roster.TryGetValue(teamId, out value) || value == null || value.Count == 0)
		{
			return false;
		}
		int teamCompetitiveScriptScore = GetTeamCompetitiveScriptScore(teamId);
		bool result = false;
		for (int i = 0; i < value.Count; i++)
		{
			ulong num = value[i];
			if (num != 0)
			{
				TeamChaosRoundScoreByPlayer[num] = teamCompetitiveScriptScore;
				if (TrySetPlayerRoundScore(num, teamCompetitiveScriptScore))
				{
					result = true;
				}
			}
		}
		return result;
	}

	private static void SyncAllTeamCompetitiveScores()
	{
		if (!NetworkServer.active || !IsTeamCompetitiveActive())
		{
			return;
		}
		EnsureTeamAssignmentsForConnectedPlayers();
		Dictionary<int, List<ulong>> dictionary = BuildConnectedTeamRoster();
		if (dictionary.Count == 0)
		{
			return;
		}
		bool flag = false;
		foreach (KeyValuePair<int, List<ulong>> item in dictionary)
		{
			if (SyncTeamCompetitiveScoreForTeam(dictionary, item.Key))
			{
				flag = true;
			}
		}
		if (flag)
		{
			RequestScoreboardRefresh();
		}
	}

	private static bool TryRegisterTeamCompetitivePlacement(ulong playerGuid, out int placement, out int totalPlayers)
	{
		placement = 0;
		totalPlayers = 0;
		if (playerGuid == 0)
		{
			return false;
		}
		int currentHoleGlobalIndex = CourseManager.CurrentHoleGlobalIndex;
		string key = BuildTeamCompetitivePlacementKey(playerGuid);
		if (TeamCompetitivePlacementByPlayerAndHole.TryGetValue(key, out placement))
		{
			TeamCompetitiveTotalPlayersByHole.TryGetValue(currentHoleGlobalIndex, out totalPlayers);
			return false;
		}
		int value = 1;
		TeamCompetitiveNextPlacementByHole.TryGetValue(currentHoleGlobalIndex, out value);
		if (value < 1)
		{
			value = 1;
		}
		placement = value;
		TeamCompetitiveNextPlacementByHole[currentHoleGlobalIndex] = value + 1;
		TeamCompetitivePlacementByPlayerAndHole[key] = placement;
		if (!TeamCompetitiveTotalPlayersByHole.TryGetValue(currentHoleGlobalIndex, out totalPlayers) || totalPlayers < 1)
		{
			totalPlayers = Mathf.Max(GetKnownParticipantGuids().Count, 1);
		}
		if (placement > totalPlayers)
		{
			totalPlayers = placement;
		}
		TeamCompetitiveTotalPlayersByHole[currentHoleGlobalIndex] = totalPlayers;
		return true;
	}

	private static int GetTeamCompetitiveFinishScore(int totalPlayers, int placement)
	{
		if