Decompiled source of KASSEN TeamBattle v1.0.6

TeamBattle.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Mirror;
using MoveClasses;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TeamBattle")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TeamBattle")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("30871c5a-f70c-4492-ba06-01b2a3b215d2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace GladioMoriKassenTeamBattle;

public enum Language
{
	English,
	Japanese
}
[BepInPlugin("jp.jyoki_tsubame.gladiomori.kassen", "-KASSEN- Team Battle", "1.0.6")]
public class GladioMoriKassenTeamBattlePlugin : BaseUnityPlugin
{
	public enum GameResultType
	{
		Win,
		Draw
	}

	public struct GameDecision
	{
		public GameResultType Result;

		public string WinningTeam;
	}

	public static class GameDecisionEvaluator
	{
		public static GameDecision EvaluateStandardGameResult(Dictionary<string, List<PlayerGameStateInfo>> teams, List<PlayerGameStateInfo> alivePlayers)
		{
			GameDecision result = default(GameDecision);
			if (alivePlayers.Count > 0 && teams.Count == 1)
			{
				result.Result = GameResultType.Win;
				string text = teams.First().Key;
				if (string.IsNullOrEmpty(text))
				{
					text = TeamHelper.ExtractTeamColor(teams.First().Value.First().player.playerName);
				}
				result.WinningTeam = text;
				LogInstance.LogInfo((object)("EvaluateStandardGameResult: Winning Team = " + text));
			}
			else
			{
				result.Result = GameResultType.Draw;
				result.WinningTeam = "";
				LogInstance.LogInfo((object)"EvaluateStandardGameResult: Draw");
			}
			return result;
		}

		public static GameDecision EvaluateCaptainGameResult(Dictionary<string, List<PlayerGameStateInfo>> teams, List<PlayerGameStateInfo> alivePlayers)
		{
			GameDecision result = default(GameDecision);
			Dictionary<string, bool> dictionary = new Dictionary<string, bool>();
			foreach (KeyValuePair<string, List<PlayerGameStateInfo>> team in teams)
			{
				string key = team.Key;
				bool flag2 = (dictionary[key] = team.Value.Any(delegate(PlayerGameStateInfo p)
				{
					string playerName = p.player.playerName;
					return (string.IsNullOrEmpty(playerName) ? "" : Regex.Replace(playerName, "<[^>]+>", "")).StartsWith("[CAP]");
				}));
				LogInstance.LogInfo((object)$"EvaluateCaptainGameResult: Team '{key}' hasCaptain = {flag2}");
			}
			List<string> list = (from kvp in dictionary
				where kvp.Value
				select kvp.Key).ToList();
			if (list.Count == 1)
			{
				result.Result = GameResultType.Win;
				result.WinningTeam = list[0];
				LogInstance.LogInfo((object)("EvaluateCaptainGameResult: Winning Team = " + list[0]));
			}
			else
			{
				result.Result = GameResultType.Draw;
				result.WinningTeam = "";
				LogInstance.LogInfo((object)"EvaluateCaptainGameResult: Draw (multiple or no teams with captain alive)");
			}
			return result;
		}
	}

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

		private object <>2__current;

		public List<MultiplayerRoomPlayer> currentPlayers;

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

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

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

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

		private bool MoveNext()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(1f);
				<>1__state = 1;
				return true;
			case 1:
			{
				<>1__state = -1;
				if (!autoTeamAssignmentEnabled)
				{
					return false;
				}
				Dictionary<int, int> dictionary = new Dictionary<int, int>();
				foreach (MultiplayerRoomPlayer currentPlayer in currentPlayers)
				{
					int key = ((((NetworkBehaviour)currentPlayer).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)currentPlayer).connectionToClient).connectionId : ((Object)currentPlayer).GetInstanceID());
					if (!playerColorSelections.TryGetValue(key, out var value) || value == 0)
					{
						continue;
					}
					int teamIndex = TeamHelper.GetTeamIndex(currentPlayer);
					if (teamIndex >= 0)
					{
						if (!dictionary.ContainsKey(teamIndex))
						{
							dictionary[teamIndex] = 0;
						}
						dictionary[teamIndex]++;
					}
				}
				foreach (MultiplayerRoomPlayer currentPlayer2 in currentPlayers)
				{
					int num = ((((NetworkBehaviour)currentPlayer2).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)currentPlayer2).connectionToClient).connectionId : ((Object)currentPlayer2).GetInstanceID());
					if (playerColorSelections.TryGetValue(num, out var value2) && value2 != 0)
					{
						continue;
					}
					int num2 = 0;
					if (dictionary.Count > 0)
					{
						num2 = dictionary.OrderBy((KeyValuePair<int, int> kvp) => kvp.Value).First().Key;
					}
					string text = CurrentAutoTeamColors[num2];
					int num3 = Array.IndexOf(colorOptions, text);
					if (num3 < 0)
					{
						LogInstance.LogWarning((object)("自動割り当て: 指定色 '" + text + "' が colorOptions に存在しません。"));
						continue;
					}
					playerColorSelections[num] = num3;
					LogInstance.LogInfo((object)$"自動割り当て: プレイヤー {currentPlayer2.playerName} (ID:{num}) をチーム '{text}' に割り当て");
					ForceUpdatePlayerName(currentPlayer2);
					if (dictionary.ContainsKey(num2))
					{
						dictionary[num2]++;
					}
					else
					{
						dictionary[num2] = 1;
					}
				}
				return false;
			}
			}
		}

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

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

	public static bool modEnabled = false;

	public static bool gameOverModEnabled = false;

	public static bool spawnPositioningEnabled = false;

	public static bool logEnabled = false;

	public static bool captainModeEnabled = false;

	public static bool autoTeamAssignmentEnabled = true;

	public static Dictionary<int, int> playerColorSelections = new Dictionary<int, int>();

	public static Dictionary<int, bool> playerDropdownOpen = new Dictionary<int, bool>();

	public static Dictionary<int, bool> captainFlags = new Dictionary<int, bool>();

	private List<MultiplayerRoomPlayer> previousPlayers = new List<MultiplayerRoomPlayer>();

	public static Dictionary<int, string> originalPlayerNames = new Dictionary<int, string>();

	public static int CurrentTeamCount = 0;

	public static string[] CurrentAutoTeamColors = null;

	private bool uiOpen;

	private Rect windowRect = new Rect(100f, 100f, 500f, 1200f);

	private KeyCode toggleKey = (KeyCode)288;

	private string teamCountInput = "2";

	private string autoTeamColorsInput = "red, blue, orange, yellow, cyan, purple, brown";

	public static Dictionary<int, HashSet<Vector3>> usedStaticSpawnPositions = new Dictionary<int, HashSet<Vector3>>();

	public static Language currentLanguage = Language.English;

	private static readonly Dictionary<string, string> englishText = new Dictionary<string, string>
	{
		{ "ModEnabled", "Team color function Enabled" },
		{ "TeamGameOverEnabled", "Team GameOver Enabled" },
		{ "SpawnPositioningEnabled", "Spawn Positioning Enabled" },
		{ "ChatBroadcastTeamAssignment", "Team Assignment Announcement" },
		{ "PromptTeamCheck", "Prompt Team Check Announcement" },
		{ "RestartAnnoucement", "Restart Announcement" },
		{ "TeamChangeAnnouncement", "Team Changing Announcement" },
		{ "RuleAnnouncement", "Rule Announcement" },
		{ "RuleAnnouncementForJP", "Rule Announcement for JP User" },
		{ "NameSelection", "Select Color for each player's name:" },
		{ "UpdateAllPlayers", "Update All Players" },
		{ "AutoTeamAssignmentSettings", "Auto Team Assignment Settings" },
		{ "TeamCount", "Team Count:" },
		{ "AutoTeamColors", "Auto Team Colors (comma separated):" },
		{ "AutoAssignTeams", "Auto Assign Teams" },
		{ "Language", "Language:" },
		{ "LogEanbled", "Log Enabled:" },
		{ "CaptainModeEnabled", "Captain Mode Enabled" },
		{ "NewPlayerAutoAssignment", "Auto team assignment on new player entry enabled" },
		{ "Captain", "Captain" },
		{ "SelectCaptain", "Selection of a captain" }
	};

	private static readonly Dictionary<string, string> japaneseText = new Dictionary<string, string>
	{
		{ "ModEnabled", "チームカラー機能有効" },
		{ "TeamGameOverEnabled", "チーム勝敗機能有効" },
		{ "SpawnPositioningEnabled", "スポーン位置調整機能有効" },
		{ "ChatBroadcastTeamAssignment", "チーム割り振り発表アナウンス" },
		{ "PromptTeamCheck", "チーム確認を促すアナウンス" },
		{ "RestartAnnoucement", "ゲーム再開アナウンス" },
		{ "TeamChangeAnnouncement", "チーム変更中アナウンス" },
		{ "RuleAnnouncement", "ルール説明アナウンス" },
		{ "RuleAnnouncementForJP", "ルール説明アナウンス(ローマ字)" },
		{ "NameSelection", "各プレイヤーの名前に付与する色:" },
		{ "UpdateAllPlayers", "全プレイヤー更新" },
		{ "AutoTeamAssignmentSettings", "自動チーム分け設定" },
		{ "TeamCount", "チーム数:" },
		{ "AutoTeamColors", "自動割り当て色(カンマ区切り):" },
		{ "AutoAssignTeams", "自動チーム分け" },
		{ "Language", "言語:" },
		{ "LogEanbled", "ログ有効:" },
		{ "CaptainModeEnabled", "大将戦有効" },
		{ "NewPlayerAutoAssignment", "新規入室時の自動チーム割り当て有効" },
		{ "Captain", "大将" },
		{ "SelectCaptain", "大将をランダムに選出" }
	};

	public static GladioMoriKassenTeamBattlePlugin Instance { get; private set; }

	public static ManualLogSource LogInstance { get; private set; }

	public static string[] colorOptions
	{
		get
		{
			if ((Object)(object)Instance == (Object)null)
			{
				return new string[23]
				{
					"nothing", "aqua", "black", "blue", "brown", "cyan", "darkblue", "fuchsia", "green", "grey",
					"lightblue", "lime", "magenta", "maroon", "navy", "olive", "orange", "purple", "red", "silver",
					"teal", "white", "yellow"
				};
			}
			List<string> list = (from s in Instance.autoTeamColorsInput.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select s.Trim().ToLower()).ToList();
			list.Insert(0, "nothing");
			return list.ToArray();
		}
	}

	public static string Localize(string key)
	{
		if (currentLanguage == Language.Japanese)
		{
			if (!japaneseText.ContainsKey(key))
			{
				return key;
			}
			return japaneseText[key];
		}
		if (!englishText.ContainsKey(key))
		{
			return key;
		}
		return englishText[key];
	}

	private void Awake()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		LogInstance = ((BaseUnityPlugin)this).Logger;
		new Harmony("jp.jyoki_tsubame.gladiomori.kassen").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"GladioMoriKassenTeamBattle: Loaded");
	}

	[IteratorStateMachine(typeof(<OnPlayerListChangedCoroutine>d__37))]
	private IEnumerator OnPlayerListChangedCoroutine(List<MultiplayerRoomPlayer> currentPlayers)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <OnPlayerListChangedCoroutine>d__37(0)
		{
			currentPlayers = currentPlayers
		};
	}

	private void Update()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(toggleKey))
		{
			uiOpen = !uiOpen;
			LogInfo("管理ウィンドウ表示状態: " + uiOpen);
		}
		MonitorPlayerList();
	}

	private void MonitorPlayerList()
	{
		List<MultiplayerRoomPlayer> list = Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0).ToList();
		if (list.Count != previousPlayers.Count || !list.Select((MultiplayerRoomPlayer p) => ((Object)p).GetInstanceID()).SequenceEqual(previousPlayers.Select((MultiplayerRoomPlayer p) => ((Object)p).GetInstanceID())))
		{
			((MonoBehaviour)this).StartCoroutine(OnPlayerListChangedCoroutine(list));
			LogInfo($"[PlayerMonitor] Player list changed: {previousPlayers.Count} -> {list.Count}");
			previousPlayers = list;
		}
	}

	private void OnGUI()
	{
		//IL_000f: 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_002a: Expected O, but got Unknown
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		if (uiOpen)
		{
			windowRect = GUI.Window(123456, windowRect, new WindowFunction(DrawWindow), "-KASSEN- Team Battle v1.0.6");
		}
	}

	private void DrawWindow(int windowID)
	{
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b4d: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button(Localize("Language") + " : " + currentLanguage, Array.Empty<GUILayoutOption>()))
		{
			currentLanguage = ((currentLanguage == Language.English) ? Language.Japanese : Language.English);
			LogInfo("Language switched to " + currentLanguage);
		}
		bool flag = GUILayout.Toggle(modEnabled, Localize("ModEnabled"), Array.Empty<GUILayoutOption>());
		if (flag != modEnabled)
		{
			modEnabled = flag;
			if (!modEnabled)
			{
				gameOverModEnabled = false;
				spawnPositioningEnabled = false;
				captainModeEnabled = false;
				autoTeamAssignmentEnabled = false;
				MultiplayerRoomPlayer[] array = Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0);
				foreach (MultiplayerRoomPlayer val in array)
				{
					int key = ((((NetworkBehaviour)val).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)val).connectionToClient).connectionId : ((Object)val).GetInstanceID());
					playerColorSelections[key] = 0;
					captainFlags[key] = false;
					ForceUpdatePlayerName(val);
				}
			}
		}
		GUI.enabled = modEnabled;
		bool enabled = GUI.enabled;
		GUI.enabled = true;
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		GUI.enabled = enabled;
		gameOverModEnabled = GUILayout.Toggle(gameOverModEnabled, Localize("TeamGameOverEnabled"), Array.Empty<GUILayoutOption>());
		spawnPositioningEnabled = GUILayout.Toggle(spawnPositioningEnabled, Localize("SpawnPositioningEnabled"), Array.Empty<GUILayoutOption>());
		bool flag2 = GUILayout.Toggle(captainModeEnabled, Localize("CaptainModeEnabled"), Array.Empty<GUILayoutOption>());
		if (flag2 != captainModeEnabled)
		{
			captainModeEnabled = flag2;
			LogInfo("Captain mode switched to " + captainModeEnabled);
			if (!captainModeEnabled)
			{
				MultiplayerRoomPlayer[] array = Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0);
				foreach (MultiplayerRoomPlayer val2 in array)
				{
					int num = ((((NetworkBehaviour)val2).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)val2).connectionToClient).connectionId : ((Object)val2).GetInstanceID());
					captainFlags[num] = false;
					ForceUpdatePlayerName(val2);
					LogInfo($"Captain mode off: Reset captain flag for player {val2.playerName} (ID: {num})");
				}
			}
		}
		if (GUILayout.Button(Localize("SelectCaptain"), Array.Empty<GUILayoutOption>()))
		{
			List<MultiplayerRoomPlayer> list = Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0).ToList();
			if (list.Count == 0)
			{
				LogInstance.LogWarning((object)"Set Random Captain: No players found.");
			}
			else
			{
				foreach (KeyValuePair<int, List<MultiplayerRoomPlayer>> item in (from p in list
					group p by TeamHelper.GetTeamIndex(p) into g
					where g.Key >= 0
					select g).ToDictionary((IGrouping<int, MultiplayerRoomPlayer> g) => g.Key, (IGrouping<int, MultiplayerRoomPlayer> g) => g.ToList()))
				{
					int key2 = item.Key;
					List<MultiplayerRoomPlayer> value = item.Value;
					foreach (MultiplayerRoomPlayer item2 in value)
					{
						int key3 = ((((NetworkBehaviour)item2).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)item2).connectionToClient).connectionId : ((Object)item2).GetInstanceID());
						captainFlags[key3] = false;
						ForceUpdatePlayerName(item2);
					}
					MultiplayerRoomPlayer val3 = value.OrderBy((MultiplayerRoomPlayer x) => Random.value).First();
					int key4 = ((((NetworkBehaviour)val3).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)val3).connectionToClient).connectionId : ((Object)val3).GetInstanceID());
					captainFlags[key4] = true;
					ForceUpdatePlayerName(val3);
					LogInfo($"Set Random Captain: For Team {key2}, assigned Captain = {val3.playerName}");
				}
			}
		}
		autoTeamAssignmentEnabled = GUILayout.Toggle(autoTeamAssignmentEnabled, Localize("NewPlayerAutoAssignment"), Array.Empty<GUILayoutOption>());
		GUILayout.Space(10f);
		if (GUILayout.Button(Localize("ChatBroadcastTeamAssignment"), Array.Empty<GUILayoutOption>()))
		{
			foreach (MultiplayerRoomPlayer item3 in Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0).ToList())
			{
				string cleanName = TeamHelper.GetCleanName(item3.NetworkplayerName);
				string text = TeamHelper.ExtractTeamColor(item3.NetworkplayerName);
				ChatHelper.BroadcastChatMessage(cleanName + ": " + text, "TeamBattleMod");
			}
		}
		if (GUILayout.Button(Localize("PromptTeamCheck"), Array.Empty<GUILayoutOption>()))
		{
			ChatHelper.BroadcastChatMessage("Press ESC to check your team", "TeamBattleMod");
		}
		if (GUILayout.Button(Localize("RestartAnnoucement"), Array.Empty<GUILayoutOption>()))
		{
			ChatHelper.BroadcastChatMessage("Get ready!", "TeamBattleMod");
		}
		if (GUILayout.Button(Localize("TeamChangeAnnouncement"), Array.Empty<GUILayoutOption>()))
		{
			ChatHelper.BroadcastChatMessage("Now, team assignments are changing...", "TeamBattleMod");
		}
		if (GUILayout.Button(Localize("RuleAnnouncement"), Array.Empty<GUILayoutOption>()))
		{
			ChatHelper.BroadcastChatMessage("Your team is your name color. Same color = friend.", "TeamBattleMod");
			ChatHelper.BroadcastChatMessage("Same color = friend, different color = enemy.", "TeamBattleMod");
			ChatHelper.BroadcastChatMessage("Kill other color Players!", "TeamBattleMod");
		}
		if (GUILayout.Button(Localize("RuleAnnouncementForJP"), Array.Empty<GUILayoutOption>()))
		{
			ChatHelper.BroadcastChatMessage("namae no iro ga team wo arawasi masu", "TeamBattleMod");
			ChatHelper.BroadcastChatMessage("player no namae no iroga onazi nara mikata, kotonaru nara teki desu ", "TeamBattleMod");
			ChatHelper.BroadcastChatMessage("namae no iro ga tigau player wo taosi masyou!", "TeamBattleMod");
		}
		GUILayout.Space(10f);
		GUILayout.Label(Localize("NameSelection"), Array.Empty<GUILayoutOption>());
		GUILayout.Space(10f);
		List<MultiplayerRoomPlayer> list2 = Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0).ToList();
		GUILayout.Label("Total: " + list2.Count, Array.Empty<GUILayoutOption>());
		Dictionary<int, int> dictionary = new Dictionary<int, int>();
		foreach (MultiplayerRoomPlayer item4 in list2)
		{
			int teamIndex = TeamHelper.GetTeamIndex(item4);
			if (!dictionary.ContainsKey(teamIndex))
			{
				dictionary[teamIndex] = 0;
			}
			dictionary[teamIndex]++;
		}
		foreach (KeyValuePair<int, int> item5 in dictionary.OrderBy((KeyValuePair<int, int> x) => x.Key))
		{
			string text2 = ((item5.Key >= 0 && CurrentAutoTeamColors != null && CurrentAutoTeamColors.Length > item5.Key) ? CurrentAutoTeamColors[item5.Key] : ((item5.Key < 0) ? "nothing" : colorOptions[item5.Key]));
			string arg = ((!(text2 != "nothing")) ? text2 : ("<color=\"" + text2 + "\">" + text2 + "</color>"));
			GUILayout.Label($"{arg}: {item5.Value}", Array.Empty<GUILayoutOption>());
		}
		GUILayout.Space(10f);
		foreach (MultiplayerRoomPlayer item6 in list2)
		{
			int num2 = ((((NetworkBehaviour)item6).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)item6).connectionToClient).connectionId : ((Object)item6).GetInstanceID());
			int value2 = 0;
			if (!playerColorSelections.TryGetValue(num2, out value2))
			{
				value2 = 0;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Player: " + item6.playerName, Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Color: " + colorOptions[value2], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }))
			{
				bool value3 = false;
				playerDropdownOpen.TryGetValue(num2, out value3);
				playerDropdownOpen[num2] = !value3;
				LogInfo($"プレイヤーID:{num2} ドロップダウン展開: {playerDropdownOpen[num2]}");
			}
			bool value4 = false;
			if (!captainFlags.TryGetValue(num2, out value4))
			{
				captainFlags[num2] = false;
				value4 = false;
			}
			bool flag3 = GUILayout.Toggle(value4, Localize("Captain"), Array.Empty<GUILayoutOption>());
			if (flag3 != value4)
			{
				captainFlags[num2] = flag3;
				ForceUpdatePlayerName(item6);
			}
			GUILayout.EndHorizontal();
			if (!(playerDropdownOpen.TryGetValue(num2, out var value5) && value5))
			{
				continue;
			}
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
			for (int j = 0; j < colorOptions.Length; j++)
			{
				if (GUILayout.Button(colorOptions[j], Array.Empty<GUILayoutOption>()))
				{
					playerColorSelections[num2] = j;
					playerDropdownOpen[num2] = false;
					LogInfo($"プレイヤーID:{num2} 色選択: {colorOptions[j]} (Index:{j})");
					ForceUpdatePlayerName(item6);
				}
			}
			GUILayout.EndVertical();
		}
		GUILayout.Space(20f);
		GUILayout.Label(Localize("AutoTeamAssignmentSettings"), Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(Localize("TeamCount"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
		teamCountInput = GUILayout.TextField(teamCountInput, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(Localize("AutoTeamColors"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
		autoTeamColorsInput = GUILayout.TextField(autoTeamColorsInput, Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		if (GUILayout.Button(Localize("AutoAssignTeams"), Array.Empty<GUILayoutOption>()))
		{
			if (int.TryParse(teamCountInput, out var result) && result > 0)
			{
				CurrentAutoTeamColors = (from s in autoTeamColorsInput.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
					select s.Trim().ToLower()).ToArray();
				CurrentTeamCount = result;
				AutoAssignTeams(result, CurrentAutoTeamColors);
				LogInfo($"自動チーム分け: チーム数 {result} に分割");
			}
			else
			{
				LogInstance.LogWarning((object)"自動チーム分け: 無効なチーム数入力");
			}
		}
		logEnabled = GUILayout.Toggle(logEnabled, Localize("LogEnabled"), Array.Empty<GUILayoutOption>());
		GUILayout.Space(10f);
		GUILayout.EndVertical();
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
	}

	public static string RemoveAllTags(string input)
	{
		if (string.IsNullOrEmpty(input))
		{
			return "Player";
		}
		string text = Regex.Replace(input, "<.*?>", "");
		if (string.IsNullOrWhiteSpace(text))
		{
			return "Player";
		}
		return text;
	}

	public static void ForceUpdatePlayerName(MultiplayerRoomPlayer player)
	{
		int num = ((((NetworkBehaviour)player).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)player).connectionToClient).connectionId : ((Object)player).GetInstanceID());
		if (!originalPlayerNames.ContainsKey(num))
		{
			originalPlayerNames[num] = player.playerName;
		}
		int value = 0;
		if (!playerColorSelections.TryGetValue(num, out value))
		{
			value = 0;
		}
		string text = colorOptions[value];
		string text2 = RemoveAllTags(originalPlayerNames[num]);
		if (string.IsNullOrEmpty(text2))
		{
			text2 = "Player";
		}
		string text3 = text2;
		bool value2 = false;
		if (!captainFlags.TryGetValue(num, out value2))
		{
			value2 = false;
		}
		if (value2)
		{
			text3 = "<b><size=20>[CAP]" + text3 + "</size></b>";
		}
		if (value != 0)
		{
			text3 = "<color=\"" + text + "\">" + text3 + "</color>";
		}
		LogInfo($"ForceUpdatePlayerName: ConnId={num}, OriginalName={text2}, SelectedIndex={value}, SelectedColor={text}, NewName={text3}");
		player.NetworkplayerName = text3;
	}

	public static void AutoAssignTeams(int teamCount, string[] autoTeamColors)
	{
		if (teamCount > autoTeamColors.Length)
		{
			LogInstance.LogWarning((object)$"チーム数 {teamCount} は自動割り当て可能な色数 {autoTeamColors.Length} を超えています。最大 {autoTeamColors.Length} に設定します。");
			teamCount = autoTeamColors.Length;
		}
		List<MultiplayerRoomPlayer> list = Object.FindObjectsByType<MultiplayerRoomPlayer>((FindObjectsSortMode)0).ToList();
		if (list.Count == 0)
		{
			LogInstance.LogWarning((object)"自動チーム分け: プレイヤーが見つかりません");
			return;
		}
		list = list.OrderBy((MultiplayerRoomPlayer p) => Random.value).ToList();
		for (int i = 0; i < list.Count; i++)
		{
			int num = i % teamCount;
			int num2 = ((((NetworkBehaviour)list[i]).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)list[i]).connectionToClient).connectionId : ((Object)list[i]).GetInstanceID());
			string text = autoTeamColors[num];
			int num3 = Array.IndexOf(colorOptions, text);
			if (num3 < 0)
			{
				LogInstance.LogWarning((object)("自動チーム分け: 指定色 '" + text + "' が利用できません。"));
				num3 = 0;
			}
			playerColorSelections[num2] = num3;
			LogInfo($"自動チーム分け: プレイヤー {list[i].playerName} (ID: {num2}) をチーム {text} に割り当て");
			ForceUpdatePlayerName(list[i]);
		}
	}

	public static GameObject GetPlayerCharacter(PlayerMultiplayerInputManager manager)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerMultiplayerInputManager), "playerCharacter");
		if (!(fieldInfo != null))
		{
			return null;
		}
		return (GameObject)fieldInfo.GetValue(manager);
	}

	public static void LogInfo(string log)
	{
		if (logEnabled)
		{
			LogInstance.LogInfo((object)log);
		}
	}

	public static void LogWarning(string log)
	{
		LogInstance.LogWarning((object)log);
	}
}
public struct ChatMessage : NetworkMessage
{
	public string message;

