Please disclose if any significant portion of your mod was created 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 SpookyCompany v1.1.3
LCGhostMod.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; 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 Dissonance; using GameNetcodeStuff; using HarmonyLib; using LethalNetworkAPI; 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: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("LCGhostMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.0.0.0")] [assembly: AssemblyInformationalVersion("0.0.0-alpha.0.36+5e52c3ae4ec2482d51e6eeeddf58f5dfe8f88f93")] [assembly: AssemblyProduct("LCGhostMod")] [assembly: AssemblyTitle("LCGhostMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.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 DobieWan { internal class EventConfigs : IConfigs { private const string GROUP_NAME = "GHOST EVENT"; internal ConfigEntry<float> MinMicAmpToTriggerGhost { get; private set; } internal ConfigEntry<float> EventTriggerCooldownMin { get; private set; } internal ConfigEntry<float> EventTriggerCooldownMax { get; private set; } void IConfigs.Initialize(ConfigFile config) { MinMicAmpToTriggerGhost = config.Bind<float>("GHOST EVENT", "Microphone Amp Threshold", 0.4f, "This is the threshold amplitude for your microphone input to trigger a ghost event. A higher value means you must speak louder to trigger the event. Recommended between 0.1 and 2.0."); EventTriggerCooldownMin = config.Bind<float>("GHOST EVENT", "Min Cooldown Time", 2f, "Minimum length of time between ghost events triggered by you."); EventTriggerCooldownMax = config.Bind<float>("GHOST EVENT", "Max Cooldown Time", 5f, "Maximum length of time between ghost events triggered by you."); } } public interface IConfigs { internal void Initialize(ConfigFile config); } internal class SfxPlayerConfigs : IConfigs { private const string GROUP_NAME = "SFX"; internal ConfigEntry<float> RandomizePitchRange { get; private set; } internal ConfigEntry<float> RandomizeVolumeRange { get; private set; } void IConfigs.Initialize(ConfigFile config) { RandomizePitchRange = config.Bind<float>("SFX", "Randomize Pitch Range", 0.2f, "Bigger number means ghost SFX pitch can be randomized further from normal."); RandomizeVolumeRange = config.Bind<float>("SFX", "Randomize Volume Range", 0.2f, "Bigger number means ghost SFX volume can be randomized further from normal."); } } [HarmonyPatch(typeof(RoundManager))] internal class RoundManagerPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void RoundManagerAwake() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown GameObject val = GameObject.Find("Systems"); GameObject val2 = new GameObject("GhostManager", new Type[1] { typeof(GhostManager) }); val2.transform.SetParent(val.transform); } } [BepInPlugin("LCGhostMod", "LCGhostMod", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private readonly Harmony m_harmony = new Harmony("LCGhostMod"); internal static Plugin Instance { get; private set; } internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; internal AssetBundle AssetBundle { get; private set; } internal EventConfigs EventConfigs { get; } = new EventConfigs(); internal SfxPlayerConfigs SfxPlayerConfigs { get; } = new SfxPlayerConfigs(); public Plugin() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Instance = this; } private void Awake() { Log.LogInfo((object)"LCGhostMod is awake!"); InitConfigs(); TryLoadAssetBundle(); ApplyPluginPatch(); } private void ApplyPluginPatch() { m_harmony.PatchAll(typeof(RoundManagerPatch)); } private void TryLoadAssetBundle() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (directoryName == null) { Log.LogError((object)"Failed to get bundle directory."); return; } AssetBundle = AssetBundle.LoadFromFile(Path.Combine(directoryName, "lcghostmodassets")); if ((Object)(object)AssetBundle == (Object)null) { Log.LogError((object)"Failed to load custom assets."); } else { Log.LogInfo((object)"LCGhostMod bundle loaded!"); } } private void InitConfigs() { ((IConfigs)EventConfigs).Initialize(((BaseUnityPlugin)this).Config); ((IConfigs)SfxPlayerConfigs).Initialize(((BaseUnityPlugin)this).Config); } } internal class GhostEventDetector { private readonly EventConfigs m_configs = null; private readonly Action<PlayerControllerB> m_hauntVictimEventAction = null; private float m_lastGhostNoiseTime = 0f; private float m_cooldownTime = 0f; internal GhostEventDetector(Action<PlayerControllerB> hauntVictimEventAction) { m_configs = Plugin.Instance.EventConfigs; m_hauntVictimEventAction = hauntVictimEventAction; m_cooldownTime = GetRandomCooldownTime(); } internal void Simulate() { StartOfRound instance = StartOfRound.Instance; PlayerControllerB localPlayerController = instance.localPlayerController; DissonanceComms voiceChatModule = instance.voiceChatModule; if (!localPlayerController.isPlayerDead || m_lastGhostNoiseTime + m_cooldownTime > Time.time || (Object)(object)voiceChatModule == (Object)null || (Object)(object)localPlayerController.spectatedPlayerScript == (Object)null) { return; } string localPlayerName = voiceChatModule.LocalPlayerName; if (!string.IsNullOrEmpty(localPlayerName)) { VoicePlayerState val = voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName); if (val != null && val.IsSpeaking && !(val.Amplitude < m_configs.MinMicAmpToTriggerGhost.Value)) { TriggerGhostEvent(localPlayerController.spectatedPlayerScript); } } } private void TriggerGhostEvent(PlayerControllerB toPlayer) { m_lastGhostNoiseTime = Time.time; m_cooldownTime = GetRandomCooldownTime(); m_hauntVictimEventAction?.Invoke(toPlayer); } private float GetRandomCooldownTime() { float value = m_configs.EventTriggerCooldownMin.Value; float value2 = m_configs.EventTriggerCooldownMax.Value; return value + Random.value * (value2 - value); } } internal class GhostManager : MonoBehaviour { private LethalClientMessage<HauntVictimEventData> m_hauntVictimEvent = null; private LethalClientMessage<VictimHauntedEventData> m_victimHauntedEvent = null; private GhostEventDetector m_ghostEventDetector = null; private GhostSfxPlayer m_ghostSfxPlayer = null; private void Start() { m_ghostEventDetector = new GhostEventDetector(TriggerHauntVictimEvent); m_ghostSfxPlayer = new GhostSfxPlayer(); m_hauntVictimEvent = new LethalClientMessage<HauntVictimEventData>("HauntVictim", (Action<HauntVictimEventData>)null, (Action<HauntVictimEventData, ulong>)ReceiveHauntVictimEvent); m_victimHauntedEvent = new LethalClientMessage<VictimHauntedEventData>("VictimHaunted", (Action<VictimHauntedEventData>)null, (Action<VictimHauntedEventData, ulong>)ReceiveVictimHauntedEvent); Plugin.Log.LogInfo((object)"GhostManager initialized!"); } private void LateUpdate() { m_ghostEventDetector.Simulate(); } private void TriggerHauntVictimEvent(PlayerControllerB forPlayer) { ulong actualClientId = forPlayer.actualClientId; Plugin.Log.LogInfo((object)$"Triggered haunt victim event for {actualClientId}"); HauntVictimEventData hauntVictimEventData = new HauntVictimEventData(actualClientId); m_hauntVictimEvent.SendAllClients(hauntVictimEventData, true, false); } private void ReceiveHauntVictimEvent(HauntVictimEventData data, ulong uselessParam) { PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; Plugin.Log.LogInfo((object)$"Haunt victim received for user {data.SpectatedUserId}. This user is {localPlayerController.actualClientId}"); if (localPlayerController.actualClientId == data.SpectatedUserId) { string text = m_ghostSfxPlayer.PlayHauntedSfx(); Plugin.Log.LogInfo((object)("Haunt victim: Playing clip " + text)); TriggerVictimHauntedEvent(text); } } private void TriggerVictimHauntedEvent(string audioClipName) { Plugin.Log.LogInfo((object)("Triggered victim haunted event with clip " + audioClipName)); VictimHauntedEventData victimHauntedEventData = new VictimHauntedEventData(audioClipName, StartOfRound.Instance.localPlayerController.actualClientId); m_victimHauntedEvent.SendAllClients(victimHauntedEventData, true, false); } private void ReceiveVictimHauntedEvent(VictimHauntedEventData data, ulong uselessParam) { PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; if (!((Object)(object)localPlayerController.spectatedPlayerScript == (Object)null)) { Plugin.Log.LogInfo((object)$"Victim haunted received from user {data.FromUserId}. The spectated user is {localPlayerController.spectatedPlayerScript.actualClientId}"); ulong actualClientId = localPlayerController.spectatedPlayerScript.actualClientId; if (actualClientId == data.FromUserId) { Plugin.Log.LogInfo((object)("Victim haunted: Playing clip: " + data.ClipName)); m_ghostSfxPlayer.PlaySpectatorSfx(data.ClipName); } } } } internal class GhostSfxPlayer { private readonly SfxPlayerConfigs m_configs = null; private readonly AudioClip[] m_ghostSfx = null; private AudioSource m_audioSource = null; private int m_ghostSfxIndex = 0; private AudioSource AudioSource { get { if ((Object)(object)m_audioSource == (Object)null) { GameObject val = GameObject.Find("Systems/Audios/SFX"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"Failed to find SFX object"); return null; } if (!val.TryGetComponent<AudioSource>(ref m_audioSource)) { Plugin.Log.LogError((object)"Failed to find SFX audio source"); return null; } } return m_audioSource; } } internal GhostSfxPlayer() { m_configs = Plugin.Instance.SfxPlayerConfigs; AssetBundle assetBundle = Plugin.Instance.AssetBundle; if (!((Object)(object)assetBundle == (Object)null)) { m_ghostSfx = assetBundle.LoadAllAssets<AudioClip>(); m_ghostSfx.Shuffle(); ManualLogSource log = Plugin.Log; AudioClip[] ghostSfx = m_ghostSfx; log.LogInfo((object)$"Loaded {((ghostSfx != null) ? ghostSfx.Length : 0)} audio clips"); } } internal string PlayHauntedSfx() { if (m_ghostSfx == null || m_ghostSfx.Length == 0 || (Object)(object)AudioSource == (Object)null) { return null; } AudioClip nextAudioClip = GetNextAudioClip(); Utility.PlayAudioClipLocalOnly(AudioSource, nextAudioClip, m_configs.RandomizePitchRange.Value, m_configs.RandomizeVolumeRange.Value); Plugin.Log.LogInfo((object)"ooOOOOOOOoooooOOOoo"); return ((Object)nextAudioClip).name; } internal AudioClip GetNextAudioClip() { if (m_ghostSfxIndex >= m_ghostSfx.Length) { ReshuffleAudioClips(); m_ghostSfxIndex = 0; } return m_ghostSfx[m_ghostSfxIndex++]; } internal void ReshuffleAudioClips() { AudioClip val = m_ghostSfx[^1]; m_ghostSfx.Shuffle(); AudioClip val2 = m_ghostSfx[0]; if (m_ghostSfx.Length > 1 && (Object)(object)val == (Object)(object)val2) { m_ghostSfx[0] = m_ghostSfx[^1]; m_ghostSfx[^1] = val2; } } internal void PlaySpectatorSfx(string clipName) { if (!TryGetAudioClipByName(clipName, out var audioClip)) { audioClip = m_ghostSfx[Random.Range(0, m_ghostSfx.Length)]; } Utility.PlayAudioClipLocalOnly(AudioSource, audioClip, m_configs.RandomizePitchRange.Value, m_configs.RandomizeVolumeRange.Value); Plugin.Log.LogInfo((object)"ooOOOOOOOoooooOOOoo"); } private bool TryGetAudioClipByName(string clipName, out AudioClip audioClip) { for (int i = 0; i < m_ghostSfx.Length; i++) { AudioClip val = m_ghostSfx[i]; if ((Object)(object)val != (Object)null && ((Object)val).name == clipName) { audioClip = val; return true; } } audioClip = null; return false; } } [Serializable] internal struct HauntVictimEventData { [SerializeField] private ulong m_spectatedUserId; internal ulong SpectatedUserId { readonly get { return m_spectatedUserId; } private set { m_spectatedUserId = value; } } internal HauntVictimEventData(ulong mSpectatedUserId) { m_spectatedUserId = 0uL; SpectatedUserId = mSpectatedUserId; } } [Serializable] internal struct VictimHauntedEventData { [SerializeField] private string m_clipName; [SerializeField] private ulong m_fromUserId; internal string ClipName { readonly get { return m_clipName; } private set { m_clipName = value; } } internal ulong FromUserId { readonly get { return m_fromUserId; } private set { m_fromUserId = value; } } internal VictimHauntedEventData(string clipName, ulong fromUserId) { m_clipName = null; m_fromUserId = 0uL; ClipName = clipName; FromUserId = fromUserId; } } internal static class Utility { internal static void Shuffle<T>(this IList<T> list) { for (int i = 0; i < list.Count; i++) { T value = list[i]; int index = Random.Range(i, list.Count); list[i] = list[index]; list[index] = value; } } internal static void PlayAudioClipLocalOnly(AudioSource audioSource, AudioClip clip, float randomizePitchRange = 0f, float randomizeVolumeRange = 0f, float volume = 1f) { if (randomizePitchRange > 0f) { audioSource.pitch = Random.Range(1f - randomizePitchRange, 1f + randomizePitchRange); } float num = 1f; if (randomizeVolumeRange > 0f) { num = Random.Range(volume - randomizeVolumeRange, volume + randomizeVolumeRange); } audioSource.PlayOneShot(clip, num); } } public static class PluginInfo { public const string PLUGIN_GUID = "LCGhostMod"; public const string PLUGIN_NAME = "LCGhostMod"; 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) { } } }