Decompiled source of Gamemode Lib v0.1.0

com.github.glarmer.Gamemode_Lib.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.CompilerServices;
using Gamemode_Lib.ConfigSync;
using Gamemode_Lib.Events;
using Gamemode_Lib.Network.Messages;
using Gamemode_Lib.Patches;
using Gamemode_Lib.Patches.Features;
using Gamemode_Lib.Teams;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Pool;
using UnityEngine.SceneManagement;
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: IgnoresAccessChecksTo("GameAssembly")]
[assembly: IgnoresAccessChecksTo("SharedAssembly")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.glarmer.Gamemode_Lib")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.5.1.0")]
[assembly: AssemblyInformationalVersion("0.5.1+852d639c41ee959ea823f8321301795369f5d33c")]
[assembly: AssemblyProduct("com.github.glarmer.Gamemode_Lib")]
[assembly: AssemblyTitle("Gamemode_Lib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace Gamemode_Lib
{
	public static class GameModeUtilities
	{
		public static Dictionary<string, IGamemode> Modes { get; } = new Dictionary<string, IGamemode>();


		public static string? CurrentGamemodeId { get; set; }

		public static bool GameEnded { get; set; } = true;


		public static void ReinitializeGameState()
		{
			string currentGamemodeId = CurrentGamemodeId;
			Plugin.Log.LogInfo((object)($"[GamemodeLib] ReinitializeGameState: serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}'", GameEnded, currentGamemodeId ?? "<null>")));
			if (currentGamemodeId != null && Modes.TryGetValue(currentGamemodeId, out IGamemode value) && value != null)
			{
				try
				{
					Harmony gamemodeHarmony = value.GamemodeHarmony;
					if (gamemodeHarmony != null)
					{
						gamemodeHarmony.UnpatchSelf();
					}
				}
				catch (Exception arg)
				{
					Plugin.Log.LogWarning((object)$"[GamemodeLib] ReinitializeGameState: failed to unpatch gamemode harmony for '{currentGamemodeId}': {arg}");
				}
			}
			ConfigSyncManager.Instance?.ClearAllScopes();
			bool active = NetworkServer.active;
			TeamManager.Instance?.ResetToDefaults(active);
			CurrentGamemodeId = null;
			GameEnded = true;
		}

		public static void RegisterGameMode(IGamemode gamemode)
		{
			if (Modes != null)
			{
				if (Modes.ContainsKey(gamemode.GameModeId))
				{
					Plugin.Log.LogError((object)("Gamemode with same ID: " + gamemode.GameModeId + " has already been registered! We will not re-register..."));
					return;
				}
				Modes.Add(gamemode.GameModeId, gamemode);
				if (gamemode.IsTeamBased)
				{
				}
				Plugin.Log.LogInfo((object)("Gamemode ID: " + gamemode.GameModeId + " has been registered!"));
			}
			else
			{
				Plugin.Log.LogError((object)("Gamemode dictionary was null! " + gamemode.Name + " is not loaded..."));
			}
		}

		public static void ApplyGamemodeStartMessage(GamemodeStartMessage message)
		{
			Plugin.Log.LogInfo((object)($"[GamemodeLib] ApplyGamemodeStartMessage: serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}' msgGamemodeId='{2}'", GameEnded, CurrentGamemodeId ?? "<null>", message.GamemodeId ?? "<null>")));
			if (NetworkServer.active)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeStartMessage: ignoring because server is active");
				return;
			}
			if (message.GamemodeId == null)
			{
				Plugin.Log.LogError((object)"[GamemodeLib] Received GamemodeStartMessage with null GamemodeId");
				return;
			}
			if (!Modes.TryGetValue(message.GamemodeId, out IGamemode value) || value == null)
			{
				Plugin.Log.LogError((object)$"[GamemodeLib] Received GamemodeStartMessage for unknown mode id '{message.GamemodeId}'. modesCount={Modes.Count}");
				return;
			}
			Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeStartMessage: starting mode '" + message.GamemodeId + "'. " + string.Format("previousState: gameEnded={0} currentGamemodeId='{1}'", GameEnded, CurrentGamemodeId ?? "<null>")));
			CurrentGamemodeId = message.GamemodeId;
			GameEnded = false;
			if ((Object)(object)ConfigSyncManager.Instance != (Object)null && !ConfigSyncManager.Instance.HasReceivedFull(message.GamemodeId))
			{
				ConfigSyncManager.Instance.RequestScopeFromHost(message.GamemodeId);
			}
			try
			{
				value.OnGameStart();
				Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeStartMessage: mode.OnGameStart() finished for '" + message.GamemodeId + "'"));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[GamemodeLib] ApplyGamemodeStartMessage: mode.OnGameStart() threw for '{message.GamemodeId}': {arg}");
				throw;
			}
		}

		public static void ApplyGamemodeEndMessage(GamemodeEndMessage message)
		{
			Plugin.Log.LogInfo((object)($"[GamemodeLib] ApplyGamemodeEndMessage: serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}' msgGamemodeId='{2}'", GameEnded, CurrentGamemodeId ?? "<null>", message.GamemodeId ?? "<null>")));
			if (NetworkServer.active)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeEndMessage: ignoring because server is active");
				return;
			}
			if (GameEnded)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeEndMessage: ignoring because GameEnded is already true");
				return;
			}
			if (message.GamemodeId == null)
			{
				Plugin.Log.LogError((object)"[GamemodeLib] Received GamemodeEndMessage with null GamemodeId");
				return;
			}
			if (!Modes.TryGetValue(message.GamemodeId, out IGamemode value) || value == null)
			{
				Plugin.Log.LogError((object)("[GamemodeLib] Received GamemodeEndMessage for unknown mode id '" + message.GamemodeId + "'. " + $"modesCount={Modes.Count}. Forcing local end state."));
				GameEnded = true;
				CurrentGamemodeId = null;
				return;
			}
			Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeEndMessage: ending mode '" + message.GamemodeId + "'. " + string.Format("previousState: gameEnded={0} currentGamemodeId='{1}'", GameEnded, CurrentGamemodeId ?? "<null>")));
			CurrentGamemodeId = message.GamemodeId;
			GameEnded = true;
			try
			{
				value.OnGameEnd();
				Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeEndMessage: mode.OnGameEnd() finished for '" + message.GamemodeId + "'"));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[GamemodeLib] ApplyGamemodeEndMessage: mode.OnGameEnd() threw for '{message.GamemodeId}': {arg}");
				throw;
			}
			CurrentGamemodeId = null;
			ConfigSyncManager.Instance?.ClearScope(message.GamemodeId);
			Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeEndMessage: cleared CurrentGamemodeId and set GameEnded=true");
		}

		internal static void TryEndCurrentGame(bool broadcastToClients)
		{
			Plugin.Log.LogInfo((object)($"[GamemodeLib] TryEndCurrentGame: broadcastToClients={broadcastToClients} serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}'", GameEnded, CurrentGamemodeId ?? "<null>")));
			if (GameEnded)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] TryEndCurrentGame: no-op because GameEnded is already true");
				return;
			}
			string currentGamemodeId = CurrentGamemodeId;
			if (currentGamemodeId == null)
			{
				Plugin.Log.LogWarning((object)"[GamemodeLib] TryEndCurrentGame: CurrentGamemodeId was null while GameEnded=false; forcing GameEnded=true");
				GameEnded = true;
				return;
			}
			if (!Modes.TryGetValue(currentGamemodeId, out IGamemode value) || value == null)
			{
				Plugin.Log.LogWarning((object)($"[GamemodeLib] TryEndCurrentGame: mode lookup failed for id '{currentGamemodeId}'. modesCount={Modes.Count}. " + "Forcing GameEnded=true and clearing CurrentGamemodeId."));
				GameEnded = true;
				CurrentGamemodeId = null;
				return;
			}
			Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: ending current mode '" + currentGamemodeId + "' (modeType=" + value.GetType().FullName + ")"));
			GameEnded = true;
			try
			{
				value.OnGameEnd();
				Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: mode.OnGameEnd() finished for '" + currentGamemodeId + "'"));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[GamemodeLib] TryEndCurrentGame: mode.OnGameEnd() threw for '{currentGamemodeId}': {arg}");
				throw;
			}
			finally
			{
				if (broadcastToClients && NetworkServer.active)
				{
					Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: broadcasting GamemodeEndMessage to all clients for '" + currentGamemodeId + "'"));
					NetworkMessageBootstrap.Register();
					GamemodeEndMessage gamemodeEndMessage = default(GamemodeEndMessage);
					gamemodeEndMessage.GamemodeId = currentGamemodeId;
					NetworkServer.SendToAll<GamemodeEndMessage>(gamemodeEndMessage, 0, false);
					Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: broadcast sent for '" + currentGamemodeId + "'"));
				}
				else
				{
					Plugin.Log.LogInfo((object)$"[GamemodeLib] TryEndCurrentGame: not broadcasting (broadcastToClients={broadcastToClients}, serverActive={NetworkServer.active})");
				}
				ConfigSyncManager.Instance?.ClearScope(currentGamemodeId);
				CurrentGamemodeId = null;
				Plugin.Log.LogInfo((object)"[GamemodeLib] TryEndCurrentGame: cleared CurrentGamemodeId");
			}
		}
	}
	public interface IGamemode
	{
		Harmony GamemodeHarmony { get; init; }

		string Name { get; }

		string ModId { get; }

		string GameModeId => ModId + ":" + Name;

		int MinPlayers { get; }

		int MaxPlayers { get; }

		bool IsTeamBased { get; }

		bool IsNormalStartProcedure { get; }

		bool IsTaggingEnabled { get; }

		int TeamCount { get; }

		string Description { get; }

		void OnGameStart();

		void OnGameEnd();

		bool CanStart(int playerCount);
	}
	public static class NetworkMessageBootstrap
	{
		private static bool _commonRegistered;

		private static bool _clientRegistered;

		private static bool _serverRegistered;

		public static void Register()
		{
			Plugin.Log.LogInfo((object)($"[GamemodeLib] NetworkMessageBootstrap.Register: clientActive={NetworkClient.active} serverActive={NetworkServer.active} " + $"commonRegistered={_commonRegistered} clientRegistered={_clientRegistered} serverRegistered={_serverRegistered}"));
			RegisterCommon();
			if (NetworkClient.active)
			{
				RegisterClient();
			}
			if (NetworkServer.active)
			{
				RegisterServer();
			}
		}

		private static void RegisterCommon()
		{
			if (_commonRegistered)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterCommon: already registered");
				return;
			}
			_commonRegistered = true;
			Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterCommon: registering readers/writers");
			Writer<TeamAssignMessage>.write = delegate(NetworkWriter writer, TeamAssignMessage msg)
			{
				NetworkWriterExtensions.WriteULong(writer, msg.PlayerGuid);
				NetworkWriterExtensions.WriteInt(writer, msg.TeamId);
			};
			Reader<TeamAssignMessage>.read = delegate(NetworkReader reader)
			{
				TeamAssignMessage result11 = default(TeamAssignMessage);
				result11.PlayerGuid = NetworkReaderExtensions.ReadULong(reader);
				result11.TeamId = NetworkReaderExtensions.ReadInt(reader);
				return result11;
			};
			Writer<TeamRequestMessage>.write = delegate(NetworkWriter writer, TeamRequestMessage msg)
			{
				NetworkWriterExtensions.WriteULong(writer, msg.PlayerGuid);
			};
			Reader<TeamRequestMessage>.read = delegate(NetworkReader reader)
			{
				TeamRequestMessage result10 = default(TeamRequestMessage);
				result10.PlayerGuid = NetworkReaderExtensions.ReadULong(reader);
				return result10;
			};
			Writer<TeamDefinitionMessage>.write = delegate(NetworkWriter writer, TeamDefinitionMessage msg)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				NetworkWriterExtensions.WriteInt(writer, msg.ID);
				NetworkWriterExtensions.WriteColor(writer, msg.Color);
				NetworkWriterExtensions.WriteString(writer, msg.Name);
			};
			Reader<TeamDefinitionMessage>.read = delegate(NetworkReader reader)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				TeamDefinitionMessage result9 = default(TeamDefinitionMessage);
				result9.ID = NetworkReaderExtensions.ReadInt(reader);
				result9.Color = NetworkReaderExtensions.ReadColor(reader);
				result9.Name = NetworkReaderExtensions.ReadString(reader);
				return result9;
			};
			Writer<GamemodeStartMessage>.write = delegate(NetworkWriter writer, GamemodeStartMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.GamemodeId);
			};
			Reader<GamemodeStartMessage>.read = delegate(NetworkReader reader)
			{
				GamemodeStartMessage result8 = default(GamemodeStartMessage);
				result8.GamemodeId = NetworkReaderExtensions.ReadString(reader);
				return result8;
			};
			Writer<GamemodeEndMessage>.write = delegate(NetworkWriter writer, GamemodeEndMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.GamemodeId);
			};
			Reader<GamemodeEndMessage>.read = delegate(NetworkReader reader)
			{
				GamemodeEndMessage result7 = default(GamemodeEndMessage);
				result7.GamemodeId = NetworkReaderExtensions.ReadString(reader);
				return result7;
			};
			Writer<RaycastRequestMessage>.write = delegate(NetworkWriter writer, RaycastRequestMessage msg)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				NetworkWriterExtensions.WriteString(writer, msg.Purpose);
				NetworkWriterExtensions.WriteULong(writer, msg.Guid);
				NetworkWriterExtensions.WriteVector3(writer, msg.Origin);
				NetworkWriterExtensions.WriteVector3(writer, msg.Direction);
				NetworkWriterExtensions.WriteFloat(writer, msg.MaxDistance);
				NetworkWriterExtensions.WriteInt(writer, msg.RaycastMask);
			};
			Reader<RaycastRequestMessage>.read = delegate(NetworkReader reader)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				RaycastRequestMessage result6 = default(RaycastRequestMessage);
				result6.Purpose = NetworkReaderExtensions.ReadString(reader);
				result6.Guid = NetworkReaderExtensions.ReadULong(reader);
				result6.Origin = NetworkReaderExtensions.ReadVector3(reader);
				result6.Direction = NetworkReaderExtensions.ReadVector3(reader);
				result6.MaxDistance = NetworkReaderExtensions.ReadFloat(reader);
				result6.RaycastMask = NetworkReaderExtensions.ReadInt(reader);
				return result6;
			};
			Writer<RaycastResultMessage>.write = delegate(NetworkWriter writer, RaycastResultMessage msg)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				NetworkWriterExtensions.WriteString(writer, msg.Purpose);
				NetworkWriterExtensions.WriteULong(writer, msg.Guid);
				NetworkWriterExtensions.WriteVector3(writer, msg.Origin);
				NetworkWriterExtensions.WriteVector3(writer, msg.Direction);
				NetworkWriterExtensions.WriteFloat(writer, msg.MaxDistance);
				NetworkWriterExtensions.WriteInt(writer, msg.RaycastMask);
				NetworkWriterExtensions.WriteBool(writer, msg.HasHit);
				NetworkWriterExtensions.WriteVector3(writer, msg.HitPoint);
				NetworkWriterExtensions.WriteVector3(writer, msg.HitNormal);
				NetworkWriterExtensions.WriteFloat(writer, msg.HitDistance);
				NetworkWriterExtensions.WriteString(writer, msg.HitObjectName);
				NetworkWriterExtensions.WriteString(writer, msg.ClosestValidRootObjectName);
			};
			Reader<RaycastResultMessage>.read = delegate(NetworkReader reader)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				RaycastResultMessage result5 = default(RaycastResultMessage);
				result5.Purpose = NetworkReaderExtensions.ReadString(reader);
				result5.Guid = NetworkReaderExtensions.ReadULong(reader);
				result5.Origin = NetworkReaderExtensions.ReadVector3(reader);
				result5.Direction = NetworkReaderExtensions.ReadVector3(reader);
				result5.MaxDistance = NetworkReaderExtensions.ReadFloat(reader);
				result5.RaycastMask = NetworkReaderExtensions.ReadInt(reader);
				result5.HasHit = NetworkReaderExtensions.ReadBool(reader);
				result5.HitPoint = NetworkReaderExtensions.ReadVector3(reader);
				result5.HitNormal = NetworkReaderExtensions.ReadVector3(reader);
				result5.HitDistance = NetworkReaderExtensions.ReadFloat(reader);
				result5.HitObjectName = NetworkReaderExtensions.ReadString(reader);
				result5.ClosestValidRootObjectName = NetworkReaderExtensions.ReadString(reader);
				return result5;
			};
			Writer<ConfigScopeRequestMessage>.write = delegate(NetworkWriter writer, ConfigScopeRequestMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.ScopeId);
			};
			Reader<ConfigScopeRequestMessage>.read = delegate(NetworkReader reader)
			{
				ConfigScopeRequestMessage result4 = default(ConfigScopeRequestMessage);
				result4.ScopeId = NetworkReaderExtensions.ReadString(reader);
				return result4;
			};
			Writer<ConfigEntry>.write = delegate(NetworkWriter writer, ConfigEntry entry)
			{
				NetworkWriterExtensions.WriteString(writer, entry.Key);
				writer.WriteByte((byte)entry.Type);
				switch (entry.Type)
				{
				case ConfigValueType.String:
					NetworkWriterExtensions.WriteString(writer, entry.StringValue);
					break;
				case ConfigValueType.Int:
					NetworkWriterExtensions.WriteInt(writer, entry.IntValue);
					break;
				case ConfigValueType.Float:
					NetworkWriterExtensions.WriteFloat(writer, entry.FloatValue);
					break;
				case ConfigValueType.Bool:
					NetworkWriterExtensions.WriteBool(writer, entry.BoolValue);
					break;
				default:
					NetworkWriterExtensions.WriteString(writer, entry.StringValue);
					break;
				}
			};
			Reader<ConfigEntry>.read = delegate(NetworkReader reader)
			{
				ConfigEntry configEntry = default(ConfigEntry);
				configEntry.Key = NetworkReaderExtensions.ReadString(reader);
				configEntry.Type = (ConfigValueType)reader.ReadByte();
				ConfigEntry result3 = configEntry;
				switch (result3.Type)
				{
				case ConfigValueType.String:
					result3.StringValue = NetworkReaderExtensions.ReadString(reader);
					break;
				case ConfigValueType.Int:
					result3.IntValue = NetworkReaderExtensions.ReadInt(reader);
					break;
				case ConfigValueType.Float:
					result3.FloatValue = NetworkReaderExtensions.ReadFloat(reader);
					break;
				case ConfigValueType.Bool:
					result3.BoolValue = NetworkReaderExtensions.ReadBool(reader);
					break;
				default:
					result3.StringValue = NetworkReaderExtensions.ReadString(reader);
					break;
				}
				return result3;
			};
			Writer<ConfigScopeUpdateMessage>.write = delegate(NetworkWriter writer, ConfigScopeUpdateMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.ScopeId);
				writer.Write<ConfigEntry>(msg.Entry);
			};
			Reader<ConfigScopeUpdateMessage>.read = delegate(NetworkReader reader)
			{
				ConfigScopeUpdateMessage result2 = default(ConfigScopeUpdateMessage);
				result2.ScopeId = NetworkReaderExtensions.ReadString(reader);
				result2.Entry = reader.Read<ConfigEntry>();
				return result2;
			};
			Writer<ConfigScopeFullMessage>.write = delegate(NetworkWriter writer, ConfigScopeFullMessage msg)
			{
				NetworkWriterExtensions.WriteString(writer, msg.ScopeId);
				int num2 = msg.Entries?.Count ?? 0;
				NetworkWriterExtensions.WriteInt(writer, num2);
				for (int j = 0; j < num2; j++)
				{
					writer.Write<ConfigEntry>(msg.Entries[j]);
				}
			};
			Reader<ConfigScopeFullMessage>.read = delegate(NetworkReader reader)
			{
				ConfigScopeFullMessage configScopeFullMessage = default(ConfigScopeFullMessage);
				configScopeFullMessage.ScopeId = NetworkReaderExtensions.ReadString(reader);
				configScopeFullMessage.Entries = new List<ConfigEntry>();
				ConfigScopeFullMessage result = configScopeFullMessage;
				int num = NetworkReaderExtensions.ReadInt(reader);
				for (int i = 0; i < num; i++)
				{
					result.Entries.Add(reader.Read<ConfigEntry>());
				}
				return result;
			};
			Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterCommon: registered network message readers/writers (teams + gamemodes + config + raycasts)");
		}

		private static void RegisterClient()
		{
			if (_clientRegistered)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterClient: already registered");
				return;
			}
			_clientRegistered = true;
			Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterClient: registering client handlers");
			NetworkClient.RegisterHandler<TeamAssignMessage>((Action<TeamAssignMessage>)delegate(TeamAssignMessage msg)
			{
				Plugin.Log.LogInfo((object)$"[GamemodeLib] Client received TeamAssignMessage: playerGuid={msg.PlayerGuid} teamId={msg.TeamId}");
				TeamManager.Instance?.ApplyTeamMessage(msg);
			}, true);
			NetworkClient.RegisterHandler<TeamDefinitionMessage>((Action<TeamDefinitionMessage>)delegate(TeamDefinitionMessage msg)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received TeamDefinitionMessage: id={0} name='{1}' color={2}", msg.ID, msg.Name ?? "<null>", msg.Color));
				TeamManager.Instance?.ApplyTeamDefinitionMessage(msg);
			}, true);
			NetworkClient.RegisterHandler<GamemodeStartMessage>((Action<GamemodeStartMessage>)delegate(GamemodeStartMessage msg)
			{
				Plugin.Log.LogInfo((object)("[GamemodeLib] Client received GamemodeStartMessage: gamemodeId='" + (msg.GamemodeId ?? "<null>") + "'"));
				GameModeUtilities.ApplyGamemodeStartMessage(msg);
			}, true);
			NetworkClient.RegisterHandler<GamemodeEndMessage>((Action<GamemodeEndMessage>)delegate(GamemodeEndMessage msg)
			{
				Plugin.Log.LogInfo((object)("[GamemodeLib] Client received GamemodeEndMessage: gamemodeId='" + (msg.GamemodeId ?? "<null>") + "'"));
				GameModeUtilities.ApplyGamemodeEndMessage(msg);
			}, true);
			NetworkClient.RegisterHandler<ConfigScopeFullMessage>((Action<ConfigScopeFullMessage>)delegate(ConfigScopeFullMessage msg)
			{
				Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received ConfigScopeFullMessage: scopeId='{0}' entries={1}", msg.ScopeId ?? "<null>", msg.Entries?.Count ?? 0));
				ConfigSyncManager.Instance?.ApplyFull(msg);
			}, true);
			NetworkClient.RegisterHandler<ConfigScopeUpdateMessage>((Action<ConfigScopeUpdateMessage>)delegate(ConfigScopeUpdateMessage msg)
			{
				Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received ConfigScopeUpdateMessage: scopeId='{0}' key='{1}' type={2}", msg.ScopeId ?? "<null>", msg.Entry.Key ?? "<null>", (byte)msg.Entry.Type));
				ConfigSyncManager.Instance?.ApplyUpdate(msg);
			}, true);
			NetworkClient.RegisterHandler<RaycastResultMessage>((Action<RaycastResultMessage>)delegate(RaycastResultMessage msg)
			{
				Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received RaycastResultMessage: purpose='{0}' hasHit={1} root='{2}'", msg.Purpose ?? "<null>", msg.HasHit, msg.ClosestValidRootObjectName ?? "<null>"));
				RaycastUtility.HandleRaycastResult(msg);
			}, true);
			Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterClient: client handlers registered");
		}

		private static void RegisterServer()
		{
			if (_serverRegistered)
			{
				Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterServer: already registered");
				return;
			}
			_serverRegistered = true;
			Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterServer: registering server handlers");
			NetworkServer.RegisterHandler<TeamRequestMessage>((Action<NetworkConnectionToClient, TeamRequestMessage>)delegate(NetworkConnectionToClient conn, TeamRequestMessage msg)
			{
				Plugin.Log.LogInfo((object)$"[GamemodeLib] Server received TeamRequestMessage: connId={conn.connectionId} playerGuid={msg.PlayerGuid}");
				TeamManager.Instance?.HandleTeamRequest(conn, msg);
			}, true);
			NetworkServer.RegisterHandler<ConfigScopeRequestMessage>((Action<NetworkConnectionToClient, ConfigScopeRequestMessage>)delegate(NetworkConnectionToClient conn, ConfigScopeRequestMessage msg)
			{
				Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Server received ConfigScopeRequestMessage: connId={0} scopeId='{1}'", conn.connectionId, msg.ScopeId ?? "<null>"));
				ConfigSyncManager.Instance?.HandleScopeRequest(conn, msg);
			}, true);
			NetworkServer.RegisterHandler<RaycastRequestMessage>((Action<NetworkConnectionToClient, RaycastRequestMessage>)delegate(NetworkConnectionToClient conn, RaycastRequestMessage msg)
			{
				Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Server received RaycastRequestMessage: connId={0} purpose='{1}' maxDistance={2} mask={3}", conn.connectionId, msg.Purpose ?? "<null>", msg.MaxDistance, msg.RaycastMask));
				RaycastUtility.HandleRaycastRequest(conn.connectionId, msg);
			}, true);
			Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterServer: server handlers registered");
		}

		[HarmonyPatch(typeof(BNetworkManager), "OnStartClient")]
		[HarmonyPostfix]
		public static void OnStartClient_Postfix()
		{
			Plugin.Log.LogInfo((object)"[GamemodeLib] BNetworkManager.OnStartClient postfix: registering network messages");
			Register();
		}

		[HarmonyPatch(typeof(BNetworkManager), "OnStartServer")]
		[HarmonyPostfix]
		public static void OnStartServer_Postfix()
		{
			Plugin.Log.LogInfo((object)"[GamemodeLib] BNetworkManager.OnStartServer postfix: registering network messages");
			Register();
		}

		[HarmonyPatch(typeof(BNetworkManager), "OnDestroy")]
		[HarmonyPrefix]
		public static void OnDestroy_Prefix()
		{
			Plugin.Log.LogInfo((object)$"[GamemodeLib] BNetworkManager.OnDestroy prefix: attempting to end current game (serverActive={NetworkServer.active})");
			GameModeUtilities.TryEndCurrentGame(NetworkServer.active);
		}
	}
	[BepInPlugin("com.github.glarmer.Gamemode_Lib", "Gamemode_Lib", "0.5.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal readonly Harmony _harmony = new Harmony("com.github.glarmer.Gamemode_Lib");

		internal static Plugin Instance;

		public const string Id = "com.github.glarmer.Gamemode_Lib";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "Gamemode_Lib";

		public static string Version => "0.5.1";

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			GameObject val = new GameObject("GamemodeLib");
			val.AddComponent<ConfigSyncManager>();
			Log.LogInfo((object)("Plugin " + Name + " (Version " + Version + ") is patching!"));
			Log.LogInfo((object)"[GamemodeLib] is running Network patches");
			_harmony.PatchAll(typeof(NetworkMessageBootstrap));
			Log.LogInfo((object)"[GamemodeLib] is patching Scoreboard");
			_harmony.PatchAll(typeof(ScoreboardPatches));
			Log.LogInfo((object)"[GamemodeLib] is patching MatchSetupPlayer");
			_harmony.PatchAll(typeof(MatchSetupPlayerPatches));
			Log.LogInfo((object)"[GamemodeLib] is patching CourseManager");
			_harmony.PatchAll(typeof(CourseManagerPatches));
			Log.LogInfo((object)"[GamemodeLib] is patching NameTagUi");
			_harmony.PatchAll(typeof(NameTagUiPatches));
			Log.LogInfo((object)"[GamemodeLib] is patching GameManager");
			_harmony.PatchAll(typeof(GameManagerPatches));
			Log.LogInfo((object)"[GamemodeLib] is patching MatchSetup");
			_harmony.PatchAll(typeof(MatchSetupMenuPatches));
			Log.LogInfo((object)"[GamemodeLib] is patching PlayerInfo");
			_harmony.PatchAll(typeof(PlayerInfoPatches));
			_harmony.PatchAll(typeof(TeeOffCountdownPatches));
			Log.LogInfo((object)"[GamemodeLib] is finished patching.");
			SceneEvents.Init();
			SceneEvents.OnReturnToLobby += OnReturnToLobby;
			PlayerEvents.Init();
			Log.LogInfo((object)"[GamemodeLib] Initialized.");
		}

		private void OnReturnToLobby(Scene hole, Scene lobby)
		{
			if (GameModeUtilities.CurrentGamemodeId != null)
			{
				GameModeUtilities.TryEndCurrentGame(broadcastToClients: true);
			}
			GameModeUtilities.ReinitializeGameState();
		}

		private void OnDestroy()
		{
			SceneEvents.OnReturnToLobby -= OnReturnToLobby;
			SceneEvents.Shutdown();
			_harmony.UnpatchSelf();
		}
	}
	public static class RaycastUtility
	{
		public readonly struct RaycastCompletedEventArgs
		{
			public readonly string Purpose;

			public readonly int RequestingConnectionId;

			public readonly ulong RequestingClientGuid;

			public readonly Vector3 Origin;

			public readonly Vector3 Direction;

			public readonly float MaxDistance;

			public readonly int RaycastMask;

			public readonly bool HasHit;

			public readonly RaycastHit Hit;

			public readonly GameObject ClosestValidRootObject;

			public RaycastCompletedEventArgs(string purpose, int requestingConnectionId, ulong requestingClientGuid, Vector3 origin, Vector3 direction, float maxDistance, int raycastMask, bool hasHit, RaycastHit hit, GameObject closestValidRootObject)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				Purpose = purpose;
				RequestingConnectionId = requestingConnectionId;
				RequestingClientGuid = requestingClientGuid;
				Origin = origin;
				Direction = direction;
				MaxDistance = maxDistance;
				RaycastMask = raycastMask;
				HasHit = hasHit;
				Hit = hit;
				ClosestValidRootObject = closestValidRootObject;
			}
		}

		public readonly struct RaycastResultReceivedEventArgs
		{
			public readonly string Purpose;

			public readonly ulong RequestingClientGuid;

			public readonly Vector3 Origin;

			public readonly Vector3 Direction;

			public readonly float MaxDistance;

			public readonly int RaycastMask;

			public readonly bool HasHit;

			public readonly Vector3 HitPoint;

			public readonly Vector3 HitNormal;

			public readonly float HitDistance;

			public readonly string HitObjectName;

			public readonly string ClosestValidRootObjectName;

			public RaycastResultReceivedEventArgs(string purpose, ulong requestingClientGuid, Vector3 origin, Vector3 direction, float maxDistance, int raycastMask, bool hasHit, Vector3 hitPoint, Vector3 hitNormal, float hitDistance, string hitObjectName, string closestValidRootObjectName)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				Purpose = purpose;
				RequestingClientGuid = requestingClientGuid;
				Origin = origin;
				Direction = direction;
				MaxDistance = maxDistance;
				RaycastMask = raycastMask;
				HasHit = hasHit;
				HitPoint = hitPoint;
				HitNormal = hitNormal;
				HitDistance = hitDistance;
				HitObjectName = hitObjectName;
				ClosestValidRootObjectName = closestValidRootObjectName;
			}
		}

		public static event Action<RaycastCompletedEventArgs> RaycastCompleted;

		public static event Action<RaycastResultReceivedEventArgs> RaycastResultReceived;

		public static GameObject GetClosestValidObjectFromMainCameraCenter(float maxDistance = 100f, LayerMask raycastMask = default(LayerMask))
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return null;
			}
			return GetClosestValidObject(((Component)main).transform.position, ((Component)main).transform.forward, maxDistance, raycastMask);
		}

		public static GameObject GetClosestValidObject(Vector3 origin, Vector3 direction, float maxDistance = 100f, LayerMask raycastMask = default(LayerMask))
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (LayerMask.op_Implicit(raycastMask) == 0)
			{
				raycastMask = LayerMask.op_Implicit(-1);
			}
			if (((Vector3)(ref direction)).sqrMagnitude <= 1E-06f)
			{
				return null;
			}
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(origin, ((Vector3)(ref direction)).normalized);
			RaycastHit[] array = Physics.RaycastAll(val, maxDistance, LayerMask.op_Implicit(raycastMask), (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RaycastHit val2 = array2[i];
				GameObject gameObject = ((Component)((RaycastHit)(ref val2)).collider).gameObject;
				if (!ShouldIgnore(gameObject))
				{
					return GetHighestParent(gameObject);
				}
			}
			return null;
		}

		public static void RequestRaycastOnHost(string purpose, ulong guid, Vector3 origin, Vector3 direction, float maxDistance = 100f, LayerMask raycastMask = default(LayerMask))
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkClient.active)
			{
				if (NetworkServer.active)
				{
					HandleRaycastRequest(-1, new RaycastRequestMessage
					{
						Purpose = purpose,
						Guid = guid,
						Origin = origin,
						Direction = direction,
						MaxDistance = maxDistance,
						RaycastMask = ((LayerMask.op_Implicit(raycastMask) == 0) ? (-1) : ((LayerMask)(ref raycastMask)).value)
					});
				}
				else
				{
					NetworkMessageBootstrap.Register();
					RaycastRequestMessage raycastRequestMessage = default(RaycastRequestMessage);
					raycastRequestMessage.Purpose = purpose;
					raycastRequestMessage.Guid = guid;
					raycastRequestMessage.Origin = origin;
					raycastRequestMessage.Direction = direction;
					raycastRequestMessage.MaxDistance = maxDistance;
					raycastRequestMessage.RaycastMask = ((LayerMask.op_Implicit(raycastMask) == 0) ? (-1) : ((LayerMask)(ref raycastMask)).value);
					NetworkClient.Send<RaycastRequestMessage>(raycastRequestMessage, 0);
				}
			}
		}

		internal static void HandleRaycastRequest(int requestingConnectionId, RaycastRequestMessage msg)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				return;
			}
			int num = ((msg.RaycastMask == 0) ? (-1) : msg.RaycastMask);
			LayerMask val = LayerMask.op_Implicit(num);
			bool flag = false;
			RaycastHit hit = default(RaycastHit);
			GameObject val2 = null;
			if (((Vector3)(ref msg.Direction)).sqrMagnitude > 1E-06f)
			{
				Ray val3 = default(Ray);
				((Ray)(ref val3))..ctor(msg.Origin, ((Vector3)(ref msg.Direction)).normalized);
				RaycastHit[] array = Physics.RaycastAll(val3, msg.MaxDistance, LayerMask.op_Implicit(val), (QueryTriggerInteraction)1);
				Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
				RaycastHit[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					RaycastHit val4 = array2[i];
					GameObject gameObject = ((Component)((RaycastHit)(ref val4)).collider).gameObject;
					if (!ShouldIgnore(gameObject))
					{
						flag = true;
						hit = val4;
						val2 = GetHighestParent(gameObject);
						break;
					}
				}
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				RaycastUtility.RaycastCompleted?.Invoke(new RaycastCompletedEventArgs(msg.Purpose, requestingConnectionId, msg.Guid, msg.Origin, msg.Direction, msg.MaxDistance, num, flag, hit, val2));
				NetworkMessageBootstrap.Register();
				RaycastResultMessage raycastResultMessage = default(RaycastResultMessage);
				raycastResultMessage.Purpose = msg.Purpose ?? string.Empty;
				raycastResultMessage.Guid = msg.Guid;
				raycastResultMessage.Origin = msg.Origin;
				raycastResultMessage.Direction = msg.Direction;
				raycastResultMessage.MaxDistance = msg.MaxDistance;
				raycastResultMessage.RaycastMask = num;
				raycastResultMessage.HasHit = flag;
				raycastResultMessage.HitPoint = (Vector3)(flag ? ((RaycastHit)(ref hit)).point : default(Vector3));
				raycastResultMessage.HitNormal = (Vector3)(flag ? ((RaycastHit)(ref hit)).normal : default(Vector3));
				raycastResultMessage.HitDistance = (flag ? ((RaycastHit)(ref hit)).distance : 0f);
				raycastResultMessage.HitObjectName = (flag ? ((Object)((Component)((RaycastHit)(ref hit)).collider).gameObject).name : string.Empty);
				raycastResultMessage.ClosestValidRootObjectName = ((Object)val2).name ?? string.Empty;
				NetworkServer.SendToAll<RaycastResultMessage>(raycastResultMessage, 0, false);
			}
		}

		internal static void HandleRaycastResult(RaycastResultMessage msg)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			RaycastUtility.RaycastResultReceived?.Invoke(new RaycastResultReceivedEventArgs(msg.Purpose, msg.Guid, msg.Origin, msg.Direction, msg.MaxDistance, msg.RaycastMask, msg.HasHit, msg.HitPoint, msg.HitNormal, msg.HitDistance, msg.HitObjectName, msg.ClosestValidRootObjectName));
		}

		private static bool ShouldIgnore(GameObject obj)
		{
			Transform val = obj.transform;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name == "Terrain")
				{
					return true;
				}
				if ((Object)(object)((Component)val).GetComponent<PlayerInfo>() != (Object)null)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static GameObject GetHighestParent(GameObject obj)
		{
			Transform val = obj.transform;
			while ((Object)(object)val.parent != (Object)null)
			{
				val = val.parent;
			}
			return ((Component)val).gameObject;
		}
	}
}
namespace Gamemode_Lib.Patches
{
	public class CourseManagerPatches
	{
		[HarmonyPatch(typeof(CourseManager), "EndCourse")]
		[HarmonyPrefix]
		public static void EndCourse_Prefix()
		{
			Plugin.Log.LogInfo((object)$"[GamemodeLib] CourseManager.EndCourse prefix: TryEndCurrentGame(broadcastToClients=true) serverActive={NetworkServer.active}");
			GameModeUtilities.TryEndCurrentGame(broadcastToClients: true);
		}
	}
	public class GameManagerPatches
	{
		[HarmonyPatch(typeof(GameManager), "Awake")]
		[HarmonyPostfix]
		public static void Awake_Postfix(GameManager __instance)
		{
			((Component)__instance).gameObject.AddComponent<TeamManager>();
		}
	}
	public class MatchSetupMenuPatches
	{
		private static readonly Dictionary<TMP_Dropdown, Dictionary<int, string>> DropdownMappings = new Dictionary<TMP_Dropdown, Dictionary<int, string>>();