	public string sender;
}
public static class ChatHelper
{
	public static void BroadcastChatMessage(string message, string sender)
	{
		if ((Object)(object)MultiplayerChat.singleton != (Object)null)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(MultiplayerChat), "RpcHandleMessage", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(MultiplayerChat.singleton, new object[2] { message, sender });
				GladioMoriKassenTeamBattlePlugin.LogInfo("ChatHelper: Broadcasted message '" + message + "' from '" + sender + "' via RpcHandleMessage");
			}
			else
			{
				GladioMoriKassenTeamBattlePlugin.LogWarning("ChatHelper: RpcHandleMessage メソッドが見つかりません");
			}
		}
		else
		{
			GladioMoriKassenTeamBattlePlugin.LogWarning("ChatHelper: MultiplayerChat.singleton が null です");
		}
	}
}
[Serializable]
public class SpawnConfig
{
	public Dictionary<string, Dictionary<string, List<Vector3Serializable>>> teams = new Dictionary<string, Dictionary<string, List<Vector3Serializable>>>();
}
[Serializable]
public struct Vector3Serializable
{
	public float x;

	public float y;

	public float z;

	public Vector3 ToVector3()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		return new Vector3(x, y, z);
	}
}
public static class SpawnConfigLoader
{
	private static readonly string DllDir = GetDllDirectory();

