Decompiled source of CaptureTheFlag v1.0.4

BepInEx/plugins/StraftatCTF/StraftatCTF.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using FishNet;
using HarmonyLib;
using MyceliumNetworking;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
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: AssemblyTitle("Capture the Flag for STRAFTAT")]
[assembly: AssemblyProduct("StraftatCTF")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: StraftatMod(false)]
[assembly: AssemblyVersion("1.0.4.0")]
namespace StraftatCTF;

internal static class CtfArt
{
	private static readonly List<Object> Owned = new List<Object>();

	private static Shader _litShader;

	private static Shader _unlitShader;

	internal static Color AllyColor
	{
		get
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Saturate(OutlineHandler.TeamColor);
			}
			catch
			{
				return new Color(0.58f, 0.67f, 1f);
			}
		}
	}

	internal static Color EnemyColor
	{
		get
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Saturate(OutlineHandler.EnemyColor);
			}
			catch
			{
				return new Color(1f, 0.24f, 0.2f);
			}
		}
	}

	private static Shader LitShader
	{
		get
		{
			if ((Object)(object)_litShader != (Object)null)
			{
				return _litShader;
			}
			_litShader = Shader.Find("Standard") ?? Shader.Find("Legacy Shaders/Diffuse") ?? Shader.Find("Sprites/Default") ?? ScavengeShader();
			return _litShader;
		}
	}

	private static Shader UnlitShader
	{
		get
		{
			if ((Object)(object)_unlitShader != (Object)null)
			{
				return _unlitShader;
			}
			_unlitShader = Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default") ?? Shader.Find("Unlit/Transparent") ?? LitShader;
			return _unlitShader;
		}
	}

	internal static void DisposeAll()
	{
		foreach (Object item in Owned)
		{
			if (item != (Object)null)
			{
				Object.Destroy(item);
			}
		}
		Owned.Clear();
	}

	internal static Color ColorForTeam(CtfState state, int teamId)
	{
		//IL_0041: 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_0049: 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_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		if (state != null)
		{
			int team = CtfGame.GetTeam(CtfGame.LocalPlayerId);
			if (state.IsPlayingTeam(team) && state.IsPlayingTeam(teamId))
			{
				return (teamId == team) ? AllyColor : EnemyColor;
			}
		}
		return FallbackColor(teamId);
	}

	private static Color FallbackColor(int teamId)
	{
		//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)
		//IL_0033: 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_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: 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)
		Color[] array = (Color[])(object)new Color[4]
		{
			new Color(0.98f, 0.28f, 0.22f),
			new Color(0.36f, 0.62f, 1f),
			new Color(0.44f, 0.94f, 0.42f),
			new Color(1f, 0.79f, 0.22f)
		};
		int num = teamId % array.Length;
		if (num < 0)
		{
			num += array.Length;
		}
		return array[num];
	}

	private static Color Saturate(Color color)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		float num = default(float);
		float num2 = default(float);
		float num3 = default(float);
		Color.RGBToHSV(color, ref num, ref num2, ref num3);
		num2 = Mathf.Clamp(num2, 0.45f, 1f);
		num3 = Mathf.Clamp(num3, 0.65f, 1f);
		Color result = Color.HSVToRGB(num, num2, num3);
		result.a = 1f;
		return result;
	}

	private static Shader ScavengeShader()
	{
		try
		{
			Renderer[] array = Object.FindObjectsOfType<Renderer>();
			foreach (Renderer val in array)
			{
				Material val2 = (((Object)(object)val != (Object)null) ? val.sharedMaterial : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.shader != (Object)null)
				{
					return val2.shader;
				}
			}
		}
		catch
		{
		}
		return null;
	}

	internal static Material Solid(Color color, float emission = 0f)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: 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_0031: Expected O, but got Unknown
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		Shader litShader = LitShader;
		if ((Object)(object)litShader == (Object)null)
		{
			return null;
		}
		Material val = new Material(litShader)
		{
			hideFlags = (HideFlags)61,
			color = color
		};
		if (emission > 0f && val.HasProperty("_EmissionColor"))
		{
			val.EnableKeyword("_EMISSION");
			val.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)4;
			val.SetColor("_EmissionColor", color * emission);
		}
		if (val.HasProperty("_Glossiness"))
		{
			val.SetFloat("_Glossiness", 0.15f);
		}
		if (val.HasProperty("_Metallic"))
		{
			val.SetFloat("_Metallic", 0.1f);
		}
		Owned.Add((Object)(object)val);
		return val;
	}

	internal static Material Glow(Color color, bool depthTested = true)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: 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_0031: Expected O, but got Unknown
		Shader unlitShader = UnlitShader;
		if ((Object)(object)unlitShader == (Object)null)
		{
			return null;
		}
		Material val = new Material(unlitShader)
		{
			hideFlags = (HideFlags)61,
			color = color
		};
		val.renderQueue = (depthTested ? 3050 : 4000);
		if (val.HasProperty("_ZWrite"))
		{
			val.SetFloat("_ZWrite", 0f);
		}
		if (!depthTested && val.HasProperty("_ZTest"))
		{
			val.SetFloat("_ZTest", 8f);
		}
		Owned.Add((Object)(object)val);
		return val;
	}

	internal static void SetColor(Material material, Color color, float emission = 0f)
	{
		//IL_000f: 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)
		if (!((Object)(object)material == (Object)null))
		{
			material.color = color;
			if (emission > 0f && material.HasProperty("_EmissionColor"))
			{
				material.SetColor("_EmissionColor", color * emission);
			}
		}
	}

	private static Mesh NewMesh(string name)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		Mesh val = new Mesh
		{
			name = name,
			hideFlags = (HideFlags)61
		};
		Owned.Add((Object)(object)val);
		return val;
	}

	internal static Mesh Cloth(int columns, int rows, float width, float height, out Vector3[] restPositions)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		columns = Mathf.Max(2, columns);
		rows = Mathf.Max(2, rows);
		int num = columns * rows;
		restPositions = (Vector3[])(object)new Vector3[num];
		Vector2[] array = (Vector2[])(object)new Vector2[num * 2];
		Vector3[] array2 = (Vector3[])(object)new Vector3[num * 2];
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				int num2 = i * columns + j;
				float num3 = (float)j / (float)(columns - 1);
				float num4 = (float)i / (float)(rows - 1);
				restPositions[num2] = new Vector3(num3 * width, (num4 - 0.5f) * height, 0f);
				array2[num2] = restPositions[num2];
				array2[num2 + num] = restPositions[num2];
				array[num2] = new Vector2(num3, num4);
				array[num2 + num] = new Vector2(num3, num4);
			}
		}
		List<int> list = new List<int>((columns - 1) * (rows - 1) * 12);
		for (int k = 0; k < rows - 1; k++)
		{
			for (int l = 0; l < columns - 1; l++)
			{
				int num5 = k * columns + l;
				int num6 = num5 + 1;
				int num7 = num5 + columns;
				int num8 = num7 + 1;
				list.Add(num5);
				list.Add(num7);
				list.Add(num6);
				list.Add(num6);
				list.Add(num7);
				list.Add(num8);
				list.Add(num5 + num);
				list.Add(num6 + num);
				list.Add(num7 + num);
				list.Add(num6 + num);
				list.Add(num8 + num);
				list.Add(num7 + num);
			}
		}
		Mesh val = NewMesh("CTF Cloth");
		val.MarkDynamic();
		val.vertices = array2;
		val.uv = array;
		val.triangles = list.ToArray();
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	internal static void WaveCloth(Mesh mesh, Vector3[] rest, Vector3[] scratch, float time, float strength)
	{
		//IL_002b: 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)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)mesh == (Object)null) && rest != null && scratch != null)
		{
			int num = rest.Length;
			for (int i = 0; i < num; i++)
			{
				Vector3 val = rest[i];
				float x = val.x;
				float num2 = Mathf.Sin(x * 7f + time * 6.5f) * 0.09f + Mathf.Sin(val.y * 5f - time * 4.1f) * 0.035f;
				val.z += num2 * x * strength * 4f;
				val.y += Mathf.Sin(x * 4f + time * 5f) * 0.02f * x * strength * 4f;
				scratch[i] = val;
				scratch[i + num] = val;
			}
			mesh.vertices = scratch;
			mesh.RecalculateNormals();
		}
	}

	internal static Mesh Tube(float radius, float height, int segments = 10)
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		segments = Mathf.Max(3, segments);
		Vector3[] array = (Vector3[])(object)new Vector3[(segments + 1) * 2];
		Vector2[] array2 = (Vector2[])(object)new Vector2[array.Length];
		int[] array3 = new int[segments * 6];
		for (int i = 0; i <= segments; i++)
		{
			float num = (float)i / (float)segments;
			float num2 = num * (float)Math.PI * 2f;
			float num3 = Mathf.Cos(num2) * radius;
			float num4 = Mathf.Sin(num2) * radius;
			array[i] = new Vector3(num3, 0f, num4);
			array[i + segments + 1] = new Vector3(num3, height, num4);
			array2[i] = new Vector2(num, 0f);
			array2[i + segments + 1] = new Vector2(num, 1f);
		}
		for (int j = 0; j < segments; j++)
		{
			int num5 = j;
			int num6 = j + 1;
			int num7 = j + segments + 1;
			int num8 = num7 + 1;
			int num9 = j * 6;
			array3[num9] = num5;
			array3[num9 + 1] = num7;
			array3[num9 + 2] = num6;
			array3[num9 + 3] = num6;
			array3[num9 + 4] = num7;
			array3[num9 + 5] = num8;
		}
		Mesh val = NewMesh("CTF Tube");
		val.vertices = array;
		val.uv = array2;
		val.triangles = array3;
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	internal static Mesh Ring(float innerRadius, float outerRadius, int segments = 48)
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		segments = Mathf.Max(6, segments);
		Vector3[] array = (Vector3[])(object)new Vector3[(segments + 1) * 2];
		Vector2[] array2 = (Vector2[])(object)new Vector2[array.Length];
		List<int> list = new List<int>(segments * 12);
		for (int i = 0; i <= segments; i++)
		{
			float num = (float)i / (float)segments;
			float num2 = num * (float)Math.PI * 2f;
			float num3 = Mathf.Cos(num2);
			float num4 = Mathf.Sin(num2);
			array[i * 2] = new Vector3(num3 * innerRadius, 0f, num4 * innerRadius);
			array[i * 2 + 1] = new Vector3(num3 * outerRadius, 0f, num4 * outerRadius);
			array2[i * 2] = new Vector2(num, 0f);
			array2[i * 2 + 1] = new Vector2(num, 1f);
		}
		for (int j = 0; j < segments; j++)
		{
			int num5 = j * 2;
			int item = num5 + 1;
			int item2 = num5 + 2;
			int item3 = num5 + 3;
			list.Add(num5);
			list.Add(item2);
			list.Add(item);
			list.Add(item);
			list.Add(item2);
			list.Add(item3);
			list.Add(num5);
			list.Add(item);
			list.Add(item2);
			list.Add(item);
			list.Add(item3);
			list.Add(item2);
		}
		Mesh val = NewMesh("CTF Ring");
		val.vertices = array;
		val.uv = array2;
		val.triangles = list.ToArray();
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	internal static Mesh Beam(float radius, float height, int segments = 14)
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		segments = Mathf.Max(3, segments);
		int num = segments + 1;
		Vector3[] array = (Vector3[])(object)new Vector3[num * 2];
		Color[] array2 = (Color[])(object)new Color[array.Length];
		Vector2[] array3 = (Vector2[])(object)new Vector2[array.Length];
		List<int> list = new List<int>(segments * 12);
		for (int i = 0; i <= segments; i++)
		{
			float num2 = (float)i / (float)segments;
			float num3 = num2 * (float)Math.PI * 2f;
			float num4 = Mathf.Cos(num3) * radius;
			float num5 = Mathf.Sin(num3) * radius;
			array[i] = new Vector3(num4, 0f, num5);
			array[i + num] = new Vector3(num4, height, num5);
			array2[i] = new Color(1f, 1f, 1f, 1f);
			array2[i + num] = new Color(1f, 1f, 1f, 0f);
			array3[i] = new Vector2(num2, 0f);
			array3[i + num] = new Vector2(num2, 1f);
		}
		for (int j = 0; j < segments; j++)
		{
			int item = j;
			int item2 = j + 1;
			int num6 = j + num;
			int item3 = num6 + 1;
			list.Add(item);
			list.Add(num6);
			list.Add(item2);
			list.Add(item2);
			list.Add(num6);
			list.Add(item3);
			list.Add(item);
			list.Add(item2);
			list.Add(num6);
			list.Add(item2);
			list.Add(item3);
			list.Add(num6);
		}
		Mesh val = NewMesh("CTF Beam");
		val.vertices = array;
		val.colors = array2;
		val.uv = array3;
		val.triangles = list.ToArray();
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	internal static Mesh Disc(float radius, int segments = 32)
	{
		//IL_0030: 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_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: 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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		segments = Mathf.Max(6, segments);
		Vector3[] array = (Vector3[])(object)new Vector3[segments + 2];
		Color[] array2 = (Color[])(object)new Color[array.Length];
		Vector2[] array3 = (Vector2[])(object)new Vector2[array.Length];
		List<int> list = new List<int>(segments * 6);
		array[0] = Vector3.zero;
		array2[0] = Color.white;
		array3[0] = new Vector2(0.5f, 0.5f);
		for (int i = 0; i <= segments; i++)
		{
			float num = (float)i / (float)segments;
			float num2 = num * (float)Math.PI * 2f;
			array[i + 1] = new Vector3(Mathf.Cos(num2) * radius, 0f, Mathf.Sin(num2) * radius);
			array2[i + 1] = new Color(1f, 1f, 1f, 0f);
			array3[i + 1] = new Vector2(num, 1f);
		}
		for (int j = 1; j <= segments; j++)
		{
			list.Add(0);
			list.Add(j);
			list.Add(j + 1);
			list.Add(0);
			list.Add(j + 1);
			list.Add(j);
		}
		Mesh val = NewMesh("CTF Disc");
		val.vertices = array;
		val.colors = array2;
		val.uv = array3;
		val.triangles = list.ToArray();
		val.RecalculateNormals();
		val.RecalculateBounds();
		return val;
	}

	internal static GameObject Node(string name, Transform parent)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		GameObject val = new GameObject(name)
		{
			hideFlags = (HideFlags)61
		};
		if ((Object)(object)parent != (Object)null)
		{
			val.transform.SetParent(parent, false);
		}
		return val;
	}

	internal static MeshRenderer Renderer(string name, Transform parent, Mesh mesh, Material material)
	{
		GameObject val = Node(name, parent);
		val.AddComponent<MeshFilter>().sharedMesh = mesh;
		MeshRenderer val2 = val.AddComponent<MeshRenderer>();
		((Renderer)val2).sharedMaterial = material;
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)val2).receiveShadows = false;
		((Renderer)val2).lightProbeUsage = (LightProbeUsage)0;
		((Renderer)val2).reflectionProbeUsage = (ReflectionProbeUsage)0;
		return val2;
	}
}
internal sealed class CtfAudio
{
	private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private readonly CtfConfig _config;