		private static TMP_Dropdown? _tmpDropdown;

		private static IGamemode? _gameMode;

		[HarmonyPatch(typeof(MatchSetupMenu), "SetEnabled")]
		[HarmonyPostfix]
		public static void SetEnabled_Postfix(MatchSetupMenu __instance)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			if ((Object)(object)_tmpDropdown == (Object)null)
			{
				_tmpDropdown = ((IEnumerable<TMP_Dropdown>)Object.FindObjectsOfType<TMP_Dropdown>(true)).FirstOrDefault((Func<TMP_Dropdown, bool>)((TMP_Dropdown dropdown) => dropdown.options != null && dropdown.options.Any((OptionData o) => o.text == "Free-for-all")));
				if ((Object)(object)_tmpDropdown == (Object)null)
				{
					Plugin.Log.LogError((object)"[GamemodeLib] Could not find TMP_Dropdown containing 'Free-for-all'");
					return;
				}
			}
			if (DropdownMappings.ContainsKey(_tmpDropdown))
			{
				return;
			}
			Dictionary<int, string> dictionary = new Dictionary<int, string>();
			int num = _tmpDropdown.options.Count;
			foreach (KeyValuePair<string, IGamemode> mode in GameModeUtilities.Modes)
			{
				string key = mode.Key;
				IGamemode value = mode.Value;
				_tmpDropdown.options.Add(new OptionData(value.Name));
				dictionary[num] = key;
				num++;
			}
			_tmpDropdown.RefreshShownValue();
			DropdownMappings[_tmpDropdown] = dictionary;
			((UnityEvent<int>)(object)_tmpDropdown.onValueChanged).AddListener((UnityAction<int>)delegate(int index)
			{
				Plugin.Log.LogInfo((object)("[GamemodeLib] Selected gamemode: " + _tmpDropdown.options[index].text + ")"));
				_gameMode = null;
				if (DropdownMappings[_tmpDropdown].TryGetValue(index, out string value2))
				{
					IGamemode gamemode = (_gameMode = GameModeUtilities.Modes[value2]);
					Plugin.Log.LogInfo((object)("[GamemodeLib] " + gamemode.Name + " is using GamemodeLib. It's ID is... " + gamemode.GameModeId));
					if (NetworkServer.active)
					{
						TeamManager.Instance.ResetTeams();
						TeamManager.Instance.ClearTeamDefinitions();
						if (_gameMode.IsTeamBased)
						{
							TeamManager.Instance.CreateAndAssignTeams(_gameMode.TeamCount);
						}
					}
				}
			});
			Plugin.Log.LogInfo((object)"[GamemodeLib] Gamemodes injected into dropdown");
		}

		[HarmonyPatch(typeof(MatchSetupMenu), "StartOrCancelMatch")]
		[HarmonyPrefix]
		public static bool StartOrCancelMatch_Prefix(MatchSetupMenu __instance)
		{
			if ((Object)(object)_tmpDropdown == (Object)null)
			{
				return true;
			}
			if (_gameMode == null)
			{
				return true;
			}
			if (_gameMode.CanStart(__instance.maxPlayers))
			{
				if (StartGame())
				{
					StopAutoNextHole.HideCursor();
					return true;
				}
			}
			else
			{
				Plugin.Log.LogError((object)"[GamemodeLib] Invalid choices, not starting gamemode.");
			}
			return false;
		}

		private static bool StartGame()
		{
			Plugin.Log.LogInfo((object)"[GamemodeLib] Starting gamemode.");
			if ((Object)(object)TeamManager.Instance != (Object)null)
			{
				TeamManager.Instance.AssignUnAssignedPlayersToTeams();
				TeamManager.Instance.SaveCurrentTeams();
				TeamManager.Instance.TryRefreshLocalPlayerTeam();
				if ((Object)(object)TeamManager.Instance.LocalPlayerTeam == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[GamemodeLib] LocalPlayerTeam is null immediately before OnGameStart()");
				}
			}
			GameModeUtilities.CurrentGamemodeId = _gameMode.GameModeId;
			GameModeUtilities.GameEnded = false;
			_gameMode.OnGameStart();
			if (NetworkServer.active)
			{
				NetworkMessageBootstrap.Register();
				ConfigSyncManager.Instance?.BroadcastScopeToClients(_gameMode.GameModeId);
				GamemodeStartMessage gamemodeStartMessage = default(GamemodeStartMessage);
				gamemodeStartMessage.GamemodeId = _gameMode.GameModeId;
				NetworkServer.SendToAll<GamemodeStartMessage>(gamemodeStartMessage, 0, false);
			}
			if (_gameMode.IsNormalStartProcedure)
			{
				return true;
			}
			Plugin.Log.LogInfo((object)"[GamemodeLib] Custom gamemode is chosen, cancelling default start procedure.");
			return false;
		}