	private static readonly string ConfigDir = Path.Combine(DllDir, "configs");

	private static readonly string ConfigPath;

	private static FileSystemWatcher _watcher;

	private static SpawnConfig _cache;

	private static void SetupWatcher()
	{
		_watcher = new FileSystemWatcher(ConfigDir, Path.GetFileName(ConfigPath))
		{
			NotifyFilter = (NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite),
			EnableRaisingEvents = true,
			IncludeSubdirectories = false
		};
		DateTime last = DateTime.MinValue;
		_watcher.Changed += delegate
		{
			try
			{
				DateTime utcNow = DateTime.UtcNow;
				if (!((utcNow - last).TotalMilliseconds < 200.0))
				{
					last = utcNow;
					Thread.Sleep(100);
					SpawnConfig spawnConfig = JsonConvert.DeserializeObject<SpawnConfig>(File.ReadAllText(ConfigPath));
					if (spawnConfig != null)
					{
						_cache = spawnConfig;
						GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)"Spawn config reloaded (watcher).");
					}
				}
			}
			catch (Exception ex)
			{
				GladioMoriKassenTeamBattlePlugin.LogInstance.LogWarning((object)("Reload failed: " + ex.Message));
			}
		};
	}

	private static string GetDllDirectory()
	{
		try
		{
			Assembly assembly = typeof(SpawnConfigLoader).Assembly;
			Uri uri = new Uri(assembly.Location);
			return Path.GetDirectoryName(uri.IsFile ? uri.LocalPath : assembly.Location) ?? Environment.CurrentDirectory;
		}
		catch (Exception ex)
		{
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogWarning((object)("GetDllDirectory failed: " + ex.Message + ". Fallback to current directory."));
			return Environment.CurrentDirectory;
		}
	}

	public static SpawnConfig GetOrLoad()
	{
		if (_cache != null)
		{
			return _cache;
		}
		try
		{
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)("Paths.ConfigPath = " + Paths.ConfigPath));
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)("ConfigDir      = " + ConfigDir));
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)("ConfigPath     = " + ConfigPath));
			bool flag = Directory.Exists(ConfigDir);
			bool flag2 = File.Exists(ConfigPath);
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)$"DirExists={flag}, FileExists={flag2}");
			if (!flag || !flag2)
			{
				GladioMoriKassenTeamBattlePlugin.LogInstance.LogWarning((object)"Spawn config missing (dir or file). Fallback to hardcoded.");
				_cache = new SpawnConfig();
				return _cache;
			}
			byte[] array = File.ReadAllBytes(ConfigPath);
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)$"Spawn config bytes={array.Length}");
			string @string = Encoding.UTF8.GetString(array);
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogInfo((object)("Spawn config head: " + @string.Substring(0, Math.Min(100, @string.Length))));
			_cache = JsonConvert.DeserializeObject<SpawnConfig>(@string);
			SetupWatcher();
			return _cache ?? new SpawnConfig();
		}
		catch (Exception ex)
		{
			GladioMoriKassenTeamBattlePlugin.LogInstance.LogWarning((object)("Spawn config load error: " + ex.GetType().Name + " " + ex.Message + "\n" + ex.StackTrace));
			_cache = new SpawnConfig();
			return _cache;
		}
	}

	public static bool TryGetSpawns(int teamCount, int teamIndex, out List<Vector3> spawns)
	{
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		spawns = null;
		SpawnConfig obj = _cache ?? GetOrLoad();
		string key = teamCount.ToString();
		string key2 = teamIndex.ToString();
		if (obj.teams.TryGetValue(key, out var value) && value.TryGetValue(key2, out var value2) && value2 != null && value2.Count > 0)
		{
			List<Vector3> list = new List<Vector3>(value2.Count);
			foreach (Vector3Serializable item in value2)
			{
				list.Add(item.ToVector3());
			}
			spawns = list;
			return true;
		}
		return false;
	}

	static SpawnConfigLoader()
	{
		//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)
		string configDir = ConfigDir;
		Scene activeScene = SceneManager.GetActiveScene();
		ConfigPath = Path.Combine(configDir, ((Scene)(ref activeScene)).name + ".json");
	}
}
public static class SpawnHelperStatic
{
	private static readonly Vector3[] team0Spawns_T2 = (Vector3[])(object)new Vector3[8]
	{
		new Vector3(0f, 1.45f, -12f),
		new Vector3(3f, 1.45f, 0f),
		new Vector3(0f, 1.45f, -3f),
		new Vector3(7f, 6f, 7f),
		new Vector3(12f, 1.45f, 0f),
		new Vector3(8f, 1.45f, 9f),
		new Vector3(7f, 6f, -7f),
		new Vector3(8f, 1.45f, -9f)
	};