	private AudioClip _taken;

	private AudioClip _dropped;

	private AudioClip _returned;

	private AudioClip _captured;

	private AudioClip _matchStart;

	private bool _resolved;

	internal CtfAudio(CtfConfig config)
	{
		_config = config;
	}

	internal void OnSceneChanged()
	{
		_resolved = false;
	}

	internal void OnRuntimeLost()
	{
		_resolved = false;
	}

	internal void Play(int kind)
	{
		if (!_config.PlaySounds.Value)
		{
			return;
		}
		float num = Mathf.Clamp01(_config.SoundVolume.Value);
		if (num <= 0f)
		{
			return;
		}
		Resolve();
		AudioClip val;
		float pitch;
		switch (kind)
		{
		default:
			return;
		case 1:
			val = _taken;
			pitch = 1.15f;
			break;
		case 2:
			val = _dropped;
			pitch = 0.85f;
			break;
		case 3:
			val = _returned;
			pitch = 1f;
			break;
		case 4:
			val = _captured;
			pitch = 1f;
			break;
		case 5:
			val = _matchStart;
			pitch = 1f;
			break;
		}
		if ((Object)(object)val == (Object)null)
		{
			CtfLog.Debug("No sound available for CTF event " + kind + "; staying quiet.");
			return;
		}
		try
		{
			AudioSource val2 = (((Object)(object)SoundManager.Instance != (Object)null) ? SoundManager.Instance._effectsSource : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				val2.pitch = pitch;
				val2.PlayOneShot(val, num);
				val2.pitch = 1f;
			}
		}
		catch
		{
		}
	}

	private void Resolve()
	{
		if (_resolved)
		{
			return;
		}
		_resolved = true;
		_taken = null;
		_dropped = null;
		_returned = null;
		_captured = null;
		_matchStart = null;
		try
		{
			RoundManager instance = RoundManager.Instance;
			PauseManager instance2 = PauseManager.Instance;
			if ((Object)(object)instance != (Object)null && instance.swooshClip != null)
			{
				if (instance.swooshClip.Length != 0)
				{
					_taken = instance.swooshClip[0];
				}
				if (instance.swooshClip.Length > 1)
				{
					_returned = instance.swooshClip[1];
				}
			}
			if ((Object)(object)instance2 != (Object)null)
			{
				_dropped = (((Object)(object)instance2.releaseMenuClip != (Object)null) ? instance2.releaseMenuClip : instance2.closeMenuClip);
				_matchStart = Private<AudioClip>((object)instance2, "startMatchClip");
			}
			if ((Object)(object)instance != (Object)null)
			{
				_captured = Private<AudioClip>((object)instance, "plusOneClip");
				if ((Object)(object)_captured == (Object)null)
				{
					_captured = Private<AudioClip>((object)instance, "winClip");
				}
			}
			if ((Object)(object)_captured == (Object)null && (Object)(object)Crosshair.Instance != (Object)null)
			{
				_captured = Crosshair.Instance.headshotHitClip;
			}
			if ((Object)(object)_matchStart == (Object)null)
			{
				_matchStart = _taken;
			}
			if ((Object)(object)_returned == (Object)null)
			{
				_returned = _taken;
			}
			if ((Object)(object)_dropped == (Object)null)
			{
				_dropped = _returned;
			}
			CtfLog.Debug("CTF audio resolved: taken=" + Name((Object)(object)_taken) + " dropped=" + Name((Object)(object)_dropped) + " returned=" + Name((Object)(object)_returned) + " captured=" + Name((Object)(object)_captured));
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not resolve CTF audio clips: " + ex.Message);
		}
	}

	private static T Private<T>(object target, string fieldName) where T : Object
	{
		if (target == null)
		{
			return default(T);
		}
		try
		{
			object? obj = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target);
			return (T)((obj is T) ? obj : null);
		}
		catch
		{
			return default(T);
		}
	}

	private static string Name(Object obj)
	{
		return (obj == (Object)null) ? "none" : obj.name;
	}
}
internal sealed class CtfConfig
{
	internal readonly ConfigEntry<bool> Enabled;

	internal readonly ConfigEntry<int> CapturesToWin;

	internal readonly ConfigEntry<float> RespawnDelay;

	internal readonly ConfigEntry<float> PickupRadius;

	internal readonly ConfigEntry<float> CaptureRadius;

	internal readonly ConfigEntry<float> DroppedReturnSeconds;

	internal readonly ConfigEntry<bool> RequireOwnFlagHome;

	internal readonly ConfigEntry<float> CarrierSpeedPenalty;

	internal readonly ConfigEntry<float> VoidDepth;

	internal readonly ConfigEntry<bool> SmartRespawns;

	internal readonly ConfigEntry<bool> RespawnUsesAllSpawnPoints;

	internal readonly ConfigEntry<float> RespawnEnemyClearance;

	internal readonly ConfigEntry<float> RespawnHazardRadius;

	internal readonly ConfigEntry<float> RespawnVariety;

	internal readonly ConfigEntry<float> SnapshotInterval;

	internal readonly ConfigEntry<float> RuleTickInterval;

	internal readonly ConfigEntry<float> MinimumBaseSeparation;

	internal readonly ConfigEntry<float> AutoBaseHeightOffset;

	internal readonly ConfigEntry<KeyCode> SetBaseAKey;

	internal readonly ConfigEntry<KeyCode> SetBaseBKey;

	internal readonly ConfigEntry<KeyCode> ClearBasesKey;

	internal readonly ConfigEntry<bool> ShowHud;

	internal readonly ConfigEntry<float> HudScale;

	internal readonly ConfigEntry<bool> ShowFlagBeacons;

	internal readonly ConfigEntry<bool> ShowWorldMarkers;

	internal readonly ConfigEntry<bool> WriteMatchLog;

