Decompiled source of StraftatDeathmatch v1.1.0
StraftatDeathmatch.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FishNet; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Managing.Scened; using FishNet.Object; using HarmonyLib; using Microsoft.CodeAnalysis; using MyceliumNetworking; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("StraftatDeathmatch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("StraftatDeathmatch")] [assembly: AssemblyTitle("StraftatDeathmatch")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 StraftatDeathmatch { public class DeathmatchHud : MonoBehaviour { private const float RefreshInterval = 0.25f; private GameObject _panel; private TextMeshProUGUI _text; private float _nextRefreshTime; private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown Canvas obj = ((Component)this).gameObject.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 1000; CanvasScaler obj2 = ((Component)this).gameObject.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); _panel = new GameObject("DeathmatchPanel"); _panel.transform.SetParent(((Component)this).transform, false); RectTransform obj3 = _panel.AddComponent<RectTransform>(); obj3.anchorMin = new Vector2(1f, 1f); obj3.anchorMax = new Vector2(1f, 1f); obj3.pivot = new Vector2(1f, 1f); obj3.anchoredPosition = new Vector2(-18f, -440f); ((Graphic)_panel.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f); VerticalLayoutGroup obj4 = _panel.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj4).padding = new RectOffset(12, 12, 8, 8); ((LayoutGroup)obj4).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)obj4).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = false; ContentSizeFitter obj5 = _panel.AddComponent<ContentSizeFitter>(); obj5.horizontalFit = (FitMode)2; obj5.verticalFit = (FitMode)2; GameObject val = new GameObject("DeathmatchText"); val.transform.SetParent(_panel.transform, false); val.AddComponent<RectTransform>(); _text = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_text).fontSize = 22f; ((TMP_Text)_text).richText = true; ((TMP_Text)_text).enableWordWrapping = false; ((TMP_Text)_text).alignment = (TextAlignmentOptions)257; ((Graphic)_text).raycastTarget = false; _panel.SetActive(false); } private void Update() { if (!(Time.unscaledTime < _nextRefreshTime)) { _nextRefreshTime = Time.unscaledTime + 0.25f; bool flag = DeathmatchPlugin.ShowScoreboard.Value && ScoreKeeper.ModeActiveLocally() && (Object)(object)PauseManager.Instance != (Object)null && !PauseManager.Instance.inMainMenu && !PauseManager.Instance.inVictoryMenu && ClientInstance.playerInstances.Count > 0; if (_panel.activeSelf != flag) { _panel.SetActive(flag); } if (flag) { ((TMP_Text)_text).text = BuildText(); } } } private static string BuildText() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("<b><color=#FF4040>DEATHMATCH</color></b> <color=#AAAAAA>first to ").Append(ScoreKeeper.EffectiveKillsToWin).Append("</color>"); int secondsLeft = ScoreKeeper.SecondsLeft; if (secondsLeft >= 0) { stringBuilder.Append(" <color=#AAAAAA>- ").Append(secondsLeft / 60).Append(':') .Append((secondsLeft % 60).ToString("00")) .Append("</color>"); } int localPlayerId = PlayerLookup.LocalPlayerId; List<ScoreKeeper.Row> rows = ScoreKeeper.GetRows(); for (int i = 0; i < rows.Count; i++) { ScoreKeeper.Row row = rows[i]; string name = PlayerLookup.GetName(row.PlayerId); stringBuilder.Append('\n'); string value = ((row.PlayerId == localPlayerId) ? "#FFD24A" : "#DDDDDD"); stringBuilder.Append("<color=").Append(value).Append('>'); int num; if (i == 0) { num = ((row.Kills > 0) ? 1 : 0); if (num != 0) { stringBuilder.Append("<b>"); } } else { num = 0; } stringBuilder.Append(name).Append(" ").Append(row.Kills) .Append(" <color=#888888>/ ") .Append(row.Deaths) .Append("</color>"); if (num != 0) { stringBuilder.Append("</b>"); } stringBuilder.Append("</color>"); } if (ScoreKeeper.MatchOver) { stringBuilder.Append("\n<color=#AAAAAA>Round over</color>"); } return stringBuilder.ToString(); } } internal static class DeathmatchPatches { private static Harmony _harmony; private static FieldInfo _fiRoundHasStarted; private static bool Active => ScoreKeeper.ModeActiveLocally(); public static void Apply() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if (_harmony == null) { _harmony = new Harmony("com.clst.straftatdeathmatch.patches"); _fiRoundHasStarted = AccessTools.Field(typeof(FirstPersonController), "roundHasStarted"); Type[] args = new Type[4] { typeof(int), typeof(int), typeof(Vector3), typeof(Quaternion) }; Type[] args2 = new Type[2] { typeof(int), typeof(int) }; Prefix(typeof(GameManager), "RpcLogic___PlayerDied_3316948804", "GameManager_PlayerDied_Prefix"); Prefix(typeof(GameManager), "WaitForDraw", "GameManager_WaitForDraw_Prefix"); Prefix(typeof(RoundManager), "CmdEndRound", "RoundManager_CmdEndRound_Prefix"); Postfix(typeof(GameManager), "RpcLogic___SetStartTime_431000436", "GameManager_SetStartTime_Postfix"); Prefix(typeof(PlayerManager), "ReturnSpawnPoint", "PlayerManager_ReturnSpawnPoint_Prefix"); Prefix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer2_Prefix", args2); Postfix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer4_Postfix", args); Prefix(typeof(PlayerManager), "WaitForRoundStart", "PlayerManager_WaitForRoundStart_Prefix"); Prefix(typeof(KillCam), "Update", "KillCam_Update_Prefix"); Postfix(typeof(PlayerHealth), "RpcLogic___ExplodeForAll_576886416", "PlayerHealth_ExplodeForAll_Postfix"); Postfix(typeof(PlayerHealth), "RpcLogic___DespawnObject_2166136261", "PlayerHealth_DespawnObject_Postfix"); Postfix(typeof(PlayerValues), "sync___set_value_playerClient", "PlayerValues_SetPlayerClient_Postfix"); Prefix(typeof(PlayerPickup), "RightHandDrop", "PlayerPickup_RightHandDrop_Prefix"); Prefix(typeof(PlayerPickup), "LeftHandDrop", "PlayerPickup_LeftHandDrop_Prefix"); Prefix(typeof(PlayerPickup), "RpcLogic___DropObjectServer_2127535046", "PlayerPickup_DropObjectServer_Prefix"); Prefix(typeof(PlayerPickup), "RpcLogic___DropObjectObserver_2127535046", "PlayerPickup_DropObjectObserver_Prefix"); Postfix(typeof(PlayerPickup), "OnStartClient", "PlayerPickup_OnStartClient_Postfix"); Prefix(typeof(PlayerSetup), "OnDisable", "PlayerSetup_OnDisable_Prefix"); Prefix(typeof(ProximityMine), "KillShockWave", "ProximityMine_KillShockWave_Prefix"); Prefix(typeof(Claymore), "KillShockWave", "Claymore_KillShockWave_Prefix"); Prefix(typeof(DamageZone), "OnEnable", "DamageZone_OnEnable_Prefix"); Prefix(typeof(FirstPersonController), "OnTriggerStay", "FirstPersonController_OnTriggerStay_Prefix"); } } private static void Prefix(Type type, string method, string patch, Type[] args = null) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown try { MethodInfo methodInfo = ((args == null) ? AccessTools.Method(type, method, (Type[])null, (Type[])null) : AccessTools.Method(type, method, args, (Type[])null)); if (methodInfo == null) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Patch] " + type.Name + "." + method + " not found")); } } else { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DeathmatchPatches), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogWarning((object)("[Patch] " + type.Name + "." + method + ": " + ex.GetType().Name + " - " + ex.Message)); } } } private static void Postfix(Type type, string method, string patch, Type[] args = null) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown try { MethodInfo methodInfo = ((args == null) ? AccessTools.Method(type, method, (Type[])null, (Type[])null) : AccessTools.Method(type, method, args, (Type[])null)); if (methodInfo == null) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Patch] " + type.Name + "." + method + " not found")); } } else { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathmatchPatches), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogWarning((object)("[Patch] " + type.Name + "." + method + ": " + ex.GetType().Name + " - " + ex.Message)); } } } public static bool GameManager_PlayerDied_Prefix(int playerId) { if (!Active || !PlayerLookup.IsServer) { return true; } if (ScoreKeeper.MatchOver) { return false; } try { if ((Object)(object)GameManager.Instance != (Object)null) { GameManager.Instance.alivePlayers.Add(playerId); } if (!ScoreKeeper.TryBeginDeath(playerId)) { return false; } RespawnController.OnServerDeath(playerId); MonoBehaviour val = (MonoBehaviour)(object)(((Object)(object)GameManager.Instance != (Object)null) ? ((DeathmatchPlugin)(object)GameManager.Instance) : DeathmatchPlugin.Instance); if ((Object)(object)val != (Object)null) { val.StartCoroutine(ResolveKill(playerId)); } } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogError((object)("[Death] handling player " + playerId + ": " + ex)); } try { RespawnController.Schedule(playerId); } catch { } } return false; } private static IEnumerator ResolveKill(int victimId) { yield return (object)new WaitForSeconds(0.1f); if (!ScoreKeeper.MatchOver) { int killerId = -1; try { killerId = PlayerLookup.FindKillerId(victimId); } catch { } ScoreKeeper.OnServerKill(victimId, killerId); } } public static bool GameManager_WaitForDraw_Prefix(ref IEnumerator __result) { if (Active && PlayerLookup.IsServer && !ScoreKeeper.MatchOver) { __result = Empty(); return false; } return true; } private static IEnumerator Empty() { yield break; } public static bool RoundManager_CmdEndRound_Prefix() { if (Active && PlayerLookup.IsServer && !ScoreKeeper.MatchOver) { return false; } return true; } public static void GameManager_SetStartTime_Postfix(float serverTimeTillStart) { ScoreKeeper.OnStartTimeIssued(serverTimeTillStart); } public static bool PlayerManager_ReturnSpawnPoint_Prefix(PlayerManager __instance, ref Transform __result) { if (!Active || !PlayerLookup.IsServer) { return true; } try { ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); if (SpawnSelector.TryPick(((Object)(object)component != (Object)null) ? component.PlayerId : (-1), out var point, out var _, out var _)) { __result = ((Component)point).transform; return false; } } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Spawn] ReturnSpawnPoint: " + ex.GetType().Name)); } } return true; } public static bool PlayerManager_SpawnPlayer2_Prefix(PlayerManager __instance, int __0, int __1) { //IL_003c: 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) if (!Active || !PlayerLookup.IsServer) { return true; } try { ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); int forPlayerId = (((Object)(object)component != (Object)null) ? component.PlayerId : (-1)); if (SpawnSelector.TryPick(forPlayerId, out var point, out var position, out var rotation) && RespawnController.InvokeSpawnPlayer(__instance, __0, __1, position, rotation)) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)("[Spawn] player=" + forPlayerId + " take-start spawn at '" + ((Object)point).name + "'")); } return false; } } catch (Exception ex) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogWarning((object)("[Spawn] SpawnPlayer: " + ex.GetType().Name + " - " + ex.Message)); } } return true; } public static void PlayerManager_SpawnPlayer4_Postfix(PlayerManager __instance, int __0, int __1) { if (!Active || (Object)(object)__instance == (Object)null) { return; } try { ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); if (!((Object)(object)component == (Object)null) && component.PlayerId >= 0 && PlayerLookup.IsServer) { RespawnController.RememberCosmetics(component.PlayerId, __0, __1); RespawnController.OnServerSpawned(component.PlayerId); if ((Object)(object)GameManager.Instance != (Object)null) { GameManager.Instance.alivePlayers.Add(component.PlayerId); } } } catch { } } public static bool PlayerManager_WaitForRoundStart_Prefix(PlayerManager __instance, ref IEnumerator __result) { if (!Active || !ScoreKeeper.IsMidMatchLocally()) { return true; } __result = QuickStart(__instance); return false; } private static IEnumerator QuickStart(PlayerManager pm) { yield return null; for (int i = 0; i < 5; i++) { if (!((Object)(object)pm != (Object)null)) { break; } if (!((Object)(object)pm.player == (Object)null)) { break; } yield return null; } if ((Object)(object)pm == (Object)null) { yield break; } try { pm.SetPlayerMove(true); } catch { } try { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.startRound = false; } } catch { } try { if ((Object)(object)pm.player != (Object)null) { pm.player.startOfRound = false; if (_fiRoundHasStarted != null) { _fiRoundHasStarted.SetValue(pm.player, true); } } } catch { } try { if ((Object)(object)pm.player != (Object)null && (Object)(object)pm.player.setupScript != (Object)null) { pm.player.setupScript.EnableTaserEffectServer(); } } catch { } float end = Time.time + 3f; while (Time.time < end) { if ((Object)(object)pm == (Object)null) { yield break; } try { if ((Object)(object)pm.player != (Object)null && !pm.player.sync___get_value_canMove()) { pm.SetPlayerMove(true); } if ((Object)(object)PauseManager.Instance != (Object)null && PauseManager.Instance.startRound) { PauseManager.Instance.startRound = false; } } catch { } yield return (object)new WaitForSeconds(0.25f); } if ((Object)(object)pm != (Object)null) { pm.waitForRoundStartCoroutine = null; } } public static bool KillCam_Update_Prefix() { if (Active) { return !ScoreKeeper.IsMidMatchLocally(); } return true; } public static void PlayerHealth_ExplodeForAll_Postfix(PlayerHealth __instance) { if (Active && !((Object)(object)__instance == (Object)null)) { RespawnController.TrackRagdoll(__instance); } } public static void PlayerHealth_DespawnObject_Postfix(PlayerHealth __instance) { try { if ((Object)(object)__instance != (Object)null && ((NetworkBehaviour)__instance).IsOwner) { ScoreKeeper.LocalDiedThisMap = true; } } catch { } } public static void PlayerValues_SetPlayerClient_Postfix(ClientInstance __0) { if (!Active || (Object)(object)__0 == (Object)null) { return; } try { if (__0.PlayerId >= 0) { RespawnController.DestroyRagdoll(__0.PlayerId); } } catch { } } private static bool IsDead(PlayerPickup pickup) { PlayerHealth val = (((Object)(object)pickup != (Object)null) ? ((Component)pickup).GetComponentInParent<PlayerHealth>() : null); if ((Object)(object)val != (Object)null) { if (!(val.sync___get_value_health() <= 0f)) { return val.sync___get_value_isKilled(); } return true; } return false; } public static bool PlayerPickup_RightHandDrop_Prefix(PlayerPickup __instance) { try { if (Active) { LoadoutKeeper.OnHandDropping(__instance); } } catch { } if (!Active || !ScoreKeeper.CleanupItemsEffective) { return true; } try { if (__instance.sync___get_value_hasObjectInHand()) { GameObject val = __instance.sync___get_value_objInHand(); if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ItemBehaviour>() == (Object)null) { RespawnController.ClearHand(__instance, rightHand: true); return false; } } if (IsDead(__instance)) { return false; } } catch { } return true; } public static bool PlayerPickup_LeftHandDrop_Prefix(PlayerPickup __instance) { try { if (Active) { LoadoutKeeper.OnHandDropping(__instance); } } catch { } if (!Active || !ScoreKeeper.CleanupItemsEffective) { return true; } try { if (__instance.sync___get_value_hasObjectInLeftHand()) { GameObject val = __instance.sync___get_value_objInLeftHand(); if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ItemBehaviour>() == (Object)null) { RespawnController.ClearHand(__instance, rightHand: false); return false; } } if (IsDead(__instance)) { return false; } } catch { } return true; } public static bool PlayerPickup_DropObjectServer_Prefix(PlayerPickup __instance, GameObject obj, bool rightHand) { if (!Active || !PlayerLookup.IsServer || !ScoreKeeper.CleanupItemsEffective) { return true; } try { if ((Object)(object)obj == (Object)null) { RespawnController.ClearHand(__instance, rightHand); return false; } NetworkObject component = obj.GetComponent<NetworkObject>(); if ((Object)(object)component != (Object)null && !component.IsSpawned) { RespawnController.ClearHand(__instance, rightHand); return false; } if (IsDead(__instance)) { RespawnController.ClearHand(__instance, rightHand); RespawnController.DespawnOrDestroy(obj); return false; } } catch { } return true; } public static bool PlayerPickup_DropObjectObserver_Prefix(GameObject obj) { if (!Active) { return true; } return (Object)(object)obj != (Object)null; } public static void PlayerPickup_OnStartClient_Postfix(PlayerPickup __instance) { if (!Active || (Object)(object)__instance == (Object)null) { return; } try { LoadoutKeeper.OnPickupStarted(__instance); } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Loadout] OnStartClient: " + ex.GetType().Name + " - " + ex.Message)); } } } public static bool PlayerSetup_OnDisable_Prefix(PlayerSetup __instance) { if (!Active || (Object)(object)__instance == (Object)null) { return true; } try { if (((NetworkBehaviour)__instance).IsOwner) { return true; } GameObject val = PlayerLookup.FindBody(PlayerLookup.LocalPlayerId); if ((Object)(object)val != (Object)null && (Object)(object)((Component)__instance).gameObject == (Object)(object)val) { return true; } } catch { return true; } return false; } public static bool ProximityMine_KillShockWave_Prefix(ProximityMine __instance) { GameObject val = (((Object)(object)__instance != (Object)null) ? __instance.sync___get_value__rootObject() : null); if ((Object)(object)val != (Object)null) { return (Object)(object)val.GetComponent<FirstPersonController>() != (Object)null; } return false; } public static bool Claymore_KillShockWave_Prefix(Claymore __instance) { GameObject val = (((Object)(object)__instance != (Object)null) ? __instance.sync___get_value__rootObject() : null); if ((Object)(object)val != (Object)null) { return (Object)(object)val.GetComponent<FirstPersonController>() != (Object)null; } return false; } public static bool DamageZone_OnEnable_Prefix(DamageZone __instance) { if (!Active || !ScoreKeeper.RemoveDamageZonesEffective) { return true; } try { Collider[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } if ((Object)(object)__instance.toDestroy != (Object)null) { Object.Destroy((Object)(object)__instance.toDestroy); } Object.Destroy((Object)(object)((Component)__instance).gameObject); } catch { } return false; } public static bool FirstPersonController_OnTriggerStay_Prefix(Collider col) { if (Active && ScoreKeeper.RemoveDamageZonesEffective && (Object)(object)col != (Object)null && ((Component)col).CompareTag("DamageZone")) { return false; } return true; } } [BepInPlugin("com.clst.straftatdeathmatch", "Straftat Deathmatch", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class DeathmatchPlugin : BaseUnityPlugin { public const string PluginGuid = "com.clst.straftatdeathmatch"; public const string PluginName = "Straftat Deathmatch"; public const string PluginVersion = "1.1.0"; public const uint ModId = 20260905u; internal static ManualLogSource Log; public static ConfigEntry<bool> Enabled; public static ConfigEntry<int> KillsToWin; public static ConfigEntry<int> TimeLimitMinutes; public static ConfigEntry<float> RespawnDelay; public static ConfigEntry<float> MinEnemyDistance; public static ConfigEntry<bool> AvoidLineOfSight; public static ConfigEntry<float> SpawnJitter; public static ConfigEntry<bool> CleanupItemsOnDeath; public static ConfigEntry<bool> CleanupMinesOnDeath; public static ConfigEntry<bool> RemoveDamageZones; public static ConfigEntry<bool> RestoreLoadoutOnRespawn; public static ConfigEntry<string> DefaultWeapon; public static ConfigEntry<string> LoadoutExcludedClasses; public static ConfigEntry<string> LoadoutExcludedWeapons; public static ConfigEntry<bool> ShowScoreboard; public static ConfigEntry<bool> KillFeedInChat; public static ConfigEntry<KeyboardShortcut> KillSelfShortcut; private bool _fishNetHooked; public static DeathmatchPlugin Instance { get; private set; } private void Awake() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Instance = this; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Deathmatch mode. Only the host's setting matters for gameplay."); KillsToWin = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Kills To Win", 20, new ConfigDescription("Kills needed to win the round.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); TimeLimitMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Time Limit Minutes", 0, new ConfigDescription("Round time limit in minutes. 0 disables it. When time runs out the player with the most kills wins; a tie goes to sudden death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 60), Array.Empty<object>())); RespawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Respawn Delay", 2f, new ConfigDescription("Seconds before a dead player respawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>())); MinEnemyDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "Min Enemy Spawn Distance", 12f, new ConfigDescription("Spawn points closer than this to a living enemy are avoided when any other point exists.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); AvoidLineOfSight = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "Avoid Enemy Line Of Sight", true, "Prefer spawn points that no living enemy can currently see."); SpawnJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "Spawn Jitter", 0.5f, new ConfigDescription("Random offset in meters applied around the chosen spawn point. 0 spawns exactly on the point.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); CleanupItemsOnDeath = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "Cleanup Items On Death", true, "Remove whatever a player was holding when they die instead of dropping it on the ground."); CleanupMinesOnDeath = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "Cleanup Mines On Death", true, "Remove mines and claymores placed by a player when they die."); RemoveDamageZones = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "Remove Damage Zones", false, "Disable map damage zones for continuous play."); RestoreLoadoutOnRespawn = ((BaseUnityPlugin)this).Config.Bind<bool>("Loadout", "Restore Loadout On Respawn", true, "Respawn holding the weapons you had when you were killed. Pick a weapon up once, then swap at map spawners when you want something else."); DefaultWeapon = ((BaseUnityPlugin)this).Config.Bind<string>("Loadout", "Default Weapon", "Gun", "Prefab name of the weapon given to a player who died empty-handed (Gun is the pistol; other examples: Glock, Revolver, AK-K, Shotgun). Empty gives nothing."); LoadoutExcludedClasses = ((BaseUnityPlugin)this).Config.Bind<string>("Loadout", "Excluded Weapon Classes", "DualLauncher", "Comma-separated Weapon component classes that are never restored. DualLauncher covers grenades and all launchers."); LoadoutExcludedWeapons = ((BaseUnityPlugin)this).Config.Bind<string>("Loadout", "Excluded Weapons", "", "Comma-separated weapon prefab names that are never restored."); ShowScoreboard = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Show Scoreboard", true, "Show the on-screen kill scoreboard."); KillFeedInChat = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Kill Feed In Chat", false, "Post the killer's running score to chat after every kill. The game already announces the kill itself."); KillSelfShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "Kill Self Shortcut", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Hotkey that kills your own player for respawn testing."); ScoreKeeper.Init(); RespawnController.Init(); LoadoutKeeper.Init(); DeathmatchPatches.Apply(); try { MyceliumNetwork.RegisterNetworkObject((object)this, 20260905u, 0); } catch (Exception ex) { Log.LogError((object)("Mycelium registration failed: " + ex.GetType().Name + " - " + ex.Message)); } try { MyceliumNetwork.PlayerEntered += OnMyceliumPlayerEntered; } catch { } SceneManager.sceneLoaded += OnSceneLoaded; GameObject val = new GameObject("DeathmatchHud"); val.transform.SetParent(((Component)this).transform, false); val.AddComponent<DeathmatchHud>(); Log.LogInfo((object)"Straftat Deathmatch 1.1.0 loaded."); } private void OnDestroy() { try { MyceliumNetwork.DeregisterNetworkObject((object)this, 20260905u, 0); } catch { } try { MyceliumNetwork.PlayerEntered -= OnMyceliumPlayerEntered; } catch { } SceneManager.sceneLoaded -= OnSceneLoaded; if (_fishNetHooked && (Object)(object)InstanceFinder.SceneManager != (Object)null) { InstanceFinder.SceneManager.OnLoadEnd -= OnFishNetSceneLoaded; } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { FullReset(); } private void OnFishNetSceneLoaded(SceneLoadEndEventArgs args) { FullReset(); } private void OnMyceliumPlayerEntered(CSteamID id) { ScoreKeeper.MarkDirty(); } internal static void FullReset() { ScoreKeeper.Reset(); RespawnController.Reset(); LoadoutKeeper.Reset(); LoadoutSpawner.Reset(); SpawnSelector.Reset(); RespawnController.CleanupWorldEffects(); try { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.startRound = false; PauseManager.Instance.onStartRoundScreen = false; } } catch { } } private void Update() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) SceneManager sceneManager = InstanceFinder.SceneManager; if (!_fishNetHooked && (Object)(object)sceneManager != (Object)null) { sceneManager.OnLoadEnd += OnFishNetSceneLoaded; _fishNetHooked = true; } else if (_fishNetHooked && (Object)(object)sceneManager == (Object)null) { _fishNetHooked = false; FullReset(); } if (Enabled.Value) { KeyboardShortcut value = KillSelfShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { KillLocalPlayerForTesting(); } } LoadoutKeeper.ClientTick(); if (!Enabled.Value || (Object)(object)GameManager.Instance == (Object)null || !PlayerLookup.IsServer) { return; } ScoreKeeper.ServerTick(); RespawnController.ServerTick(); LoadoutSpawner.ServerTick(); HashSet<int> alivePlayers = GameManager.Instance.alivePlayers; foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances) { if (!alivePlayers.Contains(playerInstance.Key)) { alivePlayers.Add(playerInstance.Key); } } } internal void BroadcastState() { try { if (MyceliumNetwork.InLobby) { MyceliumNetwork.RPC(20260905u, "SyncDeathmatchState", (ReliableType)1, new object[11] { Enabled.Value, ScoreKeeper.MatchLive, KillsToWin.Value, ScoreKeeper.SecondsLeft, CleanupItemsOnDeath.Value, RemoveDamageZones.Value, ScoreKeeper.Serialize(), RestoreLoadoutOnRespawn.Value, DefaultWeapon.Value ?? "", LoadoutExcludedClasses.Value ?? "", LoadoutExcludedWeapons.Value ?? "" }); } } catch (Exception ex) { if (Log != null) { Log.LogWarning((object)("Mycelium broadcast failed: " + ex.GetType().Name + " - " + ex.Message)); } } } [CustomRPC] public void SyncDeathmatchState(bool active, bool matchLive, int killsToWin, int secondsLeft, bool cleanupItems, bool removeZones, string scores, bool restoreLoadout, string defaultWeapon, string excludedClasses, string excludedWeapons) { if (!PlayerLookup.IsServer) { ScoreKeeper.ApplySynced(active, matchLive, killsToWin, secondsLeft, cleanupItems, removeZones, scores, restoreLoadout, defaultWeapon, excludedClasses, excludedWeapons); } } [CustomRPC] public void RequestLoadout(int playerId, string right, string left, RPCInfo info) { //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) if (!PlayerLookup.IsServer) { return; } try { LoadoutSpawner.HandleRemoteRequest(playerId, right ?? "", left ?? "", info.SenderSteamID); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[Loadout] request from player " + playerId + " failed: " + ex.GetType().Name + " - " + ex.Message)); } } } [CustomRPC] public void LoadoutSpawned(int playerId, int rightId, int leftId) { try { LoadoutKeeper.OnLoadoutSpawned(playerId, rightId, leftId); } catch { } } private static void KillLocalPlayerForTesting() { try { int localPlayerId = PlayerLookup.LocalPlayerId; if (localPlayerId < 0) { if (Log != null) { Log.LogWarning((object)"Kill Self: no local player id."); } return; } PlayerHealth val = PlayerLookup.FindHealth(localPlayerId); if ((Object)(object)val == (Object)null) { if (Log != null) { Log.LogWarning((object)("Kill Self: no PlayerHealth for player " + localPlayerId + ".")); } } else if (!val.sync___get_value_isKilled() && !(val.sync___get_value_health() <= 0f)) { if (PlayerLookup.IsServer) { val.RpcLogic___RemoveHealth_431000436(9999f); } else { val.RemoveHealth(9999f); } } } catch (Exception ex) { if (Log != null) { Log.LogWarning((object)("Kill Self failed: " + ex.GetType().Name + " - " + ex.Message)); } } } } internal static class LoadoutKeeper { private const float PollSeconds = 0.1f; private static MethodInfo _miSetObjectInHandServer; private static FieldInfo _fiCam; private static FieldInfo _fiRigBuilder; private static FieldInfo _fiPickupClip; private static string _aliveRight = ""; private static string _aliveRightClass = ""; private static string _aliveLeft = ""; private static string _aliveLeftClass = ""; private static bool _hasDeathSnapshot; private static string _deathRight = ""; private static string _deathRightClass = ""; private static string _deathLeft = ""; private static string _deathLeftClass = ""; private static GameObject _lastBody; private static bool _lastAlive; private static bool _capturedThisLife; private static float _nextPoll; private static bool _replyPending; private static int _replyRight = -1; private static int _replyLeft = -1; private static Coroutine _restore; public static bool Available { get { if (_miSetObjectInHandServer != null) { return _fiCam != null; } return false; } } public static void Init() { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; _miSetObjectInHandServer = typeof(PlayerPickup).GetMethod("SetObjectInHandServer", bindingAttr, null, new Type[5] { typeof(GameObject), typeof(Vector3), typeof(Quaternion), typeof(GameObject), typeof(bool) }, null); _fiCam = typeof(PlayerPickup).GetField("cam", bindingAttr); _fiRigBuilder = typeof(PlayerPickup).GetField("RigBuilder", bindingAttr); _fiPickupClip = typeof(PlayerPickup).GetField("pickupClip", bindingAttr); if (!Available) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)"[Loadout] PlayerPickup internals not found; loadout restore disabled."); } } } public static void Reset() { _aliveRight = (_aliveRightClass = (_aliveLeft = (_aliveLeftClass = ""))); _hasDeathSnapshot = false; _deathRight = (_deathRightClass = (_deathLeft = (_deathLeftClass = ""))); _lastBody = null; _lastAlive = false; _capturedThisLife = false; _nextPoll = 0f; _replyPending = false; _replyRight = (_replyLeft = -1); if (_restore != null && (Object)(object)DeathmatchPlugin.Instance != (Object)null) { ((MonoBehaviour)DeathmatchPlugin.Instance).StopCoroutine(_restore); } _restore = null; } public static void ClientTick() { if (Time.time < _nextPoll) { return; } _nextPoll = Time.time + 0.1f; if (!Available || !ScoreKeeper.ModeActiveLocally()) { return; } int localPlayerId = PlayerLookup.LocalPlayerId; if (localPlayerId < 0) { return; } GameObject val = PlayerLookup.FindBody(localPlayerId); bool num = IsAlive(val); if (num) { if ((Object)(object)val != (Object)(object)_lastBody) { _lastBody = val; _capturedThisLife = false; _aliveRight = (_aliveRightClass = (_aliveLeft = (_aliveLeftClass = ""))); } PlayerPickup val2 = val.GetComponent<PlayerPickup>() ?? val.GetComponentInChildren<PlayerPickup>(true); if ((Object)(object)val2 != (Object)null) { ReadHands(val2, out _aliveRight, out _aliveRightClass, out _aliveLeft, out _aliveLeftClass); } } else if (_lastAlive && !_capturedThisLife) { Capture(_aliveRight, _aliveRightClass, _aliveLeft, _aliveLeftClass, "last sample"); } _lastAlive = num; } public static void OnHandDropping(PlayerPickup pickup) { if (Available && !((Object)(object)pickup == (Object)null) && ((NetworkBehaviour)pickup).IsOwner && IsDead(pickup)) { if ((Object)(object)_lastBody != (Object)(object)((Component)pickup).gameObject) { _lastBody = ((Component)pickup).gameObject; _capturedThisLife = false; } if (!_capturedThisLife) { ReadHands(pickup, out var right, out var rightClass, out var left, out var leftClass); Capture(right, rightClass, left, leftClass, "death drop"); } } } private static void ReadHands(PlayerPickup pickup, out string right, out string rightClass, out string left, out string leftClass) { right = (rightClass = (left = (leftClass = ""))); try { GameObject go = (pickup.sync___get_value_hasObjectInHand() ? pickup.sync___get_value_objInHand() : null); GameObject go2 = (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null); right = LoadoutRules.PrefabName(go); rightClass = LoadoutRules.WeaponClass(go); left = LoadoutRules.PrefabName(go2); leftClass = LoadoutRules.WeaponClass(go2); } catch { } } private static void Capture(string right, string rightClass, string left, string leftClass, string source) { _deathRight = right ?? ""; _deathRightClass = rightClass ?? ""; _deathLeft = left ?? ""; _deathLeftClass = leftClass ?? ""; _hasDeathSnapshot = true; _capturedThisLife = true; ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)("[Loadout] died holding right='" + _deathRight + "' left='" + _deathLeft + "' (" + source + ")")); } } public static void OnPickupStarted(PlayerPickup pickup) { if (Available && !((Object)(object)pickup == (Object)null) && ((NetworkBehaviour)pickup).IsOwner && ScoreKeeper.ModeActiveLocally() && LoadoutRules.RestoreEnabled && _hasDeathSnapshot && !((Object)(object)DeathmatchPlugin.Instance == (Object)null)) { if (_restore != null) { ((MonoBehaviour)DeathmatchPlugin.Instance).StopCoroutine(_restore); } _restore = ((MonoBehaviour)DeathmatchPlugin.Instance).StartCoroutine(RestoreRoutine(pickup)); } } public static void OnLoadoutSpawned(int playerId, int rightId, int leftId) { if (playerId == PlayerLookup.LocalPlayerId) { _replyRight = rightId; _replyLeft = leftId; _replyPending = false; } } private static IEnumerator RestoreRoutine(PlayerPickup pickup) { GameObject body = ((Component)pickup).gameObject; int playerId = PlayerLookup.LocalPlayerId; float deadline = Time.time + 6f; while (Time.time < deadline) { if ((Object)(object)pickup == (Object)null) { _restore = null; yield break; } if (IsAlive(body) && (Object)/*isinst with value type is only supported in some contexts*/ != (Object)null && (_fiRigBuilder == null || _fiRigBuilder.GetValue(pickup) != null) && pickup.pickupPositionRightHand != null && pickup.pickupPositionRightHand.Length != 0) { break; } yield return null; } if ((Object)(object)pickup == (Object)null || !IsAlive(body)) { _restore = null; yield break; } FirstPersonController controller = ((Component)pickup).GetComponent<FirstPersonController>(); deadline = Time.time + 3f; while (Time.time < deadline && (Object)(object)controller != (Object)null && !controller.sync___get_value_canMove()) { yield return null; } yield return (object)new WaitForSeconds(0.1f); if ((Object)(object)pickup == (Object)null || !IsAlive(body)) { _restore = null; yield break; } BuildRequest(out var right, out var left); if (right.Length == 0 && left.Length == 0) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)"[Loadout] nothing restorable, respawning empty-handed"); } _restore = null; yield break; } _replyPending = true; _replyLeft = -1; _replyRight = -1; if (PlayerLookup.IsServer) { LoadoutSpawner.HandleLocalRequest(playerId, right, left); } else { bool flag = false; try { if (MyceliumNetwork.InLobby) { MyceliumNetwork.RPCTarget(20260905u, "RequestLoadout", MyceliumNetwork.LobbyHost, (ReliableType)1, new object[3] { playerId, right, left }); flag = true; } } catch (Exception ex) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogWarning((object)("[Loadout] request failed: " + ex.GetType().Name + " - " + ex.Message)); } } if (!flag) { _replyPending = false; _restore = null; yield break; } } deadline = Time.time + 4f; while (_replyPending && Time.time < deadline) { yield return null; } if (_replyPending) { ManualLogSource log3 = DeathmatchPlugin.Log; if (log3 != null) { log3.LogWarning((object)"[Loadout] no reply from the host; respawning empty-handed"); } _replyPending = false; _restore = null; yield break; } GameObject rightGo = null; GameObject leftGo = null; deadline = Time.time + 3f; while (Time.time < deadline) { if ((Object)(object)rightGo == (Object)null && _replyRight >= 0) { rightGo = ResolveReady(_replyRight); } if ((Object)(object)leftGo == (Object)null && _replyLeft >= 0) { leftGo = ResolveReady(_replyLeft); } bool num = _replyRight >= 0 && (Object)(object)rightGo == (Object)null; bool flag2 = _replyLeft >= 0 && (Object)(object)leftGo == (Object)null; if (!num && !flag2) { break; } yield return null; } if ((Object)(object)pickup == (Object)null || !IsAlive(body)) { _restore = null; yield break; } int num2 = 0; if ((Object)(object)rightGo != (Object)null && !pickup.sync___get_value_hasObjectInHand() && Equip(pickup, rightGo, rightHand: true)) { num2++; } if ((Object)(object)leftGo != (Object)null) { GameObject val = (pickup.sync___get_value_hasObjectInHand() ? pickup.sync___get_value_objInHand() : null); Weapon val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Weapon>() : null); if ((!((Object)(object)val2 != (Object)null) || !val2.requireBothHands) && !pickup.sync___get_value_hasObjectInLeftHand() && Equip(pickup, leftGo, rightHand: false)) { num2++; } } ManualLogSource log4 = DeathmatchPlugin.Log; if (log4 != null) { log4.LogInfo((object)("[Loadout] restored " + num2 + " weapon(s): right='" + right + "' left='" + left + "'")); } _restore = null; } private static void BuildRequest(out string right, out string left) { List<string> list = new List<string>(2); if (LoadoutRules.IsRestorable(_deathRight, _deathRightClass)) { list.Add(_deathRight); } if (LoadoutRules.IsRestorable(_deathLeft, _deathLeftClass)) { list.Add(_deathLeft); } if (list.Count == 0) { string defaultWeapon = LoadoutRules.DefaultWeapon; if (defaultWeapon.Length > 0) { if (LoadoutRules.IsKnownWeapon(defaultWeapon)) { list.Add(defaultWeapon); } else { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Loadout] default weapon '" + defaultWeapon + "' is not a known weapon prefab")); } } } } right = ((list.Count > 0) ? list[0] : ""); left = ((list.Count > 1) ? list[1] : ""); } private static GameObject ResolveReady(int objectId) { if (!TryFindSpawned(objectId, out var nob) || (Object)(object)nob == (Object)null) { return null; } GameObject gameObject = ((Component)nob).gameObject; ItemBehaviour component = gameObject.GetComponent<ItemBehaviour>(); if ((Object)(object)component == (Object)null || (Object)(object)component.gripRight == (Object)null || (Object)(object)component.gripLeft == (Object)null) { return null; } return gameObject; } private static bool TryFindSpawned(int objectId, out NetworkObject nob) { nob = null; if (objectId < 0) { return false; } NetworkManager networkManager = InstanceFinder.NetworkManager; if ((Object)(object)networkManager == (Object)null) { return false; } try { if (networkManager.IsServer && (Object)(object)networkManager.ServerManager != (Object)null && ((ManagedObjects)networkManager.ServerManager.Objects).Spawned.TryGetValue(objectId, out nob) && (Object)(object)nob != (Object)null) { return true; } if (networkManager.IsClient && (Object)(object)networkManager.ClientManager != (Object)null && ((ManagedObjects)networkManager.ClientManager.Objects).Spawned.TryGetValue(objectId, out nob) && (Object)(object)nob != (Object)null) { return true; } } catch { } nob = null; return false; } private static bool Equip(PlayerPickup pickup, GameObject go, bool rightHand) { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) try { ItemBehaviour component = go.GetComponent<ItemBehaviour>(); Weapon component2 = go.GetComponent<Weapon>(); object? value = _fiCam.GetValue(pickup); Camera val = (Camera)((value is Camera) ? value : null); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)val == (Object)null) { return false; } if (rightHand) { Transform val2 = Slot(component2.requireBothHands ? pickup.pickupPositionBothHand : pickup.pickupPositionRightHand, component.camChildIndex); if ((Object)(object)val2 == (Object)null) { return false; } PlayPickupSound(pickup); pickup.sync___set_value_objInHand(go, true); pickup.sync___set_value_hasObjectInHand(true, true); _miSetObjectInHandServer.Invoke(pickup, new object[5] { go, val2.position, val2.rotation, ((Component)val).gameObject, true }); pickup.SetRightIKTarget(component.gripRight); if (component2.requireBothHands) { pickup.SetLeftIKTarget(component.gripLeft); } } else { Transform val3 = Slot(pickup.pickupPositionLeftHand, component.camChildIndexLeftHand); if ((Object)(object)val3 == (Object)null) { return false; } PlayPickupSound(pickup); _miSetObjectInHandServer.Invoke(pickup, new object[5] { go, val3.position, val3.rotation, ((Component)val).gameObject, false }); pickup.sync___set_value_objInLeftHand(go, true); pickup.sync___set_value_hasObjectInLeftHand(true, true); pickup.SetLeftIKTarget(component.gripLeft); } component.dispenserStart = false; RigBuild(pickup); return true; } catch (Exception ex) { Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex); ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Loadout] equip failed: " + ex2.GetType().Name + " - " + ex2.Message)); } return false; } } private static Transform Slot(Transform[] slots, int index) { if (slots == null || slots.Length == 0) { return null; } if (index < 0 || index >= slots.Length) { index = 0; } return slots[index]; } private static void RigBuild(PlayerPickup pickup) { try { object obj = ((_fiRigBuilder != null) ? _fiRigBuilder.GetValue(pickup) : null); if (obj != null) { MethodInfo method = obj.GetType().GetMethod("Build", Type.EmptyTypes); if (method != null) { method.Invoke(obj, null); } } } catch { } } private static void PlayPickupSound(PlayerPickup pickup) { try { AudioClip val = (AudioClip)((_fiPickupClip != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val != (Object)null && (Object)(object)SoundManager.Instance != (Object)null) { SoundManager.Instance.PlaySound(val); } } catch { } } private static bool IsAlive(GameObject body) { if ((Object)(object)body == (Object)null || !body.activeInHierarchy) { return false; } PlayerHealth component = body.GetComponent<PlayerHealth>(); if ((Object)(object)component == (Object)null) { return false; } if (component.sync___get_value_health() > 0f) { return !component.sync___get_value_isKilled(); } return false; } private static bool IsDead(PlayerPickup pickup) { PlayerHealth val = (((Object)(object)pickup != (Object)null) ? ((Component)pickup).GetComponentInParent<PlayerHealth>() : null); if ((Object)(object)val != (Object)null) { if (!(val.sync___get_value_health() <= 0f)) { return val.sync___get_value_isKilled(); } return true; } return false; } } internal static class LoadoutRules { public static bool RestoreEnabled { get { if (!PlayerLookup.IsServer) { return ScoreKeeper.SyncedRestoreLoadout; } return DeathmatchPlugin.RestoreLoadoutOnRespawn.Value; } } public static string DefaultWeapon => ((PlayerLookup.IsServer ? DeathmatchPlugin.DefaultWeapon.Value : ScoreKeeper.SyncedDefaultWeapon) ?? "").Trim(); private static string ExcludedClasses => (PlayerLookup.IsServer ? DeathmatchPlugin.LoadoutExcludedClasses.Value : ScoreKeeper.SyncedExcludedClasses) ?? ""; private static string ExcludedWeapons => (PlayerLookup.IsServer ? DeathmatchPlugin.LoadoutExcludedWeapons.Value : ScoreKeeper.SyncedExcludedWeapons) ?? ""; public static string PrefabName(GameObject go) { if ((Object)(object)go == (Object)null) { return ""; } if ((Object)(object)go.GetComponent<Weapon>() == (Object)null || (Object)(object)go.GetComponent<ItemBehaviour>() == (Object)null) { return ""; } string text = ((Object)go).name ?? ""; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } return text.Trim(); } public static string WeaponClass(GameObject go) { Weapon val = (((Object)(object)go != (Object)null) ? go.GetComponent<Weapon>() : null); if (!((Object)(object)val != (Object)null)) { return ""; } return ((object)val).GetType().Name; } public static bool IsKnownWeapon(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return false; } try { SpawnerManager.PopulateAllWeapons(); GameObject value; return SpawnerManager.NameToWeaponDict.TryGetValue(prefabName, out value) && (Object)(object)value != (Object)null; } catch { return false; } } public static GameObject GetPrefab(string prefabName) { if (!IsKnownWeapon(prefabName)) { return null; } return SpawnerManager.NameToWeaponDict[prefabName]; } public static bool IsRestorable(string prefabName, string weaponClass) { if (!IsKnownWeapon(prefabName)) { return false; } if (InList(ExcludedWeapons, prefabName)) { return false; } if (IsExcludedClass(ResolveType(weaponClass))) { return false; } return true; } public static bool IsRestorablePrefab(string prefabName) { GameObject prefab = GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { return false; } if (InList(ExcludedWeapons, prefabName)) { return false; } Weapon component = prefab.GetComponent<Weapon>(); if ((Object)(object)component != (Object)null) { return !IsExcludedClass(((object)component).GetType()); } return false; } private static Type ResolveType(string weaponClass) { if (string.IsNullOrEmpty(weaponClass)) { return null; } try { return typeof(Weapon).Assembly.GetType(weaponClass); } catch { return null; } } private static bool IsExcludedClass(Type type) { Type type2 = type; while (type2 != null && type2 != typeof(object)) { if (InList(ExcludedClasses, type2.Name)) { return true; } type2 = type2.BaseType; } return false; } private static bool InList(string csv, string value) { if (string.IsNullOrEmpty(csv) || string.IsNullOrEmpty(value)) { return false; } string[] array = csv.Split(',', ';'); for (int i = 0; i < array.Length; i++) { if (string.Equals(array[i].Trim(), value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } internal static class LoadoutSpawner { private class Pending { public NetworkObject Nob; public int PlayerId; public float Deadline; } private const float UnclaimedSeconds = 6f; private static readonly List<Pending> _pending = new List<Pending>(); public static void Reset() { _pending.Clear(); } public static void HandleLocalRequest(int playerId, string right, string left) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) Handle(playerId, right, left, CSteamID.Nil, local: true); } public static void HandleRemoteRequest(int playerId, string right, string left, CSteamID sender) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) Handle(playerId, right, left, sender, local: false); } private static void Handle(int playerId, string right, string left, CSteamID sender, bool local) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) if (!PlayerLookup.IsServer || !ScoreKeeper.ModeActiveLocally() || !DeathmatchPlugin.RestoreLoadoutOnRespawn.Value) { return; } GameObject val = PlayerLookup.FindBody(playerId); if ((Object)(object)val == (Object)null || !val.activeInHierarchy) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Loadout] player=" + playerId + " asked for a loadout without a body")); } Reply(playerId, -1, -1, sender, local); return; } List<string> list = new List<string>(2); if (LoadoutRules.IsRestorablePrefab(right ?? "")) { list.Add(right); } if (LoadoutRules.IsRestorablePrefab(left ?? "")) { list.Add(left); } if (list.Count == 0) { string defaultWeapon = LoadoutRules.DefaultWeapon; if (defaultWeapon.Length > 0 && LoadoutRules.IsKnownWeapon(defaultWeapon)) { list.Add(defaultWeapon); } } if (list.Count > 1) { GameObject prefab = LoadoutRules.GetPrefab(list[0]); Weapon val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Weapon>() : null); if ((Object)(object)val2 != (Object)null && val2.requireBothHands) { list.RemoveAt(1); } } int rightId = ((list.Count > 0) ? SpawnOne(list[0], val, playerId) : (-1)); int leftId = ((list.Count > 1) ? SpawnOne(list[1], val, playerId) : (-1)); ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogInfo((object)("[Loadout] player=" + playerId + " spawned right='" + ((list.Count > 0) ? list[0] : "") + "' left='" + ((list.Count > 1) ? list[1] : "") + "' (ids " + rightId + ", " + leftId + ")")); } Reply(playerId, rightId, leftId, sender, local); } private static void Reply(int playerId, int rightId, int leftId, CSteamID sender, bool local) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (local) { LoadoutKeeper.OnLoadoutSpawned(playerId, rightId, leftId); return; } try { MyceliumNetwork.RPCTarget(20260905u, "LoadoutSpawned", sender, (ReliableType)1, new object[3] { playerId, rightId, leftId }); } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Loadout] reply to player " + playerId + " failed: " + ex.GetType().Name + " - " + ex.Message)); } } } private static int SpawnOne(string prefabName, GameObject body, int playerId) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) try { GameObject prefab = LoadoutRules.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { return -1; } Vector3 val = body.transform.position + body.transform.forward * 0.5f + Vector3.up * 1.2f; GameObject val2 = Object.Instantiate<GameObject>(prefab, val, body.transform.rotation); ItemBehaviour component = val2.GetComponent<ItemBehaviour>(); if ((Object)(object)component != (Object)null) { component.dispenserStart = true; } Rigidbody component2 = val2.GetComponent<Rigidbody>(); if ((Object)(object)component2 != (Object)null) { component2.isKinematic = true; component2.useGravity = false; } InstanceFinder.ServerManager.Spawn(val2, (NetworkConnection)null); NetworkObject component3 = val2.GetComponent<NetworkObject>(); if ((Object)(object)component3 == (Object)null) { Object.Destroy((Object)(object)val2); return -1; } _pending.Add(new Pending { Nob = component3, PlayerId = playerId, Deadline = Time.time + 6f }); return component3.ObjectId; } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Loadout] spawning '" + prefabName + "' failed: " + ex.GetType().Name + " - " + ex.Message)); } return -1; } } public static void ServerTick() { if (_pending.Count == 0) { return; } for (int num = _pending.Count - 1; num >= 0; num--) { Pending pending = _pending[num]; if ((Object)(object)pending.Nob == (Object)null) { _pending.RemoveAt(num); } else { GameObject gameObject = ((Component)pending.Nob).gameObject; ItemBehaviour component = gameObject.GetComponent<ItemBehaviour>(); if (IsHeld(gameObject, component)) { if ((Object)(object)component != (Object)null) { component.dispenserStart = false; } _pending.RemoveAt(num); } else if (!(Time.time < pending.Deadline)) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)("[Loadout] player=" + pending.PlayerId + " never picked up '" + ((Object)gameObject).name + "'; removing it")); } RespawnController.DespawnOrDestroy(gameObject); _pending.RemoveAt(num); } } } } private static bool IsHeld(GameObject go, ItemBehaviour item) { if ((Object)(object)go == (Object)null) { return false; } if (go.layer == 8 || (Object)(object)go.transform.parent != (Object)null) { return true; } if ((Object)(object)item != (Object)null) { if (!item.isTaken) { return (Object)(object)item.rootObject != (Object)null; } return true; } return false; } } internal static class PlayerLookup { public static bool IsServer { get { if ((Object)(object)InstanceFinder.NetworkManager != (Object)null) { return InstanceFinder.NetworkManager.IsServer; } return false; } } public static int LocalPlayerId { get { if (!((Object)(object)ClientInstance.Instance != (Object)null)) { return -1; } return ClientInstance.Instance.PlayerId; } } public static PlayerManager FindPlayerManager(int playerId) { if (playerId < 0) { return null; } if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null) { return ((Component)value).GetComponent<PlayerManager>(); } return null; } public static GameObject FindBody(int playerId) { PlayerManager val = FindPlayerManager(playerId); if ((Object)(object)val != (Object)null && (Object)(object)val.player != (Object)null) { return ((Component)val.player).gameObject; } return null; } public static PlayerHealth FindHealth(int playerId) { GameObject val = FindBody(playerId); if ((Object)(object)val != (Object)null) { PlayerHealth component = val.GetComponent<PlayerHealth>(); if ((Object)(object)component != (Object)null) { return component; } } PlayerHealth[] array = Object.FindObjectsOfType<PlayerHealth>(true); foreach (PlayerHealth val2 in array) { if ((Object)(object)val2 != (Object)null && GetPlayerId(val2.sync___get_value_playerValues()) == playerId) { return val2; } } return null; } public static PlayerPickup FindPickup(int playerId) { GameObject val = FindBody(playerId); if ((Object)(object)val != (Object)null) { PlayerPickup componentInChildren = val.GetComponentInChildren<PlayerPickup>(true); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren; } } PlayerPickup[] array = Object.FindObjectsOfType<PlayerPickup>(true); foreach (PlayerPickup val2 in array) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.playerValues != (Object)null && GetPlayerId(val2.playerValues) == playerId) { return val2; } } return null; } public static int GetPlayerId(PlayerValues values) { if ((Object)(object)values == (Object)null) { return -1; } ClientInstance val = values.sync___get_value_playerClient(); if (!((Object)(object)val != (Object)null)) { return -1; } return val.PlayerId; } public static string GetNameTag(int playerId) { if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null) { return value.PlayerNameTag; } return "Player " + playerId; } public static string GetName(int playerId) { if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null && !string.IsNullOrEmpty(value.PlayerName)) { return value.PlayerName; } return "Player " + playerId; } public static bool IsBodyAlive(int playerId, out string reason) { reason = ""; PlayerManager val = FindPlayerManager(playerId); if ((Object)(object)val == (Object)null) { reason = "missing PlayerManager"; return false; } if ((Object)(object)val.player == (Object)null) { reason = "no body"; return false; } GameObject gameObject = ((Component)val.player).gameObject; if ((Object)(object)gameObject == (Object)null || !gameObject.activeInHierarchy) { reason = "inactive body"; return false; } if (GetPlayerId(gameObject.GetComponent<PlayerValues>()) != playerId) { reason = "player id mismatch"; return false; } PlayerHealth component = gameObject.GetComponent<PlayerHealth>(); if ((Object)(object)component == (Object)null) { reason = "missing PlayerHealth"; return false; } if (component.sync___get_value_health() <= 0f || component.sync___get_value_isKilled()) { reason = "dead"; return false; } NetworkObject component2 = gameObject.GetComponent<NetworkObject>(); if ((Object)(object)component2 == (Object)null || !component2.IsSpawned) { reason = "body not spawned"; return false; } CharacterController component3 = gameObject.GetComponent<CharacterController>(); if ((Object)(object)component3 == (Object)null || !((Collider)component3).enabled) { reason = "character controller not ready"; return false; } return true; } public static int GetOwnerIdFromRootObject(GameObject root) { if ((Object)(object)root == (Object)null) { return -1; } try { ClientInstance val = root.GetComponentInParent<ClientInstance>(true) ?? root.GetComponentInChildren<ClientInstance>(true); if ((Object)(object)val != (Object)null) { return val.PlayerId; } int playerId = GetPlayerId(root.GetComponentInParent<PlayerValues>(true) ?? root.GetComponentInChildren<PlayerValues>(true)); if (playerId >= 0) { return playerId; } foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances) { PlayerManager val2 = (((Object)(object)playerInstance.Value != (Object)null) ? ((Component)playerInstance.Value).GetComponent<PlayerManager>() : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.player == (Object)null)) { GameObject gameObject = ((Component)val2.player).gameObject; if ((Object)(object)gameObject == (Object)(object)root || root.transform.IsChildOf(gameObject.transform)) { return playerInstance.Key; } } } } catch { } return -1; } public static int FindKillerId(int victimId) { PlayerHealth val = FindHealth(victimId); if ((Object)(object)val == (Object)null) { return -1; } Transform val2 = null; try { val2 = val.sync___get_value_killer(); } catch { } if ((Object)(object)val2 == (Object)null) { return -1; } ClientInstance componentInParent = ((Component)val2).GetComponentInParent<ClientInstance>(true); if ((Object)(object)componentInParent != (Object)null) { return componentInParent.PlayerId; } int playerId = GetPlayerId(((Component)val2).GetComponentInParent<PlayerValues>(true) ?? ((Component)val2).GetComponentInChildren<PlayerValues>(true)); if (playerId >= 0) { return playerId; } GameObject val3 = null; ProximityMine val4 = ((Component)val2).GetComponentInParent<ProximityMine>(true) ?? ((Component)val2).GetComponentInChildren<ProximityMine>(true); if ((Object)(object)val4 != (Object)null) { val3 = val4.sync___get_value__rootObject(); } else { Claymore val5 = ((Component)val2).GetComponentInParent<Claymore>(true) ?? ((Component)val2).GetComponentInChildren<Claymore>(true); if ((Object)(object)val5 != (Object)null) { val3 = val5.sync___get_value__rootObject(); } } if (!((Object)(object)val3 != (Object)null)) { return -1; } return GetOwnerIdFromRootObject(val3); } } internal static class RespawnController { private class Pending { public float RespawnAt; public float LastAttempt = -999f; public int Attempts; } private const float TickSeconds = 0.25f; private const float RetrySeconds = 2.5f; private const float BodilessGraceSeconds = 4f; private const float SweepSeconds = 1f; private static float _nextSweep; private static readonly Dictionary<int, Pending> _pending = new Dictionary<int, Pending>(); private static readonly Dictionary<int, float> _bodilessSince = new Dictionary<int, float>(); private static readonly Dictionary<int, GameObject> _ragdolls = new Dictionary<int, GameObject>(); private static readonly Dictionary<int, KeyValuePair<int, int>> _cosmetics = new Dictionary<int, KeyValuePair<int, int>>(); private static float _nextTick; private static FieldInfo _fiSpawnedObject; private static MethodInfo _miSpawnPlayer4; private static MethodInfo _miCmdRespawnLogic; public static void Init() { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; _fiSpawnedObject = typeof(PlayerManager).GetField("SpawnedObject", bindingAttr); _miSpawnPlayer4 = typeof(PlayerManager).GetMethod("SpawnPlayer", bindingAttr, null, new Type[4] { typeof(int), typeof(int), typeof(Vector3), typeof(Quaternion) }, null); _miCmdRespawnLogic = typeof(PlayerManager).GetMethod("RpcLogic___CmdRespawn_2166136261", bindingAttr); if (_fiSpawnedObject == null || _miSpawnPlayer4 == null) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)"[Respawn] PlayerManager internals not found; falling back to the native respawn RPC."); } } if (_miCmdRespawnLogic == null) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogWarning((object)"[Respawn] native respawn RPC logic not found."); } } } public static void Reset() { _pending.Clear(); _bodilessSince.Clear(); _ragdolls.Clear(); _nextTick = 0f; } public static void OnServerDeath(int playerId) { if (DeathmatchPlugin.CleanupItemsOnDeath.Value) { DespawnHeldItems(playerId); SweepOrphanedItems(PlayerLookup.FindBody(playerId)); } if (DeathmatchPlugin.CleanupMinesOnDeath.Value) { ClearPlacedExplosives(playerId); } Schedule(playerId); } public static void Schedule(int playerId) { float num = Mathf.Max(0.25f, DeathmatchPlugin.RespawnDelay.Value); _pending[playerId] = new Pending { RespawnAt = Time.time + num }; Log(playerId, 0, "respawn queued in " + num.ToString("0.00") + "s"); } public static void OnServerSpawned(int playerId) { _pending.Remove(playerId); _bodilessSince.Remove(playerId); } public static void RememberCosmetics(int playerId, int suit, int cig) { _cosmetics[playerId] = new KeyValuePair<int, int>(suit, cig); } public static void ServerTick() { if (ScoreKeeper.MatchOver || Time.time < _nextTick) { return; } _nextTick = Time.time + 0.25f; if (DeathmatchPlugin.CleanupItemsOnDeath.Value && Time.time >= _nextSweep) { _nextSweep = Time.time + 1f; SweepOrphanedItems(null); } foreach (int item in new List<int>(ClientInstance.playerInstances.Keys)) { if (PlayerLookup.IsBodyAlive(item, out var reason)) { _pending.Remove(item); _bodilessSince.Remove(item); continue; } if (!_pending.TryGetValue(item, out var value)) { if (!ScoreKeeper.MatchLive) { continue; } if (!_bodilessSince.TryGetValue(item, out var value2)) { _bodilessSince[item] = Time.time; continue; } if (Time.time - value2 < 4f) { continue; } Log(item, 0, "no living body (" + reason + "); scheduling spawn"); Schedule(item); value = _pending[item]; } if (!(Time.time < value.RespawnAt) && !(Time.time - value.LastAttempt < 2.5f) && (value.Attempts < 6 || !(Time.time - value.LastAttempt < 6f))) { value.LastAttempt = Time.time; value.Attempts++; TryRespawn(item, value.Attempts); } } } private static void TryRespawn(int playerId, int attempt) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) PlayerManager val = PlayerLookup.FindPlayerManager(playerId); if ((Object)(object)val == (Object)null) { Log(playerId, attempt, "missing PlayerManager"); return; } DestroyRagdoll(playerId); GetCosmetics(playerId, val, out var suit, out var cig); if (_fiSpawnedObject == null || _miSpawnPlayer4 == null || !SpawnSelector.TryPick(playerId, out var point, out var position, out var rotation)) { NativeRespawn(val, playerId, attempt); return; } try { object? value = _fiSpawnedObject.GetValue(val); GameObject val2 = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val2 != (Object)null) { if (val2.activeSelf) { val2.SetActive(false); } if (DeathmatchPlugin.CleanupItemsOnDeath.Value) { SweepOrphanedItems(val2); } DespawnOrDestroy(val2); } _miSpawnPlayer4.Invoke(val, new object[4] { suit, cig, position, rotation }); Log(playerId, attempt, "spawned at '" + ((Object)point).name + "'"); } catch (Exception ex) { Log(playerId, attempt, "direct spawn failed: " + ex.GetType().Name + " - " + ex.Message); NativeRespawn(val, playerId, attempt); } } private static void NativeRespawn(PlayerManager pm, int playerId, int attempt) { if (_miCmdRespawnLogic == null) { return; } try { _miCmdRespawnLogic.Invoke(pm, null); Log(playerId, attempt, "native respawn invoked"); } catch (Exception ex) { Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex); Log(playerId, attempt, "native respawn failed: " + ex2.GetType().Name + " - " + ex2.Message); } } public static bool InvokeSpawnPlayer(PlayerManager pm, int suit, int cig, Vector3 pos, Quaternion rot) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (_miSpawnPlayer4 == null) { return false; } _miSpawnPlayer4.Invoke(pm, new object[4] { suit, cig, pos, rot }); return true; } private static void GetCosmetics(int playerId, PlayerManager pm, out int suit, out int cig) { if (_cosmetics.TryGetValue(playerId, out var value)) { suit = value.Key; cig = value.Value; return; } try { PlayerSetup val = (((Object)(object)pm.player != (Object)null) ? ((Component)pm.player).GetComponent<PlayerSetup>() : null); if ((Object)(object)val != (Object)null) { suit = val.sync___get_value_mat(); cig = val.sync___get_value_cig(); return; } } catch { } suit = (((Object)(object)CosmeticsManager.Instance != (Object)null) ? CosmeticsManager.Instance.currentsuitIndex : 0); cig = (((Object)(object)CosmeticsManager.Instance != (Object)null) ? CosmeticsManager.Instance.currentcigIndex : 0); } public static void DespawnHeldItems(int playerId) { PlayerPickup val = PlayerLookup.FindPickup(playerId); if ((Object)(object)val == (Object)null) { return; } try { GameObject obj = val.sync___get_value_objInHand(); GameObject obj2 = (val.sync___get_value_hasObjectInLeftHand() ? val.sync___get_value_objInLeftHand() : null); val.sync___set_value_hasObjectInHand(false, true); val.sync___set_value_hasObjectInLeftHand(false, true); val.sync___set_value_objInHand((GameObject)null, true); val.sync___set_value_objInLeftHand((GameObject)null, true); DespawnOrDestroy(obj); DespawnOrDestroy(obj2); ItemBehaviour[] componentsInChildren = ((Component)((Component)val).transform.root).GetComponentsInChildren<ItemBehaviour>(true); foreach (ItemBehaviour val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { DespawnOrDestroy(((Component)val2).gameObject); } } } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Cleanup] held items for player " + playerId + ": " + ex.GetType().Name)); } } } public static void ClearPlacedExplosives(int playerId) { int num = 0; try { ProximityMine[] array = Object.FindObjectsOfType<ProximityMine>(true); foreach (ProximityMine val in array) { if (!((Object)(object)val == (Object)null) && PlayerLookup.GetOwnerIdFromRootObject(val.sync___get_value__rootObject()) == playerId) { DespawnOrDestroy(((Component)val).gameObject); num++; } } Claymore[] array2 = Object.FindObjectsOfType<Claymore>(true); foreach (Claymore val2 in array2) { if (!((Object)(object)val2 == (Object)null) && PlayerLookup.GetOwnerIdFromRootObject(val2.sync___get_value__rootObject()) == playerId) { DespawnOrDestroy(((Component)val2).gameObject); num++; } } } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Cleanup] explosives for player " + playerId + ": " + ex.GetType().Name)); } } if (num > 0) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogInfo((object)("[Cleanup] removed " + num + " placed explosive(s) of player " + playerId)); } } } public static int SweepOrphanedItems(GameObject dyingBody) { int num = 0; try { ItemBehaviour[] array = Object.FindObjectsOfType<ItemBehaviour>(true); foreach (ItemBehaviour val in array) { if (!((Object)(object)val == (Object)null) && IsOrphan(val, dyingBody)) { DespawnOrDestroy(((Component)val).gameObject); num++; } } } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)("[Cleanup] orphan sweep: " + ex.GetType().Name + " - " + ex.Message)); } } if (num > 0) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogInfo((object)("[Cleanup] removed " + num + " orphaned item(s)")); } } return num; } private static bool IsOrphan(ItemBehaviour item, GameObject dyingBody) { GameObject val = null; if (item.rootObject != null) { if ((Object)(object)item.rootObject == (Object)null) { return true; } val = item.rootObject; } if ((Object)(object)val == (Object)null && item.playerPickup != null) { if ((Object)(object)item.playerPickup == (Object)null) { return true; } val = ((Component)item.playerPickup).gameObject; } if ((Object)(object)val == (Object)null) { PlayerHealth componentInParent = ((Component)item).GetComponentInParent<PlayerHealth>(true); if ((Object)(object)componentInParent != (Object)null) { val = ((Component)componentInParent).gameObject; } } if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)dyingBody != (Object)null && (Object)(object)val == (Object)(object)dyingBody) { return true; } if (!val.activeInHierarchy) { return true; } PlayerHealth component = val.GetComponent<PlayerHealth>(); if ((Object)(object)component != (Object)null && (component.sync___get_value_health() <= 0f || component.sync___get_value_isKilled())) { return true; } return false; } public static void ClearHand(PlayerPickup pickup, bool rightHand) { if ((Object)(object)pickup == (Object)null) { return; } try { if (rightHand) { pickup.sync___set_value_hasObjectInHand(false, true); pickup.sync___set_value_objInHand((GameObject)null, true); } else { pickup.sync___set_value_hasObjectInLeftHand(false, true); pickup.sync___set_value_objInLeftHand((GameObject)null, true); } } catch { } } public static void DespawnOrDestroy(GameObject obj) { if ((Object)(object)obj == (Object)null) { return; } try { NetworkObject componentInParent = obj.GetComponentInParent<NetworkObject>(); if ((Object)(object)componentInParent != (Object)null && componentInParent.IsSpawned && (Object)(object)InstanceFinder.ServerManager != (Object)null) { InstanceFinder.ServerManager.Despawn(componentInParent, (DespawnType?)null); return; } } catch { } try { Object.Destroy((Object)(object)obj); } catch { } } public static void TrackRagdoll(PlayerHealth health) { //IL_0033: 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) try { int playerId = PlayerLookup.GetPlayerId(health.sync___get_value_playerValues()); if (playerId < 0) { return; } RagdollDress val = null; float num = float.MaxValue; RagdollDress[] array = Object.FindObjectsOfType<RagdollDress>(true); foreach (RagdollDress val2 in array) { float num2 = Vector3.Distance(((Component)val2).transform.position, ((Component)health).transform.position); if (num2 < num) { num = num2; val = val2; } } if ((Object)(object)val != (Object)null) { _ragdolls[playerId] = ((Component)val).gameObject; } } catch { } } public static void DestroyRagdoll(int playerId) { try { if (_ragdolls.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } _ragdolls.Remove(playerId); HatPosition[] array = Object.FindObjectsOfType<HatPosition>(true); foreach (HatPosition val in array) { if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform.parent == (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } catch { } } public static void CleanupWorldEffects() { try { foreach (KeyValuePair<int, GameObject> ragdoll in _ragdolls) { if ((Object)(object)ragdoll.Value != (Object)null) { Object.Destroy((Object)(object)ragdoll.Value); } } _ragdolls.Clear(); RagdollDress[] array = Object.FindObjectsOfType<RagdollDress>(true); for (int i = 0; i < array.Length; i++) { Object.Destroy((Object)(object)((Component)array[i]).gameObject); } } catch { } } private static void Log(int playerId, int attempt, string message) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)("[Respawn] player=" + playerId + " attempt=" + attempt + ": " + message)); } } } internal static class ScoreKeeper { public struct Row { public int PlayerId; public int Kills; public int Deaths; } public const string Tag = "<b><color=#FF4040>[DM]</color></b>"; public static readonly Dictionary<int, int> Kills = new Dictionary<int, int>(); public static readonly Dictionary<int, int> Deaths = new Dictionary<int, int>(); public static bool MatchOver; public static bool AnyDeathThisMap; public static bool LocalDiedThisMap; public static bool SyncedActive; public static bool SyncedMatchLive; public static int SyncedKillsToWin; public static int SyncedSecondsLeft = -1; public static bool SyncedCleanupItems = true; public static bool SyncedRemoveDamageZones; public static float LastSyncTime = -999f; public static bool SyncedRestoreLoadout = true; public static string SyncedDefaultWeapon = "Gun"; public static string SyncedExcludedClasses = "DualLauncher"; public static string SyncedExcludedWeapons = ""; private static float _mapStartTime; private static float _countdownEndsAt = -1f; private static bool _winInProgress; private static bool _suddenDeathAnnounced; private static bool _dirty; private static float _nextBroadcast; private static readonly Dictionary<int, float> _lastDeathHandled = new Dictionary<int, float>(); private static MethodInfo _miRoundWon; public static bool MatchLive { get { if (!PlayerLookup.IsServer) { return SyncedMatchLive; } return IsMidMatchLocally(); } } public static int EffectiveKillsToWin { get { if (PlayerLookup.IsServer) { return DeathmatchPlugin.KillsToWin.Value; } if (SyncedKillsToWin <= 0) { return DeathmatchPlugin.KillsToWin.Value; } return SyncedKillsToWin; } } public static bool CleanupItemsEffective { get { if (!PlayerLookup.IsServer) { return SyncedCleanupItems; } return DeathmatchPlugin.CleanupItemsOnDeath.Value; } } public static bool RemoveDamageZonesEffective { get { if (!PlayerLookup.IsServer) { return SyncedRemoveDamageZones; } return DeathmatchPlugin.RemoveDamageZones.Value; } } public static int SecondsLeft { get { if (!PlayerLookup.IsServer) { return SyncedSecondsLeft; } int value = DeathmatchPlugin.TimeLimitMinutes.Value; if (value <= 0) { return -1; } return Mathf.Max(0, Mathf.CeilToInt((float)value * 60f - (Time.time - _mapStartTime))); } } public static void Init() { _miRoundWon = typeof(GameManager).GetMethod("RoundWon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_miRoundWon == null) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogWarning((object)"GameManager.RoundWon not found; round wins will not award match points."); } } } public static void Reset() { Kills.Clear(); Deaths.Clear(); MatchOver = false; AnyDeathThisMap = false; LocalDiedThisMap = false; _mapStartTime = Time.time; _countdownEndsAt = -1f; _winInProgress = false; _suddenDeathAnnounced = false; _lastDeathHandled.Clear(); _dirty = true; _nextBroadcast = 0f; } public static bool ModeActiveLocally() { if ((Object)(object)GameManager.Instance == (Object)null) { return false; } if (PlayerLookup.IsServer) { return DeathmatchPlugin.Enabled.Value; } if (Time.unscaledTime - LastSyncTime < 6f) { return SyncedActive; } return DeathmatchPlugin.Enabled.Value; } public static bool IsMidMatchLocally() { if (AnyDeathThisMap || LocalDiedThisMap) { return true; } if (_countdownEndsAt > 0f && Time.time > _countdownEndsAt + 1f) { return true; } if (PlayerLookup.IsServer) { return false; } if (Time.unscaledTime - LastSyncTime < 6f) { return SyncedMatchLive; } return Time.timeSinceLevelLoad > 20f; } public static void OnStartTimeIssued(float secondsTillStart) { _countdownEndsAt = Time.time + Mathf.Max(0f, secondsTillStart); } public static void MarkDirty() { _dirty = true; } public static bool TryBeginDeath(int victimId) { float unscaledTime = Time.unscaledTime; if (_lastDeathHandled.TryGetValue(victimId, out var value) && unscaledTime - value < 0.5f) { return false; } _lastDeathHandled[victimId] = unscaledTime; AnyDeathThisMap = true; return true; } public static void OnServerKill(int victimId, int killerId) { if (MatchOver) { return; } Deaths[victimId] = ((!Deaths.TryGetValue(victimId, out var value)) ? 1 : (value + 1)); if (killerId >= 0 && killerId != victimId) { int value2; int num = ((!Kills.TryGetValue(killerId, out value2)) ? 1 : (value2 + 1)); Kills[killerId] = num; int value3 = DeathmatchPlugin.KillsToWin.Value; if (DeathmatchPlugin.KillFeedInChat.Value) { Chat("<b><color=#FF4040>[DM]</color></b> <b>" + PlayerLookup.GetNameTag(killerId) + "</b> <color=#00FFFF>[" + num + "/" + value3 + "]</color>"); } if (num >= value3) { StartWin(killerId, "reached the kill target"); } } _dirty = true; } public static void ServerTick() { if (MatchOver || _winInProgress) { BroadcastIfDue(); return; } int value = DeathmatchPlugin.TimeLimitMinutes.Value; if (value > 0 && MatchLive && Time.time - _mapStartTime >= (float)value * 60f) { int num = -1; int num2 = -1; bool flag = false; foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances) { int value2; int num3 = (Kills.TryGetValue(playerInstance.Key, out value2) ? value2 : 0); if (num3 > num2) { num2 = num3; num = playerInstance.Key; flag = false; } else if (num3 == num2) { flag = true; } } if (num >= 0 && !flag) { StartWin(num, _suddenDeathAnnounced ? "sudden death" : "time is up"); } else if (!_suddenDeathAnnounced) { _suddenDeathAnnounced = true; Chat("<b><color=#FF4040>[DM]</color></b> Time is up and the lead is tied. <b>Sudden death:</b> next kill wins!"); } } BroadcastIfDue(); } private static void BroadcastIfDue() { if (_dirty || !(Time.time < _nextBroadcast)) { _dirty = false; _nextBroadcast = Time.time + 2f; if ((Object)(object)DeathmatchPlugin.Instance != (Object)null) { DeathmatchPlugin.Instance.BroadcastState(); } } } private static void StartWin(int winnerId, string why) { if (!_winInProgress && !MatchOver) { _winInProgress = true; MatchOver = true; _dirty = true; ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)("[Score] player " + winnerId + " wins (" + why + ")")); } MonoBehaviour val = (MonoBehaviour)(object)(((Object)(object)GameManager.Instance != (Object)null) ? ((DeathmatchPlugin)(object)GameManager.Instance) : DeathmatchPlugin.Instance); if ((Object)(object)val != (Object)null) { val.StartCoroutine(WinSequence(winnerId)); } } } private static IEnumerator WinSequence(int winnerId) { yield return (object)new WaitForSeconds(1.5f); bool roundEnded = false; try { int num = (((Object)(object)ScoreManager.Instance != (Object)null) ? ScoreManager.Instance.GetTeamId(winnerId) : winnerId); int value; int num2 = (Kills.TryGetValue(winnerId, out value) ? value : 0); Chat("<b><color=#FF4040>[DM]</color></b> <b><color=white>" + PlayerLookup.GetNameTag(winnerId) + "</color></b> wins the round with <b>" + num2 + "</b> kills!"); if ((Object)(object)ScoreManager.Instance != (Object)null) { ScoreManager.Instance.AddRoundScore(num, 1); } if (_miRoundWon != null && (Object)(object)GameManager.Instance != (Object)null) { _miRoundWon.Invoke(GameManager.Instance, new object[1] { num }); } if ((Object)(object)RoundManager.Instance != (Object)null) { RoundManager.Instance.CmdEndRound(num); roundEnded = true; } } catch (Exception ex) { ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogError((object)("[Score] win sequence failed: " + ex)); } } yield return (object)new WaitForSeconds(4f); if (roundEnded) { try { if ((Object)(object)SceneMotor.Instance != (Object)null) { SceneMotor.Instance.ChangeNetworkScene(); } yield break; } catch (Exception ex2) { ManualLogSource log2 = DeathmatchPlugin.Log; if (log2 != null) { log2.LogError((object)("[Score] scene change failed: " + ex2)); } yield break; } } MatchOver = false; _winInProgress = false; _dirty = true; } public static void Chat(string text) { try { if (PlayerLookup.IsServer && !((Object)(object)PauseManager.Instance == (Object)null)) { PauseManager.Instance.WriteLog(text); } } catch { } } public static string Serialize() { StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances) { int key = playerInstance.Key; int value2; int value = (Kills.TryGetValue(key, out value2) ? value2 : 0); int value4; int value3 = (Deaths.TryGetValue(key, out value4) ? value4 : 0); if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(key).Append(':').Append(value) .Append(':') .Append(value3); } return stringBuilder.ToString(); } public static void ApplySynced(bool active, bool matchLive, int killsToWin, int secondsLeft, bool cleanupItems, bool removeZones, string data, bool restoreLoadout, string defaultWeapon, string excludedClasses, string excludedWeapons) { SyncedRestoreLoadout = restoreLoadout; SyncedDefaultWeapon = defaultWeapon ?? ""; SyncedExcludedClasses = excludedClasses ?? ""; SyncedExcludedWeapons = excludedWeapons ?? ""; SyncedActive = active; SyncedMatchLive = matchLive; SyncedKillsToWin = killsToWin; SyncedSecondsLeft = secondsLeft; SyncedCleanupItems = cleanupItems; SyncedRemoveDamageZones = removeZones; LastSyncTime = Time.unscaledTime; Kills.Clear(); Deaths.Clear(); if (string.IsNullOrEmpty(data)) { return; } string[] array = data.Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }); if (array2.Length == 3 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && int.TryParse(array2[2], out var result3)) { Kills[result] = result2; Deaths[result] = result3; } } } public static List<Row> GetRows() { List<Row> list = new List<Row>(); foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances) { list.Add(new Row { PlayerId = playerInstance.Key, Kills = (Kills.TryGetValue(playerInstance.Key, out var value) ? value : 0), Deaths = (Deaths.TryGetValue(playerInstance.Key, out var value2) ? value2 : 0) }); } list.Sort((Row a, Row b) => (a.Kills == b.Kills) ? a.Deaths.CompareTo(b.Deaths) : b.Kills.CompareTo(a.Kills)); return list; } } internal static class SpawnSelector { private struct Candidate { public SpawnPoint Point; public float EnemyDistance; public bool Visible; public bool Recent; } private struct Enemy { public Vector3 Position; public Transform Root; } private const float RecentSeconds = 4f; private const float RecentRadiusSqr = 4f; private const float LineOfSightRange = 45f; private const float EyeHeight = 1.6f; private static SpawnPoint[] _points = Array.Empty<SpawnPoint>(); private static string _scene; private static readonly List<KeyValuePair<Vector3, float>> _recent = new List<KeyValuePair<Vector3, float>>(); public static void Reset() { _points = Array.Empty<SpawnPoint>(); _scene = null; _recent.Clear(); } private static SpawnPoint[] GetPoints() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; bool flag = _scene != name || _points.Length == 0; if (!flag) { for (int i = 0; i < _points.Length; i++) { if ((Object)(object)_points[i] == (Object)null) { flag = true; break; } } } if (flag) { _points = Object.FindObjectsOfType<SpawnPoint>(true) ?? Array.Empty<SpawnPoint>(); _scene = name; ManualLogSource log = DeathmatchPlugin.Log; if (log != null) { log.LogInfo((object)("[Spawn] cached " + _points.Length + " spawn points in " + name)); } } return _points; } public static bool TryPick(int forPlayerId, out SpawnPoint point, out Vector3 position, out Quaternion rotation) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0143: 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_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown