Decompiled source of StraftatEightsPlugin v0.1.0
StraftatEightsPlugin.dll
Decompiled 3 hours 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ComputerysModdingUtilities; using FishNet; using FishNet.Connection; using FishNet.Managing; using FishNet.Object; using HarmonyLib; using Microsoft.CodeAnalysis; using MyceliumNetworking; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: StraftatMod(false)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("StraftatEightsPlugin")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+5c365d7c650735dc75dbce0a28beb5d122d58f51")] [assembly: AssemblyProduct("Straftat Eights")] [assembly: AssemblyTitle("StraftatEightsPlugin")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 StraftatEightsPlugin { [BepInPlugin("StraftatEightsPlugin", "Straftat Eights", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("STRAFTAT.exe")] public class Plugin : BaseUnityPlugin { internal static ConfigEntry<bool> DefaultGameModeEnabled; internal const uint FFAModId = 2718281828u; internal static ConfigEntry<bool> FFAEnabled; internal const uint GlobalModifiersModId = 1892737465u; internal static ConfigEntry<bool> MovementTweaksEnabled; internal static ConfigEntry<bool> WallJumpEnabled; internal static ConfigEntry<bool> WallJumpBoostEnabled; internal static ConfigEntry<bool> SlidingEnabled; internal static ConfigEntry<bool> SlideBoostEnabled; internal static ConfigEntry<int> MoveSpeedPercent; internal static ConfigEntry<int> AdsSpeedPercent; internal static ConfigEntry<int> GravityPercent; internal static ConfigEntry<int> MomentumPercent; internal static ConfigEntry<int> AirSpeedRatioPercent; internal const uint GlobalWeaponsModId = 1618033991u; internal static ConfigEntry<bool> WeaponTweaksEnabled; internal static ConfigEntry<string> AllowedWeapons; internal static ConfigEntry<int> SpareMagazines; internal static ConfigEntry<bool> CycleWeapons; internal const uint GunGameModId = 1618033990u; internal static ConfigEntry<bool> GunGameEnabled; internal static ConfigEntry<string> GunGameWeaponOrder; internal const uint HealthSettingsModId = 1892737466u; internal static ConfigEntry<int> MaxHealthPercent; internal static ConfigEntry<bool> HealthTweaksEnabled; internal static ConfigEntry<bool> HealthRegenEnabled; internal static ConfigEntry<int> HealthRegenDelaySeconds; internal static ConfigEntry<int> HealthRegenRate; internal const uint HotPotatoModId = 2718281830u; internal static ConfigEntry<bool> HotPotatoEnabled; internal const uint InfidelModId = 2718281831u; internal static ConfigEntry<bool> InfidelEnabled; internal const uint JuggernautModId = 3141592653u; internal static ConfigEntry<bool> JuggernautEnabled; internal const uint KillTheRatModId = 3141592655u; internal static ConfigEntry<bool> KillTheRatEnabled; internal const uint MichaelMeyersModId = 3141592654u; internal static ConfigEntry<bool> MichaelMeyersEnabled; internal const uint OneInTheChamberModId = 2718281829u; internal static ConfigEntry<bool> OneInTheChamberEnabled; internal static ManualLogSource Logger; internal static Plugin Instance; internal const uint SniperBattleModId = 1618033992u; internal static ConfigEntry<bool> SniperBattleEnabled; private void InitializeDefaultGameMode() { DefaultGameModeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Default Game Mode Enabled", false, "Host-controlled: uses normal Straftat one-life rules, map weapon spawners, and default health while keeping global movement settings active."); DefaultGameModeEnabled.SettingChanged += delegate { GameModeManager.OnSettingsChanged(); }; } private void InitializeFFA() { FFAEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Free For All Enabled", false, "Host-controlled: players score ten points per kill; the first to 100 points wins."); FFAEnabled.SettingChanged += delegate { FFAState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 2718281828u, 0); MyceliumNetwork.LobbyCreated += FFAState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += FFAState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += FFAState.OnPlayerEntered; } [CustomRPC] public void SyncFFASettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (FFAState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { FFAState.ApplySettings(enabled); } } [CustomRPC] public void SyncFFALiveState(CSteamID hostId, string killsData, int winnerId, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) FFAState.ApplyLiveState(hostId, killsData, winnerId, roundId, revision); } [CustomRPC] public void FFAAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } private void InitializeGlobalModifiers() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown MovementTweaksEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement Settings", "Movement Tweaks Enabled", true, "Host-controlled: master switch. Turn off for pure stock Straftat movement."); WallJumpEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement Settings", "Enable Wall Jump", true, "Host-controlled: allows wall jumping for everyone in the lobby."); WallJumpBoostEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement Settings", "Enable Wall Jump Speed Boost", true, "Host-controlled: whether wall jumping gives the usual Straftat horizontal speed kick (chaining wall jumps for extra speed)."); SlidingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement Settings", "Enable Sliding", true, "Host-controlled: allows crouch-sliding for everyone in the lobby."); SlideBoostEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement Settings", "Enable Slide Speed Boost", true, "Host-controlled: whether sliding gives the usual Straftat speed boost. Disable to slide like most other games."); MoveSpeedPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Movement Settings", "Move Speed %", 100, new ConfigDescription("Host-controlled: overall movement speed as a percent of normal.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 200), Array.Empty<object>())); AdsSpeedPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Movement Settings", "ADS Speed %", 100, new ConfigDescription("Host-controlled: movement speed while aiming down sights, as a percent of normal.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 100), Array.Empty<object>())); GravityPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Movement Settings", "Gravity %", 100, new ConfigDescription("Host-controlled: gravity as a percent of normal. Lower = floatier jumps and slower falling.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>())); MomentumPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Movement Settings", "Momentum %", 100, new ConfigDescription("Host-controlled: how much weight/inertia is behind movement. 100% = stock Straftat snappiness. Higher = heavier, slower to speed up/stop/turn. Lower = snappier, near-instant direction changes.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 400), Array.Empty<object>())); AirSpeedRatioPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Movement Settings", "Air Move Speed %", (int)MathF.Round(116.666664f), new ConfigDescription("Host-controlled: air move speed (not air control) as a percent of ground move speed. Stock Straftat is already faster sprinting in the air than on the ground (the default reflects that real ratio). Lower this to slow players down in the air.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 200), Array.Empty<object>())); WallJumpEnabled.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; MovementTweaksEnabled.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; SlidingEnabled.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; SlideBoostEnabled.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; WallJumpBoostEnabled.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; MoveSpeedPercent.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; AdsSpeedPercent.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; GravityPercent.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; MomentumPercent.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; AirSpeedRatioPercent.SettingChanged += delegate { GlobalModifiersState.PushIfHost(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 1892737465u, 0); MyceliumNetwork.LobbyCreated += GlobalModifiersState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += GlobalModifiersState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += GlobalModifiersState.OnPlayerEntered; } [CustomRPC] public void SyncMovementSettings(CSteamID hostId, int roundId, int revision, bool enabled, bool wallJump, bool sliding, bool slideBoost, bool wallJumpBoost, int moveSpeedPercent, int adsSpeedPercent, int gravityPercent, int momentumPercent, int airSpeedRatioPercent) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (GlobalModifiersState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { Logger.LogInfo((object)$"[MovementSettings] Received sync: enabled={enabled} wallJump={wallJump} sliding={sliding} slideBoost={slideBoost} wallJumpBoost={wallJumpBoost} moveSpeed%={moveSpeedPercent} adsSpeed%={adsSpeedPercent} gravity%={gravityPercent} momentum%={momentumPercent} airSpeed%={airSpeedRatioPercent}"); GlobalModifiersState.Apply(enabled, wallJump, sliding, slideBoost, wallJumpBoost, moveSpeedPercent, adsSpeedPercent, gravityPercent, momentumPercent, airSpeedRatioPercent); } } private void InitializeGlobalWeapons() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown WeaponTweaksEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Weapon Settings", "Weapon Tweaks Enabled", false, "Host-controlled: enables weapon override rules."); AllowedWeapons = ((BaseUnityPlugin)this).Config.Bind<string>("Weapon Settings", "Allowed Weapons", "AK-K, AR15, Bukanee, Dispenser, HK_G11, Keso, Kusma, M2000, QCW05, Glock, Silenzzio, SMG, SmithCarbine, Warden, Yangtse", "Host-controlled: exact weapon IDs allowed on spawners and for cycling."); SpareMagazines = ((BaseUnityPlugin)this).Config.Bind<int>("Weapon Settings", "Spare Magazines", 5, new ConfigDescription("Host-controlled: spare magazines granted with a weapon pickup.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>())); CycleWeapons = ((BaseUnityPlugin)this).Config.Bind<bool>("Weapon Settings", "F8 Cycle Weapons", false, "Host-controlled: F8 cycles through allowed weapons when no active mode owns weapon loadouts, and disables weapon droppers."); WeaponTweaksEnabled.SettingChanged += delegate { WeaponSettingsState.PushIfHost(); }; AllowedWeapons.SettingChanged += delegate { WeaponSettingsState.PushIfHost(); }; SpareMagazines.SettingChanged += delegate { WeaponSettingsState.PushIfHost(); }; CycleWeapons.SettingChanged += delegate { WeaponSettingsState.PushIfHost(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 1618033991u, 0); MyceliumNetwork.LobbyCreated += WeaponSettingsState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += WeaponSettingsState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += WeaponSettingsState.OnPlayerEntered; } [CustomRPC] public void SyncWeaponSettings(CSteamID hostId, int roundId, int revision, bool enabled, string allowedWeapons, int spareMagazines, bool cycleWeapons) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (WeaponSettingsState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { WeaponSettingsState.Apply(enabled, allowedWeapons, spareMagazines, cycleWeapons); } } [CustomRPC] public void RequestWeaponCycle(int playerId) { if (MyceliumNetwork.IsHost && WeaponSettingsState.Enabled && WeaponSettingsState.Cycle) { WeaponSettingsState.GiveCycledWeapon(playerId); } } [CustomRPC] public void AttachServerGrantedWeapon(int playerId) { WeaponService.AttachGrantedWeaponForOwner(playerId); } private void InitializeGunGame() { GunGameEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Gun Game Enabled", false, "Host-controlled: players advance through the weapon list with each kill."); GunGameWeaponOrder = ((BaseUnityPlugin)this).Config.Bind<string>("Game Mode Settings", "Gun Game Weapon Order", "Glock, Webley, SMG, Bukanee, SawedOff, Shotgun, Yangtse, Kusma, AR15, AK-K, QCW05, FG42, HK_G11, SmithCarbine, M2000, BaseballBat", "Host-controlled: exact prefab IDs in progression order."); GunGameEnabled.SettingChanged += delegate { GunGameState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; GunGameWeaponOrder.SettingChanged += delegate { GunGameState.PushSettingsIfHost(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 1618033990u, 0); MyceliumNetwork.LobbyCreated += GunGameState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += GunGameState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += GunGameState.OnPlayerEntered; } [CustomRPC] public void SyncGunGameSettings(CSteamID hostId, int roundId, int revision, bool enabled, string weaponOrder) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (GunGameState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { GunGameState.ApplySettings(enabled, weaponOrder); } } [CustomRPC] public void SyncGunGameLiveState(CSteamID hostId, string progressData, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GunGameState.ApplyLiveState(hostId, progressData, roundId, revision); } private void InitializeHealthSettings() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown HealthTweaksEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Settings", "Health Tweaks Enabled", true, "Host-controlled: master switch. Turn off to restore normal health and disable regeneration."); MaxHealthPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Health Settings", "Max Health %", 100, new ConfigDescription("Host-controlled: max health as a percent of normal.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 400), Array.Empty<object>())); HealthRegenEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Settings", "Enable Health Regen", true, "Host-controlled: enables health regeneration after taking damage."); HealthRegenDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Health Settings", "Regen Delay (seconds)", 5, new ConfigDescription("Host-controlled: delay after taking damage before health regeneration starts.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 15), Array.Empty<object>())); HealthRegenRate = ((BaseUnityPlugin)this).Config.Bind<int>("Health Settings", "Regen Rate (health per second)", 150, new ConfigDescription("Host-controlled: displayed HUD health restored per second after the regen delay.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[6] { 50, 100, 150, 200, 300, 400 }), Array.Empty<object>())); if (HealthRegenRate.Value != 50 && HealthRegenRate.Value != 100 && HealthRegenRate.Value != 150 && HealthRegenRate.Value != 200 && HealthRegenRate.Value != 300 && HealthRegenRate.Value != 400) { HealthRegenRate.Value = 150; } HealthTweaksEnabled.SettingChanged += delegate { HealthSettingsState.PushIfHost(); }; MaxHealthPercent.SettingChanged += delegate { HealthSettingsState.PushIfHost(); }; HealthRegenEnabled.SettingChanged += delegate { HealthSettingsState.PushIfHost(); }; HealthRegenDelaySeconds.SettingChanged += delegate { HealthSettingsState.PushIfHost(); }; HealthRegenRate.SettingChanged += delegate { HealthSettingsState.PushIfHost(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 1892737466u, 0); MyceliumNetwork.LobbyCreated += HealthSettingsState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += HealthSettingsState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += HealthSettingsState.OnPlayerEntered; } [CustomRPC] public void SyncHealthSettings(CSteamID hostId, int roundId, int revision, bool enabled, int maxHealthPercent, bool regenEnabled, int regenDelaySeconds, int regenRate) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (HealthSettingsState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { Logger.LogInfo((object)$"[HealthSettings] Received sync: tweaks={enabled} maxHealth%={maxHealthPercent} regen={regenEnabled} delay={regenDelaySeconds:0.##} rate={regenRate}"); HealthSettingsState.Apply(enabled, maxHealthPercent, regenEnabled, regenDelaySeconds, regenRate); } } private void InitializeHotPotato() { HotPotatoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Hot Potato Enabled", false, "Host-controlled: one player has a BaseballBat, all other players have Shotgun, and kills score points."); HotPotatoEnabled.SettingChanged += delegate { HotPotatoState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 2718281830u, 0); MyceliumNetwork.LobbyCreated += HotPotatoState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += HotPotatoState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += HotPotatoState.OnPlayerEntered; } [CustomRPC] public void SyncHotPotatoSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (HotPotatoState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { HotPotatoState.ApplySettings(enabled); } } [CustomRPC] public void SyncHotPotatoLiveState(CSteamID hostId, string killsData, int potatoPlayerId, int winnerId, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HotPotatoState.ApplyLiveState(hostId, killsData, potatoPlayerId, winnerId, roundId, revision); } [CustomRPC] public void HotPotatoAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } private void InitializeInfidel() { InfidelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Infidel Enabled", false, "Host-controlled: one private Infidel role, delayed AK loadouts, slow movement, and role-based scoring."); InfidelEnabled.SettingChanged += delegate { InfidelState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 2718281831u, 0); MyceliumNetwork.LobbyCreated += InfidelState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += InfidelState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += InfidelState.OnPlayerEntered; } [CustomRPC] public void SyncInfidelSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (InfidelState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { InfidelState.ApplySettings(enabled); } } [CustomRPC] public void SyncInfidelLiveState(CSteamID hostId, string scoresData, int winnerId, int subRoundId, bool weaponsUnlocked, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) InfidelState.ApplyLiveState(hostId, scoresData, winnerId, subRoundId, weaponsUnlocked, roundId, revision); } [CustomRPC] public void SyncInfidelRole(CSteamID hostId, int subRoundId, bool isInfidel, bool announce) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) InfidelState.ApplyLocalRole(hostId, subRoundId, isInfidel, announce); } [CustomRPC] public void InfidelAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } private void InitializeJuggernaut() { JuggernautEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Juggernaut Enabled", false, "Host-controlled: first blood becomes the Juggernaut; everyone else hunts them for the crown."); JuggernautEnabled.SettingChanged += delegate { JuggernautState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 3141592653u, 0); MyceliumNetwork.LobbyCreated += JuggernautState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += JuggernautState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += JuggernautState.OnPlayerEntered; } [CustomRPC] public void SyncJuggernautSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (JuggernautState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { Logger.LogInfo((object)$"[Juggernaut] Received settings sync: enabled={enabled}"); JuggernautState.ApplySettings(enabled); } } [CustomRPC] public void SyncJuggernautLiveState(CSteamID hostId, int juggernautPlayerId, int juggernautKills, string pointsData, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) JuggernautState.ApplyLiveState(hostId, juggernautPlayerId, juggernautKills, pointsData, roundId, revision); } [CustomRPC] public void JuggernautAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } [CustomRPC] public void JuggernautAnnounceTarget(string text) { GameModeHud.AnnounceTarget(ClientInstance.ReplaceAllPlayerNameTags(text)); } private void InitializeKillTheRat() { KillTheRatEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Kill the Rat Enabled", false, "Host-controlled: the Rat gains one point per second; players gain ten points for killing the Rat."); KillTheRatEnabled.SettingChanged += delegate { KillTheRatState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 3141592655u, 0); MyceliumNetwork.LobbyCreated += KillTheRatState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += KillTheRatState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += KillTheRatState.OnPlayerEntered; } [CustomRPC] public void SyncKillTheRatSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (KillTheRatState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { KillTheRatState.ApplySettings(enabled); } } [CustomRPC] public void SyncKillTheRatLiveState(CSteamID hostId, int ratPlayerId, string pointsData, int winnerId, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) KillTheRatState.ApplyLiveState(hostId, ratPlayerId, pointsData, winnerId, roundId, revision); } [CustomRPC] public void KillTheRatAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } private void InitializeMichaelMeyers() { MichaelMeyersEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Michael Meyers Enabled", false, "Host-controlled: one player hunts the other players with a Couperet; the last player alive wins."); MichaelMeyersEnabled.SettingChanged += delegate { MichaelMeyersState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 3141592654u, 0); MyceliumNetwork.LobbyCreated += MichaelMeyersState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += MichaelMeyersState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += MichaelMeyersState.OnPlayerEntered; } [CustomRPC] public void SyncMichaelMeyersSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (MichaelMeyersState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { MichaelMeyersState.ApplySettings(enabled); } } [CustomRPC] public void SyncMichaelMeyersLiveState(CSteamID hostId, int michaelPlayerId, int survivorCount, bool oneVsOne, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) MichaelMeyersState.ApplyLiveState(hostId, michaelPlayerId, survivorCount, oneVsOne, roundId, revision); } [CustomRPC] public void MichaelMeyersAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } private void InitializeOneInTheChamber() { OneInTheChamberEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "One in the Chamber Enabled", false, "Host-controlled: players get one Pistol shot, a Couperet, and no respawns; the last player alive wins."); OneInTheChamberEnabled.SettingChanged += delegate { OneInTheChamberState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 2718281829u, 0); MyceliumNetwork.LobbyCreated += OneInTheChamberState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += OneInTheChamberState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += OneInTheChamberState.OnPlayerEntered; } [CustomRPC] public void SyncOneInTheChamberSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (OneInTheChamberState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { OneInTheChamberState.ApplySettings(enabled); } } [CustomRPC] public void SyncOneInTheChamberLiveState(CSteamID hostId, string aliveData, string bulletsData, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OneInTheChamberState.ApplyLiveState(hostId, aliveData, bulletsData, roundId, revision); } [CustomRPC] public void OneInTheChamberAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } private void Awake() { //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; InitializeSafely("compatibility checks", FishNetCompatibility.LogPreflight); InitializeSafely("weapon service", WeaponService.Initialize); InitializeSafely("game mode manager", GameModeManager.Initialize); InitializeSafely("global modifiers", InitializeGlobalModifiers); InitializeSafely("health settings", InitializeHealthSettings); InitializeSafely("global weapons", InitializeGlobalWeapons); InitializeSafely("default game mode", InitializeDefaultGameMode); InitializeSafely("Michael Meyers", InitializeMichaelMeyers); InitializeSafely("Kill the Rat", InitializeKillTheRat); InitializeSafely("One in the Chamber", InitializeOneInTheChamber); InitializeSafely("Hot Potato", InitializeHotPotato); InitializeSafely("Infidel", InitializeInfidel); InitializeSafely("Free For All", InitializeFFA); InitializeSafely("Juggernaut", InitializeJuggernaut); InitializeSafely("Gun Game", InitializeGunGame); InitializeSafely("Sniper Battle", InitializeSniperBattle); try { ((Component)this).gameObject.AddComponent<GameModeHud>(); } catch (Exception ex) { Logger.LogError((object)("[GameModeHud] Startup failed: " + ex.GetBaseException().Message)); } PatchAllSafely(new Harmony("StraftatEightsPlugin")); Logger.LogInfo((object)"Plugin StraftatEightsPlugin is loaded!"); } private static void InitializeSafely(string featureName, Action initialize) { try { initialize(); } catch (Exception ex) { Logger.LogError((object)("[Startup] Failed to initialize " + featureName + ": " + ex.GetBaseException().Message)); } } private static void PatchAllSafely(Harmony harmony) { Type[] array; try { array = (from type2 in AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly) where type2.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0 select type2).OrderBy<Type, string>((Type type2) => type2.FullName, StringComparer.Ordinal).ToArray(); } catch (Exception ex) { Logger.LogError((object)("[Harmony] Could not discover patch classes: " + ex.GetBaseException().Message)); return; } Type[] array2 = array; foreach (Type type in array2) { try { int num2 = harmony.CreateClassProcessor(type).Patch().Count(); if (num2 == 0) { HarmonyPatchStatus.RecordFailure(type, "no patch target was installed"); Logger.LogError((object)("[Harmony] Disabled patch class " + type.FullName + ": no patch target was installed.")); } else { Logger.LogInfo((object)$"[Harmony] Patched {type.FullName} ({num2} method(s))."); } } catch (Exception ex2) { HarmonyPatchStatus.RecordFailure(type, ex2.GetBaseException().Message); Logger.LogError((object)("[Harmony] Disabled patch class " + type.FullName + ": " + ex2.GetBaseException().Message)); } } } private void Update() { GameModeManager.PeriodicPushIfHost(); GameModeManager.PeriodicActiveModePushIfHost(); GlobalModifiersState.PeriodicPushIfHost(); HealthSettingsState.PeriodicPushIfHost(); HealthSettingsState.ServerTick(); WeaponSettingsState.UpdateLocalCycle(); WeaponSettingsState.PeriodicPushIfHost(); WeaponSettingsState.EnsureCycleLoadouts(); GameModeManager.EnsureActiveModeLoadouts(); JuggernautOutline.EnforceOutline(); MichaelMeyersOutline.EnforceOutline(); KillTheRatOutline.EnforceOutline(); } [CustomRPC] public void SyncScorePopup(int amount) { if (amount > 0 && amount <= 100) { GameModeHud.ShowScorePopup(amount); } } [CustomRPC] public void SyncGlobalSettings(CSteamID hostId, int roundId, int revision, float respawnDelaySeconds, int pointsToWin) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (GameModeManager.TryAcceptGlobalSettingsSnapshot(hostId, roundId, revision)) { GameModeManager.ApplyGlobalSettings(respawnDelaySeconds, pointsToWin); } } [CustomRPC] public void SyncActiveGameMode(CSteamID hostId, int mode, int roundId, int phase, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (GameModeManager.TryAcceptActiveModeSnapshot(hostId, roundId, revision)) { GameModeManager.ApplyActiveMode(mode, roundId, phase); } } private void InitializeSniperBattle() { SniperBattleEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Game Mode Settings", "Sniper Battle Enabled", false, "Host-controlled: players respawn with only the M2000, which has unlimited ammo, and score ten points per kill."); SniperBattleEnabled.SettingChanged += delegate { SniperBattleState.PushSettingsIfHost(); GameModeManager.OnSettingsChanged(); }; MyceliumNetwork.RegisterNetworkObject((object)this, 1618033992u, 0); MyceliumNetwork.LobbyCreated += SniperBattleState.OnLobbyEntered; MyceliumNetwork.LobbyEntered += SniperBattleState.OnLobbyEntered; MyceliumNetwork.PlayerEntered += SniperBattleState.OnPlayerEntered; } [CustomRPC] public void SyncSniperBattleSettings(CSteamID hostId, int roundId, int revision, bool enabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SniperBattleState.TryAcceptSettingsSnapshot(hostId, roundId, revision)) { SniperBattleState.ApplySettings(enabled); } } [CustomRPC] public void SyncSniperBattleLiveState(CSteamID hostId, string pointsData, int winnerId, int roundId, int revision) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) SniperBattleState.ApplyLiveState(hostId, pointsData, winnerId, roundId, revision); } [CustomRPC] public void SniperBattleAnnounce(string text) { if ((Object)(object)PauseManager.Instance != (Object)null) { PauseManager.Instance.WriteLog(ClientInstance.ReplaceAllPlayerNameTags(text)); } } } internal static class FFAState { internal static bool Enabled; internal static int WinnerId = -1; internal static readonly Dictionary<int, int> Kills = new Dictionary<int, int>(); private static readonly ModeSyncState Sync = new ModeSyncState(); internal static int KillsToWin => GameModeManager.EffectivePointsToWin; internal static void ApplySettings(bool enabled) { bool num = Enabled != enabled; Enabled = enabled; if (num) { ResetMatchState(); } } private static void ApplySettingsFromHostConfig() { ApplySettings(Plugin.FFAEnabled.Value); } internal static void PushSettingsIfHost() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { ApplySettingsFromHostConfig(); MyceliumNetwork.RPC(2718281828u, "SyncFFASettings", (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.NextSettingsRevision(), Plugin.FFAEnabled.Value }); } } internal static void PeriodicPushSettingsIfHost() { if (Sync.IsSettingsPushDue()) { PushSettingsIfHost(); } } internal static void PeriodicPushIfHost() { PeriodicPushSettingsIfHost(); if (Sync.IsLivePushDue()) { BroadcastLiveState(); } } internal static void OnLobbyEntered() { Sync.ResetForLobby(); if (MyceliumNetwork.IsHost) { ApplySettingsFromHostConfig(); ResetMatchState(); } } internal static void OnPlayerEntered(CSteamID player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.IsHost) { MyceliumNetwork.RPCTarget(2718281828u, "SyncFFASettings", player, (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.SettingsRevision, Plugin.FFAEnabled.Value }); MyceliumNetwork.RPCTarget(2718281828u, "SyncFFALiveState", player, (ReliableType)1, new object[5] { MyceliumNetwork.LobbyHost, SerializeKills(), WinnerId, GameModeManager.RoundId, Sync.LiveRevision }); } } internal static bool TryAcceptSettingsSnapshot(CSteamID hostId, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Sync.TryAcceptSettingsSnapshot(hostId, roundId, revision); } internal static void ResetMatchState() { Sync.ResetLiveState(); WinnerId = -1; Kills.Clear(); } internal static void ApplyLiveState(CSteamID hostId, string killsData, int winnerId, int roundId, int revision) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (winnerId < -1 || !Sync.TryAcceptLiveSnapshot(hostId, roundId, revision)) { return; } WinnerId = winnerId; Kills.Clear(); foreach (KeyValuePair<int, int> item in ScoreCodec.Parse(killsData, KillsToWin)) { Kills[item.Key] = item.Value; } } internal static void OnServerKill(int deadPlayerId, int killerId) { if (Enabled && WinnerId < 0 && killerId >= 0 && killerId != deadPlayerId) { Kills.TryGetValue(killerId, out var value); int num = value + 10; Kills[killerId] = num; GameModeHud.ShowScorePopupForPlayer(killerId, 10); if (num >= KillsToWin) { WinnerId = killerId; Announce(PlayerLookup.GetPlayerNameTag(killerId) + " reached " + KillsToWin + " points and won the round!"); GameModeManager.CompleteCustomRound(ScoreManager.Instance.GetTeamId(killerId)); } BroadcastLiveState(); } } internal static string SerializeKills() { return ScoreCodec.Serialize(Kills); } private static void BroadcastLiveState() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { MyceliumNetwork.RPC(2718281828u, "SyncFFALiveState", (ReliableType)1, new object[5] { MyceliumNetwork.LobbyHost, SerializeKills(), WinnerId, GameModeManager.RoundId, Sync.NextLiveRevision() }); } } private static void Announce(string text) { if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { MyceliumNetwork.RPC(2718281828u, "FFAAnnounce", (ReliableType)1, new object[1] { text }); } } } [HarmonyPatch(typeof(FirstPersonController), "HandleAddingForce")] internal static class FirstPersonController_SlideBoost_Patch { private static void Postfix(FirstPersonController __instance) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!GlobalModifiersState.SlideBoostEnabled && __instance.isSliding) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(__instance.moveDirection.x, 0f, __instance.moveDirection.z); Vector3 val2 = val + __instance.forceAdded; float effectiveSprintSpeed = MovementTuning.GetEffectiveSprintSpeed(__instance); float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude > effectiveSprintSpeed && magnitude > 0.0001f) { __instance.forceAdded = val2 * (effectiveSprintSpeed / magnitude) - val; } } } } [HarmonyPatch(typeof(FirstPersonController), "Jump")] internal static class FirstPersonController_SlideJumpForce_Patch { private static void Prefix(FirstPersonController __instance) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (!GlobalModifiersState.SlideBoostEnabled && __instance.isSliding) { __instance.forceFactor = 0f; __instance.forceAdded = Vector3.zero; __instance.force = Vector3.zero; __instance.isCrouching = false; } } } [HarmonyPatch(typeof(FirstPersonController), "BForce")] internal static class FirstPersonController_WallJumpBoostTrack_Patch { private static void Prefix(FirstPersonController __instance) { MovementTuning.MarkWallJumpBForce(__instance, __instance.CanWallJump); } } [HarmonyPatch(typeof(FirstPersonController), "BForce")] internal static class FirstPersonController_SlideJumpBoostTrack_Patch { private static void Prefix(FirstPersonController __instance) { MovementTuning.MarkSlideBForce(__instance, __instance.IsSliding); } private static void Postfix(FirstPersonController __instance) { if (!GlobalModifiersState.SlideBoostEnabled) { MovementTuning.SuppressSlideBoost(__instance); } } } [HarmonyPatch(typeof(FirstPersonController), "HandleBForce")] internal static class FirstPersonController_WallJumpBoost_Patch { private static void Postfix(FirstPersonController __instance) { if (!GlobalModifiersState.WallJumpBoostEnabled) { MovementTuning.ClampWallJumpBoost(__instance, MovementTuning.GetEffectiveSprintSpeed(__instance)); } } } [HarmonyPatch(typeof(FirstPersonController), "Update")] [HarmonyPriority(800)] internal static class FirstPersonController_Speed_Patch { private static float _nextOwnerLogTime; private static void Prefix(FirstPersonController __instance) { float num = (__instance.isAiming ? GlobalModifiersState.AdsSpeedMultiplier : 1f); __instance.movementFactor = GlobalModifiersState.SpeedMultiplier * num; __instance.gravityMultiplier = GlobalModifiersState.GravityMultiplier; if (((NetworkBehaviour)__instance).IsOwner && Time.unscaledTime >= _nextOwnerLogTime) { _nextOwnerLogTime = Time.unscaledTime + 5f; Plugin.Logger.LogInfo((object)$"[GlobalModifiers] Enforcing on local player: movementFactor={__instance.movementFactor:0.00} gravityMultiplier={__instance.gravityMultiplier:0.00} (SpeedMultiplier={GlobalModifiersState.SpeedMultiplier:0.00}, GravityMultiplier={GlobalModifiersState.GravityMultiplier:0.00}, Enabled={GlobalModifiersState.Enabled}, TuningVersion={GlobalModifiersState.TuningVersion})"); } MovementTuning.ApplyTuningIfChanged(__instance, GlobalModifiersState.MomentumPercent, GlobalModifiersState.AirSpeedRatioPercent, GlobalModifiersState.TuningVersion); } } [HarmonyPatch] internal static class FirstPersonController_Tuning_Patch { private static MethodBase? TargetMethod() { return typeof(FirstPersonController).GetMethod("Awake___UserLogic", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(FirstPersonController).GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private static bool Prepare() { return TargetMethod() != null; } private static void Postfix(FirstPersonController __instance) { MovementTuning.ApplyTuningIfChanged(__instance, GlobalModifiersState.MomentumPercent, GlobalModifiersState.AirSpeedRatioPercent, GlobalModifiersState.TuningVersion); } } [HarmonyPatch(typeof(FirstPersonController), "HandleMovementInput")] internal static class FirstPersonController_Momentum_Patch { private static void Postfix(FirstPersonController __instance) { MovementTuning.BlendHorizontalVelocity(__instance, GlobalModifiersState.MomentumPercent); } } internal static class GlobalModifiersState { internal static bool Enabled; internal static bool WallJumpEnabled = true; internal static bool SlidingEnabled = true; internal static bool SlideBoostEnabled = true; internal static bool WallJumpBoostEnabled = true; internal static float SpeedMultiplier = 1f; internal static float AdsSpeedMultiplier = 0.8f; internal static float GravityMultiplier = 1f; internal static float MomentumPercent = 100f; internal static float AirSpeedRatioPercent = 116.666664f; internal static int TuningVersion; private static readonly ModeSyncState Sync = new ModeSyncState(); internal static void Apply(bool enabled, bool wallJump, bool sliding, bool slideBoost, bool wallJumpBoost, int moveSpeedPercent, int adsSpeedPercent, int gravityPercent, int momentumPercent, int airSpeedRatioPercent) { Enabled = enabled; if (!enabled) { WallJumpEnabled = true; SlidingEnabled = true; SlideBoostEnabled = true; WallJumpBoostEnabled = true; SpeedMultiplier = 1f; AdsSpeedMultiplier = 1f; GravityMultiplier = 1f; MomentumPercent = 100f; AirSpeedRatioPercent = 116.666664f; TuningVersion++; Plugin.Logger.LogInfo((object)"[GlobalModifiers] Apply: disabled - all values reset to stock"); return; } moveSpeedPercent = Mathf.Clamp(moveSpeedPercent, 50, 200); adsSpeedPercent = Mathf.Clamp(adsSpeedPercent, 50, 100); gravityPercent = Mathf.Clamp(gravityPercent, 10, 100); momentumPercent = Mathf.Clamp(momentumPercent, 10, 400); airSpeedRatioPercent = Mathf.Clamp(airSpeedRatioPercent, 50, 200); WallJumpEnabled = wallJump; SlidingEnabled = sliding; SlideBoostEnabled = slideBoost; WallJumpBoostEnabled = wallJumpBoost; SpeedMultiplier = (float)moveSpeedPercent / 100f; AdsSpeedMultiplier = (float)adsSpeedPercent / 100f; GravityMultiplier = (float)gravityPercent / 100f; MomentumPercent = momentumPercent; AirSpeedRatioPercent = airSpeedRatioPercent; TuningVersion++; Plugin.Logger.LogInfo((object)$"[MovementSettings] Apply: SpeedMultiplier={SpeedMultiplier:0.00} AdsSpeedMultiplier={AdsSpeedMultiplier:0.00} GravityMultiplier={GravityMultiplier:0.00} MomentumPercent={MomentumPercent} AirSpeedRatioPercent={AirSpeedRatioPercent} TuningVersion={TuningVersion}"); } private static void ApplyFromHostConfig() { Apply(Plugin.MovementTweaksEnabled.Value, Plugin.WallJumpEnabled.Value, Plugin.SlidingEnabled.Value, Plugin.SlideBoostEnabled.Value, Plugin.WallJumpBoostEnabled.Value, Plugin.MoveSpeedPercent.Value, Plugin.AdsSpeedPercent.Value, Plugin.GravityPercent.Value, Plugin.MomentumPercent.Value, Plugin.AirSpeedRatioPercent.Value); } internal static void PushIfHost() { if (!MyceliumNetwork.InLobby || !MyceliumNetwork.IsHost) { Plugin.Logger.LogInfo((object)$"[GlobalModifiers] PushIfHost skipped: InLobby={MyceliumNetwork.InLobby} IsHost={MyceliumNetwork.IsHost}"); return; } ApplyFromHostConfig(); Plugin.Logger.LogInfo((object)$"[MovementSettings] Host broadcasting movement settings to {MyceliumNetwork.PlayerCount} player(s)"); MyceliumNetwork.RPC(1892737465u, "SyncMovementSettings", (ReliableType)1, RpcArgs(Sync.NextSettingsRevision())); } internal static void PeriodicPushIfHost() { if (Sync.IsSettingsPushDue()) { PushIfHost(); } } internal static void OnLobbyEntered() { Plugin.Logger.LogInfo((object)$"[GlobalModifiers] Lobby session started, IsHost={MyceliumNetwork.IsHost}"); Sync.ResetForLobby(); if (MyceliumNetwork.IsHost) { ApplyFromHostConfig(); } } internal static void ResetForLobbyLeft() { Sync.ResetForLobby(); Apply(enabled: false, wallJump: true, sliding: true, slideBoost: true, wallJumpBoost: true, 100, 100, 100, 100, Mathf.RoundToInt(116.666664f)); } internal static void OnPlayerEntered(CSteamID player) { //IL_0012: 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) if (MyceliumNetwork.IsHost) { Plugin.Logger.LogInfo((object)$"[MovementSettings] Sending catch-up movement settings to newly joined player {player}"); MyceliumNetwork.RPCTarget(1892737465u, "SyncMovementSettings", player, (ReliableType)1, RpcArgs(Sync.SettingsRevision)); } } internal static bool TryAcceptSettingsSnapshot(CSteamID hostId, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Sync.TryAcceptSettingsSnapshot(hostId, roundId, revision); } private static object[] RpcArgs(int revision) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) return new object[13] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, revision, Plugin.MovementTweaksEnabled.Value, Plugin.WallJumpEnabled.Value, Plugin.SlidingEnabled.Value, Plugin.SlideBoostEnabled.Value, Plugin.WallJumpBoostEnabled.Value, Plugin.MoveSpeedPercent.Value, Plugin.AdsSpeedPercent.Value, Plugin.GravityPercent.Value, Plugin.MomentumPercent.Value, Plugin.AirSpeedRatioPercent.Value }; } } internal static class MovementTuning { private sealed class VelocityMemory { public Vector3 Value; public bool Initialized; } private const float BaseAcceleration = 15f; internal const float StockAirSpeedRatioPercent = 116.666664f; private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static FieldInfo _globalAcceleration = null; private static FieldInfo _globalDeceleration = null; private static FieldInfo _walkAcceleration = null; private static FieldInfo _sprintAcceleration = null; private static FieldInfo _crouchAcceleration = null; private static FieldInfo _airAcceleration = null; private static FieldInfo _sprintAirAcceleration = null; private static FieldInfo _walkSpeed = null; private static FieldInfo _sprintSpeed = null; private static FieldInfo _airSpeed = null; private static FieldInfo _sprintAirSpeed = null; private static FieldInfo _bforcefinal = null; private static FieldInfo _bfactor = null; private static bool _cached; private static readonly ConditionalWeakTable<FirstPersonController, StrongBox<int>> LastAppliedVersion = new ConditionalWeakTable<FirstPersonController, StrongBox<int>>(); private static readonly ConditionalWeakTable<FirstPersonController, VelocityMemory> VelocityByController = new ConditionalWeakTable<FirstPersonController, VelocityMemory>(); private static readonly ConditionalWeakTable<FirstPersonController, StrongBox<bool>> WallJumpBForceActive = new ConditionalWeakTable<FirstPersonController, StrongBox<bool>>(); private static readonly ConditionalWeakTable<FirstPersonController, StrongBox<bool>> SlideBForceActive = new ConditionalWeakTable<FirstPersonController, StrongBox<bool>>(); private static void EnsureCached() { if (!_cached) { Type? typeFromHandle = typeof(FirstPersonController); _globalAcceleration = typeFromHandle.GetField("globalAcceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _globalDeceleration = typeFromHandle.GetField("globalDeceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _walkAcceleration = typeFromHandle.GetField("walkAcceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sprintAcceleration = typeFromHandle.GetField("sprintAcceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _crouchAcceleration = typeFromHandle.GetField("crouchAcceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _airAcceleration = typeFromHandle.GetField("airAcceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sprintAirAcceleration = typeFromHandle.GetField("sprintAirAcceleration", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _walkSpeed = typeFromHandle.GetField("walkSpeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sprintSpeed = typeFromHandle.GetField("sprintSpeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _airSpeed = typeFromHandle.GetField("airSpeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sprintAirSpeed = typeFromHandle.GetField("sprintAirSpeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _bforcefinal = typeFromHandle.GetField("bforcefinal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _bfactor = typeFromHandle.GetField("bfactor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _cached = true; } } internal static void ApplyTuning(FirstPersonController controller, float momentumPercent, float airSpeedRatioPercent) { EnsureCached(); float num = ((momentumPercent <= 0f) ? 15f : (1500f / momentumPercent)); _globalAcceleration.SetValue(controller, num); _globalDeceleration.SetValue(controller, num); _walkAcceleration.SetValue(controller, num); _sprintAcceleration.SetValue(controller, num); _crouchAcceleration.SetValue(controller, num); _airAcceleration.SetValue(controller, num); _sprintAirAcceleration.SetValue(controller, num); float num2 = airSpeedRatioPercent / 100f; float num3 = (float)_walkSpeed.GetValue(controller); float num4 = (float)_sprintSpeed.GetValue(controller); _airSpeed.SetValue(controller, num3 * num2); _sprintAirSpeed.SetValue(controller, num4 * num2); } internal static void ApplyTuningIfChanged(FirstPersonController controller, float momentumPercent, float airSpeedRatioPercent, int version) { StrongBox<int> orCreateValue = LastAppliedVersion.GetOrCreateValue(controller); if (orCreateValue.Value != version) { ApplyTuning(controller, momentumPercent, airSpeedRatioPercent); orCreateValue.Value = version; } } internal static float GetSprintSpeed(FirstPersonController controller) { EnsureCached(); return (float)_sprintSpeed.GetValue(controller); } internal static float GetEffectiveSprintSpeed(FirstPersonController controller) { return GetSprintSpeed(controller) * GlobalModifiersState.SpeedMultiplier; } internal static void BlendHorizontalVelocity(FirstPersonController controller, float momentumPercent) { //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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) VelocityMemory orCreateValue = VelocityByController.GetOrCreateValue(controller); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(controller.moveDirection.x, 0f, controller.moveDirection.z); if (!orCreateValue.Initialized) { orCreateValue.Value = val; orCreateValue.Initialized = true; } else { float num = Mathf.Clamp01(((momentumPercent <= 0f) ? 15f : (1500f / momentumPercent)) * Time.deltaTime); orCreateValue.Value = Vector3.Lerp(orCreateValue.Value, val, num); controller.moveDirection = new Vector3(orCreateValue.Value.x, controller.moveDirection.y, orCreateValue.Value.z); } } internal static void MarkWallJumpBForce(FirstPersonController controller, bool isWallJump) { WallJumpBForceActive.GetOrCreateValue(controller).Value = isWallJump; } internal static void MarkSlideBForce(FirstPersonController controller, bool isSliding) { SlideBForceActive.GetOrCreateValue(controller).Value = isSliding; } internal static void SuppressSlideBoost(FirstPersonController controller) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (SlideBForceActive.TryGetValue(controller, out StrongBox<bool> value) && value.Value) { EnsureCached(); _bfactor.SetValue(controller, 0f); _bforcefinal.SetValue(controller, Vector3.zero); value.Value = false; } } internal static void ClampWallJumpBoost(FirstPersonController controller, float capSpeed) { //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_006f: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!WallJumpBForceActive.TryGetValue(controller, out StrongBox<bool> value) || !value.Value) { return; } EnsureCached(); if ((float)_bfactor.GetValue(controller) <= 0f) { value.Value = false; return; } Vector3 val = (Vector3)_bforcefinal.GetValue(controller); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(controller.moveDirection.x, 0f, controller.moveDirection.z); Vector3 val3 = val2 + val; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude > capSpeed && magnitude > 0.0001f) { _bforcefinal.SetValue(controller, val3 * (capSpeed / magnitude) - val2); } } } [HarmonyPatch(typeof(PlayerManager), "SpawnPlayer", new Type[] { typeof(int), typeof(int), typeof(Vector3), typeof(Quaternion) })] internal static class PlayerManager_GlobalWeaponsSpawn_Patch { private static void Postfix(PlayerManager __instance) { if (GameModeManager.ShouldIgnoreGlobalWeaponSettings || !WeaponSettingsState.Enabled || !WeaponSettingsState.Cycle || (Object)(object)__instance.player == (Object)null) { return; } ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); if ((Object)(object)component != (Object)null && !JuggernautState.IsCurrentJuggernaut(__instance.player)) { string selectedWeapon = WeaponSettingsState.GetSelectedWeapon(component.PlayerId); if (selectedWeapon != null) { WeaponSettingsState.RequestLoadout(component.PlayerId, selectedWeapon); } } } } [HarmonyPatch(typeof(PlayerPickup), "RightHandFix")] internal static class PlayerPickup_WeaponHandPolicy_Patch { private static bool Prefix(PlayerPickup __instance) { if (!GameModeManager.ShouldIgnoreGlobalWeaponSettings && WeaponSettingsState.Enabled && WeaponSettingsState.Cycle) { WeaponService.AttachUnparentedWeapon(__instance); } return !WeaponService.IsOwnerAttachmentPending(__instance); } } internal static class WeaponSettingsState { internal static bool Enabled; internal static bool Cycle; internal static int SpareMagazines = 5; internal static List<string> Allowed = new List<string>(); private static readonly Dictionary<int, string> SelectedWeapons = new Dictionary<int, string>(); private static readonly Dictionary<int, float> PendingLoadouts = new Dictionary<int, float>(); private static float _nextLoadoutCheckTime; private static readonly ModeSyncState Sync = new ModeSyncState(); internal static void Apply(bool enabled, string allowedWeapons, int spareMagazines, bool cycleWeapons) { spareMagazines = Mathf.Clamp(spareMagazines, 2, 10); if (allowedWeapons == null) { allowedWeapons = string.Empty; } List<string> list = WeaponService.ParseWeaponList(allowedWeapons); bool num = Enabled != enabled || Cycle != cycleWeapons || SpareMagazines != spareMagazines; bool flag = Allowed.Count != list.Count || !Allowed.SequenceEqual<string>(list, StringComparer.Ordinal); Enabled = enabled; Cycle = cycleWeapons; SpareMagazines = spareMagazines; Allowed = list; if (num || flag) { WeaponService.ResetPendingRequests(); PendingLoadouts.Clear(); _nextLoadoutCheckTime = 0f; } if (flag) { SelectedWeapons.Clear(); } } private static void ApplyFromConfig() { Apply(Plugin.WeaponTweaksEnabled.Value, Plugin.AllowedWeapons.Value, Plugin.SpareMagazines.Value, Plugin.CycleWeapons.Value); } internal static void PushIfHost() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { ApplyFromConfig(); MyceliumNetwork.RPC(1618033991u, "SyncWeaponSettings", (ReliableType)1, new object[7] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.NextSettingsRevision(), Plugin.WeaponTweaksEnabled.Value, Plugin.AllowedWeapons.Value, Plugin.SpareMagazines.Value, Plugin.CycleWeapons.Value }); } } internal static void PeriodicPushIfHost() { if (Sync.IsSettingsPushDue()) { PushIfHost(); } } internal static void OnLobbyEntered() { Sync.ResetForLobby(); SelectedWeapons.Clear(); PendingLoadouts.Clear(); if (MyceliumNetwork.IsHost) { ApplyFromConfig(); } } internal static void ResetForLobbyLeft() { SelectedWeapons.Clear(); PendingLoadouts.Clear(); Sync.ResetForLobby(); Apply(enabled: false, string.Empty, 5, cycleWeapons: false); } internal static void OnPlayerEntered(CSteamID player) { //IL_0014: 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) if (MyceliumNetwork.IsHost) { MyceliumNetwork.RPCTarget(1618033991u, "SyncWeaponSettings", player, (ReliableType)1, new object[7] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.SettingsRevision, Plugin.WeaponTweaksEnabled.Value, Plugin.AllowedWeapons.Value, Plugin.SpareMagazines.Value, Plugin.CycleWeapons.Value }); } } internal static bool TryAcceptSettingsSnapshot(CSteamID hostId, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Sync.TryAcceptSettingsSnapshot(hostId, roundId, revision); } internal static void UpdateLocalCycle() { if (!GameModeManager.ShouldIgnoreGlobalWeaponSettings && Enabled && Cycle && Input.GetKeyDown((KeyCode)289) && Allowed.Count != 0 && !((Object)(object)ClientInstance.Instance == (Object)null) && !JuggernautState.IsCurrentJuggernaut(ClientInstance.Instance.PlayerSpawner?.player)) { if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { GiveCycledWeapon(ClientInstance.Instance.PlayerId); } else if (MyceliumNetwork.InLobby) { MyceliumNetwork.RPC(1618033991u, "RequestWeaponCycle", (ReliableType)1, new object[1] { ClientInstance.Instance.PlayerId }); } } } internal static void GiveCycledWeapon(int playerId) { if (!GameModeManager.IsActive(GameMode.Juggernaut) || playerId != JuggernautState.CurrentJuggernautPlayerId) { string selectedWeapon = GetSelectedWeapon(playerId); if (selectedWeapon != null) { int num = Allowed.IndexOf(selectedWeapon); string text = Allowed[(num + 1) % Allowed.Count]; SelectedWeapons[playerId] = text; RequestLoadout(playerId, text); } } } internal static void RequestLoadout(int playerId, string weaponName) { if (!WeaponService.IsFinalGameScreen) { PendingLoadouts[playerId] = Time.unscaledTime + 5f; WeaponService.GiveWeapon(playerId, weaponName, SpareMagazines); } } internal static void EnsureCycleLoadouts() { if (GameModeManager.ShouldIgnoreGlobalWeaponSettings || !Enabled || !Cycle || WeaponService.IsFinalGameScreen || !MyceliumNetwork.InLobby || !MyceliumNetwork.IsHost || Time.unscaledTime < _nextLoadoutCheckTime) { return; } _nextLoadoutCheckTime = Time.unscaledTime + 1f; foreach (ClientInstance value2 in ClientInstance.playerInstances.Values) { if ((Object)(object)value2 == (Object)null || !Object.op_Implicit((Object)(object)value2) || (Object)(object)value2.PlayerSpawner == (Object)null || !Object.op_Implicit((Object)(object)value2.PlayerSpawner)) { continue; } FirstPersonController player = value2.PlayerSpawner.player; if ((Object)(object)player == (Object)null || !Object.op_Implicit((Object)(object)player) || (Object)(object)player.playerPickupScript == (Object)null || !Object.op_Implicit((Object)(object)player.playerPickupScript)) { continue; } string selectedWeapon = GetSelectedWeapon(value2.PlayerId); if (selectedWeapon != null && (!GameModeManager.IsActive(GameMode.Juggernaut) || value2.PlayerId != JuggernautState.CurrentJuggernautPlayerId)) { GameObject objInHand = player.playerPickupScript.objInHand; Weapon val = (((Object)(object)objInHand == (Object)null || !Object.op_Implicit((Object)(object)objInHand)) ? null : objInHand.GetComponent<Weapon>()); float value; if ((Object)(object)val != (Object)null && ((Object)val).name.StartsWith(selectedWeapon, StringComparison.Ordinal)) { WeaponAmmoTuning.Initialize(val, SpareMagazines); PendingLoadouts.Remove(value2.PlayerId); } else if (!PendingLoadouts.TryGetValue(value2.PlayerId, out value) || Time.unscaledTime >= value) { RequestLoadout(value2.PlayerId, selectedWeapon); } } } } internal static string? GetSelectedWeapon(int playerId) { if (Allowed.Count == 0) { return null; } if (SelectedWeapons.TryGetValue(playerId, out string value) && Allowed.Contains(value)) { return value; } string text = Allowed[0]; SelectedWeapons[playerId] = text; return text; } } [HarmonyPatch(typeof(PlayerManager), "SpawnPlayer", new Type[] { typeof(int), typeof(int), typeof(Vector3), typeof(Quaternion) })] internal static class PlayerManager_GunGameSpawn_Patch { private static void Postfix(PlayerManager __instance) { if (GameModeManager.IsActive(GameMode.GunGame) && !WeaponService.IsFinalGameScreen && !((Object)(object)__instance.player == (Object)null)) { ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); if ((Object)(object)component != (Object)null) { GunGameState.GiveStartingWeapon(component.PlayerId); } } } } internal static class GunGameState { internal static bool Enabled; internal static readonly Dictionary<int, int> Progress = new Dictionary<int, int>(); private static float _nextLoadoutCheckTime; private static readonly Dictionary<int, float> PendingLoadouts = new Dictionary<int, float>(); private static readonly ModeSyncState Sync = new ModeSyncState(); internal static List<string> WeaponOrder { get; private set; } = new List<string>(); internal static int ScoreLimit => GameModeManager.EffectivePointsToWin; internal static void ApplySettings(bool enabled, string weaponOrder) { List<string> list = WeaponService.ParseWeaponList(weaponOrder); bool num = Enabled != enabled || !WeaponOrder.SequenceEqual<string>(list, StringComparer.Ordinal); Enabled = enabled; WeaponOrder = list; if (num) { ResetMatchState(); } } private static void ApplyFromConfig() { ApplySettings(Plugin.GunGameEnabled.Value, Plugin.GunGameWeaponOrder.Value); } internal static void PushSettingsIfHost() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { ApplyFromConfig(); MyceliumNetwork.RPC(1618033990u, "SyncGunGameSettings", (ReliableType)1, new object[5] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.NextSettingsRevision(), Plugin.GunGameEnabled.Value, Plugin.GunGameWeaponOrder.Value }); } } internal static void PeriodicPushSettingsIfHost() { if (Sync.IsSettingsPushDue()) { PushSettingsIfHost(); } } internal static void PeriodicPushIfHost() { PeriodicPushSettingsIfHost(); if (Sync.IsLivePushDue()) { BroadcastLiveState(); } } internal static void OnLobbyEntered() { Sync.ResetForLobby(); if (MyceliumNetwork.IsHost) { ApplyFromConfig(); ResetMatchState(); } } internal static void OnPlayerEntered(CSteamID player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.IsHost) { MyceliumNetwork.RPCTarget(1618033990u, "SyncGunGameSettings", player, (ReliableType)1, new object[5] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.SettingsRevision, Plugin.GunGameEnabled.Value, Plugin.GunGameWeaponOrder.Value }); MyceliumNetwork.RPCTarget(1618033990u, "SyncGunGameLiveState", player, (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, SerializeProgress(), GameModeManager.RoundId, Sync.LiveRevision }); } } internal static bool TryAcceptSettingsSnapshot(CSteamID hostId, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Sync.TryAcceptSettingsSnapshot(hostId, roundId, revision); } internal static void ResetMatchState() { Sync.ResetLiveState(); _nextLoadoutCheckTime = 0f; PendingLoadouts.Clear(); Progress.Clear(); } internal static void ApplyLiveState(CSteamID hostId, string data, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!Sync.TryAcceptLiveSnapshot(hostId, roundId, revision)) { return; } Progress.Clear(); foreach (KeyValuePair<int, int> item in ScoreCodec.Parse(data, ScoreLimit)) { Progress[item.Key] = item.Value; } } internal static void OnServerKill(int deadPlayerId, int killerId) { if (Enabled && killerId >= 0 && killerId != deadPlayerId) { Progress.TryGetValue(killerId, out var value); int num = value + 10; Progress[killerId] = num; GameModeHud.ShowScorePopupForPlayer(killerId, 10); if (ScoreLimit > 0 && num >= ScoreLimit) { GameModeManager.CompleteCustomRound(ScoreManager.Instance.GetTeamId(killerId)); } else if (WeaponOrder.Count > 0) { GiveWeaponForProgress(killerId, num); } BroadcastLiveState(); } } private static int GetWeaponIndex(int progress) { if (WeaponOrder.Count <= 1 || ScoreLimit <= 1) { return 0; } return (int)Math.Min((long)progress * (long)(WeaponOrder.Count - 1) / (ScoreLimit - 1), WeaponOrder.Count - 1); } internal static void EnsureLoadouts() { if (!Enabled || !GameModeManager.IsActive(GameMode.GunGame) || !MyceliumNetwork.InLobby || !MyceliumNetwork.IsHost || WeaponService.IsFinalGameScreen || Time.unscaledTime < _nextLoadoutCheckTime) { return; } _nextLoadoutCheckTime = Time.unscaledTime + 1f; foreach (ClientInstance value3 in ClientInstance.playerInstances.Values) { if ((Object)(object)value3 == (Object)null || !Object.op_Implicit((Object)(object)value3) || (Object)(object)value3.PlayerSpawner == (Object)null || !Object.op_Implicit((Object)(object)value3.PlayerSpawner) || (Object)(object)value3.PlayerSpawner.player == (Object)null || !Object.op_Implicit((Object)(object)value3.PlayerSpawner.player)) { continue; } int value; string weaponForProgress = GetWeaponForProgress(Progress.TryGetValue(value3.PlayerId, out value) ? value : 0); if (weaponForProgress != null) { GameObject val = value3.PlayerSpawner.player.playerPickupScript?.objInHand; Weapon val2 = (((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val)) ? null : val.GetComponent<Weapon>()); float value2; if ((Object)(object)val2 != (Object)null && ((Object)val2).name.StartsWith(weaponForProgress, StringComparison.Ordinal)) { PendingLoadouts.Remove(value3.PlayerId); } else if (!PendingLoadouts.TryGetValue(value3.PlayerId, out value2) || Time.unscaledTime >= value2) { GiveStartingWeapon(value3.PlayerId); } } } } internal static void GiveStartingWeapon(int playerId) { if (Enabled && GameModeManager.IsActive(GameMode.GunGame) && MyceliumNetwork.IsHost) { int value; int progress = (Progress.TryGetValue(playerId, out value) ? value : 0); GiveWeaponForProgress(playerId, progress); } } private static void GiveWeaponForProgress(int playerId, int progress) { string weaponForProgress = GetWeaponForProgress(progress); if (weaponForProgress != null) { PendingLoadouts[playerId] = Time.unscaledTime + 5f; WeaponService.GiveWeapon(playerId, weaponForProgress, null, unlimitedAmmo: true); } } private static string? GetWeaponForProgress(int progress) { if (WeaponOrder.Count != 0) { return WeaponOrder[GetWeaponIndex(progress)]; } return null; } internal static string SerializeProgress() { return ScoreCodec.Serialize(Progress); } private static void BroadcastLiveState() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { MyceliumNetwork.RPC(1618033990u, "SyncGunGameLiveState", (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, SerializeProgress(), GameModeManager.RoundId, Sync.NextLiveRevision() }); } } } [HarmonyPatch] internal static class PlayerHealth_PassiveHealthFeedbackWriter_Patch { private static MethodBase? TargetMethod() { return FishNetCompatibility.FindGeneratedMethod(typeof(PlayerHealth), "RpcWriter___Observers_HitFeedbackObservers_", (MethodInfo method) => method.ReturnType == typeof(void)); } private static bool Prepare() { return TargetMethod() != null; } private static bool Prefix() { return !HealthSettingsTuning.ApplyingPassiveHealth; } } [HarmonyPatch(typeof(PlayerHealth), "Update")] internal static class PlayerHealth_HealthSettings_Patch { private static void Postfix(PlayerHealth __instance) { HealthSettingsTuning.ObserveHealth(__instance); HealthSettingsTuning.ApplyIfChanged(__instance, HealthSettingsState.MaxHealthMultiplier, HealthSettingsState.TuningVersion); HealthSettingsTuning.RegenerateIfNeeded(__instance, HealthSettingsTuning.GetMemory(__instance)); } } internal static class HealthSettingsState { internal static bool Enabled; internal static float MaxHealthMultiplier = 1f; internal static bool RegenEnabled; internal static float RegenDelaySeconds = 5f; internal static float RegenRate = 10f; internal static int TuningVersion; private static float _nextServerScanTime; private static readonly ModeSyncState Sync = new ModeSyncState(); internal static void Apply(bool enabled, int maxHealthPercent, bool regenEnabled, int regenDelaySeconds, int regenRate) { Enabled = enabled; if (!enabled) { MaxHealthMultiplier = 1f; RegenEnabled = false; RegenDelaySeconds = 5f; RegenRate = 25f; TuningVersion++; Plugin.Logger.LogInfo((object)"[HealthSettings] Apply: disabled - all values reset to stock"); } else { MaxHealthMultiplier = (float)Mathf.Clamp(maxHealthPercent, 10, 400) / 100f; RegenEnabled = regenEnabled; RegenDelaySeconds = Mathf.Clamp((float)regenDelaySeconds, 2f, 15f); RegenRate = NormalizeRegenRate(regenRate); TuningVersion++; Plugin.Logger.LogInfo((object)$"[HealthSettings] Apply: maxHealthMultiplier={MaxHealthMultiplier:0.##} enabled={RegenEnabled} delay={RegenDelaySeconds:0.##} rate={RegenRate:0.##} version={TuningVersion}"); } } private static void ApplyFromHostConfig() { Apply(Plugin.HealthTweaksEnabled.Value, Plugin.MaxHealthPercent.Value, Plugin.HealthRegenEnabled.Value, Plugin.HealthRegenDelaySeconds.Value, Plugin.HealthRegenRate.Value); } internal static void PushIfHost() { if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { ApplyFromHostConfig(); MyceliumNetwork.RPC(1892737466u, "SyncHealthSettings", (ReliableType)1, RpcArgs(Sync.NextSettingsRevision())); } } internal static void PeriodicPushIfHost() { if (Sync.IsSettingsPushDue()) { PushIfHost(); } } internal static void ServerTick() { if (MyceliumNetwork.IsHost && SessionState.IsActive && Enabled && !(Time.unscaledTime < _nextServerScanTime)) { _nextServerScanTime = Time.unscaledTime + 0.1f; PlayerHealth[] array = Object.FindObjectsOfType<PlayerHealth>(true); foreach (PlayerHealth controller in array) { HealthSettingsTuning.ApplyIfChanged(controller, MaxHealthMultiplier, TuningVersion); HealthSettingsTuning.RegenerateIfNeeded(controller, HealthSettingsTuning.GetMemory(controller)); } } } internal static void OnLobbyEntered() { Sync.ResetForLobby(); if (MyceliumNetwork.IsHost) { ApplyFromHostConfig(); } } internal static void ResetForLobbyLeft() { Sync.ResetForLobby(); Apply(enabled: false, 100, regenEnabled: false, 5, 25); } internal static void OnPlayerEntered(CSteamID player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.IsHost) { MyceliumNetwork.RPCTarget(1892737466u, "SyncHealthSettings", player, (ReliableType)1, RpcArgs(Sync.SettingsRevision)); } } internal static bool TryAcceptSettingsSnapshot(CSteamID hostId, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Sync.TryAcceptSettingsSnapshot(hostId, roundId, revision); } private static object[] RpcArgs(int revision) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) return new object[8] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, revision, Plugin.HealthTweaksEnabled.Value, Plugin.MaxHealthPercent.Value, Plugin.HealthRegenEnabled.Value, Plugin.HealthRegenDelaySeconds.Value, Plugin.HealthRegenRate.Value }; } private static float NormalizeRegenRate(int rate) { int num; switch (rate) { case 25: case 50: case 75: case 100: case 150: case 200: num = rate; break; default: num = 25; break; } return num; } } internal static class HealthSettingsTuning { internal sealed class Memory { public float BaselineFullHealth = -1f; public int LastAppliedVersion = -1; public float LastObservedHealth = -1f; public float LastDamageTime; public float RegenAccumulator; public float LastRegenWriteTime; public float LastLoggedHealth = -1f; public bool LastModeSpecificHealth; } internal static bool ApplyingPassiveHealth; private static readonly ConditionalWeakTable<PlayerHealth, Memory> MemoryByInstance = new ConditionalWeakTable<PlayerHealth, Memory>(); internal static void ApplyIfChanged(PlayerHealth controller, float healthMultiplier, int version) { Memory orCreateValue = MemoryByInstance.GetOrCreateValue(controller); if (orCreateValue.BaselineFullHealth < 0f) { orCreateValue.BaselineFullHealth = controller.fullHealth; } if (GameModeManager.IsActive(GameMode.Infidel)) { InfidelState.ApplyHealth(controller); orCreateValue.LastModeSpecificHealth = true; orCreateValue.LastAppliedVersion = version; return; } if (GameModeManager.IsActive(GameMode.OneInTheChamber)) { OneInTheChamberState.ApplyHealth(controller); orCreateValue.LastModeSpecificHealth = true; orCreateValue.LastAppliedVersion = version; return; } if (GameModeManager.IsActive(GameMode.Juggernaut) && JuggernautState.IsCurrentJuggernaut(controller)) { JuggernautState.ApplyHealth(controller); orCreateValue.LastModeSpecificHealth = true; orCreateValue.LastAppliedVersion = version; return; } if (GameModeManager.IsActive(GameMode.KillTheRat) && KillTheRatState.IsRat(controller)) { KillTheRatState.ApplyHealth(controller, orCreateValue.BaselineFullHealth); orCreateValue.LastModeSpecificHealth = true; orCreateValue.LastAppliedVersion = version; return; } if (GameModeManager.IsActive(GameMode.SniperBattle)) { SniperBattleState.ApplyHealth(controller); orCreateValue.LastModeSpecificHealth = true; orCreateValue.LastAppliedVersion = version; return; } if (GameModeManager.IsActive(GameMode.Default)) { controller.fullHealth = orCreateValue.BaselineFullHealth; orCreateValue.LastModeSpecificHealth = true; orCreateValue.LastAppliedVersion = version; return; } if (orCreateValue.LastModeSpecificHealth) { orCreateValue.LastModeSpecificHealth = false; orCreateValue.LastAppliedVersion = -1; } if (orCreateValue.LastAppliedVersion == version) { return; } orCreateValue.LastAppliedVersion = version; float num = orCreateValue.BaselineFullHealth * healthMultiplier; float fullHealth = controller.fullHealth; controller.fullHealth = num; Plugin.Logger.LogInfo((object)$"[HealthSettings] Health apply: owner={((NetworkBehaviour)controller).IsOwner} server={((NetworkBehaviour)controller).IsServer} baseline={orCreateValue.BaselineFullHealth:0.##} fullHealth={fullHealth:0.##}->{num:0.##} healthBefore={controller.health:0.##} multiplier={healthMultiplier:0.##} version={version}"); if (!((NetworkBehaviour)controller).IsServer) { return; } float num2 = num - fullHealth; if (!Mathf.Approximately(num2, 0f)) { ApplyingPassiveHealth = true; try { FishNetCompatibility.TryRemoveHealth(controller, 0f - num2); } finally { ApplyingPassiveHealth = false; } Plugin.Logger.LogInfo((object)$"[HealthSettings] Health server write: owner={((NetworkBehaviour)controller).IsOwner} healthAfter={controller.health:0.##} bonus={num2:0.##}"); } } internal static void RegenerateIfNeeded(PlayerHealth controller, Memory memory) { bool num = GameModeManager.IsActive(GameMode.Juggernaut) && JuggernautState.IsCurrentJuggernaut(controller); bool flag = GameModeManager.IsActive(GameMode.KillTheRat) && KillTheRatState.IsRat(controller); if (num || flag || GameModeManager.ShouldIgnoreGlobalHealthSettings || !((NetworkBehaviour)controller).IsServer || !((Component)controller).gameObject.activeInHierarchy || controller.health <= 0f) { return; } float num2 = controller.sync___get_value_health(); if (memory.LastObservedHealth < 0f) { memory.LastObservedHealth = num2; memory.LastDamageTime = Time.unscaledTime; return; } if (num2 < memory.LastObservedHealth - 0.001f) { memory.LastDamageTime = Time.unscaledTime; memory.RegenAccumulator = 0f; } memory.LastObservedHealth = num2; if (!HealthSettingsState.RegenEnabled || Time.unscaledTime - memory.LastDamageTime < HealthSettingsState.RegenDelaySeconds || num2 >= controller.fullHealth) { if (!HealthSettingsState.RegenEnabled) { memory.RegenAccumulator = 0f; } return; } float num3 = HealthSettingsState.RegenRate / 25f; memory.RegenAccumulator += Time.unscaledDeltaTime * num3; if (!(Time.unscaledTime - memory.LastRegenWriteTime < 0.1f) && !(memory.RegenAccumulator <= 0f)) { float num4 = Mathf.Min(memory.RegenAccumulator, controller.fullHealth - num2); memory.RegenAccumulator -= num4; memory.LastRegenWriteTime = Time.unscaledTime; ApplyingPassiveHealth = true; try { FishNetCompatibility.TryRemoveHealth(controller, 0f - num4); } finally { ApplyingPassiveHealth = false; } memory.LastObservedHealth = controller.sync___get_value_health(); } } internal static void ObserveHealth(PlayerHealth controller) { Memory orCreateValue = MemoryByInstance.GetOrCreateValue(controller); float num = controller.sync___get_value_health(); if (!Mathf.Approximately(orCreateValue.LastLoggedHealth, num)) { Plugin.Logger.LogInfo((object)$"[HealthSettings] Health observed: owner={((NetworkBehaviour)controller).IsOwner} server={((NetworkBehaviour)controller).IsServer} health={num:0.###} fullHealth={controller.fullHealth:0.###}"); orCreateValue.LastLoggedHealth = num; } } internal static Memory GetMemory(PlayerHealth controller) { return MemoryByInstance.GetOrCreateValue(controller); } } [HarmonyPatch(typeof(MeleeWeapon), "HitServer")] internal static class MeleeWeapon_HotPotatoBatDamage_Patch { private static void Prefix(MeleeWeapon __instance, PlayerHealth enemyHealth, ref float damageToGive) { if (GameModeManager.IsActive(GameMode.HotPotato) && !((Object)(object)__instance == (Object)null) && ((Object)__instance).name.StartsWith("BaseballBat", StringComparison.Ordinal) && !((Object)(object)enemyHealth == (Object)null)) { damageToGive = Mathf.Max(0.01f, enemyHealth.fullHealth * 0.5f); } } } [HarmonyPatch(typeof(PlayerManager), "SpawnPlayer", new Type[] { typeof(int), typeof(int), typeof(Vector3), typeof(Quaternion) })] internal static class PlayerManager_HotPotatoSpawn_Patch { private static void Postfix(PlayerManager __instance) { if (GameModeManager.IsActive(GameMode.HotPotato) && !WeaponService.IsFinalGameScreen && !((Object)(object)__instance.player == (Object)null)) { ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); if ((Object)(object)component != (Object)null) { HotPotatoState.RequestLoadout(component.PlayerId); } } } } internal static class HotPotatoState { internal const string BatWeaponName = "BaseballBat"; internal const string ShotgunWeaponName = "Shotgun"; internal static bool Enabled; internal static readonly Dictionary<int, int> Kills = new Dictionary<int, int>(); private static float _nextLoadoutCheckTime; private static readonly ModeSyncState Sync = new ModeSyncState(); private static readonly Dictionary<int, float> PendingLoadouts = new Dictionary<int, float>(); internal static int PotatoPlayerId { get; private set; } = -1; internal static int WinnerId { get; private set; } = -1; internal static int KillsToWin => GameModeManager.EffectivePointsToWin; internal static void ApplySettings(bool enabled) { bool num = Enabled != enabled; Enabled = enabled; if (num) { ResetMatchState(); } } private static void ApplySettingsFromHostConfig() { ApplySettings(Plugin.HotPotatoEnabled.Value); } internal static void PushSettingsIfHost() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { ApplySettingsFromHostConfig(); MyceliumNetwork.RPC(2718281830u, "SyncHotPotatoSettings", (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.NextSettingsRevision(), Plugin.HotPotatoEnabled.Value }); } } internal static void PeriodicPushSettingsIfHost() { if (Sync.IsSettingsPushDue()) { PushSettingsIfHost(); } } internal static void PeriodicPushIfHost() { if (Sync.IsLivePushDue()) { BroadcastLiveState(); } } internal static void OnLobbyEntered() { Sync.ResetForLobby(); if (MyceliumNetwork.IsHost) { ApplySettingsFromHostConfig(); ResetMatchState(); } } internal static void OnPlayerEntered(CSteamID player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.IsHost) { MyceliumNetwork.RPCTarget(2718281830u, "SyncHotPotatoSettings", player, (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.SettingsRevision, Plugin.HotPotatoEnabled.Value }); MyceliumNetwork.RPCTarget(2718281830u, "SyncHotPotatoLiveState", player, (ReliableType)1, new object[6] { MyceliumNetwork.LobbyHost, SerializeKills(), PotatoPlayerId, WinnerId, GameModeManager.RoundId, Sync.LiveRevision }); } } internal static bool TryAcceptSettingsSnapshot(CSteamID hostId, int roundId, int revision) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Sync.TryAcceptSettingsSnapshot(hostId, roundId, revision); } internal static void ResetMatchState() { Sync.ResetLiveState(); _nextLoadoutCheckTime = 0f; PotatoPlayerId = -1; WinnerId = -1; Kills.Clear(); PendingLoadouts.Clear(); } internal static void ApplyLiveState(CSteamID hostId, string killsData, int potatoPlayerId, int winnerId, int roundId, int revision) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (potatoPlayerId < -1 || winnerId < -1 || !Sync.TryAcceptLiveSnapshot(hostId, roundId, revision)) { return; } PotatoPlayerId = potatoPlayerId; WinnerId = winnerId; Kills.Clear(); foreach (KeyValuePair<int, int> item in ScoreCodec.Parse(killsData, KillsToWin)) { Kills[item.Key] = item.Value; } } internal static void OnRoundStarted() { if (!Enabled || !GameModeManager.IsActive(GameMode.HotPotato) || !MyceliumNetwork.IsHost) { return; } ResetMatchState(); List<int> list = new List<int>(); foreach (ClientInstance value in ClientInstance.playerInstances.Values) { if ((Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { list.Add(value.PlayerId); Kills[value.PlayerId] = 0; } } if (list.Count != 0) { PotatoPlayerId = list[Random.Range(0, list.Count)]; Announce(PlayerLookup.GetPlayerNameTag(PotatoPlayerId) + " has the <b>HOT POTATO</b>!"); EnsureLoadouts(); BroadcastLiveState(); } } internal static void OnServerKill(int deadPlayerId, int killerId) { if (Enabled && GameModeManager.IsActive(GameMode.HotPotato) && WinnerId < 0 && killerId >= 0 && killerId != deadPlayerId) { Kills.TryGetValue(killerId, out var value); int num = value + 10; Kills[killerId] = num; GameModeHud.ShowScorePopupForPlayer(killerId, 10); if (killerId == PotatoPlayerId) { PotatoPlayerId = deadPlayerId; PendingLoadouts.Remove(killerId); WeaponService.GiveWeapon(killerId, "Shotgun"); Announce(PlayerLookup.GetPlayerNameTag(deadPlayerId) + " got the <b>HOT POTATO</b>!"); } if (num >= KillsToWin) { WinnerId = killerId; Announce(PlayerLookup.GetPlayerNameTag(killerId) + " reached " + KillsToWin + " points and won the round!"); GameModeManager.CompleteCustomRound(ScoreManager.Instance.GetTeamId(killerId)); } BroadcastLiveState(); } } internal static void RequestLoadout(int playerId) { if (Enabled && GameModeManager.IsActive(GameMode.HotPotato) && MyceliumNetwork.IsHost) { PendingLoadouts[playerId] = Time.unscaledTime + 2f; GiveExpectedWeapon(playerId); } } internal static bool IsAllowedWeapon(Weapon weapon, int playerId) { if ((Object)(object)weapon == (Object)null) { return true; } string value = ((playerId == PotatoPlayerId) ? "BaseballBat" : "Shotgun"); return ((Object)weapon).name.StartsWith(value, StringComparison.Ordinal); } internal static string GetExpectedWeapon(int playerId) { if (playerId != PotatoPlayerId) { return "Shotgun"; } return "BaseballBat"; } internal static void EnsureLoadouts() { if (!Enabled || !GameModeManager.IsActive(GameMode.HotPotato) || !MyceliumNetwork.InLobby || !MyceliumNetwork.IsHost || WeaponService.IsFinalGameScreen || Time.unscaledTime < _nextLoadoutCheckTime) { return; } _nextLoadoutCheckTime = Time.unscaledTime + 0.5f; foreach (ClientInstance value2 in ClientInstance.playerInstances.Values) { if (!((Object)(object)value2 == (Object)null) && Object.op_Implicit((Object)(object)value2) && !((Object)(object)value2.PlayerSpawner == (Object)null) && Object.op_Implicit((Object)(object)value2.PlayerSpawner) && !((Object)(object)value2.PlayerSpawner.player == (Object)null) && Object.op_Implicit((Object)(object)value2.PlayerSpawner.player) && ((Component)value2.PlayerSpawner.player).gameObject.activeInHierarchy) { Weapon weapon = GetWeapon(value2.PlayerSpawner.player.playerPickupScript?.objInHand); float value; if ((Object)(object)weapon != (Object)null && IsAllowedWeapon(weapon, value2.PlayerId)) { PendingLoadouts.Remove(value2.PlayerId); } else if (!PendingLoadouts.TryGetValue(value2.PlayerId, out value) || Time.unscaledTime >= value) { GiveExpectedWeapon(value2.PlayerId); } } } } private static void GiveExpectedWeapon(int playerId) { PendingLoadouts[playerId] = Time.unscaledTime + 2f; WeaponService.GiveWeapon(playerId, GetExpectedWeapon(playerId)); } private static Weapon? GetWeapon(GameObject? heldObject) { if (!((Object)(object)heldObject == (Object)null) && Object.op_Implicit((Object)(object)heldObject)) { return heldObject.GetComponent<Weapon>(); } return null; } private static string SerializeKills() { return ScoreCodec.Serialize(Kills); } private static void BroadcastLiveState() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { MyceliumNetwork.RPC(2718281830u, "SyncHotPotatoLiveState", (ReliableType)1, new object[6] { MyceliumNetwork.LobbyHost, SerializeKills(), PotatoPlayerId, WinnerId, GameModeManager.RoundId, Sync.NextLiveRevision() }); } } private static void Announce(string text) { if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { MyceliumNetwork.RPC(2718281830u, "HotPotatoAnnounce", (ReliableType)1, new object[1] { text }); } } } [HarmonyPatch(typeof(PlayerManager), "SpawnPlayer", new Type[] { typeof(int), typeof(int), typeof(Vector3), typeof(Quaternion) })] internal static class PlayerManager_InfidelSpawn_Patch { private static void Postfix(PlayerManager __instance) { if (GameModeManager.IsActive(GameMode.Infidel) && !WeaponService.IsFinalGameScreen && !((Object)(object)__instance.player == (Object)null)) { ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>(); if ((Object)(object)component != (Object)null) { InfidelState.RequestHealthReset(component.PlayerId); InfidelState.RequestLoadout(component.PlayerId); } } } } internal static class InfidelState { internal const string WeaponName = "AK-K"; internal const int SpareMagazines = 2; internal const float InfidelHealth = 8f; internal const float TerroristHealth = 4f; internal const float MovementMultiplier = 0.7f; internal const float WeaponDelaySeconds = 10f; internal static bool Enabled; internal static readonly Dictionary<int, int> Scores = new Dictionary<int, int>(); private static readonly HashSet<int> AlivePlayers = new HashSet<int>(); private static readonly HashSet<int> PendingHealthResets = new HashSet<int>(); private static readonly Dictionary<int, float> PendingLoadouts = new Dictionary<int, float>(); private static float _nextLoadoutCheckTime; private static readonly ModeSyncState Sync = new ModeSyncState(); private static int _subRoundId; private static int _localRoleSubRoundId = -1; private static bool _subRoundEnding; internal static int InfidelPlayerId { get; private set; } = -1; internal static int WinnerId { get; private set; } = -1; internal static int KillsToWin => GameModeManager.EffectivePointsToWin; internal static bool WeaponsUnlocked { get; private set; } internal static bool LocalIsInfidel { get; private set; } internal static void ApplySettings(bool enabled) { bool num = Enabled != enabled; Enabled = enabled; if (num) { ResetMatchState(); } } private static void ApplySettingsFromHostConfig() { ApplySettings(Plugin.InfidelEnabled.Value); } internal static void PushSettingsIfHost() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { ApplySettingsFromHostConfig(); MyceliumNetwork.RPC(2718281831u, "SyncInfidelSettings", (ReliableType)1, new object[4] { MyceliumNetwork.LobbyHost, GameModeManager.RoundId, Sync.NextSettingsRevision(), Plugin.InfidelEnabled.Value }); } } internal static void PeriodicPushSettingsIfHost() { if (Sync.IsSettingsPushDue()) { PushSettingsIfHost(); } } internal static void PeriodicPushIfHost() { if (Sync.IsLivePushDue()) { BroadcastLiveState(); SendRoleStates(announce: false); } } internal static void OnLobbyEntered() { Sync.ResetForLobby(); if (MyceliumNetwork.IsHost) { ApplySettingsFromHostConfig(); ResetMatchState(); } } internal static void OnPlayerEntered(CSteamID player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missi