	private static readonly Vector3[] team1Spawns_T2 = (Vector3[])(object)new Vector3[8]
	{
		new Vector3(-12f, 1.45f, 0f),
		new Vector3(-8f, 1.45f, 9f),
		new Vector3(-7f, 6f, 7f),
		new Vector3(-3f, 1.45f, 0f),
		new Vector3(-7f, 6f, -7f),
		new Vector3(0f, 1.45f, 12f),
		new Vector3(-8f, 1.45f, -9f),
		new Vector3(0f, 1.45f, 3f)
	};

	private static readonly Vector3[] team0Spawns_T3 = (Vector3[])(object)new Vector3[6]
	{
		new Vector3(7f, 6f, -7f),
		new Vector3(7f, 6f, 7f),
		new Vector3(12f, 1.45f, 0f),
		new Vector3(8f, 1.45f, 9f),
		new Vector3(3f, 1.45f, 0f),
		new Vector3(8f, 1.45f, -9f)
	};

	private static readonly Vector3[] team1Spawns_T3 = (Vector3[])(object)new Vector3[5]
	{
		new Vector3(0f, 1.45f, 12f),
		new Vector3(-7f, 6f, 7f),
		new Vector3(0f, 1.45f, 3f),
		new Vector3(-8f, 1.45f, 9f),
		new Vector3(-3f, 1.45f, 0f)
	};

