Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BrackenReworked v2.9.6
BepInEx/plugins/BrackenReworked.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BrackenReworkedPlugin.Patches; using BrackenReworkedPlugin.Patches.Networking; using BrackenReworkedPlugin.Patches.SFX; using GameNetcodeStuff; using HarmonyLib; using LC_API.Networking; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BrackenReworked")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BrackenReworked")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("0f711ee2-5cde-49fa-8cfc-1f38737fcc4a")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace BrackenReworkedPlugin { [BepInPlugin("BrackenReworkedPlugin", "BrackenReworkedPlugin", "2.9.6")] public class BrackenReworkedPlugin : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("BrackenReworkedPlugin"); internal static ManualLogSource mls; internal static TextMeshProUGUI Mark; internal MarkingManager markingManager = new MarkingManager(); internal List<PlayerControllerB> playersInShower = new List<PlayerControllerB>(); internal bool coughingBlood; internal static ConfigEntry<int> BrackenForce; internal static ConfigEntry<bool> DropAllItems; internal static ConfigEntry<float> BrackenAttackInterval; internal static ConfigEntry<int> InfectionOnHitChance; internal static ConfigEntry<bool> StartWithMark; internal static ConfigEntry<int> HorizontalMarkOffset; internal static ConfigEntry<int> VerticalMarkOffset; internal static ConfigEntry<bool> MarkBetweenLives; internal static ConfigEntry<float> ShoweringTime; internal static ConfigEntry<int> InfectionChance; internal static ConfigEntry<float> InfectionCooldown; internal static BrackenReworkedPlugin Instance { get; private set; } private void Awake() { BrackenForce = ((BaseUnityPlugin)this).Config.Bind<int>("Bracken", "BrackenForce", 85, "Damage the Bracken can deal."); DropAllItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Bracken", "DropAllItems", true, "Bracken attacks cause players to drop all their items."); BrackenAttackInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Bracken", "BrackenAttackInterval", 5f, "Time in seconds until the Bracken attacks again."); InfectionOnHitChance = ((BaseUnityPlugin)this).Config.Bind<int>("Bracken", "InfectionOnHitChance", 10, "Chance of getting marked by the Bracken when hitting him."); StartWithMark = ((BaseUnityPlugin)this).Config.Bind<bool>("Mark Settings", "StartWithMark", false, "Starting game marked."); HorizontalMarkOffset = ((BaseUnityPlugin)this).Config.Bind<int>("Mark Settings", "HorizontalMarkOffset", 0, "Horizontal offset for the Bracken Mark position."); VerticalMarkOffset = ((BaseUnityPlugin)this).Config.Bind<int>("Mark Settings", "VerticalMarkOffset", 0, "Vertical offset for the Bracken Mark position."); MarkBetweenLives = ((BaseUnityPlugin)this).Config.Bind<bool>("Mark Settings", "MarkBetweenLives", false, "Mark remains even after death. Only a Bracken could remove the Mark."); ShoweringTime = ((BaseUnityPlugin)this).Config.Bind<float>("Mark Settings", "ShoweringTime", 3f, "Time in seconds needed in the shower to remove a Mark."); InfectionChance = ((BaseUnityPlugin)this).Config.Bind<int>("Bracken", "InfectionChance", 25, "Chance of getting infected when hitting the Bracken, or being near a marked Player"); InfectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Bracken", "InfectionCooldown", 30f, "Seconds needed before infecting other players again."); Instance = this; mls = Logger.CreateLogSource("Bracken Reworked Plugin"); harmony.PatchAll(typeof(BrackenReworkedPlugin)); harmony.PatchAll(typeof(PlayerControllerBPatches)); harmony.PatchAll(typeof(FlowemanAIPatches)); harmony.PatchAll(typeof(ShowerTriggerPatches)); harmony.PatchAll(typeof(HUDManagerPatches)); harmony.PatchAll(typeof(StartOfRoundPatches)); Network.RegisterAll(typeof(NetworkHandler)); mls.LogInfo((object)"Bracken Reworked Plugin loaded sucessfully."); } } } namespace BrackenReworkedPlugin.Patches { [HarmonyPatch(typeof(FlowermanAI))] internal class FlowemanAIPatches { private static float lastAttackTime; private static BrackenReworkedPlugin pluginInstance => BrackenReworkedPlugin.Instance; [HarmonyPatch("OnCollideWithPlayer")] [HarmonyPrefix] public static bool CollisionDetection(FlowermanAI __instance, Collider other, ref bool ___startingKillAnimationLocalClient) { if (CanAttack()) { PlayerControllerB val = ((EnemyAI)__instance).MeetsStandardPlayerCollisionConditions(other, (__instance.inKillAnimation | ___startingKillAnimationLocalClient) || __instance.carryingPlayerBody, false); if (!pluginInstance.markingManager.IsMarked() && val.health >= BrackenReworkedPlugin.BrackenForce.Value) { BrackenMarksPlayer(__instance, val); return false; } if (val.health <= BrackenReworkedPlugin.BrackenForce.Value || pluginInstance.markingManager.IsMarked()) { return true; } } __instance.angerMeter = 0f; ((EnemyAI)__instance).SwitchToBehaviourState(1); return false; } [HarmonyPatch("HitEnemy")] [HarmonyPostfix] public static void PlayerHitsBracken(FlowermanAI __instance, int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false) { pluginInstance.markingManager.TransmitMark(playerWhoHit.actualClientId, BrackenReworkedPlugin.InfectionOnHitChance.Value); } private static bool CanAttack() { return Time.time - lastAttackTime >= BrackenReworkedPlugin.BrackenAttackInterval.Value; } public static void InjurePlayer(PlayerControllerB player) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) player.DamagePlayer(BrackenReworkedPlugin.BrackenForce.Value, true, true, (CauseOfDeath)0, 0, false, default(Vector3)); HUDManager.Instance.ShakeCamera((ScreenShakeType)2); player.criticallyInjured = true; player.playerBodyAnimator.SetBool("Limp", true); player.bleedingHeavily = true; if (((NetworkBehaviour)player).IsServer) { player.MakeCriticallyInjuredClientRpc(); } else { player.MakeCriticallyInjuredServerRpc(); } } private static void BrackenMarksPlayer(FlowermanAI bracken, PlayerControllerB player) { InjurePlayer(player); pluginInstance.markingManager.AddMark(); if (BrackenReworkedPlugin.DropAllItems.Value) { player.DropAllHeldItemsAndSync(); } player.SpawnPlayerAnimation(); HUDManager.Instance.DisplayTip("BRACKEN MARK DETECTED", "Shower to remove the mark", true, false, "LC_Tip1"); lastAttackTime = Time.time; } } [HarmonyPatch(typeof(HUDManager))] internal class HUDManagerPatches { private static BrackenReworkedPlugin pluginInstance => BrackenReworkedPlugin.Instance; [HarmonyPatch("Start")] [HarmonyPostfix] private static void InitiateHUD(HUDManager __instance) { Initialize(__instance); if (BrackenReworkedPlugin.StartWithMark.Value) { pluginInstance.markingManager.AddMark(); } } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdateHudView(HUDManager __instance) { if ((Object)(object)BrackenReworkedPlugin.Mark != (Object)null) { ((TMP_Text)BrackenReworkedPlugin.Mark).text = (pluginInstance.markingManager.IsMarked() ? "MARKED" : null); } UpdateVisualEffects(__instance); } private static void Initialize(HUDManager hud) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("Systems/UI/Canvas/IngamePlayerHUD/TopLeftCorner"); if ((Object)(object)val == (Object)null) { BrackenReworkedPlugin.mls.LogError((object)"'TopLeftCorner' not found."); return; } GameObject val2 = new GameObject("PlayerStatusText"); val2.transform.SetParent(val.transform, false); BrackenReworkedPlugin.Mark = val2.AddComponent<TextMeshProUGUI>(); if ((Object)(object)hud.weightCounter != (Object)null) { BrackenReworkedPlugin.mls.LogInfo((object)"SETTING Custom"); TextMeshProUGUI weightCounter = hud.weightCounter; ((TMP_Text)BrackenReworkedPlugin.Mark).font = ((TMP_Text)weightCounter).font; ((TMP_Text)BrackenReworkedPlugin.Mark).fontSize = ((TMP_Text)weightCounter).fontSize; ((Graphic)BrackenReworkedPlugin.Mark).color = Color.red; ((TMP_Text)BrackenReworkedPlugin.Mark).alignment = (TextAlignmentOptions)514; ((TMP_Text)BrackenReworkedPlugin.Mark).enableAutoSizing = ((TMP_Text)weightCounter).enableAutoSizing; ((TMP_Text)BrackenReworkedPlugin.Mark).fontSizeMin = ((TMP_Text)weightCounter).fontSizeMin; ((TMP_Text)BrackenReworkedPlugin.Mark).fontSizeMax = ((TMP_Text)weightCounter).fontSizeMax; if ((Object)(object)((TMP_Text)weightCounter).fontMaterial != (Object)null) { ((TMP_Text)BrackenReworkedPlugin.Mark).fontSharedMaterial = new Material(((TMP_Text)weightCounter).fontMaterial); } if ((Object)(object)((TMP_Text)weightCounter).transform.parent != (Object)null) { RectTransform component = ((Component)((TMP_Text)weightCounter).transform.parent).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { RectTransform component2 = ((Component)BrackenReworkedPlugin.Mark).GetComponent<RectTransform>(); ((Transform)component2).localRotation = ((Transform)component).localRotation; } } } else { ((TMP_Text)BrackenReworkedPlugin.Mark).fontSize = 24f; ((Graphic)BrackenReworkedPlugin.Mark).color = Color.red; ((TMP_Text)BrackenReworkedPlugin.Mark).alignment = (TextAlignmentOptions)514; } RectTransform component3 = val2.GetComponent<RectTransform>(); component3.anchorMin = new Vector2(0f, 1f); component3.anchorMax = new Vector2(0f, 1f); component3.pivot = new Vector2(0f, 1f); int value = BrackenReworkedPlugin.HorizontalMarkOffset.Value; int value2 = BrackenReworkedPlugin.VerticalMarkOffset.Value; component3.anchoredPosition = new Vector2((float)(-55 + value), (float)(-95 + value2)); UpdateHudView(hud); } [HarmonyPatch("HelmetCondensationDrops")] [HarmonyPrefix] private static bool UpdateVisualEffects(HUDManager __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (pluginInstance.markingManager.IsMarked()) { Color color = __instance.helmetCondensationMaterial.color; float num = 0.1f; if (pluginInstance.coughingBlood) { Color color2 = Color.Lerp(color, Color.red, num); __instance.helmetCondensationMaterial.color = color2; pluginInstance.coughingBlood = false; __instance.localPlayer.bleedingHeavily = false; } return false; } return true; } } public class MarkingManager { private bool isMarked = false; public void AddMark() { isMarked = true; BrackenReworkedPlugin.mls.LogInfo((object)"You have been marked!"); } public void RemoveMark() { isMarked = false; BrackenReworkedPlugin.mls.LogInfo((object)"You lost the mark."); } public bool IsMarked() { return isMarked; } public bool TransmitMark(ulong playerId, int chanceOfTransmittingInfection) { Random random = new Random(); int num = random.Next(0, 101); if (num <= chanceOfTransmittingInfection) { NetworkMessages networkMessages = new NetworkMessages { PlayerId = playerId }; Network.Broadcast<NetworkMessages>("MARK_TRANSMITTING", networkMessages); return true; } BrackenReworkedPlugin.mls.LogInfo((object)"Player resisted the infection!"); return false; } public void Reset() { isMarked = false; } } [HarmonyPatch(typeof(PlayerControllerB))] internal class PlayerControllerBPatches { internal static float lastInfectionTime; internal static float OutOfBreathLastTime; private static BrackenReworkedPlugin pluginInstance => BrackenReworkedPlugin.Instance; [HarmonyPatch("Update")] [HarmonyPostfix] public static void UpdatePrefix(PlayerControllerB __instance, ref float ___sprintMeter) { float num = Time.time - OutOfBreathLastTime; if (pluginInstance.markingManager.IsMarked() && (num > 120f || ___sprintMeter <= 0.3f)) { AudioHandler.PlaySound(StartOfRound.Instance.allPlayerScripts[StartOfRound.Instance.thisClientPlayerId], "HeavyBreathing.mp3", 3f, 10f, 1f, 1f, 0f, (AudioRolloffMode)1); OutOfBreathLastTime = Time.time; } if (CanInfect(__instance)) { InfectPlayerInfront(__instance); } } [HarmonyPatch("KillPlayer")] [HarmonyPrefix] public static bool CheckKillingConditions(PlayerControllerB __instance, Vector3 bodyVelocity, bool spawnBody = true, CauseOfDeath causeOfDeath = 0, int deathAnimation = 0) { if (pluginInstance.markingManager.IsMarked() && !BrackenReworkedPlugin.MarkBetweenLives.Value) { pluginInstance.markingManager.RemoveMark(); } return true; } private static bool CanInfect(PlayerControllerB player) { if (pluginInstance.markingManager.IsMarked()) { float num = Time.time - lastInfectionTime; if (num > BrackenReworkedPlugin.InfectionCooldown.Value && num < BrackenReworkedPlugin.InfectionCooldown.Value + 5f) { return true; } } return false; } public static void InfectPlayerInfront(PlayerControllerB localPlayer) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) pluginInstance.coughingBlood = true; localPlayer.bleedingHeavily = true; Random random = new Random(); int num = random.Next(1, 4); AudioHandler.PlaySound(StartOfRound.Instance.allPlayerScripts[StartOfRound.Instance.thisClientPlayerId], "Coughing" + num + ".mp3", 3f, 10f, 1f, 1f, 0f, (AudioRolloffMode)1); Vector3 position = ((Component)localPlayer.gameplayCamera).transform.position; Vector3 forward = ((Component)localPlayer.gameplayCamera).transform.forward; int num2 = 1 << ((Component)localPlayer).gameObject.layer; float num3 = 1.5f; RaycastHit[] array = Physics.RaycastAll(position, forward, num3, num2, (QueryTriggerInteraction)1); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val = array2[i]; ulong actualClientId = ((Component)((RaycastHit)(ref val)).collider).GetComponent<PlayerControllerB>().actualClientId; PlayerControllerB val2 = StartOfRound.Instance.allPlayerScripts[actualClientId]; if (val2.actualClientId != localPlayer.actualClientId) { BrackenReworkedPlugin.mls.LogInfo((object)$"Hitting playerid: {actualClientId}"); pluginInstance.markingManager.TransmitMark(actualClientId, BrackenReworkedPlugin.InfectionChance.Value); } } lastInfectionTime = Time.time; } } [HarmonyPatch(typeof(ShowerTrigger))] internal class ShowerTriggerPatches { internal static BrackenReworkedPlugin pluginInstance = BrackenReworkedPlugin.Instance; private static float showerStartTime; [HarmonyPatch("CheckBoundsForPlayers")] [HarmonyPrefix] public static bool ShoweringPlayers(ref Collider ___showerCollider) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (pluginInstance.markingManager.IsMarked()) { PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[StartOfRound.Instance.thisClientPlayerId]; if (pluginInstance.playersInShower.Contains(val)) { if (PlayerShoweredLongEnough()) { EndShowerSession(val, ref ___showerCollider); } } else { Bounds bounds = ___showerCollider.bounds; if (((Bounds)(ref bounds)).Contains(((Component)val.gameplayCamera).transform.position)) { AddPlayerToShowerAndStartShowering(val); } } return false; } return false; } [HarmonyPatch("AddPlayerToShower")] [HarmonyPrefix] private static bool AddPlayerToShowerAndStartShowering(PlayerControllerB playerScript) { if (!pluginInstance.playersInShower.Contains(playerScript)) { BrackenReworkedPlugin.mls.LogInfo((object)$"Added player #{playerScript.playerClientId} to shower"); pluginInstance.playersInShower.Add(playerScript); showerStartTime = Time.time; return false; } return true; } [HarmonyPatch("RemovePlayerFromShower")] [HarmonyPrefix] private static bool EndShowerSession(PlayerControllerB playerScript, ref Collider ___showerCollider) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (pluginInstance.playersInShower.Contains(playerScript)) { Bounds bounds = ___showerCollider.bounds; if (((Bounds)(ref bounds)).Contains(((Component)playerScript.gameplayCamera).transform.position)) { pluginInstance.playersInShower.Remove(playerScript); pluginInstance.markingManager.RemoveMark(); Random random = new Random(); AudioHandler.PlaySound(playerScript, "Relief" + random.Next(1, 4) + ".mp3", 3f, 10f, 1f, 1f, 0f, (AudioRolloffMode)1); return false; } } return true; } internal static bool PlayerShoweredLongEnough() { return Time.time - showerStartTime >= 3f; } } [HarmonyPatch(typeof(StartOfRound))] internal class StartOfRoundPatches { private static BrackenReworkedPlugin pluginInstance => BrackenReworkedPlugin.Instance; [HarmonyPatch("playersFiredGameOver")] [HarmonyPrefix] public static bool NewGameAboutToBegin(bool abridgedVersion) { pluginInstance.markingManager.Reset(); return true; } } } namespace BrackenReworkedPlugin.Patches.SFX { public class AudioInfo { public bool IsPlaying { get; set; } public AudioSource AudioSource { get; set; } } public class AudioHandler { public static Dictionary<PlayerControllerB, AudioInfo> AudioInfoMap = new Dictionary<PlayerControllerB, AudioInfo>(); public static void PlaySound(PlayerControllerB player, string soundFileName, float minDistance = 3f, float maxDistance = 10f, float volume = 1f, float spacialBlend = 1f, float dopplerLevel = 0f, AudioRolloffMode rolloffMode = 1) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) StopAllSounds(); if (!AudioInfoMap.TryGetValue(player, out var audioInfo)) { audioInfo = new AudioInfo { IsPlaying = false, AudioSource = ((Component)player).gameObject.AddComponent<AudioSource>() }; audioInfo.AudioSource.spatialBlend = spacialBlend; audioInfo.AudioSource.dopplerLevel = dopplerLevel; audioInfo.AudioSource.rolloffMode = rolloffMode; audioInfo.AudioSource.minDistance = minDistance; audioInfo.AudioSource.maxDistance = maxDistance; audioInfo.AudioSource.volume = volume; AudioInfoMap[player] = audioInfo; } if (!audioInfo.IsPlaying) { string text = "file://" + Paths.PluginPath + "\\8-BrackenReworked\\SFX\\" + soundFileName; UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(text, (AudioType)13); audioClip.SendWebRequest(); while (!audioClip.isDone) { } AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip); audioInfo.AudioSource.clip = content; audioInfo.AudioSource.PlayOneShot(content); audioInfo.IsPlaying = true; float time = 5f; Task.Run(async delegate { await Task.Delay(TimeSpan.FromSeconds(time)); audioInfo.AudioSource.Stop(); audioInfo.IsPlaying = false; }); BrackenReworkedPlugin.mls.LogInfo((object)("Playing: " + soundFileName)); } } public static void StopAllSounds() { foreach (AudioInfo value in AudioInfoMap.Values) { if (value.IsPlaying) { value.AudioSource.Stop(); value.IsPlaying = false; } } } } } namespace BrackenReworkedPlugin.Patches.Networking { internal class NetworkHandler { private static BrackenReworkedPlugin pluginInstance => BrackenReworkedPlugin.Instance; [NetworkMessage("MARK_TRANSMITTING", false)] public static void RecievedNewInfection(ulong sender, NetworkMessages message) { if (message.PlayerId == (ulong)StartOfRound.Instance.thisClientPlayerId) { pluginInstance.markingManager.AddMark(); } } } [Serializable] internal class NetworkMessages { public ulong PlayerId { get; set; } } }