using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using AntiGrief.NetcodePatcher; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LobbyCompatibility.Enums; using LobbyCompatibility.Features; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: AssemblyCompany("AntiGrief")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Some anti-griefing features")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AntiGrief")] [assembly: AssemblyTitle("AntiGrief")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace AntiGrief { internal class AGNetworker : NetworkBehaviour { internal static GameObject prefab; internal static AGNetworker Instance { get; private set; } internal NetworkVariable DisableMasks { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal NetworkVariable DisableEggs { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal NetworkVariable DisableShovels { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal NetworkVariable DisableFriendlyFire { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal NetworkVariable DisableMisfire { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal NetworkVariable PermanentLuck { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal NetworkVariable DisableTriggerItems { get; private set; } = new NetworkVariable(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); internal static void Init() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if ((Object)(object)prefab != (Object)null) { Plugin.Logger.LogDebug((object)"Skipped network handler registration, because it has already been initialized"); return; } try { prefab = new GameObject("AGNetworker") { hideFlags = (HideFlags)61 }; NetworkObject val = prefab.AddComponent(); byte[] value = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(typeof(AGNetworker).Assembly.GetName().Name + ((Object)prefab).name)); val.GlobalObjectIdHash = BitConverter.ToUInt32(value, 0); prefab.AddComponent(); NetworkManager.Singleton.AddNetworkPrefab(prefab); Plugin.Logger.LogDebug((object)$"Successfully registered network handler (#{val.GlobalObjectIdHash})"); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Encountered some fatal error while registering network handler. The mod will not function like this!\n{arg}"); } } internal static void Create() { try { if (NetworkManager.Singleton.IsServer && (Object)(object)prefab != (Object)null) { Object.Instantiate(prefab).GetComponent().Spawn(true); } } catch { Plugin.Logger.LogError((object)"Encountered some fatal error while spawning network handler. It is likely that registration failed earlier on start-up, please consult your logs."); } } private void Awake() { Instance = this; } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); if ((Object)(object)Instance != (Object)(object)this) { NetworkObject val = default(NetworkObject); if (((Component)Instance).TryGetComponent(ref val) && !val.IsSpawned && (Object)(object)Instance != (Object)(object)prefab) { Object.Destroy((Object)(object)Instance); } Plugin.Logger.LogWarning((object)"There are 2 AGNetworkers instantiated, and the wrong one was assigned as Instance. This shouldn't happen, but is recoverable"); Instance = this; } Plugin.Logger.LogDebug((object)"Successfully spawned network handler."); } private void Start() { if (!((Object)(object)this != (Object)(object)Instance) && ((NetworkBehaviour)this).IsSpawned && ((NetworkBehaviour)this).IsServer) { DisableMasks.Value = Plugin.configDisableMasks.Value; DisableEggs.Value = Plugin.configDisableEggs.Value; DisableShovels.Value = Plugin.configDisableShovels.Value; DisableFriendlyFire.Value = Plugin.configDisableFriendlyFire.Value; DisableMisfire.Value = Plugin.configDisableMisfire.Value; PermanentLuck.Value = Plugin.configPermanentLuck.Value; DisableTriggerItems.Value = Plugin.configDisableTriggerItems.Value; } } protected override void __initializeVariables() { if (DisableMasks == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)DisableMasks).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DisableMasks, "DisableMasks"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)DisableMasks); if (DisableEggs == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)DisableEggs).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DisableEggs, "DisableEggs"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)DisableEggs); if (DisableShovels == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)DisableShovels).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DisableShovels, "DisableShovels"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)DisableShovels); if (DisableFriendlyFire == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)DisableFriendlyFire).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DisableFriendlyFire, "DisableFriendlyFire"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)DisableFriendlyFire); if (DisableMisfire == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)DisableMisfire).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DisableMisfire, "DisableMisfire"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)DisableMisfire); if (PermanentLuck == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)PermanentLuck).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)PermanentLuck, "PermanentLuck"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)PermanentLuck); if (DisableTriggerItems == null) { throw new Exception("AGNetworker.k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)DisableTriggerItems).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DisableTriggerItems, "DisableTriggerItems"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)DisableTriggerItems); ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { ((NetworkBehaviour)this).__initializeRpcs(); } protected internal override string __getTypeName() { return "AGNetworker"; } } internal static class LobbyCompatibility { internal static void Init() { PluginHelper.RegisterPlugin("butterystancakes.lethalcompany.antigrief", Version.Parse("0.0.1"), (CompatibilityLevel)2, (VersionStrictness)3); } } [HarmonyPatch] internal static class Patches { [HarmonyPatch(typeof(GameNetworkManager), "Start")] [HarmonyPostfix] private static void GameNetworkManager_Post_Start() { AGNetworker.Init(); } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] private static void StartOfRound_Post_Awake() { AGNetworker.Create(); } [HarmonyPatch(typeof(HauntedMaskItem), "EquipItem")] [HarmonyPrefix] private static void HauntedMaskItem_Pre_EquipItem(HauntedMaskItem __instance) { if (__instance.maskIsHaunted && !StartOfRound.Instance.isChallengeFile && AGNetworker.Instance.DisableMasks.Value) { __instance.maskIsHaunted = false; Plugin.Logger.LogDebug((object)$"Mask \"{((Object)__instance).name}\" (#{((Object)__instance).GetInstanceID()}) is no longer haunted"); } } [HarmonyPatch(typeof(ShotgunItem), "Update")] [HarmonyPrefix] private static void ShotgunItem_Pre_Update(ShotgunItem __instance) { if (!StartOfRound.Instance.isChallengeFile && AGNetworker.Instance.DisableMisfire.Value) { if (!__instance.hasHitGroundWithSafetyOff) { Plugin.Logger.LogDebug((object)$"Shotgun \"{((Object)__instance).name}\" (#{((Object)__instance).GetInstanceID()}) will not fire when dropped"); __instance.hasHitGroundWithSafetyOff = true; } __instance.misfireTimer = 50f; } } [HarmonyPatch(typeof(GrabbableObjectPhysicsTrigger), "OnTriggerEnter")] [HarmonyPrefix] private static bool GrabbableObjectPhysicsTrigger_Pre_OnTriggerEnter(GrabbableObjectPhysicsTrigger __instance, Collider other) { if (StartOfRound.Instance.isChallengeFile || !AGNetworker.Instance.DisableTriggerItems.Value || (!__instance.itemScript.isInShipRoom && !StartOfRound.Instance.inShipPhase)) { return true; } if ((Object)(object)__instance.itemScript != (Object)null && !__instance.itemScript.isHeld && (((Component)other).gameObject.CompareTag("Player") || ((Component)other).gameObject.CompareTag("Enemy"))) { Plugin.Logger.LogDebug((object)$"Item \"{((Object)__instance.itemScript).name}\" (#{((Object)__instance.itemScript).GetInstanceID()}) can't be triggered while inside of ship"); } return false; } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientClientRpc")] [HarmonyPrefix] private static void PlayerControllerB_Pre_DamagePlayerFromOtherClientClientRpc(PlayerControllerB __instance, ref int damageAmount) { if (!StartOfRound.Instance.isChallengeFile && AGNetworker.Instance.DisableShovels.Value) { Plugin.Logger.LogDebug((object)$"Melee damage on player \"{__instance.playerUsername}\" nullified ({damageAmount} -> 0)"); damageAmount = 0; } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")] [HarmonyPrefix] private static bool PlayerControllerB_Pre_DamagePlayer(int damageNumber, CauseOfDeath causeOfDeath) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 if (!StartOfRound.Instance.isChallengeFile && damageNumber <= 0) { if ((int)causeOfDeath != 1) { return (int)causeOfDeath != 7; } return false; } return true; } [HarmonyPatch(typeof(StunGrenadeItem), "SetExplodeOnThrowClientRpc")] [HarmonyPrefix] private static void StunGrenadeItem_Pre_SetExplodeOnThrowClientRpc(StunGrenadeItem __instance, ref bool explode) { if (explode && !StartOfRound.Instance.isChallengeFile && AGNetworker.Instance.DisableEggs.Value) { explode = false; Plugin.Logger.LogDebug((object)$"Easter egg \"{((Object)__instance).name}\" (#{((Object)__instance).GetInstanceID()}) had its explosion chance reset"); } } private static int ShotgunPlayerDamagePostProcess(ShotgunItem shotgunItem, int damage) { if (!((GrabbableObject)shotgunItem).isHeldByEnemy && !StartOfRound.Instance.isChallengeFile && AGNetworker.Instance.DisableFriendlyFire.Value) { if (damage > 0) { Plugin.Logger.LogDebug((object)$"Shotgun \"{((Object)shotgunItem).name}\" (#{((Object)shotgunItem).GetInstanceID()}) damage on player \"{GameNetworkManager.Instance.localPlayerController.playerUsername}\" nullified ({damage} -> 0)"); } return 0; } return damage; } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyTranspiler] private static IEnumerable ShotgunItem_Trans_ShootGun(IEnumerable instructions) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown List list = instructions.ToList(); MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerB), "DamagePlayer", (Type[])null, (Type[])null); int num = -1; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Brfalse) { num = i; } else if (num >= 0 && num + 3 < list.Count && list[i].opcode == OpCodes.Callvirt && list[i].operand as MethodInfo == methodInfo && list[num + 2].opcode == OpCodes.Ldloc_S) { list.Insert(num + 3, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Patches), "ShotgunPlayerDamagePostProcess", (Type[])null, (Type[])null))); list.Insert(num + 2, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); Plugin.Logger.LogDebug((object)"Transpiler (Shotgun): Alter damage call"); return list; } } Plugin.Logger.LogError((object)"Shotgun transpiler failed"); return list; } [HarmonyPatch(typeof(TimeOfDay), "CalculateLuckValue")] [HarmonyPostfix] private static void TimeOfDay_Post_CalculateLuckValue(TimeOfDay __instance) { if (StartOfRound.Instance.isChallengeFile || !AGNetworker.Instance.PermanentLuck.Value) { return; } for (int i = 0; i < StartOfRound.Instance.unlockablesList.unlockables.Count; i++) { if (StartOfRound.Instance.unlockablesList.unlockables[i].luckValue > 0f && StartOfRound.Instance.unlockablesList.unlockables[i].hasBeenUnlockedByPlayer && !__instance.furniturePlacedAtQuotaStart.Contains(i)) { __instance.furniturePlacedAtQuotaStart.Add(i); __instance.luckValue = Mathf.Clamp(__instance.luckValue + StartOfRound.Instance.unlockablesList.unlockables[i].luckValue, -0.5f, 1f); Plugin.Logger.LogDebug((object)$"Furniture luck forced to track unlockable #{i}: \"{StartOfRound.Instance.unlockablesList.unlockables[i].unlockableName}\""); } } } [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] [HarmonyPostfix] private static void TimeOfDay_Post_SetNewProfitQuota(TimeOfDay __instance) { if (!((NetworkBehaviour)__instance).IsServer || StartOfRound.Instance.isChallengeFile || !AGNetworker.Instance.PermanentLuck.Value) { return; } for (int i = 0; i < StartOfRound.Instance.unlockablesList.unlockables.Count; i++) { if (StartOfRound.Instance.unlockablesList.unlockables[i].luckValue > 0f && StartOfRound.Instance.unlockablesList.unlockables[i].hasBeenUnlockedByPlayer && !__instance.furniturePlacedAtQuotaStart.Contains(i)) { __instance.furniturePlacedAtQuotaStart.Add(i); Plugin.Logger.LogDebug((object)$"Furniture luck forced to track unlockable #{i}: \"{StartOfRound.Instance.unlockablesList.unlockables[i].unlockableName}\""); } } } [HarmonyPatch(typeof(ShipBuildModeManager), "StoreObjectServerRpc")] [HarmonyPrefix] private static void ShipBuildModeManager_Pre_StoreObjectServerRpc(ref List __state) { __state = new List(TimeOfDay.Instance.furniturePlacedAtQuotaStart); } [HarmonyPatch(typeof(ShipBuildModeManager), "StoreObjectServerRpc")] [HarmonyPostfix] private static void ShipBuildModeManager_Post_StoreObjectServerRpc(List __state) { if (!StartOfRound.Instance.isChallengeFile && __state.Count > TimeOfDay.Instance.furniturePlacedAtQuotaStart.Count && AGNetworker.Instance.PermanentLuck.Value) { TimeOfDay.Instance.furniturePlacedAtQuotaStart = TimeOfDay.Instance.furniturePlacedAtQuotaStart.Union(__state).Distinct().ToList(); Plugin.Logger.LogDebug((object)"Furniture luck blocked from untracking unlockables"); } } [HarmonyPatch(typeof(RandomPeriodicAudioPlayer), "Update")] [HarmonyPrefix] private static void RandomPeriodicAudioPlayer_Pre_Update(RandomPeriodicAudioPlayer __instance) { if (((NetworkBehaviour)__instance).IsServer && !StartOfRound.Instance.isChallengeFile && (Object)(object)__instance.attachedGrabbableObject != (Object)null && __instance.attachedGrabbableObject.isInShipRoom && AGNetworker.Instance.DisableMasks.Value && AGNetworker.Instance.DisableTriggerItems.Value) { __instance.lastIntervalTime = Time.realtimeSinceStartup; } } } [BepInPlugin("butterystancakes.lethalcompany.antigrief", "Anti-Grief", "0.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal const string PLUGIN_GUID = "butterystancakes.lethalcompany.antigrief"; internal const string PLUGIN_NAME = "Anti-Grief"; internal const string PLUGIN_VERSION = "0.0.1"; internal static ManualLogSource Logger; private const string GUID_LOBBY_COMPATIBILITY = "BMX.LobbyCompatibility"; internal static ConfigEntry configDisableMasks; internal static ConfigEntry configDisableEggs; internal static ConfigEntry configDisableShovels; internal static ConfigEntry configDisableFriendlyFire; internal static ConfigEntry configDisableMisfire; internal static ConfigEntry configPermanentLuck; internal static ConfigEntry configDisableTriggerItems; private void Awake() { //IL_011b: Unknown result type (might be due to invalid IL or missing references) NetcodePatch(); Logger = ((BaseUnityPlugin)this).Logger; if (Chainloader.PluginInfos.ContainsKey("BMX.LobbyCompatibility")) { Logger.LogInfo((object)"CROSS-COMPATIBILITY - Lobby Compatibility detected"); LobbyCompatibility.Init(); } configDisableMasks = ((BaseUnityPlugin)this).Config.Bind("Items", "Block Mask Possession", true, "Comedy/Tragedy will no longer kill players and spawn \"masked\" enemies when they are worn."); configDisableEggs = ((BaseUnityPlugin)this).Config.Bind("Items", "Block Egg Explosions", true, "Easter eggs can never explode when hitting the ground."); configDisableShovels = ((BaseUnityPlugin)this).Config.Bind("Items", "Block Shovel Damage", true, "Shovels no longer deal damage when hitting players."); configDisableFriendlyFire = ((BaseUnityPlugin)this).Config.Bind("Items", "Block Friendly Fire", true, "Double barrels no longer damage players when fired by another player. Nutcrackers are unaffected."); configDisableMisfire = ((BaseUnityPlugin)this).Config.Bind("Items", "Block Misfires", true, "Double barrels no longer fire randomly upon hitting the ground or when being held by a player, even if the safety is off."); configDisableTriggerItems = ((BaseUnityPlugin)this).Config.Bind("Items", "Block Triggering Items in Ship", true, "\"Trigger items\" (whoopie cushions and soccer balls) no longer activate when touched by players or enemies while they are inside the ship."); configPermanentLuck = ((BaseUnityPlugin)this).Config.Bind("Misc", "Permanent Luck", false, "Furniture will always be factored into luck calculations as long as it has been purchased.\nThis prevents players from irreversibly nullifying luck by storing furniture mid-quota, but *also allows you to benefit from furniture luck while keeping it in storage.*"); new Harmony("butterystancakes.lethalcompany.antigrief").PatchAll(); Logger.LogInfo((object)"Anti-Grief v0.0.1 loaded"); } private void NetcodePatch() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); for (int i = 0; i < types.Length; i++) { MethodInfo[] methods = types[i].GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0) { methodInfo.Invoke(null, null); } } } } } public static class PluginInfo { public const string PLUGIN_GUID = "AntiGrief"; public const string PLUGIN_NAME = "AntiGrief"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy(); NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable(); } } } namespace AntiGrief.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }