Decompiled source of MultiGoals v1.8.1
BepInEx/plugins/SBGMultiGoals/SBGMultiGoals.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
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