	private static readonly Vector3[] team2Spawns_T3 = (Vector3[])(object)new Vector3[5]
	{
		new Vector3(-12f, 1.45f, 0f),
		new Vector3(0f, 1.45f, -12f),
		new Vector3(-7f, 6f, -7f),
		new Vector3(0f, 1.45f, -3f),
		new Vector3(-8f, 1.45f, -9f)
	};

	private static readonly Vector3[] team0Spawns_T4 = (Vector3[])(object)new Vector3[4]
	{
		new Vector3(-7f, 6f, 7f),
		new Vector3(-8f, 1.45f, 9f),
		new Vector3(-12f, 1.45f, 0f),
		new Vector3(-3f, 1.45f, 0f)
	};

	private static readonly Vector3[] team1Spawns_T4 = (Vector3[])(object)new Vector3[4]
	{
		new Vector3(0f, 1.45f, 12f),
		new Vector3(7f, 6f, 7f),
		new Vector3(8f, 1.45f, 9f),
		new Vector3(0f, 1.45f, 3f)
	};

	private static readonly Vector3[] team2Spawns_T4 = (Vector3[])(object)new Vector3[4]
	{
		new Vector3(-7f, 6f, -7f),
		new Vector3(0f, 1.45f, -12f),
		new Vector3(0f, 1.45f, -3f),
		new Vector3(-8f, 1.45f, -9f)
	};