	internal readonly ConfigEntry<bool> PlaySounds;

	internal readonly ConfigEntry<float> SoundVolume;

	private readonly ConfigFile _file;

	private readonly Dictionary<string, ConfigEntry<string>> _mapBases = new Dictionary<string, ConfigEntry<string>>();

	internal CtfConfig(ConfigFile file)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Expected O, but got Unknown
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Expected O, but got Unknown
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Expected O, but got Unknown
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Expected O, but got Unknown
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Expected O, but got Unknown
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Expected O, but got Unknown
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_027b: Expected O, but got Unknown
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Expected O, but got Unknown
		//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Expected O, but got Unknown
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Expected O, but got Unknown
		//IL_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_035f: Expected O, but got Unknown
		//IL_038e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0398: Expected O, but got Unknown
		//IL_0443: Unknown result type (might be due to invalid IL or missing references)
		//IL_044d: Expected O, but got Unknown
		//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f6: Expected O, but got Unknown
		_file = file;
		Enabled = file.Bind<bool>("General", "Enabled", true, "Enable Capture the Flag. Every player in the lobby must have the same version of this mod installed.");
		CapturesToWin = file.Bind<int>("Rules", "CapturesToWin", 3, new ConfigDescription("Captures needed to win the current STRAFTAT round. Set to 0 to follow the lobby's own 'takes to win' setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
		RespawnDelay = file.Bind<float>("Rules", "RespawnDelay", 3f, new ConfigDescription("Seconds a killed player spends spectating before respawning.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>()));
		PickupRadius = file.Bind<float>("Rules", "PickupRadius", 1.75f, new ConfigDescription("How close you must get to take or return a flag.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>()));
		CaptureRadius = file.Bind<float>("Rules", "CaptureRadius", 2.5f, new ConfigDescription("How close to your own base you must get to score a capture.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), Array.Empty<object>()));
		DroppedReturnSeconds = file.Bind<float>("Rules", "DroppedReturnSeconds", 15f, new ConfigDescription("Seconds before a dropped flag returns home on its own.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 60f), Array.Empty<object>()));
		RequireOwnFlagHome = file.Bind<bool>("Rules", "RequireOwnFlagHome", true, "Require your own flag to be at your base before a capture counts. Turn this off for faster, messier games.");
		CarrierSpeedPenalty = file.Bind<float>("Rules", "CarrierSpeedPenalty", 0f, new ConfigDescription("Fraction of movement speed the flag carrier loses (0 = no penalty, 0.15 = 15% slower).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), Array.Empty<object>()));
		VoidDepth = file.Bind<float>("Rules", "VoidDepth", 40f, new ConfigDescription("A dropped flag this far below the lower base is considered lost and returns home immediately.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 500f), Array.Empty<object>()));
		SmartRespawns = file.Bind<bool>("Respawns", "SmartRespawns", true, "Host only: choose where players come back instead of taking the game's random spawn point. Avoids arriving inside the enemy base, on top of somebody, or in a blast that is already going off. Turn this off to use STRAFTAT's own placement exactly as it ships.");
		RespawnUsesAllSpawnPoints = file.Bind<bool>("Respawns", "RespawnUsesAllSpawnPoints", true, "Consider every spawn point in the map rather than only the group the lobby size selected. A two-player lobby normally has just two points to choose between, which is not enough for placement to mean anything. Only used when SmartRespawns is on.");
		RespawnEnemyClearance = file.Bind<float>("Respawns", "RespawnEnemyClearance", 10f, new ConfigDescription("Metres of room to try to leave between a respawning player and the nearest enemy who can see them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()));
		RespawnHazardRadius = file.Bind<float>("Respawns", "RespawnHazardRadius", 6f, new ConfigDescription("Refuse a spawn point with a live mine, claymore, grenade or damage zone within this many metres. Set to 0 to skip the check.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), Array.Empty<object>()));
		RespawnVariety = file.Bind<float>("Respawns", "RespawnVariety", 0.35f, new ConfigDescription("How much the choice is allowed to wander from the best-scoring spawn point. Near 0 always takes the best one, which is safest and also completely predictable; higher spreads it out.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 3f), Array.Empty<object>()));
		SnapshotInterval = file.Bind<float>("Networking", "SnapshotInterval", 2f, new ConfigDescription("Seconds between full state broadcasts. This is also how quickly a late joiner catches up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
		RuleTickInterval = file.Bind<float>("Networking", "RuleTickInterval", 0.06f, new ConfigDescription("Seconds between host flag-rule evaluations. Lower feels crisper and costs slightly more CPU.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 0.5f), Array.Empty<object>()));
		MinimumBaseSeparation = file.Bind<float>("Bases", "MinimumBaseSeparation", 8f, new ConfigDescription("Refuse to start CTF if the two bases end up closer together than this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), Array.Empty<object>()));
		AutoBaseHeightOffset = file.Bind<float>("Bases", "AutoBaseHeightOffset", 0.25f, new ConfigDescription("Vertical offset applied to automatically discovered bases.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 5f), Array.Empty<object>()));
		SetBaseAKey = file.Bind<KeyCode>("Bases", "SetBaseAKey", (KeyCode)289, "Host only: save the first team's base at your current position, for this map.");
		SetBaseBKey = file.Bind<KeyCode>("Bases", "SetBaseBKey", (KeyCode)290, "Host only: save the second team's base at your current position, for this map.");
		ClearBasesKey = file.Bind<KeyCode>("Bases", "ClearBasesKey", (KeyCode)291, "Host only: forget this map's saved bases and go back to automatic placement.");
		ShowHud = file.Bind<bool>("Display", "ShowHud", true, "Show the CTF scoreboard, objective and announcements.");
		HudScale = file.Bind<float>("Display", "HudScale", 1f, new ConfigDescription("Size multiplier for the CTF HUD.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>()));
		ShowFlagBeacons = file.Bind<bool>("Display", "ShowFlagBeacons", true, "Draw a light beam above flags and bases so they are readable from across the map.");
		ShowWorldMarkers = file.Bind<bool>("Display", "ShowWorldMarkers", true, "Show on-screen edge markers pointing at the flags and your base.");
		WriteMatchLog = file.Bind<bool>("Display", "WriteMatchLog", true, "Also print CTF events into STRAFTAT's own match log feed.");
		PlaySounds = file.Bind<bool>("Audio", "PlaySounds", true, "Play sound cues for pickups, returns and captures.");
		SoundVolume = file.Bind<float>("Audio", "SoundVolume", 0.8f, new ConfigDescription("Volume of the CTF sound cues.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
	}

	internal int ResolveCapturesToWin(int lobbyTakesToWin)
	{
		int value = CapturesToWin.Value;
		if (value > 0)
		{
			return value;
		}
		return (lobbyTakesToWin >= 1 && lobbyTakesToWin <= 100) ? lobbyTakesToWin : 3;
	}

	internal bool TryGetMapBases(string sceneName, out Vector3 baseA, out Vector3 baseB)
	{
		ConfigEntry<string> val = MapEntry(sceneName, isBaseA: true);
		ConfigEntry<string> val2 = MapEntry(sceneName, isBaseA: false);
		bool flag = CtfProtocol.TryParseVector(val.Value, out baseA);
		bool flag2 = CtfProtocol.TryParseVector(val2.Value, out baseB);
		return flag && flag2;
	}

	internal void SetMapBase(string sceneName, bool isBaseA, Vector3 position)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		MapEntry(sceneName, isBaseA).Value = CtfProtocol.FormatVector(position);
		Save();
	}

	internal void ClearMapBases(string sceneName)
	{
		MapEntry(sceneName, isBaseA: true).Value = "";
		MapEntry(sceneName, isBaseA: false).Value = "";
		Save();
	}

	private void Save()
	{
		try
		{
			_file.Save();
		}
		catch (Exception ex)
		{
			CtfLog.Warning("Could not write the CTF config file: " + ex.Message);
		}
	}

	private ConfigEntry<string> MapEntry(string sceneName, bool isBaseA)
	{
		string text = MapSection(sceneName);
		string text2 = (isBaseA ? "BaseA" : "BaseB");
		string key = text + "/" + text2;
		if (_mapBases.TryGetValue(key, out var value))
		{
			return value;
		}
		ConfigEntry<string> val = _file.Bind<string>(text, text2, "", isBaseA ? "Base for the lower-numbered team, as x,y,z. Set it in-game with the SetBaseAKey hotkey while hosting." : "Base for the higher-numbered team, as x,y,z. Set it in-game with the SetBaseBKey hotkey while hosting.");
		_mapBases[key] = val;
		return val;
	}

	private static string MapSection(string sceneName)
	{
		if (string.IsNullOrWhiteSpace(sceneName))
		{
			return "Map.Unknown";
		}
		char[] array = sceneName.ToCharArray();
		for (int i = 0; i < array.Length; i++)
		{
			if (!char.IsLetterOrDigit(array[i]) && array[i] != '-' && array[i] != '_')
			{
				array[i] = '_';
			}
		}
		return "Map." + new string(array);
	}
}
internal sealed class CtfController
{
	private enum EndStage
	{
		None,
		AwardPending,
		AdvancePending,
		Done
	}

	private const int PlayerLayerMask = -65601;

	private const float MaxSweptStep = 6f;

	private const float SweepSampleSpacing = 0.35f;

	private const float FreshBodyGraceSeconds = 2.5f;

	private const float MissingConfirmSeconds = 1.5f;

	private readonly CtfPlugin _plugin;

	private readonly CtfConfig _config;

	private readonly Dictionary<int, float> _respawnAt = new Dictionary<int, float>();

	private readonly List<int> _dueBuffer = new List<int>();

	private readonly Dictionary<int, float> _unfreezeAt = new Dictionary<int, float>();

	private readonly Dictionary<int, Vector3> _lastPosition = new Dictionary<int, Vector3>();

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

	private readonly Dictionary<int, float> _bodySince = new Dictionary<int, float>();

	private readonly Dictionary<int, float> _missingSince = new Dictionary<int, float>();

	private readonly List<int> _auditSeen = new List<int>();

	private readonly List<int> _auditDeparted = new List<int>();

	private CtfState _state = new CtfState();

	private string _status = "Waiting for a two-team match...";

	private float _nextDiscovery;

	private float _nextRuleTick;

	private float _nextSnapshot;

	private float _nextCompatibilityCheck;

	private float _nextRespawnAudit;

	private EndStage _endStage = EndStage.None;

	private float _endStageAt;

	private int _endingTeam = -1;

	private int _baselineScoreA;

	private int _baselineScoreB;

	private bool _scoresMirrored;

	private string _remoteSession = "";

	private int _remoteSequence = -1;

	internal CtfState State => _state;

	internal string Status => _status;

	internal bool Active => _config.Enabled.Value && _state.Active;

	internal bool Ending => _state.Active && _state.Ending;

	internal bool IsAuthority => CtfGame.IsServer && CtfNetwork.IsLobbyHost;

	internal CtfController(CtfPlugin plugin, CtfConfig config)
	{
		_plugin = plugin;
		_config = config;
	}

	internal void ResetForScene(string reason)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		RestoreTakeScores();
		CtfSpawns.Reset();
		_respawnAt.Clear();
		_unfreezeAt.Clear();
		_lastPosition.Clear();
		_bodyId.Clear();
		_bodySince.Clear();
		_missingSince.Clear();
		CtfState ctfState = new CtfState();
		Scene activeScene = SceneManager.GetActiveScene();
		ctfState.SceneName = ((Scene)(ref activeScene)).name;
		_state = ctfState;
		_remoteSession = "";
		_remoteSequence = -1;
		_endStage = EndStage.None;
		_endingTeam = -1;
		_nextDiscovery = Time.unscaledTime + 1f;
		_status = reason;
		_plugin.OnStateApplied();
	}

	internal void OnLobbyLeft()
	{
		if (_state.Active)
		{
			Deactivate("Left the lobby.", broadcast: false);
		}
	}

	internal void Tick()
	{
		float unscaledTime = Time.unscaledTime;
		if (!_config.Enabled.Value)
		{
			if (_state.Active)
			{
				Deactivate("Capture the Flag is switched off in the config.", broadcast: true);
			}
			return;
		}
		if (IsAuthority)
		{
			TickEnding(unscaledTime);
		}
		if (!CtfGame.IsPlayableScene)
		{
			string text = (CtfGame.IsExplorationMap ? "Not available in the exploration map." : "Waiting for a playable match...");
			if (_state.Active && !_state.Ending && IsAuthority)
			{
				Deactivate(text, broadcast: true);
			}
			else if (!_state.Active)
			{
				_status = text;
			}
		}
		else if (!IsAuthority)
		{
			if (!_state.Active)
			{
				_status = "Waiting for the host to start Capture the Flag...";
			}
			else
			{
				TickClientPrediction();
			}
		}
		else
		{
			if (_state.Active && _state.Ending)
			{
				return;
			}
			TickRespawns(unscaledTime);
			if (!_state.Active)
			{
				if (unscaledTime >= _nextDiscovery)
				{
					_nextDiscovery = unscaledTime + 1f;
					TryStartHostState();
				}
			}
			else if (ValidateRunningMatch(unscaledTime))
			{
				if (unscaledTime >= _nextRuleTick)
				{
					_nextRuleTick = unscaledTime + _config.RuleTickInterval.Value;
					TickRules(unscaledTime);
				}
				if (unscaledTime >= _nextSnapshot)
				{
					_nextSnapshot = unscaledTime + _config.SnapshotInterval.Value;
					Broadcast();
				}
			}
		}
	}

	private void TickClientPrediction()
	{
		float unscaledDeltaTime = Time.unscaledDeltaTime;
		CountDown(_state.FlagA, unscaledDeltaTime);
		CountDown(_state.FlagB, unscaledDeltaTime);
	}

	private static void CountDown(FlagState flag, float delta)
	{
		if (flag != null && flag.IsDropped && !(flag.ReturnIn <= 0f))
		{
			flag.ReturnIn = Mathf.Max(0f, flag.ReturnIn - delta);
		}
	}

	private bool ValidateRunningMatch(float now)
	{
		if (!CtfGame.TryGetExactlyTwoTeams(out var teamA, out var teamB) || teamA != _state.TeamA || teamB != _state.TeamB)
		{
			Deactivate("Capture the Flag paused: the lobby no longer has these same two teams.", broadcast: true);
			return false;
		}
		if (CtfGame.CountPlayersOnTeam(teamA) == 0 || CtfGame.CountPlayersOnTeam(teamB) == 0)
		{
			Deactivate("Capture the Flag paused: a team has no players left.", broadcast: true);
			return false;
		}
		if (now >= _nextCompatibilityCheck)
		{
			_nextCompatibilityCheck = now + 2f;
			if (CtfNetwork.Instance != null && !CtfNetwork.Instance.AllPlayersCompatible(out var reason))
			{
				Deactivate(reason, broadcast: true);
				return false;
			}
		}
		return true;
	}

	private void TryStartHostState()
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		if (CtfNetwork.Instance != null && !CtfNetwork.Instance.AllPlayersCompatible(out var reason))
		{
			_status = reason;
			return;
		}
		if (!CtfGame.TryGetExactlyTwoTeams(out var teamA, out var teamB))
		{
			_status = "Capture the Flag needs exactly two teams with players on them.";
			return;
		}
		if (CtfGame.GetConnectedPlayerIds().Count < 2)
		{
			_status = "Capture the Flag needs at least two players.";
			return;
		}
		Scene activeScene = SceneManager.GetActiveScene();
		string name = ((Scene)(ref activeScene)).name;
		string source;
		if (_config.TryGetMapBases(name, out var baseA, out var baseB))
		{
			source = "this map's saved bases";
		}
		else
		{
			if (!CtfGame.TryDiscoverBases(_config.AutoBaseHeightOffset.Value, out baseA, out baseB, out source))
			{
				_status = "No usable base positions found on this map. Set them with the " + ((object)_config.SetBaseAKey.Value/*cast due to .constrained prefix*/).ToString() + " and " + ((object)_config.SetBaseBKey.Value/*cast due to .constrained prefix*/).ToString() + " hotkeys.";
				return;
			}
			CtfGame.OrientBasesTowardTeams(teamA, teamB, ref baseA, ref baseB);
		}
		float num = CtfGame.HorizontalDistance(baseA, baseB);
		float num2 = Mathf.Max(_config.MinimumBaseSeparation.Value, _config.PickupRadius.Value + _config.CaptureRadius.Value + 0.5f);
		if (num < num2)
		{
			_status = "The two bases are only " + num.ToString("0.0") + "m apart; " + num2.ToString("0.0") + "m is needed. Place them by hand with " + ((object)_config.SetBaseAKey.Value/*cast due to .constrained prefix*/).ToString() + " and " + ((object)_config.SetBaseBKey.Value/*cast due to .constrained prefix*/).ToString() + ".";
			return;
		}
		int capturesToWin = _config.ResolveCapturesToWin(CtfGame.LobbyTakesToWin);
		_state = new CtfState
		{
			SessionId = Guid.NewGuid().ToString("N"),
			Sequence = 1,
			SceneName = name,
			Active = true,
			Ending = false,
			TeamA = teamA,
			TeamB = teamB,
			CapturesToWin = capturesToWin,
			BaseA = baseA,
			BaseB = baseB,
			FlagA = new FlagState
			{
				Status = FlagStatus.Home,
				CarrierPlayerId = -1,
				Position = baseA
			},
			FlagB = new FlagState
			{
				Status = FlagStatus.Home,
				CarrierPlayerId = -1,
				Position = baseB
			}
		};
		_endStage = EndStage.None;
		_endingTeam = -1;
		_respawnAt.Clear();
		_unfreezeAt.Clear();
		_lastPosition.Clear();
		_bodyId.Clear();
		_bodySince.Clear();
		_missingSince.Clear();
		_nextRuleTick = Time.unscaledTime;
		_nextSnapshot = Time.unscaledTime;
		_nextCompatibilityCheck = Time.unscaledTime + 2f;
		_nextRespawnAudit = Time.unscaledTime + 4f;
		_status = "Capture the Flag is live. Bases from " + source + ".";
		CaptureScoreBaseline();
		CtfGame.RepopulateAlivePlayers();
		CtfLog.Info("CTF started on " + name + ": teams " + teamA + " vs " + teamB + ", first to " + capturesToWin + ", bases from " + source + " (" + num.ToString("0.0") + "m apart).");
		_plugin.OnStateApplied();
		Broadcast();
		Announce(5, "CAPTURE THE FLAG - FIRST TO " + capturesToWin, "Capture the Flag: first team to " + capturesToWin + " captures wins the round.");
	}

	private void TickRules(float now)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: 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_014d: 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_0177: 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_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_025b: Unknown result type (might be due to invalid IL or missing references)
		//IL_025d: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		bool flag = false;
		flag |= MaintainFlag(_state.FlagA, _state.BaseA, _state.TeamA, now);
		flag |= MaintainFlag(_state.FlagB, _state.BaseB, _state.TeamB, now);
		foreach (int connectedPlayerId in CtfGame.GetConnectedPlayerIds())
		{
			int team = CtfGame.GetTeam(connectedPlayerId);
			if (!_state.IsPlayingTeam(team) || !CtfGame.HasLivingBody(connectedPlayerId) || CtfGame.IsFrozen(connectedPlayerId) || !CtfGame.TryGetPosition(connectedPlayerId, out var position))
			{
				continue;
			}
			Vector3 value;
			Vector3 val = (_lastPosition.TryGetValue(connectedPlayerId, out value) ? value : position);
			_lastPosition[connectedPlayerId] = position;
			FlagState flagState = _state.FlagForTeam(team);
			FlagState flagState2 = _state.FlagForTeam(_state.OtherTeam(team));
			Vector3 val2 = _state.BaseForTeam(team);
			if (flagState == null || flagState2 == null)
			{
				continue;
			}
			if (flagState.IsDropped && InZone(val, position, flagState.Position, _config.PickupRadius.Value))
			{
				SendHome(flagState, val2);
				Announce(3, CtfGame.PlayerName(connectedPlayerId).ToUpperInvariant() + " RETURNED THE FLAG", FormatLog(connectedPlayerId, "returned their flag"));
				flag = true;
			}
			if (_state.TeamCarrying(connectedPlayerId) < 0 && !flagState2.IsCarried && InZone(val, position, flagState2.Position, _config.PickupRadius.Value))
			{
				flagState2.Status = FlagStatus.Carried;
				flagState2.CarrierPlayerId = connectedPlayerId;
				flagState2.Position = position;
				flagState2.ReturnAt = 0f;
				flagState2.ReturnIn = 0f;
				Announce(1, CtfGame.PlayerName(connectedPlayerId).ToUpperInvariant() + " HAS THE FLAG", FormatLog(connectedPlayerId, "took the enemy flag"));
				flag = true;
			}
			if (flagState2.IsCarried && flagState2.CarrierPlayerId == connectedPlayerId && InZone(val, position, val2, _config.CaptureRadius.Value) && (!_config.RequireOwnFlagHome.Value || flagState.IsHome))
			{
				Capture(connectedPlayerId, team, flagState2);
				flag = true;
				if (_state.Ending)
				{
					break;
				}
			}
		}
		if (flag)
		{
			StateChanged();
		}
	}

	private bool MaintainFlag(FlagState flag, Vector3 home, int owningTeam, float now)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: 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_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		if (flag.IsHome)
		{
			flag.Position = home;
			flag.CarrierPlayerId = -1;
			flag.ReturnIn = 0f;
			return false;
		}
		if (flag.IsDropped)
		{
			float num = Mathf.Min(_state.BaseA.y, _state.BaseB.y);
			if (flag.Position.y < num - _config.VoidDepth.Value)
			{
				SendHome(flag, home);
				Announce(3, TeamLabel(owningTeam) + "'S FLAG WAS LOST AND RETURNED", TeamLabel(owningTeam, upperCase: false) + "'s flag fell out of the map and returned home.");
				return true;
			}
			if (now < flag.ReturnAt)
			{
				flag.ReturnIn = Mathf.Max(0f, flag.ReturnAt - now);
				return false;
			}
			SendHome(flag, home);
			Announce(3, TeamLabel(owningTeam) + "'S FLAG RETURNED", TeamLabel(owningTeam, upperCase: false) + "'s flag returned home.");
			return true;
		}
		int carrierPlayerId = flag.CarrierPlayerId;
		if (carrierPlayerId < 0 || !CtfGame.IsConnected(carrierPlayerId))
		{
			SendHome(flag, home);
			Announce(3, TeamLabel(owningTeam) + "'S FLAG RETURNED", TeamLabel(owningTeam, upperCase: false) + "'s flag returned home after its carrier left.");
			return true;
		}
		int team = CtfGame.GetTeam(carrierPlayerId);
		if (team == owningTeam || !_state.IsPlayingTeam(team))
		{
			SendHome(flag, home);
			Announce(3, TeamLabel(owningTeam) + "'S FLAG RETURNED", TeamLabel(owningTeam, upperCase: false) + "'s flag returned home after its carrier changed team.");
			return true;
		}
		if (!CtfGame.HasLivingBody(carrierPlayerId))
		{
			Drop(flag, carrierPlayerId, now);
			return true;
		}
		if (CtfGame.TryGetCarryPoint(carrierPlayerId, out var position))
		{
			flag.Position = position;
		}
		flag.ReturnIn = 0f;
		return false;
	}

	private void Capture(int playerId, int team, FlagState capturedFlag)
	{
		//IL_0014: 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_0188: Unknown result type (might be due to invalid IL or missing references)
		SendHome(capturedFlag, _state.BaseForTeam(_state.OtherTeam(team)));
		if (team == _state.TeamA)
		{
			_state.ScoreA++;
		}
		else
		{
			_state.ScoreB++;
		}
		int num = _state.ScoreForTeam(team);
		MirrorTakeScores();
		Announce(4, CtfGame.PlayerName(playerId).ToUpperInvariant() + " SCORED  " + num + " / " + _state.CapturesToWin, FormatLog(playerId, "captured the flag (" + num + "/" + _state.CapturesToWin + ")"));
		if (num >= _state.CapturesToWin)
		{
			_state.Ending = true;
			_endingTeam = team;
			_endStage = EndStage.AwardPending;
			_endStageAt = Time.unscaledTime + 1.5f;
			_status = TeamLabel(team, upperCase: false) + " won the Capture the Flag round.";
			SendHome(_state.FlagA, _state.BaseA);
			SendHome(_state.FlagB, _state.BaseB);
			_respawnAt.Clear();
			_unfreezeAt.Clear();
			Announce(6, TeamLabel(team) + " WINS THE ROUND", null);
		}
	}

	private void TickEnding(float now)
	{
		if (_endStage == EndStage.None || now < _endStageAt)
		{
			return;
		}
		if (_endStage == EndStage.Done)
		{
			_endStage = EndStage.None;
			if (_state.Active)
			{
				Deactivate("Capture the Flag finished, but the next map did not load. Handing back to the game's normal rules.", broadcast: true);
			}
		}
		else if (!IsAuthority || !_state.Active)
		{
			_endStage = EndStage.None;
		}
		else if (_endStage == EndStage.AwardPending)
		{
			if (CtfGame.AwardRoundWin(_endingTeam))
			{
				_scoresMirrored = false;
				_endStage = EndStage.AdvancePending;
				_endStageAt = now + 4f;
			}
			else
			{
				_endStage = EndStage.None;
				Deactivate("Capture the Flag could not end the round. Check the BepInEx log.", broadcast: true);
			}
		}
		else
		{
			_endStage = EndStage.Done;
			_endStageAt = now + 20f;
			CtfGame.AdvanceToNextRound();
		}
	}

	internal void OnPlayerDied(int playerId)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		if (IsAuthority && Active && !_state.Ending)
		{
			if (CtfGame.TryGetPosition(playerId, out var position))
			{
				CtfSpawns.RecordDeath(playerId, position);
			}
			float unscaledTime = Time.unscaledTime;
			bool flag = false;
			if (_state.FlagA.IsCarried && _state.FlagA.CarrierPlayerId == playerId)
			{
				Drop(_state.FlagA, playerId, unscaledTime);
				flag = true;
			}
			if (_state.FlagB.IsCarried && _state.FlagB.CarrierPlayerId == playerId)
			{
				Drop(_state.FlagB, playerId, unscaledTime);
				flag = true;
			}
			if (flag)
			{
				StateChanged();
			}
		}
	}

	internal void ScheduleRespawn(int playerId)
	{
		if (IsAuthority && Active && !_state.Ending && !_respawnAt.ContainsKey(playerId))
		{
			_respawnAt[playerId] = Time.unscaledTime + _config.RespawnDelay.Value;
		}
	}

	private void TickRespawns(float now)
	{
		if (Active && !_state.Ending && now >= _nextRespawnAudit)
		{
			_nextRespawnAudit = now + 1f;
			AuditForMissingPlayers(now);
		}
		if (_respawnAt.Count > 0)
		{
			_dueBuffer.Clear();
			foreach (KeyValuePair<int, float> item in _respawnAt)
			{
				if (now >= item.Value)
				{
					_dueBuffer.Add(item.Key);
				}
			}
			foreach (int item2 in _dueBuffer)
			{
				_respawnAt.Remove(item2);
				if (!Active || _state.Ending || !CtfGame.IsConnected(item2))
				{
					continue;
				}
				if (CtfGame.HasLivingBody(item2))
				{
					if (!CtfGame.IsInAliveSet(item2))
					{
						CtfGame.MarkAlive(item2);
					}
				}
				else if (!CtfGame.TryRespawn(item2))
				{
					CtfLog.Debug("Respawn for player " + item2 + " did not go through; will retry.");
					_respawnAt[item2] = now + 1f;
				}
				else
				{
					CtfGame.MarkAlive(item2);
					CtfGame.ClearStartCountdown();
					_unfreezeAt[item2] = now + 1f;
					_lastPosition.Remove(item2);
				}
			}
		}
		if (_unfreezeAt.Count == 0)
		{
			return;
		}
		_dueBuffer.Clear();
		foreach (KeyValuePair<int, float> item3 in _unfreezeAt)
		{
			if (now >= item3.Value)
			{
				_dueBuffer.Add(item3.Key);
			}
		}
		foreach (int item4 in _dueBuffer)
		{
			_unfreezeAt.Remove(item4);
			if (Active && CtfGame.IsConnected(item4))
			{
				CtfGame.ClearStartCountdown();
				CtfGame.ReleaseRespawnFreeze(item4);
			}
		}
	}

	private void AuditForMissingPlayers(float now)
	{
		if (!CtfPatches.RoundStartedThisScene)
		{
			_missingSince.Clear();
			return;
		}
		_auditSeen.Clear();
		foreach (int connectedPlayerId in CtfGame.GetConnectedPlayerIds())
		{
			_auditSeen.Add(connectedPlayerId);
			TrackBody(connectedPlayerId, now);
			float value;
			if (!_state.IsPlayingTeam(CtfGame.GetTeam(connectedPlayerId)))
			{
				_missingSince.Remove(connectedPlayerId);
			}
			else if (CtfGame.HasLivingBody(connectedPlayerId))
			{
				if (!CtfGame.IsInAliveSet(connectedPlayerId))
				{
					CtfLog.Debug("Correcting the alive set for " + CtfGame.PlayerName(connectedPlayerId) + ": listed as dead while standing there with health. Not respawning.");
					CtfGame.MarkAlive(connectedPlayerId);
				}
				_missingSince.Remove(connectedPlayerId);
			}
			else if (_respawnAt.ContainsKey(connectedPlayerId) || _unfreezeAt.ContainsKey(connectedPlayerId) || HasFreshBody(connectedPlayerId, now))
			{
				_missingSince.Remove(connectedPlayerId);
			}
			else if (!_missingSince.TryGetValue(connectedPlayerId, out value))
			{
				_missingSince[connectedPlayerId] = now;
			}
			else if (!(now - value < 1.5f))
			{
				_missingSince.Remove(connectedPlayerId);
				CtfLog.Debug("Booking a catch-up respawn for " + CtfGame.PlayerName(connectedPlayerId) + "; bodyless for " + (now - value).ToString("0.0") + "s.");
				_respawnAt[connectedPlayerId] = now + _config.RespawnDelay.Value;
			}
		}
		ForgetDeparted(_auditSeen);
	}

	private void TrackBody(int playerId, float now)
	{
		int value;
		if (!CtfGame.TryGetBodyId(playerId, out var bodyId))
		{
			_bodyId.Remove(playerId);
			_bodySince.Remove(playerId);
		}
		else if (!_bodyId.TryGetValue(playerId, out value) || value != bodyId)
		{
			_bodyId[playerId] = bodyId;
			_bodySince[playerId] = now;
		}
	}

	private bool HasFreshBody(int playerId, float now)
	{
		float value;
		return _bodySince.TryGetValue(playerId, out value) && now - value < 2.5f;
	}

	private void ForgetDeparted(List<int> stillConnected)
	{
		if (_bodyId.Count == 0 && _missingSince.Count == 0)
		{
			return;
		}
		_auditDeparted.Clear();
		foreach (int key in _bodyId.Keys)
		{
			if (!stillConnected.Contains(key))
			{
				_auditDeparted.Add(key);
			}
		}
		foreach (int key2 in _missingSince.Keys)
		{
			if (!stillConnected.Contains(key2) && !_auditDeparted.Contains(key2))
			{
				_auditDeparted.Add(key2);
			}
		}
		foreach (int item in _auditDeparted)
		{
			_bodyId.Remove(item);
			_bodySince.Remove(item);
			_missingSince.Remove(item);
		}
	}

	internal bool TrySetHostBase(bool baseA)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		if (!IsAuthority)
		{
			_plugin.OnCtfEvent(0, "ONLY THE HOST CAN PLACE CTF BASES");
			return false;
		}
		if (!CtfGame.TryGetLocalPosition(out var position))
		{
			_plugin.OnCtfEvent(0, "STAND SOMEWHERE IN THE MAP FIRST");
			return false;
		}
		Scene activeScene = SceneManager.GetActiveScene();
		string name = ((Scene)(ref activeScene)).name;
		if (!_config.TryGetMapBases(name, out var _, out var _) && _state.Active)
		{
			_config.SetMapBase(name, !baseA, baseA ? _state.BaseB : _state.BaseA);
		}
		_config.SetMapBase(name, baseA, position);
		string text = (baseA ? "A" : "B");
		CtfLog.Info("Saved base " + text + " for " + name + " at " + CtfProtocol.FormatVector(position) + ".");
		_plugin.OnCtfEvent(0, "SAVED BASE " + text + " FOR " + name.ToUpperInvariant());
		RestartHostState("Reloading this map's saved bases...");
		return true;
	}

	internal void ClearHostBases()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!IsAuthority)
		{
			_plugin.OnCtfEvent(0, "ONLY THE HOST CAN PLACE CTF BASES");
			return;
		}
		Scene activeScene = SceneManager.GetActiveScene();
		string name = ((Scene)(ref activeScene)).name;
		_config.ClearMapBases(name);
		CtfLog.Info("Cleared the saved bases for " + name + "; falling back to automatic placement.");
		_plugin.OnCtfEvent(0, "CLEARED SAVED BASES FOR " + name.ToUpperInvariant());
		RestartHostState("Returning to automatic base placement...");
	}

	private void RestartHostState(string reason)
	{
		Deactivate(reason, broadcast: true);
		_nextDiscovery = 0f;
		TryStartHostState();
	}

	internal void ApplyRemoteSnapshot(string payload)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		if (IsAuthority)
		{
			return;
		}
		if (!CtfProtocol.TryDeserialize(payload, out var state, out var error))
		{
			CtfLog.Warning("Rejected a CTF snapshot: " + error);
			return;
		}
		string sceneName = state.SceneName;
		Scene activeScene = SceneManager.GetActiveScene();
		if (string.Equals(sceneName, ((Scene)(ref activeScene)).name, StringComparison.Ordinal) && (!(state.SessionId == _remoteSession) || state.Sequence >= _remoteSequence))
		{
			_remoteSession = state.SessionId;
			_remoteSequence = state.Sequence;
			_state = state;
			_status = (state.Active ? "Capture the Flag is live." : "The host has paused Capture the Flag.");
			_plugin.OnStateApplied();
		}
	}

	internal void ApplyRemoteEvent(string sessionId, int kind, string message)
	{
		if (!IsAuthority && CtfEventKind.IsValid(kind) && (string.IsNullOrEmpty(_remoteSession) || string.IsNullOrEmpty(sessionId) || string.Equals(sessionId, _remoteSession, StringComparison.Ordinal)) && CtfProtocol.TrySanitiseAnnouncement(message, out var sanitised))
		{
			_plugin.OnCtfEvent(kind, sanitised);
		}
	}

	private void Drop(FlagState flag, int carrierId, float now)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		Vector3 position = DropPosition(carrierId, flag);
		flag.Status = FlagStatus.Dropped;
		flag.CarrierPlayerId = -1;
		flag.Position = position;
		flag.ReturnAt = now + _config.DroppedReturnSeconds.Value;
		flag.ReturnIn = _config.DroppedReturnSeconds.Value;
		Announce(2, CtfGame.PlayerName(carrierId).ToUpperInvariant() + " DROPPED THE FLAG", FormatLog(carrierId, "dropped the flag"));
	}

	private static Vector3 DropPosition(int carrierId, FlagState flag)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: 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_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		if (!CtfGame.TryGetPosition(carrierId, out var position))
		{
			return flag.Position;
		}
		try
		{
			Vector3 val = position + Vector3.up * 1.2f;
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val, Vector3.down, ref val2, 6f, -65601, (QueryTriggerInteraction)1))
			{
				return ((RaycastHit)(ref val2)).point + Vector3.up * 0.15f;
			}
		}
		catch
		{
		}
		return position + Vector3.up * 0.15f;
	}

	private static void SendHome(FlagState flag, Vector3 home)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		flag.Status = FlagStatus.Home;
		flag.CarrierPlayerId = -1;
		flag.Position = home;
		flag.ReturnAt = 0f;
		flag.ReturnIn = 0f;
	}

	private static bool InZone(Vector3 point, Vector3 centre, float radius)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: 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_002b: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Max(2.2f, radius);
		if (Mathf.Abs(point.y - centre.y) > num)
		{
			return false;
		}
		return CtfGame.HorizontalDistance(point, centre) <= radius;
	}

	private static bool InZone(Vector3 from, Vector3 to, Vector3 centre, float radius)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: 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_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		if (InZone(to, centre, radius))
		{
			return true;
		}
		Vector3 val = to - from;
		float magnitude = ((Vector3)(ref val)).magnitude;
		if (magnitude <= 0.35f || magnitude > 6f)
		{
			return false;
		}
		int num = Mathf.CeilToInt(magnitude / 0.35f);
		for (int i = 1; i < num; i++)
		{
			if (InZone(from + val * ((float)i / (float)num), centre, radius))
			{
				return true;
			}
		}
		return false;
	}

	private void StateChanged()
	{
		_state.Sequence++;
		_plugin.OnStateApplied();
		Broadcast();
	}

	private void Broadcast()
	{
		if (IsAuthority)
		{
			CtfNetwork.Instance?.BroadcastSnapshot(_state);
		}
	}

	private void Announce(int kind, string headline, string matchLogLine)
	{
		_plugin.OnCtfEvent(kind, headline);
		CtfNetwork.Instance?.BroadcastEvent(_state.SessionId, kind, headline);
		if (_config.WriteMatchLog.Value && !string.IsNullOrEmpty(matchLogLine))
		{
			CtfGame.WriteMatchLog(matchLogLine);
		}
		CtfLog.Debug("CTF event " + kind + ": " + headline);
	}

	private static string FormatLog(int playerId, string what)
	{
		return CtfGame.NameTag(playerId) + " " + what;
	}

	private string TeamLabel(int teamId, bool upperCase = true)
	{
		string text = ((teamId == _state.TeamA) ? "team 1" : ((teamId == _state.TeamB) ? "team 2" : "a team"));
		return upperCase ? text.ToUpperInvariant() : text;
	}

	private void Deactivate(string reason, bool broadcast)
	{
		bool active = _state.Active;
		RestoreTakeScores();
		_respawnAt.Clear();
		_unfreezeAt.Clear();
		_lastPosition.Clear();
		_bodyId.Clear();
		_bodySince.Clear();
		_missingSince.Clear();
		_endStage = EndStage.None;
		_endingTeam = -1;
		if (active)
		{
			_state.Active = false;
			_state.Ending = false;
			_state.Sequence++;
			if (broadcast)
			{
				Broadcast();
			}
			if (IsAuthority)
			{
				CtfGame.ClearWaitForDrawHandle();
				CtfGame.RepopulateAlivePlayers();
			}
		}
		_status = reason;
		_nextDiscovery = Time.unscaledTime + 2f;
		_plugin.OnStateApplied();
		if (active)
		{
			CtfLog.Info("Capture the Flag stopped: " + reason);
		}
		else
		{
			CtfLog.Debug("CTF stayed inactive: " + reason);
		}
	}

	private void CaptureScoreBaseline()
	{
		_baselineScoreA = 0;
		_baselineScoreB = 0;
		_scoresMirrored = false;
		try
		{
			if (!((Object)(object)ScoreManager.Instance == (Object)null))
			{
				_baselineScoreA = ScoreManager.Instance.GetRoundScore(_state.TeamA);
				_baselineScoreB = ScoreManager.Instance.GetRoundScore(_state.TeamB);
			}
		}
		catch
		{
		}
	}

	private void MirrorTakeScores()
	{
		if (IsAuthority)
		{
			_scoresMirrored = true;
			CtfGame.SyncTakeScores(_state.TeamA, _baselineScoreA + _state.ScoreA, _state.TeamB, _baselineScoreB + _state.ScoreB);
		}
	}

	private void RestoreTakeScores()
	{
		if (_scoresMirrored)
		{
			_scoresMirrored = false;
			if (IsAuthority)
			{
				CtfGame.SyncTakeScores(_state.TeamA, _baselineScoreA, _state.TeamB, _baselineScoreB);
			}
		}
	}
}
internal static class CtfGame
{
	private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static MethodInfo _roundWon;

	private static MethodInfo _updateMatchPointsHud;

	private static MethodInfo _respawnLogic;

	private static MethodInfo _setPlayerMoveLogic;

	private static FieldInfo _waitForDrawCoroutine;

	private static FieldInfo _roundHasStarted;

	private static FieldInfo _currentSpawnPoints;

	private static bool _resolved;

	private static float _nextLatchReport;

	internal static bool IsServer
	{
		get
		{
			try
			{
				return (Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer;
			}
			catch
			{
				return false;
			}
		}
	}

	internal static bool IsPlayableScene
	{
		get
		{
			try
			{
				if ((Object)(object)GameManager.Instance == (Object)null || (Object)(object)ScoreManager.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null)
				{
					return false;
				}
				if ((Object)(object)PauseManager.Instance == (Object)null)
				{
					return false;
				}
				if (PauseManager.Instance.inMainMenu || PauseManager.Instance.inVictoryMenu)
				{
					return false;
				}
				if (PauseManager.Instance.onEndRoundScreen)
				{
					return false;
				}
				if (IsExplorationMap)
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}
	}

	internal static bool IsExplorationMap
	{
		get
		{
			try
			{
				if ((Object)(object)MapsManager.Instance != (Object)null && MapsManager.Instance.inExplorationMap)
				{
					return true;
				}
				return (Object)(object)SceneMotor.Instance != (Object)null && SceneMotor.Instance.testMap;
			}
			catch
			{
				return false;
			}
		}
	}

	internal static int LobbyTakesToWin
	{
		get
		{
			try
			{
				return ((Object)(object)ScoreManager.Instance != (Object)null) ? ScoreManager.Instance.RoundScoreRequiredToWin : 3;
			}
			catch
			{
				return 3;
			}
		}
	}

	internal static int LocalPlayerId
	{
		get
		{
			try
			{
				return ((Object)(object)ClientInstance.Instance != (Object)null) ? ClientInstance.Instance.PlayerId : (-1);
			}
			catch
			{
				return -1;
			}
		}
	}

	internal static FirstPersonController LocalPlayer
	{
		get
		{
			try
			{
				int localPlayerId = LocalPlayerId;
				PlayerManager manager;
				FirstPersonController player;
				return (localPlayerId >= 0 && TryGetPlayer(localPlayerId, out manager, out player)) ? player : null;
			}
			catch
			{
				return null;
			}
		}
	}

	internal static int RespawningPlayerId { get; private set; } = -1;

	internal static bool ResolveReflection()
	{
		if (_resolved)
		{
			return true;
		}
		bool ok = true;
		_roundWon = Require(typeof(GameManager), "RoundWon", ref ok, (MethodInfo m) => m.GetParameters().Length == 1);
		_waitForDrawCoroutine = RequireField(typeof(GameManager), "waitForDrawCoroutine", ref ok);
		_respawnLogic = Require(typeof(PlayerManager), null, ref ok, (MethodInfo m) => m.Name.StartsWith("RpcLogic___CmdRespawn_", StringComparison.Ordinal) && m.GetParameters().Length == 0, "PlayerManager.RpcLogic___CmdRespawn_*");
		_setPlayerMoveLogic = Require(typeof(PlayerManager), null, ref ok, (MethodInfo m) => m.Name.StartsWith("RpcLogic___SetPlayerMove_", StringComparison.Ordinal) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(bool), "PlayerManager.RpcLogic___SetPlayerMove_*");
		_updateMatchPointsHud = Optional(typeof(GameManager), "UpdateMatchPointsHUD");
		_roundHasStarted = typeof(FirstPersonController).GetField("roundHasStarted", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (_roundHasStarted == null)
		{
			CtfLog.Warning("FirstPersonController.roundHasStarted was not found; respawned players may not trigger teleporters or void kills.");
		}
		_currentSpawnPoints = typeof(PlayerManager).GetField("CurrentSpawnPoints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (_currentSpawnPoints == null)
		{
			CtfLog.Debug("PlayerManager.CurrentSpawnPoints was not found; respawn placement will always consider every spawn point in the map.");
		}
		_resolved = ok;
		return ok;
	}

	internal static List<int> GetConnectedPlayerIds()
	{
		try
		{
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				if ((Object)(object)playerInstance.Value != (Object)null)
				{
					list.Add(playerInstance.Key);
				}
			}
			list.Sort();
			return list;
		}
		catch
		{
			return new List<int>();
		}
	}

	internal static bool IsConnected(int playerId)
	{
		try
		{
			ClientInstance value;
			return ClientInstance.playerInstances.TryGetValue(playerId, out value) && (Object)(object)value != (Object)null;
		}
		catch
		{
			return false;
		}
	}

	internal static bool TryGetExactlyTwoTeams(out int teamA, out int teamB)
	{
		teamA = -1;
		teamB = -1;
		if ((Object)(object)ScoreManager.Instance == (Object)null)
		{
			return false;
		}
		HashSet<int> hashSet = new HashSet<int>();
		foreach (int connectedPlayerId in GetConnectedPlayerIds())
		{
			int team = GetTeam(connectedPlayerId);
			if (team >= 0)
			{
				hashSet.Add(team);
			}
			if (hashSet.Count > 2)
			{
				return false;
			}
		}
		if (hashSet.Count != 2)
		{
			return false;
		}
		List<int> list = hashSet.ToList();
		list.Sort();
		teamA = list[0];
		teamB = list[1];
		return true;
	}

	internal static int GetTeam(int playerId)
	{
		try
		{
			return ((Object)(object)ScoreManager.Instance != (Object)null) ? ScoreManager.Instance.GetTeamId(playerId) : (-1);
		}
		catch
		{
			return -1;
		}
	}

	internal static int CountPlayersOnTeam(int teamId)
	{
		int num = 0;
		foreach (int connectedPlayerId in GetConnectedPlayerIds())
		{
			if (GetTeam(connectedPlayerId) == teamId)
			{
				num++;
			}
		}
		return num;
	}

	internal static bool TryGetPlayer(int playerId, out PlayerManager manager, out FirstPersonController player)
	{
		manager = null;
		player = null;
		try
		{
			if (!ClientInstance.playerInstances.TryGetValue(playerId, out var value) || (Object)(object)value == (Object)null)
			{
				return false;
			}
			manager = (((Object)(object)value.PlayerSpawner != (Object)null) ? value.PlayerSpawner : ((Component)value).GetComponent<PlayerManager>());
			if ((Object)(object)manager == (Object)null)
			{
				return false;
			}
			player = manager.player;
			return (Object)(object)player != (Object)null;
		}
		catch
		{
			return false;
		}
	}

	internal static bool TryGetPosition(int playerId, out Vector3 position)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		position = Vector3.zero;
		if (!TryGetPlayer(playerId, out var _, out var player))
		{
			return false;
		}
		Transform transform = ((Component)player).transform;
		if ((Object)(object)transform == (Object)null)
		{
			return false;
		}
		position = transform.position;
		return IsFinite(position);
	}

	internal static bool TryGetCarryPoint(int playerId, out Vector3 position)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
		position = Vector3.zero;
		if (!TryGetPosition(playerId, out var position2))
		{
			return false;
		}
		position = position2 + Vector3.up * 1.1f;
		return true;
	}

	internal static bool IsInAliveSet(int playerId)
	{
		try
		{
			return (Object)(object)GameManager.Instance != (Object)null && GameManager.Instance.alivePlayers.Contains(playerId);
		}
		catch
		{
			return false;
		}
	}

	internal static bool HasLivingBody(int playerId)
	{
		try
		{
			if (!TryGetPlayer(playerId, out var _, out var player))
			{
				return false;
			}
			if (!((Component)player).gameObject.activeInHierarchy)
			{
				return false;
			}
			PlayerHealth val = ((Component)player).GetComponent<PlayerHealth>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)player).GetComponentInChildren<PlayerHealth>(true);
			}
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			return val.health > 0f;
		}
		catch
		{
			return false;
		}
	}

	internal static bool TryGetBodyId(int playerId, out int bodyId)
	{
		bodyId = 0;
		if (!TryGetPlayer(playerId, out var _, out var player))
		{
			return false;
		}
		try
		{
			bodyId = ((Object)player).GetInstanceID();
			return true;
		}
		catch
		{
			return false;
		}
	}

	internal static bool IsFrozen(int playerId)
	{
		try
		{
			if (!TryGetPlayer(playerId, out var _, out var player))
			{
				return true;
			}
			return !player.canMove;
		}
		catch
		{
			return true;
		}
	}

	internal static string PlayerName(int playerId)
	{
		try
		{
			if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null && !string.IsNullOrEmpty(value.PlayerName))
			{
				return value.PlayerName;
			}
		}
		catch
		{
		}
		return "player " + playerId;
	}

	internal static bool TryGetLocalPosition(out Vector3 position)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		position = Vector3.zero;
		int localPlayerId = LocalPlayerId;
		return localPlayerId >= 0 && TryGetPosition(localPlayerId, out position);
	}

	internal static bool TryDiscoverBases(float heightOffset, out Vector3 baseA, out Vector3 baseB, out string source)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: 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_01d4: 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_01f1: Unknown result type (might be due to invalid IL or missing references)
		baseA = Vector3.zero;
		baseB = Vector3.zero;
		source = "";
		List<Vector3> list = new List<Vector3>();
		try
		{
			SpawnPoint[] array = Object.FindObjectsOfType<SpawnPoint>(true);
			foreach (SpawnPoint val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null))
				{
					Vector3 position = ((Component)val).transform.position;
					if (IsFinite(position))
					{
						list.Add(position);
					}
				}
			}
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Spawn point discovery failed: " + ex.Message);
		}
		if (list.Count >= 2)
		{
			source = "the map's spawn points";
		}
		else
		{
			foreach (int connectedPlayerId in GetConnectedPlayerIds())
			{
				if (TryGetPosition(connectedPlayerId, out var position2))
				{
					list.Add(position2);
				}
			}
			source = "player positions";
		}
		if (list.Count < 2)
		{
			return false;
		}
		list = (from p in list
			orderby p.x, p.z, p.y
			select p).ToList();
		float num = -1f;
		int num2 = -1;
		int index = -1;
		for (int num3 = 0; num3 < list.Count - 1; num3++)
		{
			for (int num4 = num3 + 1; num4 < list.Count; num4++)
			{
				float num5 = list[num3].x - list[num4].x;
				float num6 = list[num3].z - list[num4].z;
				float num7 = num5 * num5 + num6 * num6;
				if (!(num7 <= num))
				{
					num = num7;
					num2 = num3;
					index = num4;
				}
			}
		}
		if (num2 < 0)
		{
			return false;
		}
		baseA = list[num2] + Vector3.up * heightOffset;
		baseB = list[index] + Vector3.up * heightOffset;
		return true;
	}

	internal static float HorizontalDistance(Vector3 a, Vector3 b)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		float num = a.x - b.x;
		float num2 = a.z - b.z;
		return Mathf.Sqrt(num * num + num2 * num2);
	}

	internal static void OrientBasesTowardTeams(int teamA, int teamB, ref Vector3 baseA, ref Vector3 baseB)
	{
		//IL_0022: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		if (TryTeamCentroid(teamA, out var centroid) && TryTeamCentroid(teamB, out var centroid2))
		{
			float num = HorizontalDistance(baseA, centroid) + HorizontalDistance(baseB, centroid2);
			float num2 = HorizontalDistance(baseB, centroid) + HorizontalDistance(baseA, centroid2);
			if (!(num2 >= num))
			{
				Vector3 val = baseA;
				baseA = baseB;
				baseB = val;
			}
		}
	}

	private static bool TryTeamCentroid(int team, out Vector3 centroid)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: 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_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_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		centroid = Vector3.zero;
		int num = 0;
		foreach (int connectedPlayerId in GetConnectedPlayerIds())
		{
			if (GetTeam(connectedPlayerId) == team && TryGetPosition(connectedPlayerId, out var position))
			{
				centroid += position;
				num++;
			}
		}
		if (num == 0)
		{
			return false;
		}
		centroid /= (float)num;
		return true;
	}

	internal static bool TryRespawn(int playerId)
	{
		if (_respawnLogic == null)
		{
			return false;
		}
		if (!TryGetManager(playerId, out var manager))
		{
			return false;
		}
		int hostSuit;
		int hostCig;
		bool flag = TryWearPlayerCosmetics(manager, out hostSuit, out hostCig);
		RespawningPlayerId = playerId;
		try
		{
			_respawnLogic.Invoke(manager, null);
			return true;
		}
		catch (Exception ex)
		{
			CtfLog.Error("Could not respawn " + PlayerName(playerId) + ": " + ex);
			return false;
		}
		finally
		{
			RespawningPlayerId = -1;
			if (flag)
			{
				RestoreCosmetics(hostSuit, hostCig);
			}
		}
	}

	internal static void CollectAssignedSpawnPoints(int playerId, List<SpawnPoint> into)
	{
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		into.Clear();
		if (_currentSpawnPoints == null)
		{
			return;
		}
		try
		{
			if (!TryGetManager(playerId, out var manager) || !(_currentSpawnPoints.GetValue(manager) is SpawnPoint[] array))
			{
				return;
			}
			SpawnPoint[] array2 = array;
			foreach (SpawnPoint val in array2)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null) && ((Component)val).gameObject.activeInHierarchy && IsFinite(((Component)val).transform.position))
				{
					into.Add(val);
				}
			}
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not read the game's assigned spawn points: " + ex.Message);
			into.Clear();
		}
	}

	private static bool TryWearPlayerCosmetics(PlayerManager manager, out int hostSuit, out int hostCig)
	{
		hostSuit = 0;
		hostCig = 0;
		try
		{
			CosmeticsManager instance = CosmeticsManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			PlayerSetup val = (((Object)(object)manager.player != (Object)null) ? manager.player.setupScript : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			hostSuit = instance.currentsuitIndex;
			hostCig = instance.currentcigIndex;
			if (hostSuit == val.mat && hostCig == val.cig)
			{
				return false;
			}
			instance.currentsuitIndex = val.mat;
			instance.currentcigIndex = val.cig;
			return true;
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not preserve respawn cosmetics: " + ex.Message);
			return false;
		}
	}

	private static void RestoreCosmetics(int suit, int cig)
	{
		try
		{
			CosmeticsManager instance = CosmeticsManager.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.currentsuitIndex = suit;
				instance.currentcigIndex = cig;
			}
		}
		catch (Exception ex)
		{
			CtfLog.Error("Could not restore the host's cosmetics: " + ex);
		}
	}

	internal static void ReleaseRespawnFreeze(int playerId)
	{
		if (!TryGetManager(playerId, out var manager) || (Object)(object)manager.player == (Object)null)
		{
			return;
		}
		try
		{
			_setPlayerMoveLogic?.Invoke(manager, new object[1] { true });
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not release the respawn freeze: " + ex.Message);
		}
	}

	internal static void ClearStartCountdown()
	{
		if (!CtfPatches.RoundStartedThisScene)
		{
			return;
		}
		try
		{
			GameManager instance = GameManager.Instance;
			if (instance != null)
			{
				instance.SetStartTime(0f);
			}
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not clear the start countdown: " + ex.Message);
		}
	}

	internal static void EnforceRoundIsLive()
	{
		if (!CtfPatches.RoundStartedThisScene)
		{
			return;
		}
		try
		{
			if (PauseManager.BetweenRounds)
			{
				PauseManager.BetweenRounds = false;
				float unscaledTime = Time.unscaledTime;
				if (!(unscaledTime < _nextLatchReport))
				{
					_nextLatchReport = unscaledTime + 5f;
					CtfLog.Debug("Cleared a between-rounds latch during a live CTF round; left set it would have disarmed every explosive on this machine.");
				}
			}
		}
		catch
		{
		}
	}

	internal static void MarkAlive(int playerId)
	{
		try
		{
			GameManager.Instance?.alivePlayers.Add(playerId);
		}
		catch
		{
		}
	}

	internal static void RepopulateAlivePlayers()
	{
		try
		{
			if ((Object)(object)GameManager.Instance == (Object)null)
			{
				return;
			}
			GameManager.Instance.alivePlayers.Clear();
			foreach (int connectedPlayerId in GetConnectedPlayerIds())
			{
				GameManager.Instance.alivePlayers.Add(connectedPlayerId);
			}
		}
		catch
		{
		}
	}

	internal static void ClearWaitForDrawHandle()
	{
		try
		{
			_waitForDrawCoroutine?.SetValue(GameManager.Instance, null);
		}
		catch
		{
		}
	}

	internal static void StopWaitForDraw()
	{
		try
		{
			GameManager instance = GameManager.Instance;
			if (!((Object)(object)instance == (Object)null) && !(_waitForDrawCoroutine == null))
			{
				object? value = _waitForDrawCoroutine.GetValue(instance);
				Coroutine val = (Coroutine)((value is Coroutine) ? value : null);
				if (val != null)
				{
					((MonoBehaviour)instance).StopCoroutine(val);
				}
				_waitForDrawCoroutine.SetValue(instance, null);
			}
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not stop the draw coroutine: " + ex.Message);
		}
	}

	internal static void SyncTakeScores(int teamA, int scoreA, int teamB, int scoreB)
	{
		try
		{
			ScoreManager instance = ScoreManager.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				SetTakeScore(instance, teamA, scoreA);
				SetTakeScore(instance, teamB, scoreB);
				PushMatchPointsHud(-1);
			}
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not mirror CTF scores: " + ex.Message);
		}
	}

	private static void SetTakeScore(ScoreManager scores, int teamId, int value)
	{
		if (teamId >= 0)
		{
			int roundScore = scores.GetRoundScore(teamId);
			if (roundScore != value)
			{
				scores.AddRoundScore(teamId, value - roundScore);
			}
		}
	}

	internal static void PushMatchPointsHud(int winningTeamId)
	{
		if (_updateMatchPointsHud == null || (Object)(object)GameManager.Instance == (Object)null || (Object)(object)ScoreManager.Instance == (Object)null)
		{
			return;
		}
		try
		{
			Dictionary<int, int> roundScoreDictionary = ScoreManager.Instance.GetRoundScoreDictionary();
			_updateMatchPointsHud.Invoke(GameManager.Instance, new object[2] { winningTeamId, roundScoreDictionary });
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not refresh the match points HUD: " + ex.Message);
		}
	}

	internal static bool AwardRoundWin(int winningTeamId)
	{
		if (_roundWon == null)
		{
			CtfLog.Error("Cannot award the CTF round win: GameManager.RoundWon is missing.");
			return false;
		}
		try
		{
			PushMatchPointsHud(winningTeamId);
			_roundWon.Invoke(GameManager.Instance, new object[1] { winningTeamId });
			RoundManager.Instance.CmdEndRound(winningTeamId);
			CtfLog.Info("Team " + winningTeamId + " won the CTF round; handed off to STRAFTAT's round-end flow.");
			return true;
		}
		catch (Exception ex)
		{
			CtfLog.Error("Could not finish the CTF round: " + ex);
			return false;
		}
	}

	internal static void AdvanceToNextRound()
	{
		try
		{
			RepopulateAlivePlayers();
			SceneMotor instance = SceneMotor.Instance;
			if (instance != null)
			{
				instance.ChangeNetworkScene();
			}
		}
		catch (Exception ex)
		{
			CtfLog.Error("Could not advance to the next round: " + ex);
		}
	}

	internal static void WriteMatchLog(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return;
		}
		try
		{
			PauseManager instance = PauseManager.Instance;
			if (instance != null)
			{
				instance.WriteLog(text);
			}
		}
		catch (Exception ex)
		{
			CtfLog.Debug("Could not write to the match log: " + ex.Message);
		}
	}