		[HarmonyPatch(typeof(MatchSetupMenu), "StartOrCancelMatch")]
		[HarmonyPostfix]
		public static void StartOrCancelMatch_Postfix(MatchSetupMenu __instance)
		{
			TeamManager.Instance.ReloadSavedTeams();
		}
	}
	public class MatchSetupPlayerPatches
	{
		private const string SwapButtonName = "SwapTeamButton";

		[HarmonyPatch(typeof(MatchSetupPlayer), "Update")]
		[HarmonyPostfix]
		public static void Update_Postfix(MatchSetupPlayer __instance)
		{
			UpdateBackground(__instance);
		}

		[HarmonyPatch(typeof(MatchSetupPlayer), "Awake")]
		[HarmonyPostfix]
		public static void Awake_Postfix(MatchSetupPlayer __instance)
		{
			AddSwapButton(__instance);
		}

		private static void UpdateBackground(MatchSetupPlayer playerUI)
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)TeamManager.Instance == (Object)null)
			{
				return;
			}
			ulong guid = playerUI.Guid;
			PlayerTeam playerTeam = null;
			foreach (PlayerTeam player in TeamManager.Instance.Players)
			{
				if ((Object)(object)player == (Object)null || (Object)(object)player.playerInfo == (Object)null || player.playerInfo.PlayerId.guid != guid)
				{
					continue;
				}
				playerTeam = player;
				break;
			}
			if ((Object)(object)playerTeam == (Object)null || !TeamManager.Instance.TryGetTeam(playerTeam.teamId, out TeamData team))
			{
				return;
			}
			Transform val = ((Component)playerUI).transform.Find("Background");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Image component = ((Component)val).GetComponent<Image>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			((Graphic)component).color = team.Color;
			Transform val2 = ((Component)playerUI).transform.Find("Portrait");
			if (!((Object)(object)val2 == (Object)null))
			{
				Image component2 = ((Component)val2).GetComponent<Image>();
				if (!((Object)(object)component2 == (Object)null))
				{
					((Graphic)component2).color = team.Color * 0.7f;
				}
			}
		}

		private static void AddSwapButton(MatchSetupPlayer ui)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Expected O, but got Unknown
			MatchSetupPlayer ui2 = ui;
			Transform val = ((Component)ui2).transform.Find("Info").Find("Buttons");
			if ((Object)(object)val == (Object)null || (Object)(object)val.Find("SwapTeamButton") != (Object)null)
			{
				return;
			}
			Button kickButton = ui2.kickButton;
			if ((Object)(object)kickButton == (Object)null)
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)kickButton).gameObject, val);
			((Object)val2).name = "SwapTeamButton";
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			foreach (Transform item in val2.transform)
			{
				Transform val3 = item;
				Object.Destroy((Object)(object)((Component)val3).gameObject);
			}
			GameObject val4 = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val2.transform, false);
			RectTransform component2 = val4.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = Vector2.zero;
			component2.offsetMax = Vector2.zero;
			TextMeshProUGUI val5 = val4.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val5).text = "<->";
			((TMP_Text)val5).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val5).fontSize = 24f;
			((TMP_Text)val5).enableAutoSizing = true;
			((TMP_Text)val5).fontSizeMin = 12f;
			((TMP_Text)val5).fontSizeMax = 28f;
			((Graphic)val5).raycastTarget = false;
			((TMP_Text)val5).font = TMP_Settings.defaultFontAsset;
			Image component3 = val2.GetComponent<Image>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.sprite = null;
				((Graphic)component3).color = new Color(0.25f, 0.25f, 0.25f, 0.9f);
			}
			LayoutElement val6 = val2.GetComponent<LayoutElement>();
			if ((Object)(object)val6 == (Object)null)
			{
				val6 = val2.AddComponent<LayoutElement>();
			}
			val6.preferredWidth = 60f;
			val6.preferredHeight = 40f;
			((UnityEventBase)component.onClick).RemoveAllListeners();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				OnSwapClicked(ui2);
			});
			val2.SetActive(NetworkServer.active && NetworkClient.active);
		}

		private static void OnSwapClicked(MatchSetupPlayer ui)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			TeamManager instance = TeamManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			ulong guid = ui.Guid;
			foreach (PlayerTeam player in instance.Players)
			{
				if ((Object)(object)player == (Object)null || (Object)(object)player.playerInfo == (Object)null || player.playerInfo.PlayerId.guid != guid)
				{
					continue;
				}
				int nextTeam = GetNextTeam(player.teamId, instance);
				instance.SetTeam(player, nextTeam);
				break;
			}
		}

		private static int GetNextTeam(int current, TeamManager manager)
		{
			if (manager.Teams.Count == 0)
			{
				return -1;
			}
			List<int> list = manager.Teams.Keys.OrderBy((int x) => x).ToList();
			int num = list.IndexOf(current);
			if (num == -1 || num + 1 >= list.Count)
			{
				return list[0];
			}
			return list[num + 1];
		}
	}
	public class NameTagUiPatches
	{
		[HarmonyPatch(typeof(NameTagUi), "LateUpdate")]
		[HarmonyPostfix]
		public static void LateUpdate_Postfix(NameTagUi __instance)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)SingletonNetworkBehaviour<CourseManager>.Instance != (Object)null && SingletonNetworkBehaviour<CourseManager>.Instance.currentHoleCourseIndex == -1)
			{
				((Graphic)__instance.tag).color = Color.white;
			}
			if (!((Object)(object)TeamManager.Instance == (Object)null) && (GameModeUtilities.CurrentGamemodeId == null || GameModeUtilities.Modes[GameModeUtilities.CurrentGamemodeId].IsTeamBased) && TeamManager.Instance.SavedTeamIdByGuid != null && TeamManager.Instance.SavedTeamIdByGuid.Count != 0 && TeamManager.Instance.Teams != null && TeamManager.Instance.Teams.Count != 0)
			{
				PlayerInfo playerInfo = __instance.playerInfo;
				if (!((Object)(object)playerInfo == (Object)null))
				{
					int num = TeamManager.Instance.SavedTeamIdByGuid[playerInfo.PlayerId.guid];
					Color color = ((num == -1) ? Color.white : TeamManager.Instance.Teams[num].Color);
					((Graphic)__instance.tag).color = color;
				}
			}
		}
	}
	public class PlayerInfoPatches
	{
		[HarmonyPatch(typeof(PlayerInfo), "Start")]
		[HarmonyPostfix]
		public static void Start_Postfix(PlayerInfo __instance)
		{
			TeamManager instance = TeamManager.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.EnsurePlayerTeam(__instance);
				instance.RequestTeamFromHost(__instance);
			}
		}

		[HarmonyPatch(typeof(PlayerInfo), "ServerInitializeAsParticipant")]
		[HarmonyPostfix]
		public static void ServerInitializeAsParticipant_Postfix(PlayerInfo __instance)
		{
			Plugin.Log.LogInfo((object)"ServerInitializeAsParticipant_Postfix");
			TeamManager instance = TeamManager.Instance;
			Plugin.Log.LogInfo((object)"ServerInitializeAsParticipant_Postfix2");
			if (!((Object)(object)instance == (Object)null))
			{
				Plugin.Log.LogInfo((object)"ServerInitializeAsParticipant_Postfix3");
				instance.EnsurePlayerTeam(__instance);
				Plugin.Log.LogInfo((object)"ServerInitializeAsParticipant_Postfix4");
				instance.TryApplySavedTeam(__instance);
				Plugin.Log.LogInfo((object)"ServerInitializeAsParticipant_Postfix5");
			}
		}
	}
	public class ScoreboardPatches
	{
		private class ColorCache
		{
			public Color background;

			public Color statusBackground;

			public Color infoBackground;

			public Color statsBackground;

			public Color stripes;
		}

		private static readonly Dictionary<ScoreboardEntry, ColorCache> OriginalColors = new Dictionary<ScoreboardEntry, ColorCache>();

		[HarmonyPatch(typeof(ScoreboardEntry), "PopulateWith")]
		[HarmonyPostfix]
		public static void PopulateWith_Postfix(ScoreboardEntry __instance, PlayerState playerState)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			CacheOriginalColors(__instance);
			ApplyTeamColors(__instance, playerState);
		}

		private static void CacheOriginalColors(ScoreboardEntry entry)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!OriginalColors.ContainsKey(entry))
			{
				OriginalColors[entry] = new ColorCache
				{
					background = ((Graphic)entry.background).color,
					statusBackground = ((Graphic)entry.statusBackground).color,
					infoBackground = ((Graphic)entry.infoBackground).color,
					statsBackground = ((Graphic)entry.statsBackground).color,
					stripes = ((Graphic)entry.stripes).color
				};
			}
		}

		private static void ApplyTeamColors(ScoreboardEntry entry, PlayerState state)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			PlayerInfo val = null;
			if (!GameManager.TryFindPlayerByGuid(state.playerGuid, ref val))
			{
				Plugin.Log.LogWarning((object)$"[Teams] Could not find player with guid={state.playerGuid}");
				RestoreOriginalColors(entry);
				return;
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)$"[Teams] Could not find player with guid={state.playerGuid}");
				RestoreOriginalColors(entry);
				return;
			}
			PlayerTeam component = ((Component)val).GetComponent<PlayerTeam>();
			if ((Object)(object)component == (Object)null || component.teamId < 0)
			{
				Plugin.Log.LogWarning((object)$"[Teams] Could not find player team for player with guid={state.playerGuid}");
				RestoreOriginalColors(entry);
				return;
			}
			if ((Object)(object)TeamManager.Instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[Teams] TeamManager not initialised yet; cannot apply team colors.");
				RestoreOriginalColors(entry);
				return;
			}
			if (!TeamManager.Instance.TryGetTeam(component.teamId, out TeamData team))
			{
				Plugin.Log.LogWarning((object)$"[Teams] Could not find team with id={component.teamId}");
				RestoreOriginalColors(entry);
				return;
			}
			Color color = team.Color;
			Color background = OriginalColors[entry].background;
			((Graphic)entry.background).color = Color.Lerp(background, color, 0.5f);
			((Graphic)entry.statusBackground).color = color;
			((Graphic)entry.infoBackground).color = color;
			Color color2 = color;
			color2.a *= 0.5f;
			((Graphic)entry.statsBackground).color = color2;
			Color stripes = OriginalColors[entry].stripes;
			Color color3 = Color.Lerp(stripes, color, 0.5f);
			color3.a = stripes.a;
			((Graphic)entry.stripes).color = color3;
			Plugin.Log.LogInfo((object)("[Teams] Applied team color to " + ((Object)val).name));
		}

		private static void RestoreOriginalColors(ScoreboardEntry entry)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (OriginalColors.TryGetValue(entry, out ColorCache value))
			{
				((Graphic)entry.background).color = value.background;
				((Graphic)entry.statusBackground).color = value.statusBackground;
				((Graphic)entry.infoBackground).color = value.infoBackground;
				((Graphic)entry.statsBackground).color = value.statsBackground;
				((Graphic)entry.stripes).color = value.stripes;
			}
		}
	}
	public class TeeOffCountdownPatches
	{
		[HarmonyPatch(typeof(TeeOffCountdown), "Hide")]
		[HarmonyPostfix]
		public static void Hide_Postfix(TeeOffCountdown __instance)
		{
			MatchEvents.InvokeOnTeeOffFinished();
		}
	}
}
namespace Gamemode_Lib.Patches.Features
{
	public class DisableLevelBounds
	{
		[HarmonyPatch(typeof(LevelBoundsTracker), "Awake")]
		[HarmonyPostfix]
		public static void Awake_Prefix(LevelBoundsTracker __instance)
		{
			HideLevelBoundsObject();
		}

