using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks.CompilerServices; using Gamemode_Lib.ConfigSync; using Gamemode_Lib.Events; using Gamemode_Lib.Network.Messages; using Gamemode_Lib.Patches; using Gamemode_Lib.Patches.Features; using Gamemode_Lib.Teams; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Pool; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("GameAssembly")] [assembly: IgnoresAccessChecksTo("SharedAssembly")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.github.glarmer.Gamemode_Lib")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.5.1.0")] [assembly: AssemblyInformationalVersion("0.5.1+852d639c41ee959ea823f8321301795369f5d33c")] [assembly: AssemblyProduct("com.github.glarmer.Gamemode_Lib")] [assembly: AssemblyTitle("Gamemode_Lib")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.5.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace Gamemode_Lib { public static class GameModeUtilities { public static Dictionary Modes { get; } = new Dictionary(); public static string? CurrentGamemodeId { get; set; } public static bool GameEnded { get; set; } = true; public static void ReinitializeGameState() { string currentGamemodeId = CurrentGamemodeId; Plugin.Log.LogInfo((object)($"[GamemodeLib] ReinitializeGameState: serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}'", GameEnded, currentGamemodeId ?? ""))); if (currentGamemodeId != null && Modes.TryGetValue(currentGamemodeId, out IGamemode value) && value != null) { try { Harmony gamemodeHarmony = value.GamemodeHarmony; if (gamemodeHarmony != null) { gamemodeHarmony.UnpatchSelf(); } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[GamemodeLib] ReinitializeGameState: failed to unpatch gamemode harmony for '{currentGamemodeId}': {arg}"); } } ConfigSyncManager.Instance?.ClearAllScopes(); bool active = NetworkServer.active; TeamManager.Instance?.ResetToDefaults(active); CurrentGamemodeId = null; GameEnded = true; } public static void RegisterGameMode(IGamemode gamemode) { if (Modes != null) { if (Modes.ContainsKey(gamemode.GameModeId)) { Plugin.Log.LogError((object)("Gamemode with same ID: " + gamemode.GameModeId + " has already been registered! We will not re-register...")); return; } Modes.Add(gamemode.GameModeId, gamemode); if (gamemode.IsTeamBased) { } Plugin.Log.LogInfo((object)("Gamemode ID: " + gamemode.GameModeId + " has been registered!")); } else { Plugin.Log.LogError((object)("Gamemode dictionary was null! " + gamemode.Name + " is not loaded...")); } } public static void ApplyGamemodeStartMessage(GamemodeStartMessage message) { Plugin.Log.LogInfo((object)($"[GamemodeLib] ApplyGamemodeStartMessage: serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}' msgGamemodeId='{2}'", GameEnded, CurrentGamemodeId ?? "", message.GamemodeId ?? ""))); if (NetworkServer.active) { Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeStartMessage: ignoring because server is active"); return; } if (message.GamemodeId == null) { Plugin.Log.LogError((object)"[GamemodeLib] Received GamemodeStartMessage with null GamemodeId"); return; } if (!Modes.TryGetValue(message.GamemodeId, out IGamemode value) || value == null) { Plugin.Log.LogError((object)$"[GamemodeLib] Received GamemodeStartMessage for unknown mode id '{message.GamemodeId}'. modesCount={Modes.Count}"); return; } Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeStartMessage: starting mode '" + message.GamemodeId + "'. " + string.Format("previousState: gameEnded={0} currentGamemodeId='{1}'", GameEnded, CurrentGamemodeId ?? ""))); CurrentGamemodeId = message.GamemodeId; GameEnded = false; if ((Object)(object)ConfigSyncManager.Instance != (Object)null && !ConfigSyncManager.Instance.HasReceivedFull(message.GamemodeId)) { ConfigSyncManager.Instance.RequestScopeFromHost(message.GamemodeId); } try { value.OnGameStart(); Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeStartMessage: mode.OnGameStart() finished for '" + message.GamemodeId + "'")); } catch (Exception arg) { Plugin.Log.LogError((object)$"[GamemodeLib] ApplyGamemodeStartMessage: mode.OnGameStart() threw for '{message.GamemodeId}': {arg}"); throw; } } public static void ApplyGamemodeEndMessage(GamemodeEndMessage message) { Plugin.Log.LogInfo((object)($"[GamemodeLib] ApplyGamemodeEndMessage: serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}' msgGamemodeId='{2}'", GameEnded, CurrentGamemodeId ?? "", message.GamemodeId ?? ""))); if (NetworkServer.active) { Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeEndMessage: ignoring because server is active"); return; } if (GameEnded) { Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeEndMessage: ignoring because GameEnded is already true"); return; } if (message.GamemodeId == null) { Plugin.Log.LogError((object)"[GamemodeLib] Received GamemodeEndMessage with null GamemodeId"); return; } if (!Modes.TryGetValue(message.GamemodeId, out IGamemode value) || value == null) { Plugin.Log.LogError((object)("[GamemodeLib] Received GamemodeEndMessage for unknown mode id '" + message.GamemodeId + "'. " + $"modesCount={Modes.Count}. Forcing local end state.")); GameEnded = true; CurrentGamemodeId = null; return; } Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeEndMessage: ending mode '" + message.GamemodeId + "'. " + string.Format("previousState: gameEnded={0} currentGamemodeId='{1}'", GameEnded, CurrentGamemodeId ?? ""))); CurrentGamemodeId = message.GamemodeId; GameEnded = true; try { value.OnGameEnd(); Plugin.Log.LogInfo((object)("[GamemodeLib] ApplyGamemodeEndMessage: mode.OnGameEnd() finished for '" + message.GamemodeId + "'")); } catch (Exception arg) { Plugin.Log.LogError((object)$"[GamemodeLib] ApplyGamemodeEndMessage: mode.OnGameEnd() threw for '{message.GamemodeId}': {arg}"); throw; } CurrentGamemodeId = null; ConfigSyncManager.Instance?.ClearScope(message.GamemodeId); Plugin.Log.LogInfo((object)"[GamemodeLib] ApplyGamemodeEndMessage: cleared CurrentGamemodeId and set GameEnded=true"); } internal static void TryEndCurrentGame(bool broadcastToClients) { Plugin.Log.LogInfo((object)($"[GamemodeLib] TryEndCurrentGame: broadcastToClients={broadcastToClients} serverActive={NetworkServer.active} clientActive={NetworkClient.active} " + string.Format("gameEnded={0} currentGamemodeId='{1}'", GameEnded, CurrentGamemodeId ?? ""))); if (GameEnded) { Plugin.Log.LogInfo((object)"[GamemodeLib] TryEndCurrentGame: no-op because GameEnded is already true"); return; } string currentGamemodeId = CurrentGamemodeId; if (currentGamemodeId == null) { Plugin.Log.LogWarning((object)"[GamemodeLib] TryEndCurrentGame: CurrentGamemodeId was null while GameEnded=false; forcing GameEnded=true"); GameEnded = true; return; } if (!Modes.TryGetValue(currentGamemodeId, out IGamemode value) || value == null) { Plugin.Log.LogWarning((object)($"[GamemodeLib] TryEndCurrentGame: mode lookup failed for id '{currentGamemodeId}'. modesCount={Modes.Count}. " + "Forcing GameEnded=true and clearing CurrentGamemodeId.")); GameEnded = true; CurrentGamemodeId = null; return; } Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: ending current mode '" + currentGamemodeId + "' (modeType=" + value.GetType().FullName + ")")); GameEnded = true; try { value.OnGameEnd(); Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: mode.OnGameEnd() finished for '" + currentGamemodeId + "'")); } catch (Exception arg) { Plugin.Log.LogError((object)$"[GamemodeLib] TryEndCurrentGame: mode.OnGameEnd() threw for '{currentGamemodeId}': {arg}"); throw; } finally { if (broadcastToClients && NetworkServer.active) { Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: broadcasting GamemodeEndMessage to all clients for '" + currentGamemodeId + "'")); NetworkMessageBootstrap.Register(); GamemodeEndMessage gamemodeEndMessage = default(GamemodeEndMessage); gamemodeEndMessage.GamemodeId = currentGamemodeId; NetworkServer.SendToAll(gamemodeEndMessage, 0, false); Plugin.Log.LogInfo((object)("[GamemodeLib] TryEndCurrentGame: broadcast sent for '" + currentGamemodeId + "'")); } else { Plugin.Log.LogInfo((object)$"[GamemodeLib] TryEndCurrentGame: not broadcasting (broadcastToClients={broadcastToClients}, serverActive={NetworkServer.active})"); } ConfigSyncManager.Instance?.ClearScope(currentGamemodeId); CurrentGamemodeId = null; Plugin.Log.LogInfo((object)"[GamemodeLib] TryEndCurrentGame: cleared CurrentGamemodeId"); } } } public interface IGamemode { Harmony GamemodeHarmony { get; init; } string Name { get; } string ModId { get; } string GameModeId => ModId + ":" + Name; int MinPlayers { get; } int MaxPlayers { get; } bool IsTeamBased { get; } bool IsNormalStartProcedure { get; } bool IsTaggingEnabled { get; } int TeamCount { get; } string Description { get; } void OnGameStart(); void OnGameEnd(); bool CanStart(int playerCount); } public static class NetworkMessageBootstrap { private static bool _commonRegistered; private static bool _clientRegistered; private static bool _serverRegistered; public static void Register() { Plugin.Log.LogInfo((object)($"[GamemodeLib] NetworkMessageBootstrap.Register: clientActive={NetworkClient.active} serverActive={NetworkServer.active} " + $"commonRegistered={_commonRegistered} clientRegistered={_clientRegistered} serverRegistered={_serverRegistered}")); RegisterCommon(); if (NetworkClient.active) { RegisterClient(); } if (NetworkServer.active) { RegisterServer(); } } private static void RegisterCommon() { if (_commonRegistered) { Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterCommon: already registered"); return; } _commonRegistered = true; Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterCommon: registering readers/writers"); Writer.write = delegate(NetworkWriter writer, TeamAssignMessage msg) { NetworkWriterExtensions.WriteULong(writer, msg.PlayerGuid); NetworkWriterExtensions.WriteInt(writer, msg.TeamId); }; Reader.read = delegate(NetworkReader reader) { TeamAssignMessage result11 = default(TeamAssignMessage); result11.PlayerGuid = NetworkReaderExtensions.ReadULong(reader); result11.TeamId = NetworkReaderExtensions.ReadInt(reader); return result11; }; Writer.write = delegate(NetworkWriter writer, TeamRequestMessage msg) { NetworkWriterExtensions.WriteULong(writer, msg.PlayerGuid); }; Reader.read = delegate(NetworkReader reader) { TeamRequestMessage result10 = default(TeamRequestMessage); result10.PlayerGuid = NetworkReaderExtensions.ReadULong(reader); return result10; }; Writer.write = delegate(NetworkWriter writer, TeamDefinitionMessage msg) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) NetworkWriterExtensions.WriteInt(writer, msg.ID); NetworkWriterExtensions.WriteColor(writer, msg.Color); NetworkWriterExtensions.WriteString(writer, msg.Name); }; Reader.read = delegate(NetworkReader reader) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) TeamDefinitionMessage result9 = default(TeamDefinitionMessage); result9.ID = NetworkReaderExtensions.ReadInt(reader); result9.Color = NetworkReaderExtensions.ReadColor(reader); result9.Name = NetworkReaderExtensions.ReadString(reader); return result9; }; Writer.write = delegate(NetworkWriter writer, GamemodeStartMessage msg) { NetworkWriterExtensions.WriteString(writer, msg.GamemodeId); }; Reader.read = delegate(NetworkReader reader) { GamemodeStartMessage result8 = default(GamemodeStartMessage); result8.GamemodeId = NetworkReaderExtensions.ReadString(reader); return result8; }; Writer.write = delegate(NetworkWriter writer, GamemodeEndMessage msg) { NetworkWriterExtensions.WriteString(writer, msg.GamemodeId); }; Reader.read = delegate(NetworkReader reader) { GamemodeEndMessage result7 = default(GamemodeEndMessage); result7.GamemodeId = NetworkReaderExtensions.ReadString(reader); return result7; }; Writer.write = delegate(NetworkWriter writer, RaycastRequestMessage msg) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) NetworkWriterExtensions.WriteString(writer, msg.Purpose); NetworkWriterExtensions.WriteULong(writer, msg.Guid); NetworkWriterExtensions.WriteVector3(writer, msg.Origin); NetworkWriterExtensions.WriteVector3(writer, msg.Direction); NetworkWriterExtensions.WriteFloat(writer, msg.MaxDistance); NetworkWriterExtensions.WriteInt(writer, msg.RaycastMask); }; Reader.read = delegate(NetworkReader reader) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) RaycastRequestMessage result6 = default(RaycastRequestMessage); result6.Purpose = NetworkReaderExtensions.ReadString(reader); result6.Guid = NetworkReaderExtensions.ReadULong(reader); result6.Origin = NetworkReaderExtensions.ReadVector3(reader); result6.Direction = NetworkReaderExtensions.ReadVector3(reader); result6.MaxDistance = NetworkReaderExtensions.ReadFloat(reader); result6.RaycastMask = NetworkReaderExtensions.ReadInt(reader); return result6; }; Writer.write = delegate(NetworkWriter writer, RaycastResultMessage msg) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) NetworkWriterExtensions.WriteString(writer, msg.Purpose); NetworkWriterExtensions.WriteULong(writer, msg.Guid); NetworkWriterExtensions.WriteVector3(writer, msg.Origin); NetworkWriterExtensions.WriteVector3(writer, msg.Direction); NetworkWriterExtensions.WriteFloat(writer, msg.MaxDistance); NetworkWriterExtensions.WriteInt(writer, msg.RaycastMask); NetworkWriterExtensions.WriteBool(writer, msg.HasHit); NetworkWriterExtensions.WriteVector3(writer, msg.HitPoint); NetworkWriterExtensions.WriteVector3(writer, msg.HitNormal); NetworkWriterExtensions.WriteFloat(writer, msg.HitDistance); NetworkWriterExtensions.WriteString(writer, msg.HitObjectName); NetworkWriterExtensions.WriteString(writer, msg.ClosestValidRootObjectName); }; Reader.read = delegate(NetworkReader reader) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) RaycastResultMessage result5 = default(RaycastResultMessage); result5.Purpose = NetworkReaderExtensions.ReadString(reader); result5.Guid = NetworkReaderExtensions.ReadULong(reader); result5.Origin = NetworkReaderExtensions.ReadVector3(reader); result5.Direction = NetworkReaderExtensions.ReadVector3(reader); result5.MaxDistance = NetworkReaderExtensions.ReadFloat(reader); result5.RaycastMask = NetworkReaderExtensions.ReadInt(reader); result5.HasHit = NetworkReaderExtensions.ReadBool(reader); result5.HitPoint = NetworkReaderExtensions.ReadVector3(reader); result5.HitNormal = NetworkReaderExtensions.ReadVector3(reader); result5.HitDistance = NetworkReaderExtensions.ReadFloat(reader); result5.HitObjectName = NetworkReaderExtensions.ReadString(reader); result5.ClosestValidRootObjectName = NetworkReaderExtensions.ReadString(reader); return result5; }; Writer.write = delegate(NetworkWriter writer, ConfigScopeRequestMessage msg) { NetworkWriterExtensions.WriteString(writer, msg.ScopeId); }; Reader.read = delegate(NetworkReader reader) { ConfigScopeRequestMessage result4 = default(ConfigScopeRequestMessage); result4.ScopeId = NetworkReaderExtensions.ReadString(reader); return result4; }; Writer.write = delegate(NetworkWriter writer, ConfigEntry entry) { NetworkWriterExtensions.WriteString(writer, entry.Key); writer.WriteByte((byte)entry.Type); switch (entry.Type) { case ConfigValueType.String: NetworkWriterExtensions.WriteString(writer, entry.StringValue); break; case ConfigValueType.Int: NetworkWriterExtensions.WriteInt(writer, entry.IntValue); break; case ConfigValueType.Float: NetworkWriterExtensions.WriteFloat(writer, entry.FloatValue); break; case ConfigValueType.Bool: NetworkWriterExtensions.WriteBool(writer, entry.BoolValue); break; default: NetworkWriterExtensions.WriteString(writer, entry.StringValue); break; } }; Reader.read = delegate(NetworkReader reader) { ConfigEntry configEntry = default(ConfigEntry); configEntry.Key = NetworkReaderExtensions.ReadString(reader); configEntry.Type = (ConfigValueType)reader.ReadByte(); ConfigEntry result3 = configEntry; switch (result3.Type) { case ConfigValueType.String: result3.StringValue = NetworkReaderExtensions.ReadString(reader); break; case ConfigValueType.Int: result3.IntValue = NetworkReaderExtensions.ReadInt(reader); break; case ConfigValueType.Float: result3.FloatValue = NetworkReaderExtensions.ReadFloat(reader); break; case ConfigValueType.Bool: result3.BoolValue = NetworkReaderExtensions.ReadBool(reader); break; default: result3.StringValue = NetworkReaderExtensions.ReadString(reader); break; } return result3; }; Writer.write = delegate(NetworkWriter writer, ConfigScopeUpdateMessage msg) { NetworkWriterExtensions.WriteString(writer, msg.ScopeId); writer.Write(msg.Entry); }; Reader.read = delegate(NetworkReader reader) { ConfigScopeUpdateMessage result2 = default(ConfigScopeUpdateMessage); result2.ScopeId = NetworkReaderExtensions.ReadString(reader); result2.Entry = reader.Read(); return result2; }; Writer.write = delegate(NetworkWriter writer, ConfigScopeFullMessage msg) { NetworkWriterExtensions.WriteString(writer, msg.ScopeId); int num2 = msg.Entries?.Count ?? 0; NetworkWriterExtensions.WriteInt(writer, num2); for (int j = 0; j < num2; j++) { writer.Write(msg.Entries[j]); } }; Reader.read = delegate(NetworkReader reader) { ConfigScopeFullMessage configScopeFullMessage = default(ConfigScopeFullMessage); configScopeFullMessage.ScopeId = NetworkReaderExtensions.ReadString(reader); configScopeFullMessage.Entries = new List(); ConfigScopeFullMessage result = configScopeFullMessage; int num = NetworkReaderExtensions.ReadInt(reader); for (int i = 0; i < num; i++) { result.Entries.Add(reader.Read()); } return result; }; Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterCommon: registered network message readers/writers (teams + gamemodes + config + raycasts)"); } private static void RegisterClient() { if (_clientRegistered) { Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterClient: already registered"); return; } _clientRegistered = true; Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterClient: registering client handlers"); NetworkClient.RegisterHandler((Action)delegate(TeamAssignMessage msg) { Plugin.Log.LogInfo((object)$"[GamemodeLib] Client received TeamAssignMessage: playerGuid={msg.PlayerGuid} teamId={msg.TeamId}"); TeamManager.Instance?.ApplyTeamMessage(msg); }, true); NetworkClient.RegisterHandler((Action)delegate(TeamDefinitionMessage msg) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received TeamDefinitionMessage: id={0} name='{1}' color={2}", msg.ID, msg.Name ?? "", msg.Color)); TeamManager.Instance?.ApplyTeamDefinitionMessage(msg); }, true); NetworkClient.RegisterHandler((Action)delegate(GamemodeStartMessage msg) { Plugin.Log.LogInfo((object)("[GamemodeLib] Client received GamemodeStartMessage: gamemodeId='" + (msg.GamemodeId ?? "") + "'")); GameModeUtilities.ApplyGamemodeStartMessage(msg); }, true); NetworkClient.RegisterHandler((Action)delegate(GamemodeEndMessage msg) { Plugin.Log.LogInfo((object)("[GamemodeLib] Client received GamemodeEndMessage: gamemodeId='" + (msg.GamemodeId ?? "") + "'")); GameModeUtilities.ApplyGamemodeEndMessage(msg); }, true); NetworkClient.RegisterHandler((Action)delegate(ConfigScopeFullMessage msg) { Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received ConfigScopeFullMessage: scopeId='{0}' entries={1}", msg.ScopeId ?? "", msg.Entries?.Count ?? 0)); ConfigSyncManager.Instance?.ApplyFull(msg); }, true); NetworkClient.RegisterHandler((Action)delegate(ConfigScopeUpdateMessage msg) { Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received ConfigScopeUpdateMessage: scopeId='{0}' key='{1}' type={2}", msg.ScopeId ?? "", msg.Entry.Key ?? "", (byte)msg.Entry.Type)); ConfigSyncManager.Instance?.ApplyUpdate(msg); }, true); NetworkClient.RegisterHandler((Action)delegate(RaycastResultMessage msg) { Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Client received RaycastResultMessage: purpose='{0}' hasHit={1} root='{2}'", msg.Purpose ?? "", msg.HasHit, msg.ClosestValidRootObjectName ?? "")); RaycastUtility.HandleRaycastResult(msg); }, true); Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterClient: client handlers registered"); } private static void RegisterServer() { if (_serverRegistered) { Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterServer: already registered"); return; } _serverRegistered = true; Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterServer: registering server handlers"); NetworkServer.RegisterHandler((Action)delegate(NetworkConnectionToClient conn, TeamRequestMessage msg) { Plugin.Log.LogInfo((object)$"[GamemodeLib] Server received TeamRequestMessage: connId={conn.connectionId} playerGuid={msg.PlayerGuid}"); TeamManager.Instance?.HandleTeamRequest(conn, msg); }, true); NetworkServer.RegisterHandler((Action)delegate(NetworkConnectionToClient conn, ConfigScopeRequestMessage msg) { Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Server received ConfigScopeRequestMessage: connId={0} scopeId='{1}'", conn.connectionId, msg.ScopeId ?? "")); ConfigSyncManager.Instance?.HandleScopeRequest(conn, msg); }, true); NetworkServer.RegisterHandler((Action)delegate(NetworkConnectionToClient conn, RaycastRequestMessage msg) { Plugin.Log.LogInfo((object)string.Format("[GamemodeLib] Server received RaycastRequestMessage: connId={0} purpose='{1}' maxDistance={2} mask={3}", conn.connectionId, msg.Purpose ?? "", msg.MaxDistance, msg.RaycastMask)); RaycastUtility.HandleRaycastRequest(conn.connectionId, msg); }, true); Plugin.Log.LogInfo((object)"[GamemodeLib] NetworkMessageBootstrap.RegisterServer: server handlers registered"); } [HarmonyPatch(typeof(BNetworkManager), "OnStartClient")] [HarmonyPostfix] public static void OnStartClient_Postfix() { Plugin.Log.LogInfo((object)"[GamemodeLib] BNetworkManager.OnStartClient postfix: registering network messages"); Register(); } [HarmonyPatch(typeof(BNetworkManager), "OnStartServer")] [HarmonyPostfix] public static void OnStartServer_Postfix() { Plugin.Log.LogInfo((object)"[GamemodeLib] BNetworkManager.OnStartServer postfix: registering network messages"); Register(); } [HarmonyPatch(typeof(BNetworkManager), "OnDestroy")] [HarmonyPrefix] public static void OnDestroy_Prefix() { Plugin.Log.LogInfo((object)$"[GamemodeLib] BNetworkManager.OnDestroy prefix: attempting to end current game (serverActive={NetworkServer.active})"); GameModeUtilities.TryEndCurrentGame(NetworkServer.active); } } [BepInPlugin("com.github.glarmer.Gamemode_Lib", "Gamemode_Lib", "0.5.1")] public class Plugin : BaseUnityPlugin { internal readonly Harmony _harmony = new Harmony("com.github.glarmer.Gamemode_Lib"); internal static Plugin Instance; public const string Id = "com.github.glarmer.Gamemode_Lib"; internal static ManualLogSource Log { get; private set; } public static string Name => "Gamemode_Lib"; public static string Version => "0.5.1"; private void Awake() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; GameObject val = new GameObject("GamemodeLib"); val.AddComponent(); Log.LogInfo((object)("Plugin " + Name + " (Version " + Version + ") is patching!")); Log.LogInfo((object)"[GamemodeLib] is running Network patches"); _harmony.PatchAll(typeof(NetworkMessageBootstrap)); Log.LogInfo((object)"[GamemodeLib] is patching Scoreboard"); _harmony.PatchAll(typeof(ScoreboardPatches)); Log.LogInfo((object)"[GamemodeLib] is patching MatchSetupPlayer"); _harmony.PatchAll(typeof(MatchSetupPlayerPatches)); Log.LogInfo((object)"[GamemodeLib] is patching CourseManager"); _harmony.PatchAll(typeof(CourseManagerPatches)); Log.LogInfo((object)"[GamemodeLib] is patching NameTagUi"); _harmony.PatchAll(typeof(NameTagUiPatches)); Log.LogInfo((object)"[GamemodeLib] is patching GameManager"); _harmony.PatchAll(typeof(GameManagerPatches)); Log.LogInfo((object)"[GamemodeLib] is patching MatchSetup"); _harmony.PatchAll(typeof(MatchSetupMenuPatches)); Log.LogInfo((object)"[GamemodeLib] is patching PlayerInfo"); _harmony.PatchAll(typeof(PlayerInfoPatches)); _harmony.PatchAll(typeof(TeeOffCountdownPatches)); Log.LogInfo((object)"[GamemodeLib] is finished patching."); SceneEvents.Init(); SceneEvents.OnReturnToLobby += OnReturnToLobby; PlayerEvents.Init(); Log.LogInfo((object)"[GamemodeLib] Initialized."); } private void OnReturnToLobby(Scene hole, Scene lobby) { if (GameModeUtilities.CurrentGamemodeId != null) { GameModeUtilities.TryEndCurrentGame(broadcastToClients: true); } GameModeUtilities.ReinitializeGameState(); } private void OnDestroy() { SceneEvents.OnReturnToLobby -= OnReturnToLobby; SceneEvents.Shutdown(); _harmony.UnpatchSelf(); } } public static class RaycastUtility { public readonly struct RaycastCompletedEventArgs { public readonly string Purpose; public readonly int RequestingConnectionId; public readonly ulong RequestingClientGuid; public readonly Vector3 Origin; public readonly Vector3 Direction; public readonly float MaxDistance; public readonly int RaycastMask; public readonly bool HasHit; public readonly RaycastHit Hit; public readonly GameObject ClosestValidRootObject; public RaycastCompletedEventArgs(string purpose, int requestingConnectionId, ulong requestingClientGuid, Vector3 origin, Vector3 direction, float maxDistance, int raycastMask, bool hasHit, RaycastHit hit, GameObject closestValidRootObject) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) Purpose = purpose; RequestingConnectionId = requestingConnectionId; RequestingClientGuid = requestingClientGuid; Origin = origin; Direction = direction; MaxDistance = maxDistance; RaycastMask = raycastMask; HasHit = hasHit; Hit = hit; ClosestValidRootObject = closestValidRootObject; } } public readonly struct RaycastResultReceivedEventArgs { public readonly string Purpose; public readonly ulong RequestingClientGuid; public readonly Vector3 Origin; public readonly Vector3 Direction; public readonly float MaxDistance; public readonly int RaycastMask; public readonly bool HasHit; public readonly Vector3 HitPoint; public readonly Vector3 HitNormal; public readonly float HitDistance; public readonly string HitObjectName; public readonly string ClosestValidRootObjectName; public RaycastResultReceivedEventArgs(string purpose, ulong requestingClientGuid, Vector3 origin, Vector3 direction, float maxDistance, int raycastMask, bool hasHit, Vector3 hitPoint, Vector3 hitNormal, float hitDistance, string hitObjectName, string closestValidRootObjectName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) Purpose = purpose; RequestingClientGuid = requestingClientGuid; Origin = origin; Direction = direction; MaxDistance = maxDistance; RaycastMask = raycastMask; HasHit = hasHit; HitPoint = hitPoint; HitNormal = hitNormal; HitDistance = hitDistance; HitObjectName = hitObjectName; ClosestValidRootObjectName = closestValidRootObjectName; } } public static event Action RaycastCompleted; public static event Action RaycastResultReceived; public static GameObject GetClosestValidObjectFromMainCameraCenter(float maxDistance = 100f, LayerMask raycastMask = default(LayerMask)) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return null; } return GetClosestValidObject(((Component)main).transform.position, ((Component)main).transform.forward, maxDistance, raycastMask); } public static GameObject GetClosestValidObject(Vector3 origin, Vector3 direction, float maxDistance = 100f, LayerMask raycastMask = default(LayerMask)) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (LayerMask.op_Implicit(raycastMask) == 0) { raycastMask = LayerMask.op_Implicit(-1); } if (((Vector3)(ref direction)).sqrMagnitude <= 1E-06f) { return null; } Ray val = default(Ray); ((Ray)(ref val))..ctor(origin, ((Vector3)(ref direction)).normalized); RaycastHit[] array = Physics.RaycastAll(val, maxDistance, LayerMask.op_Implicit(raycastMask), (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val2 = array2[i]; GameObject gameObject = ((Component)((RaycastHit)(ref val2)).collider).gameObject; if (!ShouldIgnore(gameObject)) { return GetHighestParent(gameObject); } } return null; } public static void RequestRaycastOnHost(string purpose, ulong guid, Vector3 origin, Vector3 direction, float maxDistance = 100f, LayerMask raycastMask = default(LayerMask)) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (NetworkClient.active) { if (NetworkServer.active) { HandleRaycastRequest(-1, new RaycastRequestMessage { Purpose = purpose, Guid = guid, Origin = origin, Direction = direction, MaxDistance = maxDistance, RaycastMask = ((LayerMask.op_Implicit(raycastMask) == 0) ? (-1) : ((LayerMask)(ref raycastMask)).value) }); } else { NetworkMessageBootstrap.Register(); RaycastRequestMessage raycastRequestMessage = default(RaycastRequestMessage); raycastRequestMessage.Purpose = purpose; raycastRequestMessage.Guid = guid; raycastRequestMessage.Origin = origin; raycastRequestMessage.Direction = direction; raycastRequestMessage.MaxDistance = maxDistance; raycastRequestMessage.RaycastMask = ((LayerMask.op_Implicit(raycastMask) == 0) ? (-1) : ((LayerMask)(ref raycastMask)).value); NetworkClient.Send(raycastRequestMessage, 0); } } } internal static void HandleRaycastRequest(int requestingConnectionId, RaycastRequestMessage msg) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { return; } int num = ((msg.RaycastMask == 0) ? (-1) : msg.RaycastMask); LayerMask val = LayerMask.op_Implicit(num); bool flag = false; RaycastHit hit = default(RaycastHit); GameObject val2 = null; if (((Vector3)(ref msg.Direction)).sqrMagnitude > 1E-06f) { Ray val3 = default(Ray); ((Ray)(ref val3))..ctor(msg.Origin, ((Vector3)(ref msg.Direction)).normalized); RaycastHit[] array = Physics.RaycastAll(val3, msg.MaxDistance, LayerMask.op_Implicit(val), (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val4 = array2[i]; GameObject gameObject = ((Component)((RaycastHit)(ref val4)).collider).gameObject; if (!ShouldIgnore(gameObject)) { flag = true; hit = val4; val2 = GetHighestParent(gameObject); break; } } } if (!((Object)(object)val2 == (Object)null)) { RaycastUtility.RaycastCompleted?.Invoke(new RaycastCompletedEventArgs(msg.Purpose, requestingConnectionId, msg.Guid, msg.Origin, msg.Direction, msg.MaxDistance, num, flag, hit, val2)); NetworkMessageBootstrap.Register(); RaycastResultMessage raycastResultMessage = default(RaycastResultMessage); raycastResultMessage.Purpose = msg.Purpose ?? string.Empty; raycastResultMessage.Guid = msg.Guid; raycastResultMessage.Origin = msg.Origin; raycastResultMessage.Direction = msg.Direction; raycastResultMessage.MaxDistance = msg.MaxDistance; raycastResultMessage.RaycastMask = num; raycastResultMessage.HasHit = flag; raycastResultMessage.HitPoint = (Vector3)(flag ? ((RaycastHit)(ref hit)).point : default(Vector3)); raycastResultMessage.HitNormal = (Vector3)(flag ? ((RaycastHit)(ref hit)).normal : default(Vector3)); raycastResultMessage.HitDistance = (flag ? ((RaycastHit)(ref hit)).distance : 0f); raycastResultMessage.HitObjectName = (flag ? ((Object)((Component)((RaycastHit)(ref hit)).collider).gameObject).name : string.Empty); raycastResultMessage.ClosestValidRootObjectName = ((Object)val2).name ?? string.Empty; NetworkServer.SendToAll(raycastResultMessage, 0, false); } } internal static void HandleRaycastResult(RaycastResultMessage msg) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) RaycastUtility.RaycastResultReceived?.Invoke(new RaycastResultReceivedEventArgs(msg.Purpose, msg.Guid, msg.Origin, msg.Direction, msg.MaxDistance, msg.RaycastMask, msg.HasHit, msg.HitPoint, msg.HitNormal, msg.HitDistance, msg.HitObjectName, msg.ClosestValidRootObjectName)); } private static bool ShouldIgnore(GameObject obj) { Transform val = obj.transform; while ((Object)(object)val != (Object)null) { if (((Object)val).name == "Terrain") { return true; } if ((Object)(object)((Component)val).GetComponent() != (Object)null) { return true; } val = val.parent; } return false; } private static GameObject GetHighestParent(GameObject obj) { Transform val = obj.transform; while ((Object)(object)val.parent != (Object)null) { val = val.parent; } return ((Component)val).gameObject; } } } namespace Gamemode_Lib.Patches { public class CourseManagerPatches { [HarmonyPatch(typeof(CourseManager), "EndCourse")] [HarmonyPrefix] public static void EndCourse_Prefix() { Plugin.Log.LogInfo((object)$"[GamemodeLib] CourseManager.EndCourse prefix: TryEndCurrentGame(broadcastToClients=true) serverActive={NetworkServer.active}"); GameModeUtilities.TryEndCurrentGame(broadcastToClients: true); } } public class GameManagerPatches { [HarmonyPatch(typeof(GameManager), "Awake")] [HarmonyPostfix] public static void Awake_Postfix(GameManager __instance) { ((Component)__instance).gameObject.AddComponent(); } } public class MatchSetupMenuPatches { private static readonly Dictionary> DropdownMappings = new Dictionary>(); private static TMP_Dropdown? _tmpDropdown; private static IGamemode? _gameMode; [HarmonyPatch(typeof(MatchSetupMenu), "SetEnabled")] [HarmonyPostfix] public static void SetEnabled_Postfix(MatchSetupMenu __instance) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown if ((Object)(object)_tmpDropdown == (Object)null) { _tmpDropdown = ((IEnumerable)Object.FindObjectsOfType(true)).FirstOrDefault((Func)((TMP_Dropdown dropdown) => dropdown.options != null && dropdown.options.Any((OptionData o) => o.text == "Free-for-all"))); if ((Object)(object)_tmpDropdown == (Object)null) { Plugin.Log.LogError((object)"[GamemodeLib] Could not find TMP_Dropdown containing 'Free-for-all'"); return; } } if (DropdownMappings.ContainsKey(_tmpDropdown)) { return; } Dictionary dictionary = new Dictionary(); int num = _tmpDropdown.options.Count; foreach (KeyValuePair mode in GameModeUtilities.Modes) { string key = mode.Key; IGamemode value = mode.Value; _tmpDropdown.options.Add(new OptionData(value.Name)); dictionary[num] = key; num++; } _tmpDropdown.RefreshShownValue(); DropdownMappings[_tmpDropdown] = dictionary; ((UnityEvent)(object)_tmpDropdown.onValueChanged).AddListener((UnityAction)delegate(int index) { Plugin.Log.LogInfo((object)("[GamemodeLib] Selected gamemode: " + _tmpDropdown.options[index].text + ")")); _gameMode = null; if (DropdownMappings[_tmpDropdown].TryGetValue(index, out string value2)) { IGamemode gamemode = (_gameMode = GameModeUtilities.Modes[value2]); Plugin.Log.LogInfo((object)("[GamemodeLib] " + gamemode.Name + " is using GamemodeLib. It's ID is... " + gamemode.GameModeId)); if (NetworkServer.active) { TeamManager.Instance.ResetTeams(); TeamManager.Instance.ClearTeamDefinitions(); if (_gameMode.IsTeamBased) { TeamManager.Instance.CreateAndAssignTeams(_gameMode.TeamCount); } } } }); Plugin.Log.LogInfo((object)"[GamemodeLib] Gamemodes injected into dropdown"); } [HarmonyPatch(typeof(MatchSetupMenu), "StartOrCancelMatch")] [HarmonyPrefix] public static bool StartOrCancelMatch_Prefix(MatchSetupMenu __instance) { if ((Object)(object)_tmpDropdown == (Object)null) { return true; } if (_gameMode == null) { return true; } if (_gameMode.CanStart(__instance.maxPlayers)) { if (StartGame()) { StopAutoNextHole.HideCursor(); return true; } } else { Plugin.Log.LogError((object)"[GamemodeLib] Invalid choices, not starting gamemode."); } return false; } private static bool StartGame() { Plugin.Log.LogInfo((object)"[GamemodeLib] Starting gamemode."); if ((Object)(object)TeamManager.Instance != (Object)null) { TeamManager.Instance.AssignUnAssignedPlayersToTeams(); TeamManager.Instance.SaveCurrentTeams(); TeamManager.Instance.TryRefreshLocalPlayerTeam(); if ((Object)(object)TeamManager.Instance.LocalPlayerTeam == (Object)null) { Plugin.Log.LogWarning((object)"[GamemodeLib] LocalPlayerTeam is null immediately before OnGameStart()"); } } GameModeUtilities.CurrentGamemodeId = _gameMode.GameModeId; GameModeUtilities.GameEnded = false; _gameMode.OnGameStart(); if (NetworkServer.active) { NetworkMessageBootstrap.Register(); ConfigSyncManager.Instance?.BroadcastScopeToClients(_gameMode.GameModeId); GamemodeStartMessage gamemodeStartMessage = default(GamemodeStartMessage); gamemodeStartMessage.GamemodeId = _gameMode.GameModeId; NetworkServer.SendToAll(gamemodeStartMessage, 0, false); } if (_gameMode.IsNormalStartProcedure) { return true; } Plugin.Log.LogInfo((object)"[GamemodeLib] Custom gamemode is chosen, cancelling default start procedure."); return false; } [HarmonyPatch(typeof(MatchSetupMenu), "StartOrCancelMatch")] [HarmonyPostfix] public static void StartOrCancelMatch_Postfix(MatchSetupMenu __instance) { TeamManager.Instance.ReloadSavedTeams(); } } public class MatchSetupPlayerPatches { private const string SwapButtonName = "SwapTeamButton"; [HarmonyPatch(typeof(MatchSetupPlayer), "Update")] [HarmonyPostfix] public static void Update_Postfix(MatchSetupPlayer __instance) { UpdateBackground(__instance); } [HarmonyPatch(typeof(MatchSetupPlayer), "Awake")] [HarmonyPostfix] public static void Awake_Postfix(MatchSetupPlayer __instance) { AddSwapButton(__instance); } private static void UpdateBackground(MatchSetupPlayer playerUI) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TeamManager.Instance == (Object)null) { return; } ulong guid = playerUI.Guid; PlayerTeam playerTeam = null; foreach (PlayerTeam player in TeamManager.Instance.Players) { if ((Object)(object)player == (Object)null || (Object)(object)player.playerInfo == (Object)null || player.playerInfo.PlayerId.guid != guid) { continue; } playerTeam = player; break; } if ((Object)(object)playerTeam == (Object)null || !TeamManager.Instance.TryGetTeam(playerTeam.teamId, out TeamData team)) { return; } Transform val = ((Component)playerUI).transform.Find("Background"); if ((Object)(object)val == (Object)null) { return; } Image component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null) { return; } ((Graphic)component).color = team.Color; Transform val2 = ((Component)playerUI).transform.Find("Portrait"); if (!((Object)(object)val2 == (Object)null)) { Image component2 = ((Component)val2).GetComponent(); if (!((Object)(object)component2 == (Object)null)) { ((Graphic)component2).color = team.Color * 0.7f; } } } private static void AddSwapButton(MatchSetupPlayer ui) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Expected O, but got Unknown MatchSetupPlayer ui2 = ui; Transform val = ((Component)ui2).transform.Find("Info").Find("Buttons"); if ((Object)(object)val == (Object)null || (Object)(object)val.Find("SwapTeamButton") != (Object)null) { return; } Button kickButton = ui2.kickButton; if ((Object)(object)kickButton == (Object)null) { return; } GameObject val2 = Object.Instantiate(((Component)kickButton).gameObject, val); ((Object)val2).name = "SwapTeamButton"; Button component = val2.GetComponent