	private static readonly Vector3[] team3Spawns_T4 = (Vector3[])(object)new Vector3[4]
	{
		new Vector3(7f, 6f, -7f),
		new Vector3(12f, 1.45f, 0f),
		new Vector3(3f, 1.45f, 0f),
		new Vector3(8f, 1.45f, -9f)
	};

	private static readonly Vector3[] team0Spawns_T5 = (Vector3[])(object)new Vector3[4]
	{
		new Vector3(7f, 6f, -7f),
		new Vector3(8f, 1.45f, -9f),
		new Vector3(0f, 1.45f, -3f),
		new Vector3(0f, 1.45f, -12f)
	};

	private static readonly Vector3[] team1Spawns_T5 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(8f, 1.45f, 9f),
		new Vector3(0f, 1.45f, 3f),
		new Vector3(0f, 1.45f, 12f)
	};

	private static readonly Vector3[] team2Spawns_T5 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(-8f, 1.45f, -9f),
		new Vector3(-3f, 1.45f, 0f),
		new Vector3(-7f, 6f, -7f)
	};

	private static readonly Vector3[] team3Spawns_T5 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(12f, 1.45f, 0f),
		new Vector3(3f, 1.45f, 0f),
		new Vector3(7f, 6f, 7f)
	};

	private static readonly Vector3[] team4Spawns_T5 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(-12f, 1.45f, 0f),
		new Vector3(-7f, 6f, 7f),
		new Vector3(-8f, 1.45f, 9f)
	};

	private static readonly Vector3[] team0Spawns_T6 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(-3f, 1.45f, 0f),
		new Vector3(-12f, 1.45f, 0f),
		new Vector3(-7f, 6f, 7f)
	};

	private static readonly Vector3[] team1Spawns_T6 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(3f, 1.45f, 0f),
		new Vector3(0f, 1.45f, -12f),
		new Vector3(7f, 6f, -7f)
	};

	private static readonly Vector3[] team2Spawns_T6 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(0f, 1.45f, 3f),
		new Vector3(-8f, 1.45f, 9f),
		new Vector3(0f, 1.45f, 12f)
	};

	private static readonly Vector3[] team3Spawns_T6 = (Vector3[])(object)new Vector3[3]
	{
		new Vector3(-8f, 1.45f, -9f),
		new Vector3(-7f, 6f, -7f),
		new Vector3(0f, 1.45f, -3f)
	};

	private static readonly Vector3[] team4Spawns_T6 = (Vector3[])(object)new Vector3[2]
	{
		new Vector3(8f, 1.45f, 9f),
		new Vector3(7f, 6f, 7f)
	};

	private static readonly Vector3[] team5Spawns_T6 = (Vector3[])(object)new Vector3[2]
	{
		new Vector3(12f, 1.45f, 0f),
		new Vector3(8f, 1.45f, -9f)
	};

	private static Vector3[] GetDefaultSpawnArrayForTeam(int teamCount, int teamIndex)
	{
		switch (teamCount)
		{
		case 2:
			if (teamIndex != 0)
			{
				return team1Spawns_T2;
			}
			return team0Spawns_T2;
		case 3:
			return teamIndex switch
			{
				0 => team0Spawns_T3, 
				1 => team1Spawns_T3, 
				2 => team2Spawns_T3, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		case 4:
			return teamIndex switch
			{
				0 => team0Spawns_T4, 
				1 => team1Spawns_T4, 
				2 => team2Spawns_T4, 
				3 => team3Spawns_T4, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		case 5:
			return teamIndex switch
			{
				0 => team0Spawns_T5, 
				1 => team1Spawns_T5, 
				2 => team2Spawns_T5, 
				3 => team3Spawns_T5, 
				4 => team4Spawns_T5, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		case 6:
			return teamIndex switch
			{
				0 => team0Spawns_T6, 
				1 => team1Spawns_T6, 
				2 => team2Spawns_T6, 
				3 => team3Spawns_T6, 
				4 => team4Spawns_T6, 
				5 => team5Spawns_T6, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		default:
			throw new NotImplementedException("この実装はチーム数が2,3,4,5,6の場合のみ対応しています。");
		}
	}

	private static Vector3[] GetSpawnArrayForTeam(int teamCount, int teamIndex)
	{
		if (SpawnConfigLoader.TryGetSpawns(teamCount, teamIndex, out var spawns))
		{
			return spawns.ToArray();
		}
		return GetDefaultSpawnArrayForTeam(teamCount, teamIndex);
	}

	public static Vector3 GetUniqueStaticSpawnPointForTeam(int teamIndex, int teamCount)
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: 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_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		Vector3[] spawnArrayForTeam = GetSpawnArrayForTeam(teamCount, teamIndex);
		if (!GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions.ContainsKey(teamIndex))
		{
			GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[teamIndex] = new HashSet<Vector3>();
		}
		Vector3[] array = spawnArrayForTeam.OrderByDescending(delegate(Vector3 sp)
		{
			//IL_0000: 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_000c: 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)
			Vector2 val3 = new Vector2(sp.x, sp.z);
			return ((Vector2)(ref val3)).magnitude;
		}).ToArray();
		Vector3[] array2 = array;
		foreach (Vector3 val in array2)
		{
			if (!GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[teamIndex].Contains(val))
			{
				GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[teamIndex].Add(val);
				return val;
			}
		}
		GladioMoriKassenTeamBattlePlugin.LogInstance.LogWarning((object)$"All static spawn positions for team {teamIndex} are used. Returning a random spawn.");
		Vector3 val2 = array[Random.Range(0, array.Length)];
		GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[teamIndex].Add(val2);
		return val2;
	}

	public static void ClearUsedStaticSpawnPositions()
	{
		foreach (int item in GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions.Keys.ToList())
		{
			GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[item].Clear();
		}
	}
}
[HarmonyPatch(typeof(MultiplayerRoomPlayer), "UserCode_CmdChangePlayerName__String")]
public static class NameChangerPatch
{
	private static bool Prefix(MultiplayerRoomPlayer __instance, ref string newPlayerName)
	{
		if (!GladioMoriKassenTeamBattlePlugin.modEnabled)
		{
			return true;
		}
		int num = ((((NetworkBehaviour)__instance).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)__instance).connectionToClient).connectionId : ((Object)__instance).GetInstanceID());
		int value = 0;
		GladioMoriKassenTeamBattlePlugin.playerColorSelections.TryGetValue(num, out value);
		string text = GladioMoriKassenTeamBattlePlugin.colorOptions[value];
		GladioMoriKassenTeamBattlePlugin.LogInfo($"[NameChangerPatch] ConnId={num} : Before Process newPlayerName={newPlayerName}, SelectedIndex={value}, SelectedColor={text}");
		if (newPlayerName.StartsWith("<color=") && newPlayerName.EndsWith("</color>"))
		{
			int num2 = newPlayerName.IndexOf(">") + 1;
			int num3 = newPlayerName.LastIndexOf("</color>");
			if (num2 > 0 && num3 > num2)
			{
				newPlayerName = newPlayerName.Substring(num2, num3 - num2);
			}
		}
		if (value != 0)
		{
			newPlayerName = "<color=\"" + text + "\">" + newPlayerName + "</color>";
		}
		GladioMoriKassenTeamBattlePlugin.LogInfo($"[NameChangerPatch] ConnId={num} : After Process newPlayerName={newPlayerName}");
		return true;
	}
}
[HarmonyPatch(typeof(PlayerMultiplayerInputManager), "CreatePlayer")]
public static class SpawnPatch
{
	private static bool Prefix(PlayerMultiplayerInputManager __instance)
	{
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		if (!GladioMoriKassenTeamBattlePlugin.spawnPositioningEnabled)
		{
			return true;
		}
		if (!NetworkServer.active)
		{
			Debug.LogWarning((object)"[Server] CreatePlayer called when server was not active");
			return false;
		}
		if ((Object)(object)__instance.multiplayerRoomPlayer == (Object)null)
		{
			GladioMoriKassenTeamBattlePlugin.LogInfo("SpawnPatch: multiplayerRoomPlayer not found");
			return false;
		}
		int teamIndex = TeamHelper.GetTeamIndex(__instance.multiplayerRoomPlayer);
		GladioMoriKassenTeamBattlePlugin.LogInfo($"SpawnPatch: teamIndex = {teamIndex}");
		int currentTeamCount = GladioMoriKassenTeamBattlePlugin.CurrentTeamCount;
		if (teamIndex < 0 || currentTeamCount <= 0)
		{
			GladioMoriKassenTeamBattlePlugin.LogInfo($"SpawnPatch: illegal state teamIndex:{teamIndex} or teamCount:{currentTeamCount}");
			return true;
		}
		Vector3 uniqueStaticSpawnPointForTeam = SpawnHelperStatic.GetUniqueStaticSpawnPointForTeam(teamIndex, currentTeamCount);
		Quaternion identity = Quaternion.identity;
		GameObject val = Object.Instantiate<GameObject>(__instance.playerPrefab, uniqueStaticSpawnPointForTeam, identity);
		AccessTools.Field(typeof(PlayerMultiplayerInputManager), "playerCharacter").SetValue(__instance, val);
		NetworkServer.Spawn(val, (NetworkConnection)null);
		FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerMultiplayerInputManager), "ballMovements");
		List<BallMovement> value = val.GetComponentsInChildren<BallMovement>().ToList();
		fieldInfo.SetValue(__instance, value);
		__instance.rotatePlayer = val.GetComponentsInChildren<RotatePlayer>(true).FirstOrDefault();
		FieldInfo fieldInfo2 = AccessTools.Field(typeof(PlayerMultiplayerInputManager), "playerAnimator");
		PlayerAnimator componentInChildren = val.GetComponentInChildren<PlayerAnimator>();
		fieldInfo2.SetValue(__instance, componentInChildren);
		FieldInfo fieldInfo3 = AccessTools.Field(typeof(PlayerMultiplayerInputManager), "playerHealth");
		PlayerHealth component = val.GetComponent<PlayerHealth>();
		fieldInfo3.SetValue(__instance, component);
		if (__instance.moveSet != null && (Object)(object)componentInChildren != (Object)null)
		{
			componentInChildren.SetMoveSet(__instance.moveSet, false, false);
			__instance.UpdateDefaultMovesetSettings();
		}
		component.SetEquipment(__instance.equippedEquipment, true);
		NetworkIdentity component2 = val.GetComponent<NetworkIdentity>();
		__instance.NetworkplayerHealthIdentity = component2.netId;
		component.OnlyPhysical();
		return false;
	}
}
public static class TeamHelper
{
	public static int GetTeamIndex(MultiplayerRoomPlayer mrp)
	{
		int key = ((((NetworkBehaviour)mrp).connectionToClient != null) ? ((NetworkConnection)((NetworkBehaviour)mrp).connectionToClient).connectionId : ((Object)mrp).GetInstanceID());
		if (GladioMoriKassenTeamBattlePlugin.playerColorSelections.TryGetValue(key, out var value))
		{
			string value2 = GladioMoriKassenTeamBattlePlugin.colorOptions[value];
			if (GladioMoriKassenTeamBattlePlugin.CurrentAutoTeamColors != null)
			{
				return Array.IndexOf(GladioMoriKassenTeamBattlePlugin.CurrentAutoTeamColors, value2);
			}
			return value;
		}
		return -1;
	}