		[HarmonyPatch(typeof(LevelBoundsTracker), "InformLevelBoundsStateChanged")]
		[HarmonyPrefix]
		public static void InformLevelBoundsStateChanged_Prefix(ref BoundsState boundsState)
		{
			bool flag = BoundsStateExtensions.HasState(boundsState, (BoundsState)1) || BoundsStateExtensions.HasState(boundsState, (BoundsState)2) || BoundsStateExtensions.HasState(boundsState, (BoundsState)4);
			if (BoundsStateExtensions.HasState(boundsState, (BoundsState)8) && !flag)
			{
				boundsState = (BoundsState)0;
			}
		}

		private static void HideLevelBoundsObject()
		{
			GameObject val = GameObject.Find("Level bounds");
			if (!((Object)(object)val == (Object)null))
			{
				MeshRenderer component = val.GetComponent<MeshRenderer>();
				if (!((Object)(object)component == (Object)null))
				{
					((Renderer)component).forceRenderingOff = true;
				}
			}
		}
	}
	public class HideAheadOfBallMessage
	{
		[HarmonyPatch(typeof(AheadOfBallMessage), "Update")]
		[HarmonyPrefix]
		public static void Update_Prefix(AheadOfBallMessage __instance)
		{
			if (SingletonBehaviour<RestartPrompt>.HasInstance)
			{
				RestartPrompt instance = SingletonBehaviour<RestartPrompt>.Instance;
				Object.Destroy((Object)(object)instance);
			}
			__instance.HideInternal();
		}
	}
	public class StopAutoNextHole
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnNextClicked;
		}

		[CompilerGenerated]
		private sealed class <FixLayoutNextFrame>d__4 : IAsyncStateMachine
		{
			public int <>1__state;

			public AsyncUniTaskMethodBuilder <>t__builder;

			public RectTransform rect;

			private Awaiter <>u__1;

			private void MoveNext()
			{
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				try
				{
					Awaiter awaiter;
					if (num != 0)
					{
						YieldAwaitable val = UniTask.Yield();
						awaiter = ((YieldAwaitable)(ref val)).GetAwaiter();
						if (!((Awaiter)(ref awaiter)).IsCompleted)
						{
							num = (<>1__state = 0);
							<>u__1 = awaiter;
							<FixLayoutNextFrame>d__4 <FixLayoutNextFrame>d__ = this;
							((AsyncUniTaskMethodBuilder)(ref <>t__builder)).AwaitUnsafeOnCompleted<Awaiter, <FixLayoutNextFrame>d__4>(ref awaiter, ref <FixLayoutNextFrame>d__);
							return;
						}
					}
					else
					{
						awaiter = <>u__1;
						<>u__1 = default(Awaiter);
						num = (<>1__state = -1);
					}
					((Awaiter)(ref awaiter)).GetResult();
					if (!((Object)(object)rect == (Object)null))
					{
						LayoutRebuilder.ForceRebuildLayoutImmediate(rect);
						Canvas.ForceUpdateCanvases();
					}
				}
				catch (Exception exception)
				{
					<>1__state = -2;
					((AsyncUniTaskMethodBuilder)(ref <>t__builder)).SetException(exception);
					return;
				}
				<>1__state = -2;
				((AsyncUniTaskMethodBuilder)(ref <>t__builder)).SetResult();
			}

			void IAsyncStateMachine.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				this.MoveNext();
			}

			[DebuggerHidden]
			private void SetStateMachine(IAsyncStateMachine stateMachine)
			{
			}

			void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
			{
				//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
				this.SetStateMachine(stateMachine);
			}
		}

		private static GameObject nextButtonInstance;

		public static bool END_GAME;

		[HarmonyPatch(typeof(CourseManager), "OnMatchStateChanged")]
		[HarmonyPrefix]
		public static bool OnMatchStateChanged_Prefix(CourseManager __instance, ref MatchState currentState)
		{
			if ((int)currentState == 6)
			{
				currentState = (MatchState)4;
				ServerInitiateMatchFinish(__instance);
				CreateNextButton();
				return false;
			}
			return true;
		}

		public static void CreateNextButton()
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Expected O, but got Unknown
			if (!NetworkServer.active || !NetworkClient.active || (Object)(object)nextButtonInstance != (Object)null)
			{
				return;
			}
			GameObject val = ((IEnumerable<GameObject>)Resources.FindObjectsOfTypeAll<GameObject>()).FirstOrDefault((Func<GameObject, bool>)((GameObject o) => ((Object)o).name == "Message Button"));
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogError((object)"Message Button not found!");
				return;
			}
			Canvas val2 = ((IEnumerable<Canvas>)Object.FindObjectsOfType<Canvas>()).FirstOrDefault((Func<Canvas, bool>)((Canvas c) => ((Behaviour)c).isActiveAndEnabled && (int)c.renderMode != 2));
			if ((Object)(object)val2 == (Object)null)
			{
				Debug.LogError((object)"Canvas not found!");
				return;
			}
			nextButtonInstance = Object.Instantiate<GameObject>(val);
			((Object)nextButtonInstance).name = "Next Button";
			nextButtonInstance.transform.SetParent(((Component)val2).transform, false);
			RectTransform component = nextButtonInstance.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0f);
			component.anchorMax = new Vector2(0.5f, 0f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = new Vector2(0f, 120f);
			((Transform)component).localScale = Vector3.one;
			component.sizeDelta = val.GetComponent<RectTransform>().sizeDelta;
			nextButtonInstance.SetActive(true);
			CanvasGroup[] componentsInChildren = nextButtonInstance.GetComponentsInChildren<CanvasGroup>(true);
			foreach (CanvasGroup val3 in componentsInChildren)
			{
				val3.alpha = 1f;
				val3.interactable = true;
				val3.blocksRaycasts = true;
			}
			Graphic[] componentsInChildren2 = nextButtonInstance.GetComponentsInChildren<Graphic>(true);
			foreach (Graphic val4 in componentsInChildren2)
			{
				((Behaviour)val4).enabled = true;
			}
			TextMeshProUGUI componentInChildren = nextButtonInstance.GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((TMP_Text)componentInChildren).text = "Next";
				((TMP_Text)componentInChildren).enableWordWrapping = false;
				((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)514;
			}
			Button component2 = nextButtonInstance.GetComponent<Button>();
			if ((Object)(object)component2 != (Object)null)
			{
				((UnityEventBase)component2.onClick).RemoveAllListeners();
				ButtonClickedEvent onClick = component2.onClick;
				object obj = <>O.<0>__OnNextClicked;
				if (obj == null)
				{
					UnityAction val5 = OnNextClicked;
					<>O.<0>__OnNextClicked = val5;
					obj = (object)val5;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj);
			}
			UniTaskExtensions.Forget(FixLayoutNextFrame(component));
			ShowCursor();
		}

		[AsyncStateMachine(typeof(<FixLayoutNextFrame>d__4))]
		[DebuggerStepThrough]
		private static UniTask FixLayoutNextFrame(RectTransform rect)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			<FixLayoutNextFrame>d__4 <FixLayoutNextFrame>d__ = new <FixLayoutNextFrame>d__4();
			<FixLayoutNextFrame>d__.<>t__builder = AsyncUniTaskMethodBuilder.Create();
			<FixLayoutNextFrame>d__.rect = rect;
			<FixLayoutNextFrame>d__.<>1__state = -1;
			((AsyncUniTaskMethodBuilder)(ref <FixLayoutNextFrame>d__.<>t__builder)).Start<<FixLayoutNextFrame>d__4>(ref <FixLayoutNextFrame>d__);
			return ((AsyncUniTaskMethodBuilder)(ref <FixLayoutNextFrame>d__.<>t__builder)).Task;
		}

		private static void ShowCursor()
		{
			CursorManager.SetCursorForceUnlocked(true);
		}

		public static void HideCursor()
		{
			CursorManager.SetCursorForceUnlocked(false);
			CursorManager.ApplyCursorLock();
		}

		private static void OnNextClicked()
		{
			HideCursor();
			CourseManager instance = SingletonNetworkBehaviour<CourseManager>.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if ((Object)(object)nextButtonInstance != (Object)null)
				{
					Object.Destroy((Object)(object)nextButtonInstance);
					nextButtonInstance = null;
				}
				if (!END_GAME)
				{
					SingletonNetworkBehaviour<CourseManager>.Instance.ServerStartNextMatch(false);
				}
				else
				{
					CourseManager.EndCourse();
				}
			}
		}

		private static void ServerInitiateMatchFinish(CourseManager courseManager)
		{
			ServerFinishMatchDelayed(courseManager, isCourseFinished: false);
		}

		private static void AwardCourseBonus(CourseManager courseManager)
		{
			AwardCourseBonusAsync(courseManager);
		}

		private static async void ServerFinishMatchDelayed(CourseManager courseManager, bool isCourseFinished)
		{
			if (!MatchSetupRules.IsCheatsEnabled() && isCourseFinished)
			{
				AwardCourseBonus(courseManager);
			}
			NextMatchCountdown.Show();
			((TMP_Text)SingletonNetworkBehaviour<NextMatchCountdown>.Instance.message).SetText("Waiting for host!");
			float delayDuration = (isCourseFinished ? GameManager.MatchSettings.FinishCourseDelay : GameManager.MatchSettings.StartNextMatchDelay);
			for (float time = 0f; time < delayDuration; time += Time.deltaTime)
			{
				if (!courseManager.forceDisplayScoreboard && time >= GameManager.MatchSettings.MatchEndScoreboardDisplayDelay)
				{
					courseManager.NetworkforceDisplayScoreboard = true;
				}
				await UniTask.Yield();
				if ((Object)(object)courseManager == (Object)null)
				{
					return;
				}
			}
			if (isCourseFinished)
			{
				courseManager.EndCourseInternal();
			}
		}

		private static async void AwardCourseBonusAsync(CourseManager courseManager)
		{
			await UniTask.WaitForSeconds(1f, false, (PlayerLoopTiming)8, default(CancellationToken), false);
			if ((Object)(object)courseManager == (Object)null)
			{
				return;
			}
			List<PlayerState> playerStatesInternal = courseManager.GetSortedPlayerStatesInternal(false);
			if (playerStatesInternal.Count <= 1)
			{
				return;
			}
			List<PlayerState> list = default(List<PlayerState>);
			PooledObject<List<PlayerState>> val = CollectionPool<List<PlayerState>, PlayerState>.Get(ref list);
			try
			{
				NetworkConnectionToClient connection = default(NetworkConnectionToClient);
				for (int i = 0; i < playerStatesInternal.Count; i++)
				{
					PlayerState playerState = playerStatesInternal[i];
					if (playerState.isConnected && !playerState.isSpectator && BNetworkManager.singleton.ServerTryGetConnectionFromPlayerGuid(playerState.playerGuid, ref connection))
					{
						float awardMultiplier = ((i == 0) ? 1f : ((i >= playerStatesInternal.Count / 2) ? 0.5f : 0.75f));
						courseManager.RpcAwardCourseBonus(connection, awardMultiplier);
					}
					connection = null;
				}
			}
			finally
			{
				((IDisposable)val).Dispose();
			}
		}
	}
	public class StopCountdownToMatchEnd
	{
		[HarmonyPatch(typeof(CourseManager), "BeginCountdownToMatchEnd")]
		[HarmonyPrefix]
		public static bool BeginCountdownToMatchEnd_Postfix(CourseManager __instance)
		{
			return false;
		}
	}
}
namespace Gamemode_Lib.Teams
{
	public struct GamemodeEndMessage : NetworkMessage
	{
		public string GamemodeId;
	}
	public struct GamemodeStartMessage : NetworkMessage
	{
		public string GamemodeId;
	}
	public struct TeamAssignMessage : NetworkMessage
	{
		public ulong PlayerGuid;