	internal static string NameTag(int playerId)
	{
		try
		{
			if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
			{
				return value.PlayerNameTag;
			}
		}
		catch
		{
		}
		return PlayerName(playerId);
	}

	internal static void EnsureRoundStartedFlag(FirstPersonController player)
	{
		if (_roundHasStarted == null || (Object)(object)player == (Object)null)
		{
			return;
		}
		try
		{
			if (!(bool)_roundHasStarted.GetValue(player))
			{
				_roundHasStarted.SetValue(player, true);
			}
		}
		catch
		{
		}
	}

	internal static bool IsFinite(Vector3 v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		return !float.IsNaN(v.x) && !float.IsNaN(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.x) && !float.IsInfinity(v.y) && !float.IsInfinity(v.z);
	}

	private static bool TryGetManager(int playerId, out PlayerManager manager)
	{
		manager = null;
		try
		{
			if (!ClientInstance.playerInstances.TryGetValue(playerId, out var value) || (Object)(object)value == (Object)null)
			{
				return false;
			}
			manager = (((Object)(object)value.PlayerSpawner != (Object)null) ? value.PlayerSpawner : ((Component)value).GetComponent<PlayerManager>());
			return (Object)(object)manager != (Object)null;
		}
		catch
		{
			return false;
		}
	}

	private static MethodInfo Require(Type type, string name, ref bool ok, Func<MethodInfo, bool> predicate = null, string label = null)
	{
		MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => (name == null || m.Name == name) && (predicate == null || predicate(m)));
		if (methodInfo != null)
		{
			return methodInfo;
		}
		ok = false;
		CtfLog.Error("Missing required game member: " + (label ?? (type.Name + "." + name)) + ". This STRAFTAT version is not supported; Capture the Flag will stay inactive.");
		return null;
	}

	private static FieldInfo RequireField(Type type, string name, ref bool ok)
	{
		FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field != null)
		{
			return field;
		}
		ok = false;
		CtfLog.Error("Missing required game field: " + type.Name + "." + name + ". This STRAFTAT version is not supported; Capture the Flag will stay inactive.");
		return null;
	}

	private static MethodInfo Optional(Type type, string name)
	{
		MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (method == null)
		{
			CtfLog.Debug("Optional game member not found: " + type.Name + "." + name);
		}
		return method;
	}
}
internal sealed class CtfHud
{
	private sealed class CtfMarker
	{
		private const float EdgeInset = 90f;

		private readonly TextMeshProU