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 ForestKeeper SonidosCustom Sozak v1.0.2
ChaseThemes.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ChaseThemes.Patches; using HarmonyLib; using LCSoundTool; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ChaseThemes")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A template for Lethal Company")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0cbe734292361bd380907923d22e3585590eecc9")] [assembly: AssemblyProduct("ChaseThemes")] [assembly: AssemblyTitle("ChaseThemes")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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 ChaseThemes { [BepInPlugin("LineLoad.ChaseThemes", "Chase Themes", "1.0.0")] public class ChaseThemesBase : BaseUnityPlugin { private const string pluginGUID = "LineLoad.ChaseThemes"; private const string pluginName = "Chase Themes"; private const string pluginVersion = "1.0.0"; private readonly Harmony harmony = new Harmony("LineLoad.ChaseThemes"); public static ChaseThemesBase Instance; internal ManualLogSource logger; private static string path = Path.Combine(Paths.PluginPath, "LineLoad.ChaseThemes".Replace('.', '-')); private static string[] acceptedFileTypes = new string[3] { "*.ogg", "*.mp3", "*.wav" }; private static readonly char[] _invalidConfigChars = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' }; private static string enabledEnemiesCategoryName = "*Enabled Creature Chase Themes*"; private static string[] enemyList = new string[7] { "THUMPER", "BUNKER SPIDER", "HOARDING BUG", "FORESTKEEPER", "GHOSTGIRL", "BLOB", "NUTCRACKER" }; private static Dictionary<string, bool> enabledEnemyThemes = new Dictionary<string, bool>(); private static List<string> themePaths; private static List<string> themeNames; public static string[] themeCategories = new string[5] { "MAIN", "FORESTKEEPER", "GHOSTGIRL", "BLOB", "NUTCRACKER" }; public static Dictionary<string, AudioClip[]> themeAudioClips; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } logger = Logger.CreateLogSource("LineLoad.ChaseThemes"); harmony.PatchAll(typeof(ChaseThemesBase)); harmony.PatchAll(typeof(RoundManagerPatch)); harmony.PatchAll(typeof(EnemyAIPatch)); Array.Sort(themeCategories); Array.Sort(enemyList); GenerateConfig(); LoadAudioFiles(); PatchConfigEnabledEnemies(); logger.LogInfo((object)"CHASE THEMES: Plugin LineLoad.ChaseThemes is loaded!"); } private void PatchConfigEnabledEnemies() { string[] array = enemyList; foreach (string text in array) { if (isConfigEnabledEnemy(text)) { switch (text) { case "THUMPER": harmony.PatchAll(typeof(CrawlerAIPatch)); logger.LogDebug((object)"CHASE THEMES: CrawlerAI patched!"); break; case "BUNKER SPIDER": harmony.PatchAll(typeof(SandSpiderAIPatch)); logger.LogDebug((object)"CHASE THEMES: SandSpiderAI patched!"); break; case "HOARDING BUG": harmony.PatchAll(typeof(HoardingBugAIPatch)); logger.LogDebug((object)"CHASE THEMES: HoardingBugAI patched!"); break; case "FORESTKEEPER": harmony.PatchAll(typeof(ForestKeeperAIPatch)); logger.LogDebug((object)"CHASE THEMES: ForestKeeperAI patched!"); break; case "GHOSTGIRL": harmony.PatchAll(typeof(GhostGirlAIPatch)); logger.LogDebug((object)"CHASE THEMES: GhostGirlAI patched!"); break; case "BLOB": harmony.PatchAll(typeof(BlobAIPatch)); logger.LogDebug((object)"CHASE THEMES: BlobAI patched!"); break; case "NUTCRACKER": harmony.PatchAll(typeof(NutcrackerAIPatch)); logger.LogDebug((object)"CHASE THEMES: NutcrackerAI patched!"); break; } } } } private void GenerateConfig() { string[] array = enemyList; ConfigEntry<bool> val = default(ConfigEntry<bool>); foreach (string text in array) { AddEntryToConfig(enabledEnemiesCategoryName, text, defaultValue: true); ((BaseUnityPlugin)this).Config.TryGetEntry<bool>(enabledEnemiesCategoryName, text, ref val); enabledEnemyThemes.Add(text, val.Value); } } private void UpdateConfigThemes() { logger.LogDebug((object)"CHASE THEMES: Updating config"); logger.LogDebug((object)("CHASE THEMES: Config keys: " + ((BaseUnityPlugin)this).Config.Keys.ToString())); foreach (ConfigDefinition key in ((BaseUnityPlugin)this).Config.Keys) { logger.LogDebug((object)("CHASE THEMES: Checking config entry for " + ((object)key).ToString())); logger.LogDebug((object)("CHASE THEMES: Entry section " + key.Section)); logger.LogDebug((object)("CHASE THEMES: Entry key " + key.Key)); logger.LogDebug((object)("CHASE THEMES: themeCategories.Contains(key.Section) " + themeCategories.Contains(key.Section))); logger.LogDebug((object)("CHASE THEMES: !themeNames.Contains(key.Key) " + !themeNames.Contains(key.Key))); if (themeCategories.Contains(key.Section) && !themeNames.Contains(key.Key)) { logger.LogDebug((object)("CHASE THEMES: Removing " + ((object)key).ToString())); ((BaseUnityPlugin)this).Config.Remove(key); } } } private void AddEntryToConfig(string category, string name, bool defaultValue) { try { logger.LogDebug((object)("CHASE THEMES: Attempting to add entry to the config: " + category + " | " + name)); ((BaseUnityPlugin)this).Config.Bind<bool>(category, name, defaultValue, (ConfigDescription)null); } catch (Exception ex) { logger.LogError((object)ex); } } private string SanitiseString(string s) { logger.LogDebug((object)("CHASE THEMES: Sanitising string: " + s)); char[] invalidConfigChars = _invalidConfigChars; foreach (char c in invalidConfigChars) { s = s.Replace(c.ToString(), ""); } logger.LogDebug((object)("CHASE THEMES: Sanitised string: " + s)); return s; } private bool isConfigEnabledEnemy(string enemy) { ConfigEntry<bool> val = default(ConfigEntry<bool>); ((BaseUnityPlugin)this).Config.TryGetEntry<bool>(enabledEnemiesCategoryName, enemy, ref val); return val.Value; } private void LoadAudioFiles() { themePaths = new List<string>(); themeNames = new List<string>(); int num = 0; logger.LogDebug((object)"CHASE THEMES: Retrieving themes..."); string[] array = acceptedFileTypes; foreach (string searchPattern in array) { themePaths.AddRange(Directory.GetFiles(path, searchPattern)); } if (themePaths.Count() == 0) { logger.LogWarning((object)"CHASE THEMES: No themes found!"); return; } logger.LogDebug((object)("CHASE THEMES: Retrieved themes successfully. Number of themes retrieved: " + themePaths.Count())); themePaths.Sort(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); List<string> list = new List<string>(); themeAudioClips = new Dictionary<string, AudioClip[]>(); string[] array2 = themeCategories; foreach (string key in array2) { dictionary.Add(key, 0); } logger.LogInfo((object)"CHASE THEMES: Loading themes..."); int num2 = 0; string text = themeCategories[num2]; ConfigEntry<bool> val = default(ConfigEntry<bool>); for (int k = 0; k < themePaths.Count(); k++) { if (!themePaths[k].Contains(text)) { num2++; text = themeCategories[num2]; } string text2 = SanitiseString(themePaths[k].Replace(path, "")); logger.LogDebug((object)("CHASE THEMES: Detected " + text + " theme: " + text2)); themeNames.Add(text2); AddEntryToConfig(text, text2, defaultValue: true); ((BaseUnityPlugin)this).Config.TryGetEntry<bool>(text, text2, ref val); if (val.Value) { list.Add(themePaths[k]); dictionary[text]++; logger.LogDebug((object)("CHASE THEMES: " + text + " theme number " + dictionary[text] + " accepted: " + text2)); } } string[] array3 = themeCategories; foreach (string text3 in array3) { logger.LogDebug((object)("CHASE THEMES: Number of " + text3 + " themes:" + dictionary[text3])); themeAudioClips.Add(text3, (AudioClip[])(object)new AudioClip[dictionary[text3]]); } num2 = 0; text = themeCategories[num2]; foreach (string item in list) { bool flag = false; num++; if (!item.Contains(text)) { num2++; text = themeCategories[num2]; } string text2 = SanitiseString(item.Replace(path, "")); logger.LogDebug((object)("CHASE THEMES: Loading " + text2)); if (item.Contains(text)) { dictionary[text]--; themeAudioClips[text][dictionary[text]] = SoundTool.GetAudioClip(Paths.PluginPath, item); logger.LogInfo((object)("CHASE THEMES: Loaded " + text + " theme: " + text2)); flag = true; } if (!flag) { num--; logger.LogWarning((object)("CHASE THEMES: Theme failed to load: " + text2)); } } if (num == list.Count()) { logger.LogInfo((object)"CHASE THEMES: All themes loaded successfully!"); } else if (num > 0) { logger.LogWarning((object)"CHASE THEMES: Some themes failed to load!"); } else { logger.LogWarning((object)"CHASE THEMES: Failed to load themes!"); } } } public static class PluginInfo { public const string PLUGIN_GUID = "ChaseThemes"; public const string PLUGIN_NAME = "ChaseThemes"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace ChaseThemes.Patches { [HarmonyPatch(typeof(BlobAI))] internal class BlobAIPatch : MonoBehaviour { private static string audioCategory = "BLOB"; private static bool audioPlaying = false; private static float playedTime = 0f; private static float volume = 0.2f; [HarmonyPatch("Update")] [HarmonyPostfix] private static void PlaychosenMainClip(ref AudioSource ___creatureSFX) { if (!audioPlaying) { ___creatureSFX.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory], volume); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); audioPlaying = true; playedTime = 0f; } else { playedTime += Time.deltaTime; if (playedTime > RoundManagerPatch.chosenThemes[audioCategory].length) { audioPlaying = false; } } } } [HarmonyPatch(typeof(RedLocustBees))] internal class CircuitBeeAIPatch { private static string audioCategory = "MAIN"; private static bool alreadyPlaying = false; [HarmonyPatch("Update")] [HarmonyPostfix] private static void PlayChosenMainClip(ref int ___currentBehaviourStateIndex, ref AudioSource ___creatureVoice) { alreadyPlaying = false; if (___currentBehaviourStateIndex == 2 && !alreadyPlaying) { ___creatureVoice.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory]); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); alreadyPlaying = true; } } } [HarmonyPatch(typeof(CrawlerAI))] internal class CrawlerAIPatch : MonoBehaviour { private static string audioCategory = "MAIN"; private static float volume = 0.75f; [HarmonyPatch("BeginChasingPlayerClientRpc")] [HarmonyPostfix] private static void PlaychosenMainClip(CrawlerAI __instance, ref bool ___hasEnteredChaseMode) { if (((EnemyAI)__instance).currentBehaviourStateIndex == 1 && !___hasEnteredChaseMode) { ((EnemyAI)__instance).creatureVoice.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory], volume); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); } } } [HarmonyPatch(typeof(EnemyAI))] internal class EnemyAIPatch : MonoBehaviour { [HarmonyPatch("KillEnemyClientRpc")] [HarmonyPostfix] private static void StopThemeOnDeath(EnemyAI __instance) { StopTheme(__instance); } [HarmonyPatch("SwitchToBehaviourStateOnLocalClient")] [HarmonyPostfix] private static void StopThemeOnPassiveBehaviourState(EnemyAI __instance) { if (__instance.currentBehaviourStateIndex == 0 && (isEnemy(__instance, "crawler") || isEnemy(__instance, "forestgiant"))) { StopTheme(__instance); } else if (__instance.currentBehaviourStateIndex != 2 && (isEnemy(__instance, "hoarding bug") || isEnemy(__instance, "sandspider"))) { StopTheme(__instance); } else if (__instance.currentBehaviourStateIndex == 0 && isEnemy(__instance, "girl")) { GhostGirlAIPatch.GirlThemeSource.Stop(); } } private static void StopTheme(EnemyAI __instance) { __instance.creatureVoice.Stop(); ChaseThemesBase.Instance.logger.LogDebug((object)"Chase theme stopped!"); } private static bool isEnemy(EnemyAI enemy, string enemyName) { return enemy.enemyType.enemyName.ToLower() == enemyName.ToLower(); } } [HarmonyPatch(typeof(ForestGiantAI))] internal class ForestKeeperAIPatch : MonoBehaviour { private static string audioCategory = "FORESTKEEPER"; private static float volume = 0.7f; [HarmonyPatch("BeginChasingNewPlayerClientRpc")] [HarmonyPostfix] private static void PlaychosenMainClip(ref int ___currentBehaviourStateIndex, ref bool ___chasingPlayerInLOS, ref AudioSource ___creatureVoice) { if (___currentBehaviourStateIndex == 1 && !___chasingPlayerInLOS) { ___creatureVoice.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory], volume); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); } } } [HarmonyPatch(typeof(DressGirlAI))] internal class GhostGirlAIPatch : MonoBehaviour { private static string audioCategory = "GHOSTGIRL"; private static bool alreadyPlaying = false; private static float volume = 1.15f; public static AudioSource GirlThemeSource = new AudioSource(); public static float posInSong = 0f; [HarmonyPatch("Start")] [HarmonyPostfix] private static void resetGirl() { GirlThemeSource.volume = volume; posInSong = 0f; } [HarmonyPatch("BeginChasing")] [HarmonyPostfix] private static void PlaychosenMainClip(ref int ___currentBehaviourStateIndex, ref AudioSource ___creatureVoice, ref float ___chaseTimer) { alreadyPlaying = false; GirlThemeSource = ___creatureVoice; GirlThemeSource.clip = RoundManagerPatch.chosenThemes[audioCategory]; GirlThemeSource.loop = true; if (posInSong > GirlThemeSource.clip.length) { posInSong -= GirlThemeSource.clip.length; } ChaseThemesBase.Instance.logger.LogInfo((object)("Song will start playing " + posInSong + " seconds in...")); ChaseThemesBase.Instance.logger.LogInfo((object)"Loaded Ghost Girl Clip"); ChaseThemesBase.Instance.logger.LogInfo((object)"Ghost Girl Method Triggered"); if (___currentBehaviourStateIndex == 1 && !alreadyPlaying) { ChaseThemesBase.Instance.logger.LogInfo((object)("Should be starting " + posInSong + " into the song")); GirlThemeSource.Play(); GirlThemeSource.time = posInSong; ChaseThemesBase.Instance.logger.LogInfo((object)("Starting " + GirlThemeSource.time + " into the song")); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); alreadyPlaying = true; } } [HarmonyPatch("StopChasing")] [HarmonyPostfix] private static void getTimeRemaining(ref float ___chaseTimer) { posInSong += 20f - ___chaseTimer; } } [HarmonyPatch(typeof(HoarderBugAI))] internal class HoardingBugAIPatch { private static string audioCategory = "MAIN"; private static float volume = 0.95f; [HarmonyPatch("IsHoarderBugAngry")] [HarmonyPostfix] private static void PlaychosenMainClip(ref int ___currentBehaviourStateIndex, ref AudioSource ___creatureVoice, ref bool ___inChase) { if (___currentBehaviourStateIndex == 2 && !___inChase) { ___creatureVoice.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory], volume); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); } } } [HarmonyPatch(typeof(NutcrackerEnemyAI))] internal class NutcrackerAIPatch : MonoBehaviour { private static string audioCategory = "NUTCRACKER"; private static bool audioPlaying = false; private static float playedTime = 0f; private static float volume = 0.7f; [HarmonyPatch("Start")] [HarmonyPostfix] private static void reset() { audioPlaying = false; playedTime = 0f; } [HarmonyPatch("Update")] [HarmonyPostfix] private static void PlaychosenMainClip(ref AudioSource ___longRangeAudio) { if (!audioPlaying) { ___longRangeAudio.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory], volume); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); audioPlaying = true; playedTime = 0f; } else { playedTime += Time.deltaTime; if (playedTime > RoundManagerPatch.chosenThemes[audioCategory].length) { audioPlaying = false; } } } [HarmonyPatch("StopInspection")] [HarmonyPostfix] private static void stopClip(ref AudioSource ___longRangeAudio, ref bool ___isEnemyDead) { if (___isEnemyDead) { ___longRangeAudio.Stop(); } } } [HarmonyPatch(typeof(RoundManager))] internal class RoundManagerPatch { public static Dictionary<string, AudioClip> chosenThemes = new Dictionary<string, AudioClip>(); [HarmonyPatch("GenerateNewLevelClientRpc")] [HarmonyPostfix] private static void LoadTheme(ref StartOfRound ___playersManager) { try { SelectRandomThemes(getLevelSeed(ref ___playersManager)); ChaseThemesBase.Instance.logger.LogInfo((object)"CHASE THEMES: Chase theme loaded successfully!"); } catch (Exception ex) { ChaseThemesBase.Instance.logger.LogWarning((object)ex); } } private static int getLevelSeed(ref StartOfRound ___playersManager) { ChaseThemesBase.Instance.logger.LogDebug((object)("CHASE THEMES: Map seed is " + ___playersManager.randomMapSeed + " !!!")); return ___playersManager.randomMapSeed; } private static void SelectRandomThemes(int seed) { chosenThemes.Clear(); string[] themeCategories = ChaseThemesBase.themeCategories; foreach (string text in themeCategories) { int num = ChaseThemesBase.themeAudioClips[text].Length; int num2 = seed % num; chosenThemes.TryAdd(text, ChaseThemesBase.themeAudioClips[text][num2]); ChaseThemesBase.Instance.logger.LogDebug((object)("CHASE THEMES: Number of clips: " + num + " Chosen clip number " + num2)); ChaseThemesBase.Instance.logger.LogInfo((object)("CHASE THEMES: " + text + " clip successfully chosen: " + ((object)chosenThemes[text]).ToString())); } } } [HarmonyPatch(typeof(SandSpiderAI))] internal class SandSpiderAIPatch { private static string audioCategory = "MAIN"; private static bool audioPlaying = false; private static float playedTime = 0f; private static float volume = 0.8f; [HarmonyPatch("Update")] [HarmonyPostfix] private static void PlaychosenMainClip(ref int ___currentBehaviourStateIndex, ref AudioSource ___creatureVoice, ref float ___chaseTimer, ref bool ___watchFromDistance) { if (___currentBehaviourStateIndex == 2 && ___chaseTimer > 0f && !audioPlaying && !___watchFromDistance) { ___creatureVoice.PlayOneShot(RoundManagerPatch.chosenThemes[audioCategory], volume); ChaseThemesBase.Instance.logger.LogInfo((object)"Chase theme started!"); playedTime = 0f; audioPlaying = true; } else if (audioPlaying) { playedTime += Time.deltaTime; if (playedTime > RoundManagerPatch.chosenThemes[audioCategory].length) { audioPlaying = false; } } } } }