	public static string GetCleanNameFromNetwork(MultiplayerRoomPlayer mrp)
	{
		string networkplayerName = mrp.NetworkplayerName;
		if (!string.IsNullOrEmpty(networkplayerName) && networkplayerName.StartsWith("<color=\"") && networkplayerName.EndsWith("</color>"))
		{
			int num = networkplayerName.IndexOf(">") + 1;
			int num2 = networkplayerName.LastIndexOf("</color>");
			if (num > 0 && num2 > num)
			{
				return networkplayerName.Substring(num, num2 - num).ToLower();
			}
		}
		return networkplayerName;
	}

	public static string ExtractTeamColor(string coloredName)
	{
		if (!string.IsNullOrEmpty(coloredName) && coloredName.StartsWith("<color=\"") && coloredName.Contains("\">"))
		{
			int length = "<color=\"".Length;
			int num = coloredName.IndexOf("\">", length);
			if (num > length)
			{
				string text = coloredName.Substring(length, num - length).ToLower();
				GladioMoriKassenTeamBattlePlugin.LogInfo("ExtractTeamColor: Raw='" + coloredName + "', Extracted='" + text + "'");
				return text;
			}
		}
		GladioMoriKassenTeamBattlePlugin.LogInstance.LogWarning((object)("ExtractTeamColor: Invalid input. Value = '" + coloredName + "'"));
		return "";
	}