		public int TeamId;
	}
	public struct TeamDefinitionMessage : NetworkMessage
	{
		public int ID;

		public Color Color;

		public string Name;
	}
	public class PlayerTag : MonoBehaviour
	{
		public enum TagHitType
		{
			Dive,
			GolfSwing
		}

		private Hittable hittable;

		private PlayerTeam playerTeam;

		public static event Action<PlayerInfo, PlayerInfo, TagHitType> PlayerTagged;

		private void Awake()
		{
			hittable = ((Component)this).GetComponent<Hittable>();
			playerTeam = ((Component)this).GetComponent<PlayerTeam>();
			if ((Object)(object)hittable != (Object)null)
			{
				hittable.WasHitByDive += OnWasHitByDive;
				hittable.WasHitByGolfSwing += OnWasHitByGolfSwing;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)hittable != (Object)null)
			{
				hittable.WasHitByDive -= OnWasHitByDive;
				hittable.WasHitByGolfSwing -= OnWasHitByGolfSwing;
			}
		}

		public void OnWasHitByDive(PlayerMovement hitter)
		{
			if ((GameModeUtilities.CurrentGamemodeId == null || GameModeUtilities.Modes[GameModeUtilities.CurrentGamemodeId].IsTaggingEnabled) && !((Object)(object)hittable == (Object)null))
			{
				PlayerInfo val = (PlayerInfo)(((Object)(object)playerTeam != (Object)null) ? ((object)playerTeam.playerInfo) : ((object)((Component)this).GetComponent<PlayerInfo>()));
				PlayerInfo val2 = (((Object)(object)hitter != (Object)null) ? ((Component)hitter).GetComponent<PlayerInfo>() : null);
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)null))
				{
					Plugin.Log.LogInfo((object)("Player " + (((val != null) ? ((Object)((Component)val).gameObject).name : null) ?? ((Object)((Component)this).gameObject).name) + " was hit by dive from " + (((val2 != null) ? ((Object)((Component)val2).gameObject).name : null) ?? ((hitter != null) ? ((Object)((Component)hitter).gameObject).name : null) ?? "unknown")));
					PlayerTag.PlayerTagged?.Invoke(val, val2, TagHitType.Dive);
				}
			}
		}

		public void OnWasHitByGolfSwing(PlayerGolfer hitter, Vector3 vector3, float arg3, bool arg4)
		{
			if ((GameModeUtilities.CurrentGamemodeId == null || GameModeUtilities.Modes[GameModeUtilities.CurrentGamemodeId].IsTaggingEnabled) && !((Object)(object)hittable == (Object)null))
			{
				PlayerInfo val = (PlayerInfo)(((Object)(object)playerTeam != (Object)null) ? ((object)playerTeam.playerInfo) : ((object)((Component)this).GetComponent<PlayerInfo>()));
				PlayerInfo val2 = (((Object)(object)hitter != (Object)null) ? ((Component)hitter).GetComponent<PlayerInfo>() : null);
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)null))
				{
					Plugin.Log.LogInfo((object)("Player " + (((val != null) ? ((Object)((Component)val).gameObject).name : null) ?? ((Object)((Component)this).gameObject).name) + " was hit by swing from " + (((val2 != null) ? ((Object)((Component)val2).gameObject).name : null) ?? ((hitter != null) ? ((Object)((Component)hitter).gameObject).name : null) ?? "unknown")));
					PlayerTag.PlayerTagged?.Invoke(val, val2, TagHitType.GolfSwing);
				}
			}
		}
	}
	public class PlayerTeam : MonoBehaviour
	{
		public int teamId = -1;

		public PlayerInfo playerInfo;

		private void Awake()
		{
			((Component)this).gameObject.AddComponent<PlayerTag>();
			playerInfo = ((Component)this).GetComponent<PlayerInfo>();
			if ((Object)(object)TeamManager.Instance != (Object)null)
			{
				TeamManager.Instance.RegisterPlayer(this);
			}
		}

		public void SetLocalTeam(int newTeam)
		{
			int num = teamId;
			teamId = newTeam;
			Plugin.Log.LogInfo((object)$"[LOCAL] Team changed {num} -> {newTeam}");
			TeamManager.Instance?.NotifyTeamChanged(this, num, newTeam);
		}

		private void OnDestroy()
		{
			TeamManager.Instance?.UnregisterPlayer(this);
		}
	}
	public class TeamData
	{
		public int ID;

		public Color Color;

		public string Name;

		public int Score;

		public readonly HashSet<PlayerTeam> Members = new HashSet<PlayerTeam>();

		public int MemberCount => Members.Count;

		internal void AddMember(PlayerTeam player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				Members.Add(player);
			}
		}

		internal void RemoveMember(PlayerTeam player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				Members.Remove(player);
			}
		}

		internal void ClearMembers()
		{
			Members.Clear();
		}
	}
	public class TeamManager : MonoBehaviour
	{
		private readonly struct BroadcastSuppressScope : IDisposable
		{
			private readonly TeamManager _manager;

			public BroadcastSuppressScope(TeamManager manager)
			{
				_manager = manager;
				_manager._broadcastSuppressDepth++;
			}

			public void Dispose()
			{
				_manager._broadcastSuppressDepth = Mathf.Max(0, _manager._broadcastSuppressDepth - 1);
			}
		}

		[CompilerGenerated]
		private sealed class <PlayerTeamsInScene>d__43 : IEnumerable<PlayerTeam>, IEnumerable, IEnumerator<PlayerTeam>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private PlayerTeam <>2__current;

			private int <>l__initialThreadId;

			public TeamManager <>4__this;

			private PlayerInfo[] <>s__1;

			private int <>s__2;

			private PlayerInfo <info>5__3;

			private PlayerTeam <team>5__4;

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

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

			[DebuggerHidden]
			public <PlayerTeamsInScene>d__43(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>s__1 = null;
				<info>5__3 = null;
				<team>5__4 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_008d;
				}
				<>1__state = -1;
				<>s__1 = Object.FindObjectsByType<PlayerInfo>((FindObjectsSortMode)0);
				<>s__2 = 0;
				goto IL_00aa;
				IL_008d:
				<team>5__4 = null;
				<info>5__3 = null;
				<>s__2++;
				goto IL_00aa;
				IL_00aa:
				if (<>s__2 < <>s__1.Length)
				{
					<info>5__3 = <>s__1[<>s__2];
					<team>5__4 = <>4__this.EnsurePlayerTeam(<info>5__3);
					if ((Object)(object)<team>5__4 != (Object)null)
					{
						<>2__current = <team>5__4;
						<>1__state = 1;
						return true;
					}
					goto IL_008d;
				}
				<>s__1 = null;
				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();
			}

			[DebuggerHidden]
			IEnumerator<PlayerTeam> IEnumerable<PlayerTeam>.GetEnumerator()
			{
				<PlayerTeamsInScene>d__43 result;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					result = this;
				}
				else
				{
					result = new <PlayerTeamsInScene>d__43(0)
					{
						<>4__this = <>4__this
					};
				}
				return result;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<PlayerTeam>)this).GetEnumerator();
			}
		}

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

			private object <>2__current;

			public PlayerInfo info;

			public int instanceId;

			public TeamManager <>4__this;

			private int <i>5__1;

			private ulong <guid>5__2;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						goto end_IL_0000;
					case 0:
						<>1__state = -1;
						<>1__state = -3;
						<i>5__1 = 0;
						break;
					case 1:
						<>1__state = -3;
						<i>5__1++;
						break;
					}
					if (<i>5__1 < 300)
					{
						if ((Object)(object)info == (Object)null)
						{
							result = false;
							goto IL_011f;
						}
						<guid>5__2 = info.PlayerId.guid;
						if (<guid>5__2 != 0)
						{
							NetworkMessageBootstrap.Register();
							TeamRequestMessage teamRequestMessage = default(TeamRequestMessage);
							teamRequestMessage.PlayerGuid = <guid>5__2;
							NetworkClient.Send<TeamRequestMessage>(teamRequestMessage, 0);
							Plugin.Log.LogInfo((object)$"[Teams] Requested team for local player guid={<guid>5__2}");
							result = false;
							goto IL_011f;
						}
						<>2__current = null;
						<>1__state = 1;
						result = true;
					}
					else
					{
						Plugin.Log.LogWarning((object)"[Teams] Timed out waiting for local player guid; team request not sent.");
						<>m__Finally1();
						result = false;
					}
					goto end_IL_0000;
					IL_011f:
					<>m__Finally1();
					end_IL_0000:;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				<>4__this._requestedTeamInstanceIds.Remove(instanceId);
			}

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

		[CompilerGenerated]
		private sealed class <ValidPlayers>d__41 : IEnumerable<PlayerTeam>, IEnumerable, IEnumerator<PlayerTeam>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private PlayerTeam <>2__current;

			private int <>l__initialThreadId;

			public TeamManager <>4__this;

			private HashSet<PlayerTeam>.Enumerator <>s__1;

			private PlayerTeam <player>5__2;

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

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

			[DebuggerHidden]
			public <ValidPlayers>d__41(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>s__1 = default(HashSet<PlayerTeam>.Enumerator);
				<player>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>4__this.Players.RemoveWhere((PlayerTeam player) => (Object)(object)player == (Object)null);
						<>s__1 = <>4__this.Players.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						<player>5__2 = null;
						break;
					}
					if (<>s__1.MoveNext())
					{
						<player>5__2 = <>s__1.Current;
						<>2__current = <player>5__2;
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>s__1 = default(HashSet<PlayerTeam>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>s__1).Dispose();
			}

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

			[DebuggerHidden]
			IEnumerator<PlayerTeam> IEnumerable<PlayerTeam>.GetEnumerator()
			{
				<ValidPlayers>d__41 result;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					result = this;
				}
				else
				{
					result = new <ValidPlayers>d__41(0)
					{
						<>4__this = <>4__this
					};
				}
				return result;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<PlayerTeam>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <ValidPlayersWithInfo>d__42 : IEnumerable<(PlayerTeam Player, PlayerInfo Info)>, IEnumerable, IEnumerator<(PlayerTeam Player, PlayerInfo Info)>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private (PlayerTeam Player, PlayerInfo Info) <>2__current;

			private int <>l__initialThreadId;

			public TeamManager <>4__this;

			private IEnumerator<PlayerTeam> <>s__1;

			private PlayerTeam <player>5__2;

			(PlayerTeam, PlayerInfo) IEnumerator<(PlayerTeam, PlayerInfo)>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

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

			[DebuggerHidden]
			public <ValidPlayersWithInfo>d__42(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>s__1 = null;
				<player>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					int num = <>1__state;
					if (num != 0)
					{
						if (num != 1)
						{
							return false;
						}
						<>1__state = -3;
						goto IL_009c;
					}
					<>1__state = -1;
					<>s__1 = <>4__this.ValidPlayers().GetEnumerator();
					<>1__state = -3;
					goto IL_00a4;
					IL_009c:
					<player>5__2 = null;
					goto IL_00a4;
					IL_00a4:
					if (<>s__1.MoveNext())
					{
						<player>5__2 = <>s__1.Current;
						if ((Object)(object)<player>5__2.playerInfo != (Object)null)
						{
							<>2__current = (<player>5__2, <player>5__2.playerInfo);
							<>1__state = 1;
							return true;
						}
						goto IL_009c;
					}
					<>m__Finally1();
					<>s__1 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>s__1 != null)
				{
					<>s__1.Dispose();
				}
			}

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

			[DebuggerHidden]
			IEnumerator<(PlayerTeam Player, PlayerInfo Info)> IEnumerable<(PlayerTeam, PlayerInfo)>.GetEnumerator()
			{
				<ValidPlayersWithInfo>d__42 result;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					result = this;
				}
				else
				{
					result = new <ValidPlayersWithInfo>d__42(0)
					{
						<>4__this = <>4__this
					};
				}
				return result;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<(PlayerTeam, PlayerInfo)>)this).GetEnumerator();
			}
		}

		public static TeamManager Instance;

		public readonly Dictionary<int, TeamData> Teams = new Dictionary<int, TeamData>();

		public readonly HashSet<PlayerTeam> Players = new HashSet<PlayerTeam>();

		public readonly Dictionary<ulong, int> SavedTeamIdByGuid = new Dictionary<ulong, int>();

		public PlayerTeam LocalPlayerTeam;

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

		private readonly HashSet<int> _requestedTeamInstanceIds = new HashSet<int>();

		private int _broadcastSuppressDepth;

		private int? _lastAllPlayersOnOneTeamId;

		private bool IsBroadcastSuppressed => _broadcastSuppressDepth > 0;

		public event Action<TeamData> AllPlayersOnOneTeam;

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			foreach (PlayerTeam item in PlayerTeamsInScene())
			{
			}
		}

		public void RegisterPlayer(PlayerTeam player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				Players.Add(player);
				if (player.teamId >= 0)
				{
					EnsureTeamData(player.teamId)?.AddMember(player);
				}
				EvaluateAllPlayersOnOneTeam();
			}
		}

		public void UnregisterPlayer(PlayerTeam player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Players.Remove(player);
			foreach (TeamData value in Teams.Values)
			{
				value?.RemoveMember(player);
			}
			EvaluateAllPlayersOnOneTeam();
		}

		public PlayerTeam EnsurePlayerTeam(PlayerInfo info)
		{
			if ((Object)(object)info == (Object)null)
			{
				return null;
			}
			PlayerTeam playerTeam = default(PlayerTeam);
			if (!((Component)info).TryGetComponent<PlayerTeam>(ref playerTeam) || (Object)(object)playerTeam == (Object)null)
			{
				playerTeam = ((Component)info).gameObject.AddComponent<PlayerTeam>();
			}
			playerTeam.playerInfo = info;
			RegisterPlayer(playerTeam);
			if ((Object)(object)SingletonBehaviour<GameManager>.Instance?.localPlayerInfo == (Object)(object)info)
			{
				LocalPlayerTeam = playerTeam;
			}
			ApplyPendingTeamIfAny(info, playerTeam);
			return playerTeam;
		}

		public bool TryRefreshLocalPlayerTeam()
		{
			LocalPlayerTeam = EnsurePlayerTeam(SingletonBehaviour<GameManager>.Instance?.localPlayerInfo);
			return (Object)(object)LocalPlayerTeam != (Object)null;
		}

		public void SetTeam(PlayerTeam player, int teamId, bool broadcastToClients = true)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			if (broadcastToClients)
			{
				player.SetLocalTeam(teamId);
				return;
			}
			using (SuppressBroadcast())
			{
				player.SetLocalTeam(teamId);
			}
		}

		internal void NotifyTeamChanged(PlayerTeam player, int oldTeamId, int newTeamId)
		{
			MoveMember(player, oldTeamId, newTeamId);
			if (NetworkServer.active && TryGetGuid(player, out var guid))
			{
				SaveTeamId(guid, newTeamId);
				Plugin.Log.LogInfo((object)$"[Teams] Persisted team change guid={guid}: {oldTeamId} -> {newTeamId}");
				if (!IsBroadcastSuppressed)
				{
					BroadcastTeam(guid, newTeamId);
				}
			}
			EvaluateAllPlayersOnOneTeam();
		}

		public void AssignUnAssignedPlayersToTeams(bool broadcastToClients = true)
		{
			if (!NetworkServer.active || Teams.Count <= 0)
			{
				return;
			}
			int num = 0;
			foreach (PlayerTeam item in ValidPlayers())
			{
				if (item.teamId == -1)
				{
					SetTeam(item, num % Teams.Count, broadcastToClients);
					num++;
				}
			}
		}

		public void CreateAndAssignTeams(int teamCount)
		{
			if (!NetworkServer.active || teamCount <= 0)
			{
				return;
			}
			Teams.Clear();
			for (int i = 0; i < teamCount; i++)
			{
				SendTeamDefinitionToClients(EnsureTeamData(i));
			}
			int num = 0;
			foreach (PlayerTeam item in PlayerTeamsInScene())
			{
				SetTeam(item, num % teamCount);
				num++;
			}
		}

		public void ResetTeams()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (PlayerTeam item in PlayerTeamsInScene())
			{
				SetTeam(item, -1);
			}
		}

		public void ResetToDefaults(bool broadcastToClients)
		{
			SavedTeamIdByGuid.Clear();
			_pendingTeamIdByGuid.Clear();
			_requestedTeamInstanceIds.Clear();
			_lastAllPlayersOnOneTeamId = null;
			Teams.Clear();
			foreach (PlayerTeam item in ValidPlayers())
			{
				SetTeam(item, -1, broadcastToClients);
			}
			LocalPlayerTeam = null;
			TryRefreshLocalPlayerTeam();
			EvaluateAllPlayersOnOneTeam();
		}

		public void SaveCurrentTeams()
		{
			SavedTeamIdByGuid.Clear();
			foreach (var (playerTeam, val) in ValidPlayersWithInfo())
			{
				SaveTeamId(val.PlayerId.guid, playerTeam.teamId);
			}
		}

		public int ReloadSavedTeams(bool broadcastToClients = true)
		{
			int num = 0;
			foreach (var (player, val) in ValidPlayersWithInfo())
			{
				if (SavedTeamIdByGuid.TryGetValue(val.PlayerId.guid, out var value))
				{
					SetTeam(player, value, broadcastToClients);
					num++;
				}
			}
			return num;
		}

		public bool TryApplySavedTeam(PlayerInfo info, bool broadcastToClients = true)
		{
			if ((Object)(object)info == (Object)null)
			{
				return false;
			}
			if (!SavedTeamIdByGuid.TryGetValue(info.PlayerId.guid, out var value))
			{
				return false;
			}
			SetTeam(EnsurePlayerTeam(info), value, broadcastToClients);
			return true;
		}

		public void RequestTeamFromHost(PlayerInfo info)
		{
			if (!((Object)(object)info == (Object)null) && NetworkClient.active && !NetworkServer.active && !((Object)(object)SingletonBehaviour