Decompiled source of SBG Teams v1.0.0

SBG_Teams.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SBG_Teams")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+32ef81f0f533046f0a86bb7579ad5dc270254836")]
[assembly: AssemblyProduct("SBG Teams Mod")]
[assembly: AssemblyTitle("SBG_Teams")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SBGTeams
{
	internal class CallRPC : NetworkBehaviour
	{
		private struct RpcCallMessage : NetworkMessage
		{
			public string actionId;
		}

		private struct RpcCallMessageWithParam : NetworkMessage
		{
			public string actionId;

			public string param;
		}

		private struct CmdCallMessage : NetworkMessage
		{
			public string actionId;
		}

		private struct CmdCallMessageWithParam : NetworkMessage
		{
			public string actionId;

			public string param;
		}

		public static CallRPC Instance = null;

		private static Dictionary<string, Action> clientActions = new Dictionary<string, Action>();

		private static Dictionary<string, Action<string>> clientActionsWithParam = new Dictionary<string, Action<string>>();

		private static Dictionary<string, Action> serverActions = new Dictionary<string, Action>();

		private static Dictionary<string, Action<string>> serverActionsWithParam = new Dictionary<string, Action<string>>();

		private static Dictionary<string, Action<NetworkConnectionToClient, string>> serverActionsWithConn = new Dictionary<string, Action<NetworkConnectionToClient, string>>();

		public static Dictionary<ulong, NetworkConnectionToClient> ModdedClients = new Dictionary<ulong, NetworkConnectionToClient>();

		public static event Action OnSpawned;

		private void Awake()
		{
			Instance = this;
		}

		public override void OnStartClient()
		{
			CallRPC.OnSpawned?.Invoke();
		}

		public override void OnStartServer()
		{
			CallRPC.OnSpawned?.Invoke();
		}

		[Server]
		public static void RegisterModdedClient(ulong id, NetworkConnectionToClient conn)
		{
			ModdedClients[id] = conn;
			Plugin.Logger.LogInfo((object)$"Registered modded client: {id}");
		}

		[Server]
		public static void UnregisterModdedClient(ulong id)
		{
			if (ModdedClients.Remove(id))
			{
				Plugin.Logger.LogInfo((object)$"Unregistered modded client: {id}");
			}
		}

		[Server]
		public static bool IsModdedClient(ulong id)
		{
			return ModdedClients.ContainsKey(id);
		}

		[Server]
		public static void ClearModdedClients()
		{
			ModdedClients.Clear();
		}

		public static void Register()
		{
			RegisterRpc();
			CallRPCHelper.RegisterClass();
		}

		public static void RegisterClientAction(string id, Action action)
		{
			clientActions[id] = action;
		}

		public static void RegisterClientAction(string id, Action<string> action)
		{
			clientActionsWithParam[id] = action;
		}

		public static void RegisterServerAction(string id, Action action)
		{
			serverActions[id] = action;
		}

		public static void RegisterServerAction(string id, Action<NetworkConnectionToClient, string> action)
		{
			serverActionsWithConn[id] = action;
		}

		public static void RegisterServerAction(string id, Action<string> action)
		{
			serverActionsWithParam[id] = action;
		}

		private static void RegisterRpc()
		{
			Writer<RpcCallMessage>.write = delegate(NetworkWriter writer, RpcCallMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.actionId);
			};
			Reader<RpcCallMessage>.read = delegate(NetworkReader reader)
			{
				RpcCallMessage result4 = default(RpcCallMessage);
				result4.actionId = NetworkReaderExtensions.ReadString(reader);
				return result4;
			};
			NetworkClient.RegisterHandler<RpcCallMessage>((Action<RpcCallMessage>)OnReceiveCall, true);
			Writer<RpcCallMessageWithParam>.write = delegate(NetworkWriter writer, RpcCallMessageWithParam msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.actionId);
				NetworkWriterExtensions.WriteString(writer, msg.param);
			};
			Reader<RpcCallMessageWithParam>.read = delegate(NetworkReader reader)
			{
				RpcCallMessageWithParam result3 = default(RpcCallMessageWithParam);
				result3.actionId = NetworkReaderExtensions.ReadString(reader);
				result3.param = NetworkReaderExtensions.ReadString(reader);
				return result3;
			};
			NetworkClient.RegisterHandler<RpcCallMessageWithParam>((Action<RpcCallMessageWithParam>)OnReceiveCallWithParam, true);
			Writer<CmdCallMessage>.write = delegate(NetworkWriter writer, CmdCallMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.actionId);
			};
			Reader<CmdCallMessage>.read = delegate(NetworkReader reader)
			{
				CmdCallMessage result2 = default(CmdCallMessage);
				result2.actionId = NetworkReaderExtensions.ReadString(reader);
				return result2;
			};
			NetworkServer.RegisterHandler<CmdCallMessage>((Action<NetworkConnectionToClient, CmdCallMessage>)OnReceiveCommand, true);
			Writer<CmdCallMessageWithParam>.write = delegate(NetworkWriter writer, CmdCallMessageWithParam msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.actionId);
				NetworkWriterExtensions.WriteString(writer, msg.param);
			};
			Reader<CmdCallMessageWithParam>.read = delegate(NetworkReader reader)
			{
				CmdCallMessageWithParam result = default(CmdCallMessageWithParam);
				result.actionId = NetworkReaderExtensions.ReadString(reader);
				result.param = NetworkReaderExtensions.ReadString(reader);
				return result;
			};
			NetworkServer.RegisterHandler<CmdCallMessageWithParam>((Action<NetworkConnectionToClient, CmdCallMessageWithParam>)OnReceiveCommandWithParam, true);
		}

		[Server]
		public void RpcCallToModdedClients(string actionId)
		{
			RpcCallMessage rpcCallMessage = default(RpcCallMessage);
			rpcCallMessage.actionId = actionId;
			RpcCallMessage rpcCallMessage2 = rpcCallMessage;
			foreach (NetworkConnectionToClient value in ModdedClients.Values)
			{
				if (value != null && ((NetworkConnection)value).isReady)
				{
					((NetworkConnection)value).Send<RpcCallMessage>(rpcCallMessage2, 0);
				}
			}
		}

		[Server]
		public void RpcCallToModdedClients(string actionId, string param)
		{
			RpcCallMessageWithParam rpcCallMessageWithParam = default(RpcCallMessageWithParam);
			rpcCallMessageWithParam.actionId = actionId;
			rpcCallMessageWithParam.param = param;
			RpcCallMessageWithParam rpcCallMessageWithParam2 = rpcCallMessageWithParam;
			foreach (NetworkConnectionToClient value in ModdedClients.Values)
			{
				if (value != null && ((NetworkConnection)value).isReady)
				{
					((NetworkConnection)value).Send<RpcCallMessageWithParam>(rpcCallMessageWithParam2, 0);
				}
			}
		}

		[Server]
		public void RpcCallToClients(string actionId, IEnumerable<NetworkConnectionToClient> targets)
		{
			RpcCallMessage rpcCallMessage = default(RpcCallMessage);
			rpcCallMessage.actionId = actionId;
			RpcCallMessage rpcCallMessage2 = rpcCallMessage;
			foreach (NetworkConnectionToClient target in targets)
			{
				if (target != null && ((NetworkConnection)target).isReady)
				{
					((NetworkConnection)target).Send<RpcCallMessage>(rpcCallMessage2, 0);
				}
			}
		}

		[Server]
		public void RpcCallToClients(string actionId, string param, IEnumerable<NetworkConnectionToClient> targets)
		{
			RpcCallMessageWithParam rpcCallMessageWithParam = default(RpcCallMessageWithParam);
			rpcCallMessageWithParam.actionId = actionId;
			rpcCallMessageWithParam.param = param;
			RpcCallMessageWithParam rpcCallMessageWithParam2 = rpcCallMessageWithParam;
			foreach (NetworkConnectionToClient target in targets)
			{
				if (target != null && ((NetworkConnection)target).isReady)
				{
					((NetworkConnection)target).Send<RpcCallMessageWithParam>(rpcCallMessageWithParam2, 0);
				}
			}
		}

		[Server]
		public void RpcCallToClient(string actionId, NetworkConnectionToClient target)
		{
			if (target != null && ((NetworkConnection)target).isReady)
			{
				((NetworkConnection)target).Send<RpcCallMessage>(new RpcCallMessage
				{
					actionId = actionId
				}, 0);
			}
		}

		[Server]
		public void RpcCallToClient(string actionId, string param, NetworkConnectionToClient target)
		{
			if (target != null && ((NetworkConnection)target).isReady)
			{
				((NetworkConnection)target).Send<RpcCallMessageWithParam>(new RpcCallMessageWithParam
				{
					actionId = actionId,
					param = param
				}, 0);
			}
		}

		private static void OnReceiveCall(RpcCallMessage msg)
		{
			if (clientActions.TryGetValue(msg.actionId, out var value))
			{
				value();
			}
			else
			{
				Debug.LogWarning((object)("No action registered for id: " + msg.actionId));
			}
		}

		private static void OnReceiveCallWithParam(RpcCallMessageWithParam msg)
		{
			if (clientActionsWithParam.TryGetValue(msg.actionId, out var value))
			{
				value(msg.param);
			}
			else
			{
				Debug.LogWarning((object)("No parameterized action registered for id: " + msg.actionId));
			}
		}

		public void CmdCallToServer(string actionId)
		{
			CmdCallMessage cmdCallMessage = default(CmdCallMessage);
			cmdCallMessage.actionId = actionId;
			NetworkClient.Send<CmdCallMessage>(cmdCallMessage, 0);
		}

		public void CmdCallToServer(string actionId, string param)
		{
			CmdCallMessageWithParam cmdCallMessageWithParam = default(CmdCallMessageWithParam);
			cmdCallMessageWithParam.actionId = actionId;
			cmdCallMessageWithParam.param = param;
			NetworkClient.Send<CmdCallMessageWithParam>(cmdCallMessageWithParam, 0);
		}

		private static void OnReceiveCommand(NetworkConnectionToClient conn, CmdCallMessage msg)
		{
			if (serverActions.TryGetValue(msg.actionId, out var value))
			{
				value();
			}
			else
			{
				Debug.LogWarning((object)("No server action registered for id: " + msg.actionId));
			}
		}

		private static void OnReceiveCommandWithParam(NetworkConnectionToClient conn, CmdCallMessageWithParam msg)
		{
			Action<string> value2;
			if (serverActionsWithConn.TryGetValue(msg.actionId, out var value))
			{
				value(conn, msg.param);
			}
			else if (serverActionsWithParam.TryGetValue(msg.actionId, out value2))
			{
				value2(msg.param);
			}
			else
			{
				Debug.LogWarning((object)("No server action registered for id: " + msg.actionId));
			}
		}
	}
	internal class CallRPCHelper
	{
		[HarmonyPatch(typeof(BNetworkManager), "OnStartServer")]
		public class ServerStartNetworkManagerPatch
		{
			private static void Postfix(BNetworkManager __instance)
			{
				Plugin.Logger.LogInfo((object)"starting as server");
				JoinSetup();
			}
		}

		[HarmonyPatch(typeof(BNetworkManager), "OnStartClient")]
		public class ClientStartNetworkManagerPatch
		{
			private static void Postfix(BNetworkManager __instance)
			{
				if (!NetworkServer.active)
				{
					Plugin.Logger.LogInfo((object)"starting as client");
					JoinSetup();
				}
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static SpawnHandlerDelegate <0>__SpawnCallRpc;

			public static UnSpawnDelegate <1>__UnspawnCallRpc;

			public static Action <2>__OnCallRPCReady;
		}

		[CompilerGenerated]
		private sealed class <DelayedHandshake>d__4 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			private ulong <localId>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedHandshake>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!Object.op_Implicit((Object)(object)GameManager.LocalPlayerId))
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				<localId>5__1 = GetLocalPlayerId();
				if (NetworkServer.active)
				{
					CallRPC.RegisterModdedClient(<localId>5__1, (NetworkConnectionToClient)(object)NetworkServer.localConnection);
					Plugin.Logger.LogInfo((object)$"Registered host as modded client: {<localId>5__1}");
				}
				else
				{
					Plugin.Logger.LogInfo((object)$"Sending mod handshake as: {<localId>5__1}");
					CallRPC.Instance.CmdCallToServer("modHandshake", <localId>5__1.ToString());
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static readonly uint callRpcUint = 876542u;

		public static void RegisterClass()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			if (NetworkServer.active && (Object)(object)CallRPC.Instance == (Object)null)
			{
				GameObject val = SpawnCallRpc(default(SpawnMessage));
				val.SetActive(true);
				Object.DontDestroyOnLoad((Object)(object)val);
				NetworkServer.Spawn(val, callRpcUint, (NetworkConnectionToClient)null);
			}
			uint num = callRpcUint;
			object obj = <>O.<0>__SpawnCallRpc;
			if (obj == null)
			{
				SpawnHandlerDelegate val2 = SpawnCallRpc;
				<>O.<0>__SpawnCallRpc = val2;
				obj = (object)val2;
			}
			object obj2 = <>O.<1>__UnspawnCallRpc;
			if (obj2 == null)
			{
				UnSpawnDelegate val3 = UnspawnCallRpc;
				<>O.<1>__UnspawnCallRpc = val3;
				obj2 = (object)val3;
			}
			NetworkClient.RegisterSpawnHandler(num, (SpawnHandlerDelegate)obj, (UnSpawnDelegate)obj2);
			CallRPC.RegisterServerAction("modHandshake", delegate(NetworkConnectionToClient conn, string param)
			{
				ulong num2 = ulong.Parse(param);
				CallRPC.RegisterModdedClient(num2, conn);
				Plugin.Logger.LogInfo((object)$"Registered modded client: {num2} (conn {conn.connectionId})");
			});
		}

		private static GameObject SpawnCallRpc(SpawnMessage msg)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("callRPCObject");
			val.SetActive(false);
			NetworkIdentity val2 = val.AddComponent<NetworkIdentity>();
			val.AddComponent<CallRPC>();
			Object.DontDestroyOnLoad((Object)(object)val);
			return val;
		}

		private static ulong GetLocalPlayerId()
		{
			if (Object.op_Implicit((Object)(object)GameManager.LocalPlayerId))
			{
				return GameManager.LocalPlayerInfo.PlayerId.Guid;
			}
			return 0uL;
		}

		[IteratorStateMachine(typeof(<DelayedHandshake>d__4))]
		private static IEnumerator DelayedHandshake()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedHandshake>d__4(0);
		}

		private static void UnspawnCallRpc(GameObject spawned)
		{
			Object.Destroy((Object)(object)spawned);
		}

		private static void JoinSetup()
		{
			if (!((Object)(object)CallRPC.Instance != (Object)null))
			{
				CallRPC.Register();
				CallRPC.OnSpawned += OnCallRPCReady;
			}
		}

		private static void OnCallRPCReady()
		{
			((Component)CallRPC.Instance).gameObject.AddComponent<TestUsingCallRPC>();
			((MonoBehaviour)CallRPC.Instance).StartCoroutine(DelayedHandshake());
			CallRPC.OnSpawned -= OnCallRPCReady;
		}
	}
	[BepInPlugin("SBG_Teams", "SBG Teams Mod", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Harmony val = new Harmony("com.robb.teams");
			val.PatchAll();
			Logger.LogInfo((object)"Plugin SBG_Teams is loaded!");
		}
	}
	public struct TeamData
	{
		public string teamName;

		public ulong leader;

		public List<ulong> members;

		public uint ballNetId;

		public int maxMembers;

		public Color teamColor;
	}
	[Serializable]
	public struct AllTeamsData
	{
		public TeamData[] teams;
	}
	public class Team
	{
		public string name;

		private ulong leaderGuid;

		private List<ulong> memberGuids;

		private GolfBall teamBall;

		public Color color;

		public int maxMembers;

		public ulong LeaderGuid => leaderGuid;

		public List<ulong> MemberGuids => memberGuids;

		public GolfBall TeamBall => teamBall;

		public PlayerGolfer Leader => SteamGuidToPlayerGolfer(leaderGuid);

		public List<PlayerGolfer> Members => (from g in memberGuids.Select(SteamGuidToPlayerGolfer)
			where (Object)(object)g != (Object)null
			select g).ToList();

		public Team(string name, int teamSize, Color color)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			memberGuids = new List<ulong>();
			maxMembers = teamSize;
			this.color = color;
		}

		public Team(string name, List<ulong> members, int teamSize, Color color)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			memberGuids = new List<ulong>();
			foreach (ulong member in members)
			{
				memberGuids.Add(member);
			}
			leaderGuid = memberGuids.FirstOrDefault();
			teamBall = null;
			maxMembers = teamSize;
			this.color = color;
		}

		public Team(string name, List<PlayerGolfer> members, int teamSize, Color color)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			memberGuids = new List<ulong>();
			foreach (PlayerGolfer member in members)
			{
				memberGuids.Add(member.PlayerInfo.PlayerId.Guid);
			}
			leaderGuid = memberGuids.FirstOrDefault();
			teamBall = FindTeamBall();
			maxMembers = teamSize;
			this.color = color;
		}

		public void SetFromData(TeamData data)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			name = data.teamName;
			leaderGuid = data.leader;
			memberGuids = new List<ulong>(data.members);
			maxMembers = data.maxMembers;
			color = data.teamColor;
			if (data.ballNetId != 0 && NetworkClient.spawned.TryGetValue(data.ballNetId, out var value))
			{
				teamBall = ((Component)value).GetComponent<GolfBall>();
			}
			else
			{
				teamBall = null;
			}
		}

		public static ulong PlayerGolferToSteamGuid(PlayerGolfer golfer)
		{
			return golfer.PlayerInfo.PlayerId.Guid;
		}

		public static PlayerGolfer SteamGuidToPlayerGolfer(ulong guid)
		{
			if (!Object.op_Implicit((Object)(object)SingletonBehaviour<GameManager>.Instance))
			{
				return null;
			}
			if ((Object)(object)GameManager.LocalPlayerInfo == (Object)null)
			{
				Plugin.Logger.LogError((object)"SteamGuidToPlayerGolfer: LocalPlayerInfo is null");
				return null;
			}
			if (GameManager.LocalPlayerInfo.PlayerId.Guid == guid)
			{
				return GameManager.LocalPlayerAsGolfer;
			}
			PlayerInfo val = default(PlayerInfo);
			if (!GameManager.TryFindPlayerByGuid(guid, ref val))
			{
				return null;
			}
			return val.AsGolfer;
		}

		public void AddTeamMember(ulong guid)
		{
			memberGuids.Add(guid);
			SetTeamLeader();
			if (!Object.op_Implicit((Object)(object)teamBall))
			{
				SetTeamBall();
			}
		}

		public void RemoveTeamMember(ulong guid)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			memberGuids.Remove(guid);
			if (leaderGuid == guid)
			{
				leaderGuid = 0uL;
				return;
			}
			SetTeamLeader();
			teamBall = Leader.ServerSpawnBall(((Component)Leader).transform.position, Quaternion.identity);
			Leader.CmdReturnBallToPlayerFromConsole();
		}

		public void SetTeamLeader()
		{
			if ((Object)(object)Leader == (Object)null)
			{
				leaderGuid = memberGuids.FirstOrDefault();
			}
		}

		public void SetTeamBall()
		{
			DeleteTeamatesBalls();
			if (memberGuids.Count != 0)
			{
				teamBall = FindTeamBall();
			}
		}

		private GolfBall FindTeamBall()
		{
			if (!Object.op_Implicit((Object)(object)Leader.NetworkownBall))
			{
				foreach (PlayerGolfer member in Members)
				{
					if (Object.op_Implicit((Object)(object)member.NetworkownBall))
					{
						return member.NetworkownBall;
					}
				}
				return null;
			}
			return Leader.NetworkownBall;
		}

		public void DeleteTeamatesBalls()
		{
			if (!Object.op_Implicit((Object)(object)teamBall))
			{
				return;
			}
			foreach (PlayerGolfer member in Members)
			{
				if (!((Object)(object)((Component)member.NetworkownBall).GetComponent<GolfBall>() == (Object)(object)teamBall))
				{
					NetworkServer.Destroy(((Component)member.NetworkownBall).gameObject);
					member.NetworkownBall = teamBall;
				}
			}
		}
	}
	[HarmonyPatch(typeof(CourseManager), "StartCourse")]
	internal static class StartCoursePatch
	{
		private static void Postfix()
		{
			if (!Object.op_Implicit((Object)(object)UIManager.Instance))
			{
				((Component)TeamManager.Instance).gameObject.AddComponent<UIManager>();
			}
			if (!NetworkServer.active)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)TeamManager.Instance) && (Object)(object)CallRPC.Instance != (Object)null)
			{
				if (TeamManager.gamemodeActive)
				{
					TeamManager.Instance.AssignRemainingPlayersToRandomTeam();
					TeamManager.Instance.CleanTeams();
					TeamManager.Instance.SyncTeamsToClients();
				}
			}
			else
			{
				Plugin.Logger.LogError((object)$"Not ready - TeamManager: {(Object)(object)TeamManager.Instance != (Object)null}, CallRPC: {(Object)(object)CallRPC.Instance != (Object)null}");
			}
		}
	}
	[HarmonyPatch(typeof(CourseManager), "BeginHoleOverviewAndTeeOffCountdown")]
	internal static class CourseManagerBeginHolePatch
	{
		private static void Postfix(CourseManager __instance)
		{
			if (Object.op_Implicit((Object)(object)UIManager.Instance))
			{
				UIManager.Instance.SetupGamemodeUI();
				UIManager.Instance.UpdatePlayerInfoColors();
			}
			if (NetworkServer.active && CourseManager.CurrentHoleCourseIndex != -1)
			{
				if (!Object.op_Implicit((Object)(object)TeamManager.Instance))
				{
					Plugin.Logger.LogError((object)"CourseManagerBeginHolePatch: no team manager");
				}
				else if (TeamManager.gamemodeActive)
				{
					TeamManager.Instance.CleanTeams();
					TeamManager.Instance.GetTeamsReadyForHole();
					TeamManager.Instance.RPCSendClientsGamemodeData();
				}
			}
		}
	}
	public struct ChangeTeamData
	{
		public ulong playerGuid;

		public string teamName;
	}
	public class TeamManager : MonoBehaviour
	{
		private readonly List<Team> teams = new List<Team>();

		public static int teamDefaultMaxSize = 2;

		public static TeamManager Instance;

		public static bool gamemodeActive = false;

		public List<Team> Teams => teams;

		private void Awake()
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			gamemodeActive = false;
			TeamMemberManager.Initialize();
			CallRPC.RegisterClientAction("SyncTeamData", OnReceiveTeamData);
			CallRPC.RegisterClientAction("OnReceiveClientGamemodeActive", OnReceiveClientGamemodeActive);
			CallRPC.RegisterServerAction("OnClientRequestedTeamData", OnClientRequestedTeamData);
			CallRPC.RegisterServerAction("OnClientRequestedGamemodeData", OnClientRequestedGamemodeData);
			CallRPC.RegisterServerAction("HandleClientRequestedChangeTeam", HandleClientRequestedChangeTeam);
			if (!NetworkServer.active)
			{
				RequestTeamDataFromServer();
				RequestGamemodeDataFromServer();
			}
			else
			{
				Instance.Teams.Add(new Team("Black", 2, Color.black));
				Instance.Teams.Add(new Team("Green", 2, Color.green));
				Instance.Teams.Add(new Team("Blue", 2, Color.blue));
				Instance.Teams.Add(new Team("Red", 2, Color.red));
			}
			if (!Object.op_Implicit((Object)(object)UIManager.Instance))
			{
				((Component)Instance).gameObject.AddComponent<UIManager>();
			}
		}

		public string SerializeTeams()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			foreach (Team team in teams)
			{
				string name = team.name;
				string text = team.LeaderGuid.ToString();
				string text2 = string.Join(",", team.MemberGuids.Select((ulong g) => g.ToString()));
				string text3 = (((Object)(object)team.TeamBall != (Object)null) ? ((NetworkBehaviour)team.TeamBall).netId.ToString() : "0");
				string text4 = team.maxMembers.ToString();
				string text5 = ColorUtility.ToHtmlStringRGB(team.color);
				list.Add(text + ":" + text2 + ":" + text3 + ":" + text4 + ":" + name + ":" + text5);
			}
			return string.Join(";", list);
		}

		private void OnReceiveTeamData(string data)
		{
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active || string.IsNullOrEmpty(data))
			{
				return;
			}
			teams.Clear();
			string[] array = data.Split(new char[1] { ';' });
			string[] array2 = array;
			Color val = default(Color);
			foreach (string text in array2)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				string[] array3 = text.Split(new char[1] { ':' });
				ulong result = 0uL;
				if (!string.IsNullOrEmpty(array3[0]))
				{
					ulong.TryParse(array3[0], out result);
				}
				List<ulong> members = new List<ulong>();
				if (!string.IsNullOrEmpty(array3[1]))
				{
					members = (from s in array3[1].Split(new char[1] { ',' })
						where !string.IsNullOrEmpty(s)
						select ulong.Parse(s)).ToList();
				}
				uint.TryParse(array3[2], out var result2);
				int.TryParse(array3[3], out var result3);
				string text2 = array3[4];
				string text3 = "#" + array3[5];
				if (!ColorUtility.TryParseHtmlString(text3, ref val))
				{
					Plugin.Logger.LogError((object)("Couldn't parse color from: " + array3[5]));
					((Color)(ref val))..ctor(Random.value, Random.value, Random.value);
				}
				TeamData teamData = default(TeamData);
				teamData.teamName = text2;
				teamData.leader = result;
				teamData.members = members;
				teamData.ballNetId = result2;
				teamData.maxMembers = result3;
				teamData.teamColor = val;
				TeamData fromData = teamData;
				Team team = new Team(text2, result3, val);
				team.SetFromData(fromData);
				teams.Add(team);
			}
		}

		public string SerializeChangeTeams(ulong guid, string teamName)
		{
			return $"{guid}:{teamName}";
		}

		private void HandleClientRequestedChangeTeam(string data)
		{
			if (NetworkServer.active && !string.IsNullOrEmpty(data))
			{
				string[] array = data.Split(new char[1] { ':' });
				ulong playerGuid = ulong.Parse(array[0]);
				string teamName = array[1];
				ChangeTeamData changeTeamData = default(ChangeTeamData);
				changeTeamData.playerGuid = playerGuid;
				changeTeamData.teamName = teamName;
				ChangeTeamData changeTeamData2 = changeTeamData;
				ChangePlayerTeam(changeTeamData2.playerGuid, changeTeamData2.teamName);
				SyncTeamsToClients();
			}
		}

		private void OnClientRequestedTeamData()
		{
			Instance.CleanTeams();
			SyncTeamsToClients();
		}

		private void OnClientRequestedGamemodeData()
		{
			SendClientsGamemodeData();
		}

		private void SendClientsGamemodeData()
		{
			CallRPC.Instance.RpcCallToModdedClients("OnReceiveClientGamemodeActive", gamemodeActive.ToString());
		}

		public void RPCSendClientsGamemodeData()
		{
			SendClientsGamemodeData();
		}

		public void RequestGamemodeDataFromServer()
		{
			if ((Object)(object)CallRPC.Instance != (Object)null)
			{
				CallRPC.Instance.CmdCallToServer("OnClientRequestedGamemodeData");
			}
		}

		public void RequestTeamDataFromServer()
		{
			if ((Object)(object)CallRPC.Instance != (Object)null)
			{
				CallRPC.Instance.CmdCallToServer("OnClientRequestedTeamData");
			}
		}

		private void OnReceiveClientGamemodeActive(string value)
		{
			if (!NetworkServer.active)
			{
				bool flag = (gamemodeActive = ((value == "True") ? true : false));
				if (Object.op_Implicit((Object)(object)UIManager.Instance))
				{
					Plugin.Logger.LogInfo((object)"UI manager instance exists");
					UIManager.Instance.UpdateGamemodeUI(flag);
					UIManager.Instance.ToggleHideReorderableLists(flag);
				}
				else
				{
					Plugin.Logger.LogError((object)"UI manager instance does not exist");
				}
			}
		}

		public void SyncTeamsToClients()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if ((Object)(object)CallRPC.Instance == (Object)null)
			{
				Plugin.Logger.LogError((object)"SyncTeamsToClients: CallRPC.Instance is null!");
				return;
			}
			string text = SerializeTeams();
			if (text == null)
			{
				Plugin.Logger.LogError((object)"SyncTeamsToClients: json is null!");
				return;
			}
			CallRPC.Instance.RpcCallToModdedClients("SyncTeamData", text);
			Plugin.Logger.LogInfo((object)("SyncTeamsToClients: sent successfully " + text));
		}

		private void CMDRequestChangeTeam(string ChangeTeamData)
		{
			CallRPC.Instance.CmdCallToServer("HandleClientRequestedChangeTeam", ChangeTeamData);
		}

		public void CMDRequestChangeTeam(ulong guid, string teamName)
		{
			string changeTeamData = SerializeChangeTeams(guid, teamName);
			CMDRequestChangeTeam(changeTeamData);
		}

		public void AssignRemainingPlayersToRandomTeam()
		{
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ulong, int> connectionIdPerPlayerGuid = BNetworkManager.singleton.connectionIdPerPlayerGuid;
			List<ulong> list = new List<ulong>(connectionIdPerPlayerGuid.Keys);
			List<PlayerState> list2 = new List<PlayerState>();
			CourseManager.GetConnectedPlayerStates(list2);
			IEnumerable<ulong> source = list2.Select((PlayerState state) => state.playerGuid);
			foreach (ulong guid in list)
			{
				if (GetPlayerTeam(guid) != null)
				{
					continue;
				}
				if (!CallRPC.IsModdedClient(guid))
				{
					if (!CourseManager.IsPlayerSpectator(Team.SteamGuidToPlayerGolfer(guid)))
					{
						CourseManager.SetPlayerSpectator(Team.SteamGuidToPlayerGolfer(guid), true);
					}
				}
				else if (source.Contains(guid))
				{
					PlayerState val = list2.Find((PlayerState state) => state.playerGuid == guid);
					if (!val.isSpectator)
					{
						AddPlayerToAvailableTeam(guid);
					}
				}
			}
		}

		public void MakeRandomTeams(int teamSize)
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				return;
			}
			Dictionary<ulong, int> connectionIdPerPlayerGuid = BNetworkManager.singleton.connectionIdPerPlayerGuid;
			List<ulong> list = new List<ulong>(connectionIdPerPlayerGuid.Keys);
			int num = (int)Math.Ceiling((float)connectionIdPerPlayerGuid.Count / (float)teamSize);
			teams.Clear();
			for (int i = 0; i < num; i++)
			{
				List<PlayerGolfer> list2 = new List<PlayerGolfer>();
				int num2 = i * teamSize;
				int num3 = Math.Min(num2 + teamSize, list.Count);
				for (int j = num2; j < num3; j++)
				{
					ulong guid = list[j];
					PlayerGolfer val = Team.SteamGuidToPlayerGolfer(guid);
					if ((Object)(object)val != (Object)null)
					{
						list2.Add(val);
					}
				}
				if (list2.Count > 0)
				{
					Plugin.Logger.LogInfo((object)$"MakeTeams: creating team {i} with {list2.Count} members");
					Team item = new Team($"Team {i + 1}", list2, teamDefaultMaxSize, new Color(Random.value, Random.value, Random.value));
					teams.Add(item);
				}
			}
			SyncTeamsToClients();
		}

		public void GetTeamsReadyForHole()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (Team team in teams)
			{
				team.SetTeamLeader();
				team.SetTeamBall();
			}
			SyncTeamsToClients();
			TeamMemberManager.SpawnPlayerTags();
		}

		public void ChangePlayerTeam(ulong guid, string teamName)
		{
			if (GetPlayerTeam(guid) != null)
			{
				if (GetPlayerTeam(guid).name == teamName)
				{
					return;
				}
				RemovePlayerFromTeam(guid);
			}
			Team teamByTeamName = GetTeamByTeamName(teamName);
			teamByTeamName.AddTeamMember(guid);
			CleanTeams();
		}

		public void CleanTeams()
		{
			foreach (Team team in teams)
			{
				if ((Object)(object)team.Leader == (Object)null)
				{
					team.SetTeamLeader();
				}
				team.SetTeamBall();
			}
		}

		public bool BallBelongsToPlayer(PlayerGolfer player, GolfBall ball)
		{
			foreach (Team team in teams)
			{
				if (team.Members.Contains(player))
				{
					return (Object)(object)team.TeamBall == (Object)(object)ball;
				}
			}
			return false;
		}

		public Team GetPlayerTeam(ulong member)
		{
			foreach (Team team in teams)
			{
				if (team.MemberGuids.Contains(member))
				{
					return team;
				}
			}
			return null;
		}

		public Team GetPlayerTeam(PlayerGolfer member)
		{
			return GetPlayerTeam(member.PlayerInfo.PlayerId.Guid);
		}

		public Team GetTeamByTeamName(string name)
		{
			foreach (Team team in teams)
			{
				if (team.name == name)
				{
					return team;
				}
			}
			return null;
		}

		public GolfBall GetPlayerTeamBall(PlayerGolfer player)
		{
			return GetPlayerTeam(player)?.TeamBall;
		}

		public static List<T> ShuffleList<T>(List<T> list)
		{
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = Random.Range(0, num + 1);
				T value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			return list;
		}

		public void AddPlayerToAvailableTeam(ulong player)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (Team item2 in ShuffleList(teams))
			{
				num = item2.maxMembers;
				if (item2.Members.Count < item2.maxMembers)
				{
					item2.AddTeamMember(player);
					return;
				}
			}
			Plugin.Logger.LogInfo((object)"couldn't find team, making one");
			List<ulong> list = new List<ulong>();
			list.Add(player);
			Team item = new Team($"{player % 1000}'s team", list, teamDefaultMaxSize, new Color(Random.value, Random.value, Random.value));
			teams.Add(item);
		}

		public void RemovePlayerFromTeam(ulong player)
		{
			GetPlayerTeam(player)?.RemoveTeamMember(player);
		}

		private void LogTeams()
		{
			int num = 0;
			foreach (Team team in teams)
			{
				num++;
				PlayerGolfer leader = team.Leader;
				Plugin.Logger.LogInfo((object)string.Format("LogTeams: Team {0} - Leader: {1}", num, ((Object)(object)leader != (Object)null) ? ((Object)leader).name : "not resolved yet"));
				foreach (ulong memberGuid in team.MemberGuids)
				{
					PlayerGolfer val = Team.SteamGuidToPlayerGolfer(memberGuid);
					Plugin.Logger.LogInfo((object)$"LogTeams: {(((Object)(object)val != (Object)null) ? ((Object)val).name : memberGuid.ToString())} on team {num}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(CourseManager), "RegisterMatchParticipant")]
	internal static class RegisterPlayerPatch
	{
		private static bool Prefix(CourseManager __instance, PlayerGolfer participant)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				return true;
			}
			if (!TeamManager.gamemodeActive)
			{
				return true;
			}
			if (TeamManager.Instance.GetPlayerTeam(participant) == null)
			{
				CourseManager.SetPlayerSpectator(participant, true);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(CourseManager), "DeregisterPlayer")]
	internal static class DeregisterPlayerPatch
	{
		private static void Prefix(CourseManager __instance, NetworkConnectionToClient connection)
		{
			if (Object.op_Implicit((Object)(object)TeamManager.Instance) && TeamManager.gamemodeActive)
			{
				ulong player = default(ulong);
				if (!BNetworkManager.singleton.ServerTryGetPlayerGuidFromConnection(connection, ref player))
				{
					Debug.LogError((object)$"Failed to get player GUID for connecion {connection.connectionId} while registering them", (Object)(object)((Component)__instance).gameObject);
					return;
				}
				TeamManager.Instance.RemovePlayerFromTeam(player);
				TeamManager.Instance.SyncTeamsToClients();
			}
		}
	}
	internal class TeamManagerObjectSetupHelper
	{
		[HarmonyPatch(typeof(BNetworkManager), "OnStartServer")]
		public class ServerStartNetworkManagerPatch
		{
			private static void Postfix(BNetworkManager __instance)
			{
				if (NetworkServer.active)
				{
					Plugin.Logger.LogInfo((object)"server creating team manager");
					RegisterClass();
				}
			}
		}

		[HarmonyPatch(typeof(BNetworkManager), "OnStartClient")]
		public class ClientStartNetworkManagerPatch
		{
			private static void Postfix(BNetworkManager __instance)
			{
				if (!NetworkServer.active)
				{
					Plugin.Logger.LogInfo((object)"client creating team manager");
					RegisterClass();
				}
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static SpawnHandlerDelegate <0>__SpawnTeamManager;

			public static UnSpawnDelegate <1>__UnspawnTeamManager;
		}

		private static readonly uint teamManagerUint = 876532u;

		public static void RegisterClass()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			if (NetworkServer.active && (Object)(object)TeamManager.Instance == (Object)null)
			{
				GameObject val = SpawnTeamManager(default(SpawnMessage));
				val.SetActive(true);
				Object.DontDestroyOnLoad((Object)(object)val);
				NetworkServer.Spawn(val, teamManagerUint, (NetworkConnectionToClient)null);
			}
			uint num = teamManagerUint;
			object obj = <>O.<0>__SpawnTeamManager;
			if (obj == null)
			{
				SpawnHandlerDelegate val2 = SpawnTeamManager;
				<>O.<0>__SpawnTeamManager = val2;
				obj = (object)val2;
			}
			object obj2 = <>O.<1>__UnspawnTeamManager;
			if (obj2 == null)
			{
				UnSpawnDelegate val3 = UnspawnTeamManager;
				<>O.<1>__UnspawnTeamManager = val3;
				obj2 = (object)val3;
			}
			NetworkClient.RegisterSpawnHandler(num, (SpawnHandlerDelegate)obj, (UnSpawnDelegate)obj2);
		}

		private static GameObject SpawnTeamManager(SpawnMessage msg)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("teamManagerObject");
			val.SetActive(false);
			NetworkIdentity val2 = val.AddComponent<NetworkIdentity>();
			val.AddComponent<TeamManager>();
			Object.DontDestroyOnLoad((Object)(object)val);
			return val;
		}

		private static void UnspawnTeamManager(GameObject spawned)
		{
			Object.Destroy((Object)(object)spawned);
		}
	}
	public static class TeamMemberManager
	{
		public static void Initialize()
		{
			CallRPC.RegisterClientAction("SpawnTeamBallIcon", SpawnTeamBallIcon);
			CallRPC.RegisterClientAction("UpdateBallNameTag", UpdateBallNameTag);
		}

		public static void AddStrokesToTeam(PlayerGolfer hitter, bool suppressPopup)
		{
			Team playerTeam = TeamManager.Instance.GetPlayerTeam(hitter);
			foreach (PlayerGolfer member in playerTeam.Members)
			{
				if (!((Object)(object)hitter == (Object)(object)member))
				{
					CourseManager.AddPenaltyStroke(member, suppressPopup);
				}
			}
		}

		public static void SpawnPlayerTags()
		{
			CallRPC.Instance.RpcCallToModdedClients("SpawnTeamBallIcon");
			CallRPC.Instance.RpcCallToModdedClients("UpdateBallNameTag");
		}

		private static void SpawnTeamBallIcon()
		{
			PlayerGolfer component = ((Component)((Component)GameManager.LocalPlayerAsGolfer).transform).GetComponent<PlayerGolfer>();
			GolfBall playerTeamBall = TeamManager.Instance.GetPlayerTeamBall(component);
			WorldspaceIconUi unusedIcon = WorldspaceIconManager.GetUnusedIcon();
			WorldspaceIconUiSettings ballIconSettings = WorldspaceIconManager.BallIconSettings;
			unusedIcon.Initialize(ballIconSettings, ((Component)playerTeamBall).transform, ((Component)component).transform, WorldspaceIconManager.BallIcon);
		}

		private static void UpdateBallNameTag()
		{
			foreach (Team team in TeamManager.Instance.Teams)
			{
			}
		}
	}
	[HarmonyPatch(typeof(PlayerGolfer), "CanHitCollider")]
	public class CanHitColliderPatch
	{
		private static bool Prefix(PlayerGolfer __instance, ref bool __result, Collider collider, out Hittable hittable)
		{
			if (!ComponentExtensions.TryGetComponentInParent<Hittable>((Component)(object)collider, ref hittable, false))
			{
				return true;
			}
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				return true;
			}
			if (!TeamManager.gamemodeActive)
			{
				return true;
			}
			if (TeamManager.Instance.GetPlayerTeam(__instance.PlayerInfo.PlayerId.Guid) == null)
			{
				return true;
			}
			if (MatchSetupRules.GetValueAsBool((Rule)10))
			{
				return true;
			}
			if (hittable.AsEntity.IsGolfBall)
			{
				__result = TeamManager.Instance.BallBelongsToPlayer(__instance, hittable.AsEntity.AsGolfBall);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Hittable), "IsHittableBySwing")]
	public class IsHittableBySwingPatch
	{
		private static bool Prefix(Hittable __instance, ref bool __result, PlayerGolfer hitter)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				return true;
			}
			if (!TeamManager.gamemodeActive)
			{
				return true;
			}
			if (TeamManager.Instance.GetPlayerTeam(hitter.PlayerInfo.PlayerId.Guid) == null)
			{
				return true;
			}
			if (MatchSetupRules.GetValueAsBool((Rule)10))
			{
				return true;
			}
			if (__instance.AsEntity.IsGolfBall)
			{
				__result = TeamManager.Instance.BallBelongsToPlayer(hitter, __instance.AsEntity.AsGolfBall);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(GolfBall), "UpdateNotAllowedVisuals")]
	public class PatchUpdateNotAllowedVisuals
	{
		private static FieldInfo isDisplayingField = typeof(GolfBall).GetField("isDisplayingNotAllowedVisuals", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo meshRenderersField = typeof(GolfBall).GetField("meshRenderers", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo originalMaterialsField = typeof(GolfBall).GetField("meshRendererOriginalMaterials", BindingFlags.Instance | BindingFlags.NonPublic);

		private static void Postfix(GolfBall __instance)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance) || !TeamManager.gamemodeActive)
			{
				return;
			}
			PlayerGolfer component = ((Component)((Component)GameManager.LocalPlayerAsGolfer).transform).GetComponent<PlayerGolfer>();
			Team playerTeam = TeamManager.Instance.GetPlayerTeam(component.PlayerInfo.PlayerId.Guid);
			if (playerTeam == null || (Object)(object)playerTeam.TeamBall != (Object)(object)__instance)
			{
				return;
			}
			isDisplayingField.SetValue(__instance, false);
			List<MeshRenderer> list = (List<MeshRenderer>)meshRenderersField.GetValue(__instance);
			List<Material> list2 = (List<Material>)originalMaterialsField.GetValue(__instance);
			for (int i = 0; i < list.Count; i++)
			{
				if ((Object)(object)list[i] != (Object)null)
				{
					((Renderer)list[i]).sharedMaterial = list2[i];
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hittable), "HitWithGolfSwing")]
	public static class HitWithGolfSwingPatch
	{
		private static void Postfix(Hittable __instance, PlayerGolfer hitter)
		{
			if (Object.op_Implicit((Object)(object)TeamManager.Instance) && TeamManager.gamemodeActive && TeamManager.Instance.GetPlayerTeam(hitter) != null && __instance.AsEntity.IsGolfBall && !((Object)(object)__instance.AsEntity.AsGolfBall == (Object)(object)hitter.NetworkownBall) && !((Object)(object)__instance.AsEntity.AsGolfBall != (Object)(object)TeamManager.Instance.GetPlayerTeamBall(hitter)))
			{
				HoleProgressBarUi.IncrementStrokes();
				MethodInfo method = typeof(PlayerGolfer).GetMethod("OnPlayerHitOwnBall", BindingFlags.Instance | BindingFlags.NonPublic);
				method.Invoke(hitter, null);
				if (!((NetworkBehaviour)hitter).isServer)
				{
					MethodInfo method2 = typeof(PlayerGolfer).GetMethod("CmdInformHitOwnBall", BindingFlags.Instance | BindingFlags.NonPublic);
					method2.Invoke(hitter, null);
				}
			}
		}
	}
	[HarmonyPatch(typeof(CourseManager), "OnServerPlayerHitOwnBall")]
	public static class OnServerPlayerHitOwnBallPatch
	{
		private static void Postfix(CourseManager __instance, PlayerGolfer hitter)
		{
			if (Object.op_Implicit((Object)(object)TeamManager.Instance) && TeamManager.gamemodeActive && TeamManager.Instance.GetPlayerTeam(hitter) != null)
			{
				TeamMemberManager.AddStrokesToTeam(hitter, suppressPopup: false);
			}
		}
	}
	[HarmonyPatch(typeof(GolfBall), "ServerReturnToBounds")]
	public static class ServerReturnToBoundsPatch
	{
		private static void Postfix(GolfBall __instance)
		{
			if (Object.op_Implicit((Object)(object)TeamManager.Instance) && TeamManager.gamemodeActive)
			{
				PlayerGolfer networkowner = __instance.Networkowner;
				if (TeamManager.Instance.GetPlayerTeam(networkowner) != null)
				{
					TeamMemberManager.AddStrokesToTeam(networkowner, suppressPopup: true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(GolfBall), "OnEnteredHole")]
	public static class EnteredHolePatch
	{
		private static void Postfix(GolfBall __instance, GolfHole hole)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance) || !TeamManager.gamemodeActive)
			{
				return;
			}
			PlayerGolfer networkowner = __instance.Networkowner;
			if (TeamManager.Instance.GetPlayerTeam(networkowner) == null)
			{
				return;
			}
			Team playerTeam = TeamManager.Instance.GetPlayerTeam(networkowner);
			foreach (PlayerGolfer member in playerTeam.Members)
			{
				if (!((Object)(object)networkowner == (Object)(object)member))
				{
					member.InformScored(hole);
				}
			}
		}
	}
	[HarmonyPatch(typeof(CourseManager), "InformPlayerScoredInternal")]
	public static class InformPlayerScoredPatch
	{
		private static FieldInfo matchScoredPlayersField = typeof(CourseManager).GetField("matchScoredPlayers", BindingFlags.Instance | BindingFlags.NonPublic);

		private static void Prefix(CourseManager __instance, PlayerGolfer playerAsGolfer, GolfHole hole)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance) || !TeamManager.gamemodeActive || TeamManager.Instance.GetPlayerTeam(playerAsGolfer) == null)
			{
				return;
			}
			Team playerTeam = TeamManager.Instance.GetPlayerTeam(playerAsGolfer);
			List<PlayerGolfer> list = (List<PlayerGolfer>)matchScoredPlayersField.GetValue(SingletonNetworkBehaviour<CourseManager>.Instance);
			for (int i = 0; i < playerTeam.Members.Count; i++)
			{
				PlayerGolfer item = playerTeam.Members[i];
				if (list.Contains(item))
				{
					list.Remove(item);
				}
			}
		}
	}
	internal class TestUsingCallRPC : NetworkBehaviour
	{
		private void Awake()
		{
			CallRPC.RegisterClientAction("SayHello", SayHello);
		}

		private void SayHello()
		{
			Debug.Log((object)("Hello " + ((Object)((Component)GameManager.LocalPlayerAsGolfer).transform).name + "!"));
		}

		private void RPCSayHello()
		{
			CallRPC.Instance.RpcCallToModdedClients("SayHello");
		}

		private void Update()
		{
		}
	}
	[HarmonyPatch(typeof(MenuOpenInteraction), "LocalPlayerInteract")]
	internal static class LocalPlayerInteract
	{
		private static void Postfix(MenuOpenInteraction __instance)
		{
			if (((Object)__instance).name != "Station")
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)UIManager.Instance))
			{
				((Component)TeamManager.Instance).gameObject.AddComponent<UIManager>();
			}
			if (Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				UIManager.Instance.SetupGamemodeUI();
				UIManager.Instance.UpdateGamemodeUI(TeamManager.gamemodeActive);
				if (TeamManager.gamemodeActive && NetworkServer.active)
				{
					UIManager.Instance.UpdateTeamReorderableLists();
					UIManager.Instance.ToggleHideReorderableLists(TeamManager.gamemodeActive);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "OpenMatchSetup")]
	internal static class MatchSetupMenuStartPatch
	{
		private static void Postfix(PauseMenu __instance)
		{
			if (!Object.op_Implicit((Object)(object)UIManager.Instance))
			{
				((Component)TeamManager.Instance).gameObject.AddComponent<UIManager>();
			}
			if (Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				UIManager.Instance.SetupGamemodeUI();
				UIManager.Instance.UpdateGamemodeUI(TeamManager.gamemodeActive);
				if (TeamManager.gamemodeActive && NetworkServer.active)
				{
					UIManager.Instance.UpdateTeamReorderableLists();
					UIManager.Instance.ToggleHideReorderableLists(TeamManager.gamemodeActive);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Toggle), "InternalToggle")]
	internal static class ControllerSelectableSubmitPatch
	{
		private static bool Prefix(ControllerSelectable __instance)
		{
			if (!(((Object)__instance).name == "Item 0: Free-for-all") && !(((Object)__instance).name == "Item 1: Teams"))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)SingletonBehaviour<GameManager>.Instance) && CourseManager.CurrentHoleCourseIndex == -1)
			{
				return true;
			}
			return false;
		}

		private static void Postfix(ControllerSelectable __instance)
		{
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)TeamManager.Instance) || (!(((Object)__instance).name == "Item 0: Free-for-all") && !(((Object)__instance).name == "Item 1: Teams")) || CourseManager.CurrentHoleCourseIndex != -1)
			{
				return;
			}
			if (((Object)__instance).name == "Item 0: Free-for-all")
			{
				TeamManager.gamemodeActive = false;
			}
			else if (((Object)__instance).name == "Item 1: Teams")
			{
				if (!Object.op_Implicit((Object)(object)UIManager.Instance))
				{
					Plugin.Logger.LogError((object)"manager instance not found");
				}
				TeamManager.gamemodeActive = true;
				UIManager.Instance.UpdateTeamReorderableLists();
			}
			TeamManager.Instance.RPCSendClientsGamemodeData();
			UIManager.Instance.ToggleHideReorderableLists(TeamManager.gamemodeActive);
		}
	}
	[HarmonyPatch(typeof(ReorderableListElement), "Update")]
	internal class ReorderableListScrollPatch
	{
		private static void Postfix(ReorderableListElement __instance, bool ___pointerDown)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!___pointerDown)
			{
				return;
			}
			float y = ((InputControl<Vector2>)(object)Mouse.current.scroll).ReadValue().y;
			if (y != 0f)
			{
				ReorderableList currentParent = __instance.CurrentParent;
				ScrollRect val = ((currentParent != null) ? ((Component)currentParent).GetComponentInParent<ScrollRect>() : null);
				if ((Object)(object)val != (Object)null)
				{
					val.verticalNormalizedPosition += y * 0.1f;
					val.verticalNormalizedPosition = Mathf.Clamp01(val.verticalNormalizedPosition);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Scoreboard), "Refresh")]
	internal class ScoreboardRefreshPatch
	{
		private static void Postfix(Scoreboard __instance)
		{
			if (Object.op_Implicit((Object)(object)TeamManager.Instance) && Object.op_Implicit((Object)(object)UIManager.Instance) && TeamManager.gamemodeActive)
			{
				UIManager.Instance.UpdatePlayerInfoColors();
			}
		}
	}
	internal class UIManager : MonoBehaviour
	{
		public static UIManager Instance;

		public Dictionary<string, ReorderableList> teamLists = new Dictionary<string, ReorderableList>();

		private void Awake()
		{
			Instance = this;
		}

		private void Start()
		{
			SetupGamemodeUI();
			UpdateGamemodeUI(TeamManager.gamemodeActive);
		}

		private TMP_Dropdown getDropdown()
		{
			MatchSetupMenu val = Object.FindFirstObjectByType<MatchSetupMenu>();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogError((object)"couldn't find menu");
				return null;
			}
			Transform child = ((Component)val).transform.GetChild(0).GetChild(1).GetChild(2)
				.GetChild(0)
				.GetChild(2)
				.GetChild(0)
				.GetChild(0)
				.GetChild(2)
				.GetChild(0);
			return ((Component)child).GetComponent<TMP_Dropdown>();
		}

		private void DestroyOldLists()
		{
			for (int i = 0; i < teamLists.Count; i++)
			{
				if (!((Object)(object)teamLists.Values.ElementAt(i) == (Object)null))
				{
					ReorderableList val = teamLists.Values.ElementAt(i);
					Transform child = ((Component)val).transform.parent.GetChild(((Component)val).transform.GetSiblingIndex() - 1);
					Object.Destroy((Object)(object)((Component)val).gameObject);
					Object.Destroy((Object)(object)((Component)child).gameObject);
				}
			}
			teamLists.Clear();
		}

		public void MoveTeammatesOnUI()
		{
			ReorderableList playersList = SingletonNetworkBehaviour<MatchSetupMenu>.Instance.playersList;
			ReorderableListElement[] componentsInChildren = ((Component)playersList).GetComponentsInChildren<ReorderableListElement>();
			ReorderableListElement[] array = componentsInChildren;
			PlayerInfo val2 = default(PlayerInfo);
			foreach (ReorderableListElement val in array)
			{
				if (GameManager.TryFindPlayerByGuid(((Component)val).GetComponent<MatchSetupPlayer>().Guid, ref val2))
				{
					Team playerTeam = TeamManager.Instance.GetPlayerTeam(val2.PlayerId.Guid);
					if (playerTeam == null)
					{
						Plugin.Logger.LogError((object)"Couldn't find team for player");
						continue;
					}
					ReorderableList val3 = teamLists[playerTeam.name];
					val.AssignTo(val3);
				}
			}
		}

		public void ToggleHideReorderableLists(bool isActive)
		{
			foreach (KeyValuePair<string, ReorderableList> teamList in teamLists)
			{
				if (!((Object)(object)teamList.Value == (Object)null) && !((Object)(object)((Component)teamList.Value).gameObject == (Object)null))
				{
					Transform child = ((Component)teamList.Value).transform.parent.GetChild(((Component)teamList.Value).transform.GetSiblingIndex() - 1);
					((Component)teamList.Value).gameObject.SetActive(isActive);
					((Component)child).gameObject.SetActive(isActive);
					((TMP_Text)((Component)child).GetComponent<TextMeshProUGUI>()).text = teamList.Key;
				}
			}
		}

		public void UpdateTeamReorderableLists()
		{
			DestroyOldLists();
			ReorderableList playersList = SingletonNetworkBehaviour<MatchSetupMenu>.Instance.playersList;
			GameObject gameObject = ((Component)((Component)((Component)playersList).transform.parent).GetComponentInChildren<TextMeshProUGUI>()).gameObject;
			foreach (Team team in TeamManager.Instance.Teams)
			{
				CreateTeamLabel(gameObject, playersList, team);
				ReorderableList teamUI = CreateTeamList(gameObject, playersList, team);
				ChangeListHeightByMemberCount(teamUI, team.MemberGuids.Count);
			}
			if (TeamManager.gamemodeActive)
			{
				MoveTeammatesOnUI();
			}
		}

		private ReorderableList CreateTeamList(GameObject UITeamLabel, ReorderableList playerList, Team team)
		{
			ReorderableList val = Object.Instantiate<ReorderableList>(playerList, ((Component)playerList).transform.parent);
			ReorderableListElement[] componentsInChildren = ((Component)((Component)val).transform).GetComponentsInChildren<ReorderableListElement>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)((Component)componentsInChildren[i]).gameObject);
			}
			((Component)val).transform.SetSiblingIndex(3);
			((Object)val).name = team.name;
			ReorderableList list = ((Component)val).GetComponent<ReorderableList>();
			teamLists[team.name] = list;
			list.OnElementMoved += delegate(ReorderableListElement element)
			{
				HandlePlayerMoved(list, element);
			};
			return val;
		}

		private void CreateTeamLabel(GameObject UITeamLabel, ReorderableList playerList, Team team)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(UITeamLabel, ((Component)playerList).transform.parent);
			((Object)val).name = team.name;
			val.transform.SetSiblingIndex(2);
			((Graphic)val.GetComponent<TextMeshProUGUI>()).color = team.color;
			((TMP_Text)val.GetComponent<TextMeshProUGUI>()).text = team.name;
		}

		private void ChangeListHeightByMemberCount(ReorderableList teamUI, int members)
		{
			((Component)teamUI).GetComponent<LayoutElement>().flexibleHeight = 1f;
			float preferredHeight = 50f * Math.Max(1f, (float)Math.Ceiling((float)members / 2f));
			((Component)teamUI).GetComponent<LayoutElement>().preferredHeight = preferredHeight;
		}

		private void HandlePlayerMoved(ReorderableList list, ReorderableListElement playerElement)
		{
			PlayerInfo val = default(PlayerInfo);
			if (CourseManager.CurrentHoleCourseIndex == -1 && GameManager.TryFindPlayerByGuid(((Component)playerElement).GetComponent<MatchSetupPlayer>().Guid, ref val))
			{
				bool flag = val.PlayerId.Guid == GameManager.LocalPlayerInfo.PlayerId.Guid;
				string name = ((Object)((Component)playerElement).transform.parent).name;
				if (NetworkServer.active)
				{
					TeamManager.Instance.ChangePlayerTeam(val.PlayerId.Guid, name);
					TeamManager.Instance.SyncTeamsToClients();
				}
				else if (!flag)
				{
				}
			}
		}

		public static string StripTMPTags(string text)
		{
			return Regex.Replace(text, "<.*?>", "");
		}

		public void UpdatePlayerInfoColors()
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			List<ScoreboardEntry> scoreboardEntries = Object.FindObjectsByType<ScoreboardEntry>((FindObjectsSortMode)1).ToList();
			Dictionary<string, TextMeshProUGUI> playersScoreboardNames = GetPlayersScoreboardNames(scoreboardEntries);
			FieldInfo field = typeof(PlayerId).GetField("nameTag", BindingFlags.Instance | BindingFlags.NonPublic);
			FieldInfo field2 = typeof(ScoreboardEntry).GetField("name", BindingFlags.Instance | BindingFlags.NonPublic);
			foreach (Team team in TeamManager.Instance.Teams)
			{
				foreach (PlayerGolfer member in team.Members)
				{
					if (field != null)
					{
						object? value = field.GetValue(member.PlayerInfo.PlayerId);
						NameTagUi val = (NameTagUi)((value is NameTagUi) ? value : null);
						if ((Object)(object)val != (Object)null)
						{
							((Graphic)((Component)val).GetComponent<TextMeshProUGUI>()).color = team.color;
						}
					}
					if (playersScoreboardNames.ContainsKey(((Object)member).name))
					{
						((Graphic)playersScoreboardNames[((Object)member).name]).color = team.color;
					}
				}
			}
		}

		private Dictionary<string, TextMeshProUGUI> GetPlayersScoreboardNames(List<ScoreboardEntry> scoreboardEntries)
		{
			Dictionary<string, TextMeshProUGUI> dictionary = new Dictionary<string, TextMeshProUGUI>();
			foreach (ScoreboardEntry scoreboardEntry in scoreboardEntries)
			{
				TextMeshProUGUI component = ((Component)((Component)scoreboardEntry).transform.GetChild(2).GetChild(3)).GetComponent<TextMeshProUGUI>();
				if (Object.op_Implicit((Object)(object)component))
				{
					dictionary[StripTMPTags(((TMP_Text)component).text)] = component;
				}
			}
			return dictionary;
		}

		private void UpdateDropdownOptions(TMP_Dropdown tmp_dropdown)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			List<OptionData> list = new List<OptionData>();
			list.Add(new OptionData("Teams"));
			tmp_dropdown.AddOptions(list);
			tmp_dropdown.RefreshShownValue();
		}

		public void SetupGamemodeUI()
		{
			try
			{
				TMP_Dropdown dropdown = getDropdown();
				if (dropdown.options.Count < 2)
				{
					UpdateDropdownOptions(dropdown);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Couldn't set up the ui: {arg}");
			}
		}

		public void UpdateGamemodeUI(bool teamsActive)
		{
			TMP_Dropdown dropdown = getDropdown();
			if ((Object)(object)dropdown == (Object)null)
			{
				Plugin.Logger.LogError((object)"couldn't find dropdown");
				return;
			}
			string text = (teamsActive ? "Teams" : "Free-for-all");
			dropdown.SetValueWithoutNotify(teamsActive ? 1 : 0);
			dropdown.RefreshShownValue();
		}

		public static bool RemovePlayerFromTeam(ReorderableListElement playerElement)
		{
			PlayerInfo val = default(PlayerInfo);
			if (!GameManager.TryFindPlayerByGuid(((Component)playerElement).GetComponent<MatchSetupPlayer>().Guid, ref val))
			{
				return true;
			}
			bool flag = val.PlayerId.Guid == GameManager.LocalPlayerInfo.PlayerId.Guid;
			if (NetworkServer.active)
			{
				TeamManager.Instance.RemovePlayerFromTeam(val.PlayerId.Guid);
				TeamManager.Instance.CleanTeams();
				TeamManager.Instance.SyncTeamsToClients();
			}
			else if (!flag)
			{
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(MatchSetupMenu), "OnPlayerMovedToPlayers")]
	public static class PlayerMovedToPlayersPatch
	{
		private static bool Prefix(MatchSetupMenu __instance, ReorderableListElement playerElement)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				Plugin.Logger.LogError((object)"Couldn't find team manager instance");
				return true;
			}
			if (!TeamManager.gamemodeActive)
			{
				return true;
			}
			return UIManager.RemovePlayerFromTeam(playerElement);
		}
	}
	[HarmonyPatch(typeof(MatchSetupMenu), "OnPlayerMovedToSpectate")]
	public static class PlayerMovedToSpectatorPatch
	{
		private static bool Prefix(MatchSetupMenu __instance, ReorderableListElement playerElement)
		{
			if (!Object.op_Implicit((Object)(object)TeamManager.Instance))
			{
				Plugin.Logger.LogError((object)"Couldn't find team manager instance");
				return true;
			}
			if (!TeamManager.gamemodeActive)
			{
				return true;
			}
			return UIManager.RemovePlayerFromTeam(playerElement);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "SBG_Teams";

		public const string PLUGIN_NAME = "SBG Teams Mod";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}