	public static string GetCleanName(string coloredName)
	{
		if (!string.IsNullOrEmpty(coloredName) && coloredName.StartsWith("<color=\"") && coloredName.EndsWith("</color>"))
		{
			int num = coloredName.IndexOf(">") + 1;
			int num2 = coloredName.LastIndexOf("</color>");
			if (num > 0 && num2 > num)
			{
				return coloredName.Substring(num, num2 - num);
			}
		}
		return coloredName;
	}
}
[HarmonyPatch(typeof(GameMaster), "GameOver")]
public static class GameOverPatch
{
	private static bool Prefix(GameMaster __instance, bool forceLoss)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Expected O, but got Unknown
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		if (!GladioMoriKassenTeamBattlePlugin.gameOverModEnabled)
		{
			return true;
		}
		if (__instance.gameIsOver || __instance.testScene)
		{
			return false;
		}
		__instance.gameIsOver = true;
		if ((Object)(object)ReplayManager.singleton != (Object)null)
		{
			ReplayManager.singleton.PauseRecording();
		}
		WinScreenInfo val = new WinScreenInfo();
		List<PlayerGameStateInfo> list = __instance.registeredPlayers.Where((PlayerGameStateInfo x) => x.player.alive).ToList();
		GladioMoriKassenTeamBattlePlugin.LogInfo($"GameOverPatch: AlivePlayers Count = {list.Count}");
		Dictionary<string, List<PlayerGameStateInfo>> dictionary = new Dictionary<string, List<PlayerGameStateInfo>>();
		foreach (PlayerGameStateInfo item in list)
		{
			string text = TeamHelper.ExtractTeamColor(item.player.playerName);
			GladioMoriKassenTeamBattlePlugin.LogInfo("GameOverPatch: Player " + item.player.playerName + " チーム = " + text);
			if (!dictionary.ContainsKey(text))
			{
				dictionary[text] = new List<PlayerGameStateInfo>();
			}
			dictionary[text].Add(item);
		}
		if (forceLoss)
		{
			val.gameEndResultType = (GameEndResultType)2;
		}
		else
		{
			GladioMoriKassenTeamBattlePlugin.GameDecision gameDecision = ((!GladioMoriKassenTeamBattlePlugin.captainModeEnabled) ? GladioMoriKassenTeamBattlePlugin.GameDecisionEvaluator.EvaluateStandardGameResult(dictionary, list) : GladioMoriKassenTeamBattlePlugin.GameDecisionEvaluator.EvaluateCaptainGameResult(dictionary, list));
			val.gameEndResultType = (GameEndResultType)((gameDecision.Result != 0) ? 1 : 0);
			val.winningPlayerName = gameDecision.WinningTeam;
		}
		val.playerList = new List<WinScreenPlayerInfo>();
		foreach (PlayerGameStateInfo registeredPlayer in __instance.registeredPlayers)
		{
			val.playerList.Add(new WinScreenPlayerInfo
			{
				deathTime = registeredPlayer.deathTime,
				playerName = registeredPlayer.player.playerName,
				deathReason = registeredPlayer.deathReason
			});
		}
		if ((Object)(object)SingleplayerManager.singleton != (Object)null)
		{
			bool flag = false;
			if (!forceLoss && list.Count > 0 && dictionary.Count == 1 && !dictionary.First().Value.First().player.ai)
			{
				flag = true;
			}
			SingleplayerManager.singleton.HandleFightResult(val.gameEndResultType, flag);
		}
		if ((Object)(object)__instance.multiplayerGameMaster != (Object)null)
		{
			GladioMoriKassenTeamBattlePlugin.LogInfo("GameOverPatch: Calling multiplayerGameMaster.GameOver");
			__instance.multiplayerGameMaster.GameOver(val);
			foreach (int item2 in GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions.Keys.ToList())
			{
				GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[item2].Clear();
			}
			GladioMoriKassenTeamBattlePlugin.LogInfo("GameOverPatch: usedSpawnPositions cleared.");
			return false;
		}
		if ((Object)(object)__instance.gameMenu != (Object)null)
		{
			__instance.gameMenu.ShowWinScreenInfo(val);
		}
		foreach (int item3 in GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions.Keys.ToList())
		{
			GladioMoriKassenTeamBattlePlugin.usedStaticSpawnPositions[item3].Clear();
		}
		GladioMoriKassenTeamBattlePlugin.LogInfo("GameOverPatch: usedSpawnPositions cleared.");
		return false;
	}
}
[HarmonyPatch(typeof(GameMaster), "InformPlayerDeath")]
public static class InformPlayerDeathPatch
{
	private static void Postfix(GameMaster __instance, PlayerHealth player, DeathReason newDeathReason, PlayerHealth newKiller)
	{
		if (!GladioMoriKassenTeamBattlePlugin.gameOverModEnabled)
		{
			return;
		}
		string playerName = player.playerName;
		string text = (string.IsNullOrEmpty(playerName) ? playerName : Regex.Replace(playerName, "<color=\"[^\"]*\">|</color>", ""));
		if (text.StartsWith("<b><size=20>[CAP]"))
		{
			string text2 = TeamHelper.ExtractTeamColor(playerName);
			string text3 = Regex.Replace(text, "<.*?>", string.Empty);
			string text4 = "Captain " + text3 + " of team " + text2 + " has died!";
			ChatHelper.BroadcastChatMessage(text4, "TeamBattleMod");
			GladioMoriKassenTeamBattlePlugin.LogInfo("InformPlayerDeathPatch: Announced captain death: " + text4);
		}
		List<PlayerGameStateInfo> list = __instance.registeredPlayers.Where((PlayerGameStateInfo x) => !x.player.ai && x.player.alive).ToList();
		Dictionary<string, List<PlayerGameStateInfo>> dictionary = new Dictionary<string, List<PlayerGameStateInfo>>();
		foreach (PlayerGameStateInfo item in list)
		{
			string key = TeamHelper.ExtractTeamColor(item.player.playerName);
			if (!dictionary.ContainsKey(key))
			{
				dictionary[key] = new List<PlayerGameStateInfo>();
			}
			dictionary[key].Add(item);
		}
		List<string> values = dictionary.Keys.ToList();
		GladioMoriKassenTeamBattlePlugin.LogInfo(string.Format("InformPlayerDeathPatch: AliveNonAIMembers={0}, UniqueTeams={1}", list.Count, string.Join(", ", values)));
		GladioMoriKassenTeamBattlePlugin.GameDecision gameDecision = ((!GladioMoriKassenTeamBattlePlugin.captainModeEnabled) ? GladioMoriKassenTeamBattlePlugin.GameDecisionEvaluator.EvaluateStandardGameResult(dictionary, list) : GladioMoriKassenTeamBattlePlugin.GameDecisionEvaluator.EvaluateCaptainGameResult(dictionary, list));
		GladioMoriKassenTeamBattlePlugin.LogInfo($"InformPlayerDeathPatch: Game decision result = {gameDecision.Result}, WinningTeam = {gameDecision.WinningTeam}");
		if (gameDecision.Result == GladioMoriKassenTeamBattlePlugin.GameResultType.Win && !__instance.gameIsOver)
		{
			GladioMoriKassenTeamBattlePlugin.LogInfo("InformPlayerDeathPatch: Game decision reached, starting GameOverTimer");
			MethodInfo methodInfo = AccessTools.Method(typeof(GameMaster), "GameOverTimer", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				IEnumerator enumerator2 = (IEnumerator)methodInfo.Invoke(__instance, null);
				((MonoBehaviour)__instance).StartCoroutine(enumerator2);
			}
			else
			{
				GladioMoriKassenTeamBattlePlugin.LogInstance.LogError((object)"InformPlayerDeathPatch: GameOverTimer method not found");
			}
		}
	}
}
[HarmonyPatch(typeof(GameMenu), "RestartGame")]
public static class RestartGamePatch
{
	private static void Prefix()
	{
		SpawnHelperStatic.ClearUsedStaticSpawnPositions();
		GladioMoriKassenTeamBattlePlugin.LogInfo("RestartGamePatch: usedStaticSpawnPositions cleared.");
	}
}
[HarmonyPatch(typeof(MultiplayerMenuManager), "Start")]
public static class MultiplayerMenuManagerStartPatch
{
	private static void Prefix()
	{
		GladioMoriKassenTeamBattlePlugin.originalPlayerNames.Clear();
	}
}