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 Ominous v1.0.0
Ominous.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Ominous")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+901b84ab23f2f10926b13865f9b40bb283490874")] [assembly: AssemblyProduct("Ominous")] [assembly: AssemblyTitle("Ominous")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 Ominous { public class ClipLibrary { private readonly Dictionary<string, AudioClip> m_clips = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, string> m_errors = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public bool Loading { get; private set; } public int Loaded { get; private set; } public int Failed { get; private set; } public string CurrentFile { get; private set; } public string LastError { get; private set; } public int Pending { get; private set; } public AudioClip Get(string fileName) { if (string.IsNullOrEmpty(fileName)) { return null; } if (!m_clips.TryGetValue(fileName, out var value)) { return null; } return value; } public bool HasClip(string fileName) { if (!string.IsNullOrEmpty(fileName)) { return m_clips.ContainsKey(fileName); } return false; } public string ErrorFor(string fileName) { if (!m_errors.TryGetValue(fileName ?? "", out var value)) { return null; } return value; } public void Reset() { foreach (AudioClip value in m_clips.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } m_clips.Clear(); m_errors.Clear(); Loaded = 0; Failed = 0; Pending = 0; CurrentFile = null; LastError = null; } public IEnumerator LoadAll(IEnumerable<string> fileNames, string tracksDir, Action onComplete) { Reset(); Loading = true; List<string> queue = new List<string>(); foreach (string fileName in fileNames) { if (!string.IsNullOrWhiteSpace(fileName)) { queue.Add(fileName.Trim()); } } Pending = queue.Count; try { for (int i = 0; i < queue.Count; i++) { string name = (CurrentFile = queue[i]); if (m_clips.ContainsKey(name)) { Loaded++; continue; } AudioClip val = null; string error = null; string path = Path.Combine(tracksDir, name); if (!File.Exists(path)) { error = "File not found in tracks folder"; } else { string text2 = Path.GetExtension(name).ToLowerInvariant(); if (text2 == ".wav") { try { val = LoadWav(name, path); if ((Object)(object)val == (Object)null) { error = "Unsupported WAV format"; } } catch (Exception ex) { error = ex.Message; } } else if (text2 == ".mp3") { AudioClip decoded = null; yield return LoadMp3(name, path, delegate(AudioClip result) { decoded = result; }); val = decoded; if ((Object)(object)val == (Object)null) { error = "MP3 decode failed"; } } else { error = "Unsupported audio type " + text2; } } if ((Object)(object)val != (Object)null) { Object.DontDestroyOnLoad((Object)(object)val); m_clips[name] = val; Loaded++; } else { m_errors[name] = error ?? "unknown error"; LastError = name + ": " + m_errors[name]; Failed++; Logger.LogWarning((object)("[Ominous] Failed to load track '" + name + "': " + m_errors[name])); } } } finally { ClipLibrary clipLibrary = this; clipLibrary.Loading = false; clipLibrary.CurrentFile = null; clipLibrary.Pending = 0; } onComplete?.Invoke(); } private static AudioClip LoadWav(string name, string path) { byte[] array = File.ReadAllBytes(path); if (array.Length < 44 || !Tag(array, 0, "RIFF") || !Tag(array, 8, "WAVE")) { return null; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; byte[] array2 = null; int num5 = 12; while (num5 + 8 <= array.Length) { string text = Encoding.ASCII.GetString(array, num5, 4); int num6 = BitConverter.ToInt32(array, num5 + 4); int num7 = num5 + 8; if (num6 < 0 || num7 > array.Length) { break; } if (num7 + num6 > array.Length) { num6 = array.Length - num7; } if (text == "fmt " && num7 + 16 <= array.Length) { num = BitConverter.ToUInt16(array, num7); num2 = BitConverter.ToUInt16(array, num7 + 2); num3 = BitConverter.ToInt32(array, num7 + 4); num4 = BitConverter.ToUInt16(array, num7 + 14); if (num == 65534 && num7 + 26 <= array.Length) { num = BitConverter.ToUInt16(array, num7 + 24); } } else if (text == "data") { array2 = new byte[num6]; Array.Copy(array, num7, array2, 0, num6); } num5 = num7 + num6 + (num6 & 1); } if (array2 == null || num2 < 1 || num2 > 8 || num3 < 1) { return null; } int num8 = num4 / 8; if (num8 < 1) { return null; } int num9 = num8 * num2; int num10 = array2.Length / num9; if (num10 < 1) { return null; } float[] array3 = new float[num10 * num2]; for (int i = 0; i < array3.Length; i++) { int num11 = i * num8; if (num11 + num8 > array2.Length) { break; } array3[i] = DecodeSample(array2, num11, num, num4); } AudioClip obj = AudioClip.Create(name, num10, num2, num3, false); obj.SetData(array3, 0); return obj; } private static float DecodeSample(byte[] data, int offset, int format, int bits) { if (format == 3) { return BitConverter.ToSingle(data, offset); } switch (bits) { case 8: return (float)(data[offset] - 128) / 128f; case 16: return (float)BitConverter.ToInt16(data, offset) / 32768f; case 24: { int num = data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16); if ((num & 0x800000) != 0) { num |= -16777216; } return (float)num / 8388608f; } case 32: return (float)BitConverter.ToInt32(data, offset) / 2.1474836E+09f; default: throw new NotSupportedException(bits + "-bit WAV"); } } private static bool Tag(byte[] bytes, int offset, string tag) { if (offset + 4 > bytes.Length) { return false; } if (bytes[offset] == tag[0] && bytes[offset + 1] == tag[1] && bytes[offset + 2] == tag[2]) { return bytes[offset + 3] == tag[3]; } return false; } private static IEnumerator LoadMp3(string name, string path, Action<AudioClip> done) { string text = "file:///" + path.Replace('\\', '/').TrimStart('/'); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(text, (AudioType)13); yield return request.SendWebRequest(); if ((int)request.result != 1) { Logger.LogWarning((object)("[Ominous] MP3 '" + name + "' failed: " + request.error)); request.Dispose(); yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)clip == (Object)null) { request.Dispose(); yield break; } ((Object)clip).name = name; done(clip); yield return null; bool num = (Object)(object)clip != (Object)null; request.Dispose(); if (!num) { Logger.LogWarning((object)("[Ominous] MP3 '" + name + "' did not survive loader disposal. Convert to WAV.")); } } } public class OminousAudio : MonoBehaviour { private AudioSource m_sourceA; private AudioSource m_sourceB; private bool m_usingSourceA = true; private string m_currentTrackA = ""; private string m_currentTrackB = ""; private float m_targetVolA; private float m_targetVolB; private float m_targetPitchA = 1f; private float m_targetPitchB = 1f; public static OminousAudio Instance { get; private set; } public float CurrentDucking { get; private set; } public string ActiveTrack { get; private set; } = ""; public float ActiveVolume { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); m_sourceA = ((Component)this).gameObject.AddComponent<AudioSource>(); ConfigureSource(m_sourceA); m_sourceB = ((Component)this).gameObject.AddComponent<AudioSource>(); ConfigureSource(m_sourceB); } private void ConfigureSource(AudioSource src) { src.playOnAwake = false; src.loop = true; src.spatialBlend = 0f; src.volume = 0f; src.pitch = 1f; src.priority = 64; AssignMixer(src); } public void AssignMixer(AudioSource src) { try { if ((Object)(object)MusicMan.instance != (Object)null && (Object)(object)MusicMan.instance.m_musicMixer != (Object)null) { src.outputAudioMixerGroup = MusicMan.instance.m_musicMixer; } } catch { } } private void Update() { float deltaTime = Time.deltaTime; if (deltaTime <= 0f) { return; } if ((Object)(object)m_sourceA.outputAudioMixerGroup == (Object)null && (Object)(object)MusicMan.instance != (Object)null && (Object)(object)MusicMan.instance.m_musicMixer != (Object)null) { m_sourceA.outputAudioMixerGroup = MusicMan.instance.m_musicMixer; m_sourceB.outputAudioMixerGroup = MusicMan.instance.m_musicMixer; } float num = ((OminousConfig.Data != null) ? OminousConfig.Data.FadeInSpeed : 0.6f); float num2 = ((OminousConfig.Data != null) ? OminousConfig.Data.FadeOutSpeed : 0.35f); float num3 = ((m_targetVolA > m_sourceA.volume) ? num : num2); m_sourceA.volume = Mathf.MoveTowards(m_sourceA.volume, m_targetVolA, num3 * deltaTime); m_sourceA.pitch = Mathf.MoveTowards(m_sourceA.pitch, m_targetPitchA, 0.5f * deltaTime); if (m_sourceA.volume <= 0.001f && m_targetVolA <= 0f) { if (m_sourceA.isPlaying) { m_sourceA.Stop(); } m_currentTrackA = ""; } float num4 = ((m_targetVolB > m_sourceB.volume) ? num : num2); m_sourceB.volume = Mathf.MoveTowards(m_sourceB.volume, m_targetVolB, num4 * deltaTime); m_sourceB.pitch = Mathf.MoveTowards(m_sourceB.pitch, m_targetPitchB, 0.5f * deltaTime); if (m_sourceB.volume <= 0.001f && m_targetVolB <= 0f) { if (m_sourceB.isPlaying) { m_sourceB.Stop(); } m_currentTrackB = ""; } float num5 = (ActiveVolume = Mathf.Max(m_sourceA.volume, m_sourceB.volume)); float num7 = ((OminousConfig.Data != null) ? OminousConfig.Data.DuckingStrength : 0.85f); CurrentDucking = Mathf.Clamp01(num5 * num7); if (m_usingSourceA && m_sourceA.isPlaying) { ActiveTrack = m_currentTrackA; } else if (!m_usingSourceA && m_sourceB.isPlaying) { ActiveTrack = m_currentTrackB; } else if (m_sourceA.isPlaying) { ActiveTrack = m_currentTrackA; } else if (m_sourceB.isPlaying) { ActiveTrack = m_currentTrackB; } else { ActiveTrack = ""; } } public void SetThreat(string trackName, float targetVolume, float targetPitch) { if (string.IsNullOrEmpty(trackName) || targetVolume <= 0.001f) { m_targetVolA = 0f; m_targetVolB = 0f; return; } AudioSource val = (m_usingSourceA ? m_sourceA : m_sourceB); if (!m_usingSourceA) { _ = m_sourceA; } else { _ = m_sourceB; } if (string.Equals(m_usingSourceA ? m_currentTrackA : m_currentTrackB, trackName, StringComparison.OrdinalIgnoreCase) && val.isPlaying) { if (m_usingSourceA) { m_targetVolA = targetVolume; m_targetPitchA = targetPitch; m_targetVolB = 0f; } else { m_targetVolB = targetVolume; m_targetPitchB = targetPitch; m_targetVolA = 0f; } return; } AudioClip val2 = OminousPlugin.Library.Get(trackName); if ((Object)(object)val2 == (Object)null) { return; } m_usingSourceA = !m_usingSourceA; if (m_usingSourceA) { m_currentTrackA = trackName; m_sourceA.clip = val2; m_sourceA.pitch = targetPitch; m_targetPitchA = targetPitch; m_targetVolA = targetVolume; if (!m_sourceA.isPlaying) { m_sourceA.Play(); } m_targetVolB = 0f; } else { m_currentTrackB = trackName; m_sourceB.clip = val2; m_sourceB.pitch = targetPitch; m_targetPitchB = targetPitch; m_targetVolB = targetVolume; if (!m_sourceB.isPlaying) { m_sourceB.Play(); } m_targetVolA = 0f; } } public void StopAllImmediate() { m_targetVolA = 0f; m_targetVolB = 0f; m_sourceA.volume = 0f; m_sourceB.volume = 0f; m_sourceA.Stop(); m_sourceB.Stop(); CurrentDucking = 0f; ActiveVolume = 0f; ActiveTrack = ""; } } public class OminousBeacon : MonoBehaviour { private GameObject m_beaconRoot; private Light m_light; private ParticleSystem[] m_particles; private Renderer m_orbRenderer; private AudioSource m_pingSource; private float m_currentIntensity; private Color m_currentColor = new Color(0.25f, 0.75f, 1f); public static OminousBeacon Instance { get; private set; } public bool IsActive { get; set; } public float TensionFactor { get; set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void Start() { CreateBeaconVisual(); } private void CreateBeaconVisual() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0053: 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_00a4: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected O, but got Unknown //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_beaconRoot != (Object)null) { return; } m_beaconRoot = new GameObject("[Ominous_Beacon_Visual]"); Object.DontDestroyOnLoad((Object)(object)m_beaconRoot); if ((Object)(object)OminousItem.WispBallPrefab != (Object)null) { GameObject val = Object.Instantiate<GameObject>(OminousItem.WispBallPrefab, m_beaconRoot.transform); val.transform.localPosition = Vector3.zero; Demister component = val.GetComponent<Demister>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } m_light = val.GetComponentInChildren<Light>(); m_particles = val.GetComponentsInChildren<ParticleSystem>(); } if ((Object)(object)m_light == (Object)null) { GameObject val2 = new GameObject("BeaconLight"); val2.transform.SetParent(m_beaconRoot.transform, false); m_light = val2.AddComponent<Light>(); m_light.type = (LightType)2; m_light.range = 14f; m_light.shadows = (LightShadows)0; } if (m_particles == null || m_particles.Length == 0) { GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)val3).name = "BeaconSphere"; val3.transform.SetParent(m_beaconRoot.transform, false); val3.transform.localScale = Vector3.one * 0.16f; Collider component2 = val3.GetComponent<Collider>(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } m_orbRenderer = val3.GetComponent<Renderer>(); if ((Object)(object)m_orbRenderer != (Object)null) { Shader val4 = Shader.Find("Custom/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Unlit/Color"); if ((Object)(object)val4 != (Object)null) { Material val5 = new Material(val4); val5.color = new Color(0.3f, 0.8f, 1f, 0.9f); if (val5.HasProperty("_EmissionColor")) { val5.EnableKeyword("_EMISSION"); val5.SetColor("_EmissionColor", new Color(0.3f, 0.8f, 1f) * 2f); } m_orbRenderer.material = val5; } } } m_pingSource = m_beaconRoot.AddComponent<AudioSource>(); m_pingSource.playOnAwake = false; m_pingSource.loop = false; m_pingSource.spatialBlend = 0.5f; m_pingSource.minDistance = 2f; m_pingSource.maxDistance = 20f; m_pingSource.volume = 0.8f; m_beaconRoot.SetActive(false); } private void Update() { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || !IsActive || (OminousConfig.Data != null && !OminousConfig.Data.EnableBeaconLight)) { if ((Object)(object)m_beaconRoot != (Object)null && m_beaconRoot.activeSelf) { m_currentIntensity = Mathf.MoveTowards(m_currentIntensity, 0f, 2f * Time.deltaTime); if ((Object)(object)m_light != (Object)null) { m_light.intensity = m_currentIntensity; } if (m_currentIntensity <= 0.01f) { m_beaconRoot.SetActive(false); } } return; } if ((Object)(object)m_beaconRoot == (Object)null) { CreateBeaconVisual(); } if (!m_beaconRoot.activeSelf) { m_beaconRoot.SetActive(true); } float num = Mathf.Sin(Time.time * 2.2f) * 0.08f; Vector3 val = ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.up * 1.75f + ((Component)localPlayer).transform.right * 0.45f - ((Component)localPlayer).transform.forward * 0.2f + Vector3.up * num; m_beaconRoot.transform.position = Vector3.Lerp(m_beaconRoot.transform.position, val, 7f * Time.deltaTime); Color val2 = default(Color); ((Color)(ref val2))..ctor(0.25f, 0.75f, 1f); Color val3 = default(Color); ((Color)(ref val3))..ctor(1f, 0.65f, 0.05f); Color val4 = default(Color); ((Color)(ref val4))..ctor(1f, 0.12f, 0.12f); Color val5 = ((!(TensionFactor <= 0.5f)) ? Color.Lerp(val3, val4, (TensionFactor - 0.5f) * 2f) : Color.Lerp(val2, val3, TensionFactor * 2f)); m_currentColor = Color.Lerp(m_currentColor, val5, 4f * Time.deltaTime); float num2 = Mathf.Lerp(1.5f, 7f, TensionFactor); float num3 = Mathf.Lerp(0.12f, 0.6f, TensionFactor); float num4 = Mathf.Sin(Time.time * num2 * MathF.PI * 2f) * num3; float num5 = ((OminousConfig.Data != null) ? OminousConfig.Data.BeaconBaseIntensity : 1.2f) + num4; m_currentIntensity = Mathf.MoveTowards(m_currentIntensity, num5, 3f * Time.deltaTime); if ((Object)(object)m_light != (Object)null) { m_light.color = m_currentColor; m_light.intensity = m_currentIntensity; int num6 = ((!((Object)(object)OminousTracker.Instance != (Object)null)) ? 1 : OminousTracker.Instance.ActiveQuality); float num7 = ((OminousConfig.Data != null) ? OminousConfig.Data.BeaconLightRange : 14f); m_light.range = num7 + (float)(num6 - 1) * 2f; } if (m_particles != null) { for (int i = 0; i < m_particles.Length; i++) { ParticleSystem val6 = m_particles[i]; if ((Object)(object)val6 != (Object)null) { MainModule main = val6.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(m_currentColor); } } } if ((Object)(object)m_orbRenderer != (Object)null && (Object)(object)m_orbRenderer.material != (Object)null) { m_orbRenderer.material.color = m_currentColor; if (m_orbRenderer.material.HasProperty("_EmissionColor")) { m_orbRenderer.material.SetColor("_EmissionColor", m_currentColor * (1f + TensionFactor * 2f)); } } } public void PlayPing() { if (!((Object)(object)m_pingSource == (Object)null)) { AudioClip val = OminousPlugin.Library.Get("radar_ping.wav"); if ((Object)(object)val != (Object)null) { m_pingSource.PlayOneShot(val, 0.85f); } } } } [Serializable] public class CreatureOminousEntry { public string Prefab = ""; public string Track = ""; public float TriggerDistance = 60f; public float MaxVolumeDistance = 18f; public float Volume = 0.85f; public int Priority = 10; public bool Enabled = true; public string Biome = ""; public int RequiredTier = 1; public CreatureOminousEntry() { } public CreatureOminousEntry(string prefab, string track, float triggerDist, float maxVolDist, float volume, int priority, string biome = "", int requiredTier = 1) { Prefab = prefab; Track = track; TriggerDistance = triggerDist; MaxVolumeDistance = maxVolDist; Volume = volume; Priority = priority; Enabled = true; Biome = biome; RequiredTier = requiredTier; } } [Serializable] public class OminousConfigData { public bool Enabled = true; public float MasterVolume = 1f; public float DuckingStrength = 0.85f; public bool PitchScaling = true; public float FadeInSpeed = 0.6f; public float FadeOutSpeed = 0.35f; public float ScanInterval = 0.25f; public bool RequireEquippedItem = true; public bool EnableBeaconLight = true; public float BeaconLightRange = 14f; public float BeaconBaseIntensity = 1.2f; public bool PingOnPerimeterEnter = true; public int WebPort = 8788; public List<CreatureOminousEntry> Creatures = new List<CreatureOminousEntry>(); } public static class OminousConfig { private static string s_pluginDir; private static string s_configPath; private static string s_tracksDir; public static OminousConfigData Data { get; private set; } = new OminousConfigData(); public static string PluginDir { get { if (string.IsNullOrEmpty(s_pluginDir)) { s_pluginDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "."; } return s_pluginDir; } } public static string ConfigPath { get { if (string.IsNullOrEmpty(s_configPath)) { s_configPath = Path.Combine(PluginDir, "ominous_config.json"); } return s_configPath; } } public static string TracksDir { get { if (string.IsNullOrEmpty(s_tracksDir)) { s_tracksDir = Path.Combine(PluginDir, "tracks"); } return s_tracksDir; } } public static void Load() { try { if (!Directory.Exists(TracksDir)) { Directory.CreateDirectory(TracksDir); } if (File.Exists(ConfigPath)) { OminousConfigData ominousConfigData = JsonConvert.DeserializeObject<OminousConfigData>(File.ReadAllText(ConfigPath)); if (ominousConfigData != null) { Data = ominousConfigData; Logger.LogInfo((object)$"[Ominous] Loaded config with {Data.Creatures.Count} creature entries."); return; } } } catch (Exception ex) { Logger.LogWarning((object)("[Ominous] Failed to read config file, generating defaults: " + ex.Message)); } CreateDefaults(); Save(); } public static void Save() { try { string contents = JsonConvert.SerializeObject((object)Data, (Formatting)1); File.WriteAllText(ConfigPath, contents); Logger.LogInfo((object)"[Ominous] Config saved successfully."); } catch (Exception ex) { Logger.LogError((object)("[Ominous] Failed to save config: " + ex.Message)); } } public static void CreateDefaults() { Data = new OminousConfigData { Enabled = true, RequireEquippedItem = true, EnableBeaconLight = true, BeaconLightRange = 14f, BeaconBaseIntensity = 1.2f, PingOnPerimeterEnter = true, MasterVolume = 1f, DuckingStrength = 0.85f, PitchScaling = true, FadeInSpeed = 0.6f, FadeOutSpeed = 0.35f, ScanInterval = 0.25f, WebPort = 8788, Creatures = new List<CreatureOminousEntry> { new CreatureOminousEntry("Troll", "troll_jaws.wav", 60f, 18f, 0.85f, 10, "BlackForest"), new CreatureOminousEntry("Greydwarf_Elite", "wolf_stalker.wav", 45f, 15f, 0.8f, 7, "BlackForest"), new CreatureOminousEntry("Skeleton", "wraith_spectral.wav", 40f, 14f, 0.75f, 6, "BlackForest"), new CreatureOminousEntry("Wraith", "wraith_spectral.wav", 55f, 20f, 0.85f, 9, "Swamp", 2), new CreatureOminousEntry("Abomination", "troll_jaws.wav", 55f, 18f, 0.85f, 9, "Swamp", 2), new CreatureOminousEntry("Serpent", "serpent_abyss.wav", 75f, 25f, 0.9f, 10, "Ocean", 2), new CreatureOminousEntry("Draugr_Elite", "troll_jaws.wav", 45f, 15f, 0.8f, 8, "Swamp", 2), new CreatureOminousEntry("Wolf", "wolf_stalker.wav", 50f, 15f, 0.8f, 8, "Mountain", 3), new CreatureOminousEntry("Fenring", "wolf_stalker.wav", 50f, 16f, 0.85f, 9, "Mountain", 3), new CreatureOminousEntry("StoneGolem", "troll_jaws.wav", 55f, 18f, 0.85f, 9, "Mountain", 3), new CreatureOminousEntry("Deathsquito", "wolf_stalker.wav", 45f, 12f, 0.85f, 9, "Plains", 4), new CreatureOminousEntry("Lox", "troll_jaws.wav", 55f, 18f, 0.8f, 7, "Plains", 4), new CreatureOminousEntry("GoblinBrute", "troll_jaws.wav", 50f, 16f, 0.85f, 9, "Plains", 4), new CreatureOminousEntry("Gjall", "wraith_spectral.wav", 70f, 25f, 0.9f, 10, "Mistlands", 5), new CreatureOminousEntry("Seeker", "wolf_stalker.wav", 45f, 15f, 0.8f, 8, "Mistlands", 5), new CreatureOminousEntry("SeekerSoldier", "troll_jaws.wav", 55f, 18f, 0.85f, 9, "Mistlands", 5), new CreatureOminousEntry("Morgen", "troll_jaws.wav", 60f, 20f, 0.9f, 10, "Ashlands", 6), new CreatureOminousEntry("FallenValkyrie", "wraith_spectral.wav", 65f, 22f, 0.9f, 9, "Ashlands", 6), new CreatureOminousEntry("Asksvin", "wolf_stalker.wav", 50f, 16f, 0.85f, 8, "Ashlands", 6) } }; } public static int InferTierForCreature(string prefabName, string biome) { if (!string.IsNullOrEmpty(biome)) { switch (biome.ToLowerInvariant()) { case "meadows": case "blackforest": return 1; case "ocean": case "swamp": return 2; case "mountain": case "mountains": return 3; case "plains": return 4; case "mistlands": return 5; case "ashlands": case "deepnorth": return 6; } } string text = (prefabName ?? "").ToLowerInvariant(); if (text.Contains("troll") || text.Contains("greydwarf") || text.Contains("skeleton") || text.Contains("ghost")) { return 1; } if (text.Contains("wraith") || text.Contains("abomination") || text.Contains("draugr") || text.Contains("leech") || text.Contains("serpent") || text.Contains("blob")) { return 2; } if (text.Contains("wolf") || text.Contains("drake") || text.Contains("fenring") || text.Contains("golem") || text.Contains("bat")) { return 3; } if (text.Contains("lox") || text.Contains("mosquito") || text.Contains("goblin") || text.Contains("growth")) { return 4; } if (text.Contains("gjall") || text.Contains("seeker") || text.Contains("tick") || text.Contains("dvergr")) { return 5; } if (text.Contains("morgen") || text.Contains("valkyrie") || text.Contains("asksvin") || text.Contains("bonemaw") || text.Contains("charred")) { return 6; } return 1; } public static CreatureOminousEntry FindEntry(string prefabName) { if (string.IsNullOrEmpty(prefabName) || Data == null || Data.Creatures == null) { return null; } for (int i = 0; i < Data.Creatures.Count; i++) { CreatureOminousEntry creatureOminousEntry = Data.Creatures[i]; if (creatureOminousEntry.Enabled && string.Equals(creatureOminousEntry.Prefab, prefabName, StringComparison.OrdinalIgnoreCase)) { return creatureOminousEntry; } } return null; } public static IEnumerable<string> GetAllReferencedTracks() { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (Data != null && Data.Creatures != null) { foreach (CreatureOminousEntry creature in Data.Creatures) { if (!string.IsNullOrEmpty(creature.Track)) { hashSet.Add(creature.Track.Trim()); } } } return hashSet; } } public static class OminousItem { public const string PrefabName = "OminousRadar"; private static readonly FieldRef<Humanoid, ItemData> s_utilityItem = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_utilityItem"); public static GameObject ItemPrefab { get; private set; } public static GameObject WispBallPrefab { get; private set; } public static void Init() { PrefabManager.OnVanillaPrefabsAvailable += RegisterItem; LocalizationManager.Instance.AddToken("item_ominous_radar", "Ominous Sounder", false); LocalizationManager.Instance.AddToken("item_ominous_radar_desc", "An ancient runic proximity sounder and warning beacon. Floats beside you, illuminating the dark with a calm aura and sounding ominous alerts as predators close in.", false); } private static void RegisterItem() { //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Expected O, but got Unknown //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) PrefabManager.OnVanillaPrefabsAvailable -= RegisterItem; try { GameObject prefab = PrefabManager.Instance.GetPrefab("Demister"); if ((Object)(object)prefab != (Object)null) { ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { StatusEffect equipStatusEffect = component.m_itemData.m_shared.m_equipStatusEffect; SE_Demister val = (SE_Demister)(object)((equipStatusEffect is SE_Demister) ? equipStatusEffect : null); if (val != null) { WispBallPrefab = val.m_ballPrefab; } } } GameObject prefab2 = PrefabManager.Instance.GetPrefab("Wishbone"); if ((Object)(object)prefab2 == (Object)null) { prefab2 = PrefabManager.Instance.GetPrefab("BeltStrength"); } if ((Object)(object)prefab2 == (Object)null) { prefab2 = PrefabManager.Instance.GetPrefab("Demister"); } if ((Object)(object)prefab2 == (Object)null) { Logger.LogWarning((object)"[Ominous] Could not find base utility item to clone."); return; } ItemPrefab = PrefabManager.Instance.CreateClonedPrefab("OminousRadar", prefab2); ItemDrop component2 = ItemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component2 != (Object)null) { component2.m_itemData.m_shared.m_name = "$item_ominous_radar"; component2.m_itemData.m_shared.m_description = "$item_ominous_radar_desc"; component2.m_itemData.m_shared.m_itemType = (ItemType)18; component2.m_itemData.m_shared.m_maxStackSize = 1; component2.m_itemData.m_shared.m_weight = 1f; component2.m_itemData.m_shared.m_maxQuality = 6; component2.m_itemData.m_shared.m_equipStatusEffect = null; } ItemConfig val2 = new ItemConfig(); val2.Name = "Ominous Sounder"; val2.Description = "An ancient runic proximity sounder and warning beacon. Floats beside you, illuminating the dark with a calm aura and sounding ominous alerts as predators close in."; val2.CraftingStation = CraftingStations.Workbench; val2.MinStationLevel = 1; val2.Amount = 1; val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[4] { new RequirementConfig { Item = "Wood", Amount = 10, AmountPerLevel = 5 }, new RequirementConfig { Item = "Copper", Amount = 2, AmountPerLevel = 2 }, new RequirementConfig { Item = "Resin", Amount = 5, AmountPerLevel = 5 }, new RequirementConfig { Item = "LeatherScraps", Amount = 2, AmountPerLevel = 2 } }; ItemConfig val3 = val2; CustomItem val4 = new CustomItem(ItemPrefab, false, val3); ItemManager.Instance.AddItem(val4); Logger.LogInfo((object)"[Ominous] Registered 'Ominous Sounder' utility item and recipe."); } catch (Exception arg) { Logger.LogError((object)$"[Ominous] Failed to register Ominous Sounder item: {arg}"); } } public static ItemData GetEquippedSounder(Player player) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 if ((Object)(object)player == (Object)null) { return null; } try { ItemData val = s_utilityItem.Invoke((Humanoid)(object)player); if (val != null) { if ((Object)(object)val.m_dropPrefab != (Object)null && string.Equals(((Object)val.m_dropPrefab).name, "OminousRadar", StringComparison.OrdinalIgnoreCase)) { return val; } if (string.Equals(val.m_shared.m_name, "$item_ominous_radar", StringComparison.OrdinalIgnoreCase) || string.Equals(val.m_shared.m_name, "Ominous Sounder", StringComparison.OrdinalIgnoreCase)) { return val; } } } catch { } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { foreach (ItemData equippedItem in inventory.GetEquippedItems()) { if ((int)equippedItem.m_shared.m_itemType == 18 && (((Object)(object)equippedItem.m_dropPrefab != (Object)null && ((Object)equippedItem.m_dropPrefab).name == "OminousRadar") || equippedItem.m_shared.m_name == "$item_ominous_radar" || equippedItem.m_shared.m_name == "Ominous Sounder")) { return equippedItem; } } } return null; } public static ItemData FindSounderInInventory(Player player) { if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null) { return null; } foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null && string.Equals(((Object)allItem.m_dropPrefab).name, "OminousRadar", StringComparison.OrdinalIgnoreCase)) { return allItem; } if (string.Equals(allItem.m_shared.m_name, "$item_ominous_radar", StringComparison.OrdinalIgnoreCase) || string.Equals(allItem.m_shared.m_name, "Ominous Sounder", StringComparison.OrdinalIgnoreCase)) { return allItem; } } return null; } public static bool IsSounderEquipped(Player player) { return GetEquippedSounder(player) != null; } public static int GetSounderQuality(ItemData sounder) { if (sounder == null) { return 1; } return Mathf.Clamp(sounder.m_quality, 1, 6); } public static bool IsBiomeAttuned(ItemData sounder, string biome, int requiredTier = 1) { if (sounder == null) { return false; } if (Mathf.Clamp(sounder.m_quality, 1, 6) >= requiredTier) { return true; } if (sounder.m_customData != null) { if (!string.IsNullOrEmpty(biome) && sounder.m_customData.ContainsKey("Ominous_" + biome)) { return true; } if (requiredTier <= 2 && (sounder.m_customData.ContainsKey("Ominous_Swamp") || sounder.m_customData.ContainsKey("Ominous_Ocean"))) { return true; } if (requiredTier <= 3 && sounder.m_customData.ContainsKey("Ominous_Mountain")) { return true; } if (requiredTier <= 4 && sounder.m_customData.ContainsKey("Ominous_Plains")) { return true; } if (requiredTier <= 5 && sounder.m_customData.ContainsKey("Ominous_Mistlands")) { return true; } if (requiredTier <= 6 && sounder.m_customData.ContainsKey("Ominous_Ashlands")) { return true; } } return false; } public static void AttuneBiome(ItemData sounder, string biome, int tier) { if (sounder != null) { if (sounder.m_customData == null) { sounder.m_customData = new Dictionary<string, string>(); } if (!string.IsNullOrEmpty(biome)) { sounder.m_customData["Ominous_" + biome] = "true"; } if (tier > sounder.m_quality) { sounder.m_quality = Mathf.Clamp(tier, 1, 6); } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] public static class Patch_ItemData_GetTooltip { [HarmonyPostfix] public static void Postfix(ItemData item, ref string __result) { if (item != null && (((Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == "OminousRadar") || item.m_shared.m_name == "$item_ominous_radar" || item.m_shared.m_name == "Ominous Sounder")) { int num = Mathf.Clamp(item.m_quality, 1, 6); bool flag = OminousItem.IsBiomeAttuned(item, "Swamp", 2); bool flag2 = OminousItem.IsBiomeAttuned(item, "Mountain", 3); bool flag3 = OminousItem.IsBiomeAttuned(item, "Plains", 4); bool flag4 = OminousItem.IsBiomeAttuned(item, "Mistlands", 5); bool flag5 = OminousItem.IsBiomeAttuned(item, "Ashlands", 6); float num2 = 50f + (float)(num - 1) * 5f; float num3 = 14f + (float)(num - 1) * 2f; StringBuilder stringBuilder = new StringBuilder(__result); stringBuilder.AppendLine(); stringBuilder.AppendLine($"\n<color=#FFD760>✦ Biome Attunements (Tier {num}/6) ✦</color>"); stringBuilder.AppendLine($"<color=#40C8FF>Threat Radar Range:</color> {num2:N0}m"); stringBuilder.AppendLine($"<color=#40C8FF>Beacon Aura Range:</color> {num3:N0}m"); stringBuilder.AppendLine("<color=#60E070> ✓ Meadows & Black Forest</color>"); stringBuilder.AppendLine(flag ? "<color=#60E070> ✓ Swamp & Ocean</color>" : "<color=#808080> ✗ Swamp & Ocean (Locked)</color>"); stringBuilder.AppendLine(flag2 ? "<color=#60E070> ✓ Mountains</color>" : "<color=#808080> ✗ Mountains (Locked)</color>"); stringBuilder.AppendLine(flag3 ? "<color=#60E070> ✓ Plains</color>" : "<color=#808080> ✗ Plains (Locked)</color>"); stringBuilder.AppendLine(flag4 ? "<color=#60E070> ✓ Mistlands</color>" : "<color=#808080> ✗ Mistlands (Locked)</color>"); stringBuilder.AppendLine(flag5 ? "<color=#60E070> ✓ Ashlands & Deep North</color>" : "<color=#808080> ✗ Ashlands & Deep North (Locked)</color>"); __result = stringBuilder.ToString(); } } } [BepInPlugin("com.dfg.ominous", "Ominous", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class OminousPlugin : BaseUnityPlugin { public const string ModGUID = "com.dfg.ominous"; public const string ModName = "Ominous"; public const string ModVersion = "1.0.0"; private Harmony m_harmony; private OminousWebGui m_webGui; private readonly ConcurrentQueue<Action> m_mainThreadQueue = new ConcurrentQueue<Action>(); private ConfigEntry<bool> m_cfgEnabled; private ConfigEntry<int> m_cfgWebPort; private ConfigEntry<bool> m_cfgEnableWebGui; public static OminousPlugin Instance { get; private set; } public static ClipLibrary Library { get; private set; } = new ClipLibrary(); private void Awake() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) Instance = this; m_cfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable or disable Ominous proximity music system."); m_cfgEnableWebGui = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableWebGui", true, "Enable the localhost web management dashboard."); m_cfgWebPort = ((BaseUnityPlugin)this).Config.Bind<int>("General", "WebPort", 8788, "Localhost port for the web editor (default 8788)."); OminousConfig.Load(); OminousConfig.Data.Enabled = m_cfgEnabled.Value; m_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.dfg.ominous"); Logger.LogInfo((object)"[Ominous] Harmony patches applied."); OminousItem.Init(); GameObject val = new GameObject("[Ominous_Core]"); Object.DontDestroyOnLoad((Object)val); val.AddComponent<OminousAudio>(); val.AddComponent<OminousBeacon>(); val.AddComponent<OminousTracker>(); ReloadTracks(); if (m_cfgEnableWebGui.Value) { int port = ((m_cfgWebPort.Value > 0) ? m_cfgWebPort.Value : 8788); m_webGui = new OminousWebGui(this, port); m_webGui.Start(); } Logger.LogInfo((object)"[Ominous] Ominous v1.0.0 initialized successfully."); } private void Update() { Action result; while (m_mainThreadQueue.TryDequeue(out result)) { try { result?.Invoke(); } catch (Exception arg) { Logger.LogError((object)$"[Ominous] Main thread action error: {arg}"); } } } private void OnDestroy() { m_webGui?.Stop(); Harmony harmony = m_harmony; if (harmony != null) { harmony.UnpatchSelf(); } Library?.Reset(); } public void ReloadTracks() { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string allReferencedTrack in OminousConfig.GetAllReferencedTracks()) { hashSet.Add(allReferencedTrack); } try { if (Directory.Exists(OminousConfig.TracksDir)) { string[] files = Directory.GetFiles(OminousConfig.TracksDir); foreach (string path in files) { string text = Path.GetExtension(path).ToLowerInvariant(); if (text == ".wav" || text == ".mp3") { hashSet.Add(Path.GetFileName(path)); } } } } catch (Exception ex) { Logger.LogWarning((object)("[Ominous] Error discovering tracks: " + ex.Message)); } Logger.LogInfo((object)$"[Ominous] Loading {hashSet.Count} audio track(s)..."); ((MonoBehaviour)this).StartCoroutine(Library.LoadAll(hashSet, OminousConfig.TracksDir, delegate { Logger.LogInfo((object)$"[Ominous] Loaded {Library.Loaded} track(s) ({Library.Failed} failed)."); })); } public void Ask(Action action) { if (action != null) { m_mainThreadQueue.Enqueue(action); } } } public class OminousTracker : MonoBehaviour { private readonly List<Character> m_nearbyChars = new List<Character>(64); private float m_scanTimer; private bool m_wasInThreat; public static OminousTracker Instance { get; private set; } public bool HasPlayer { get; private set; } public bool IsEquipped { get; private set; } public int ActiveQuality { get; private set; } = 1; public string ActiveCreaturePrefab { get; private set; } = ""; public float ActiveCreatureDistance { get; private set; } public float ActiveProximityFactor { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void Update() { if (OminousConfig.Data == null || !OminousConfig.Data.Enabled) { if ((Object)(object)OminousAudio.Instance != (Object)null && OminousAudio.Instance.ActiveVolume > 0f) { OminousAudio.Instance.SetThreat(null, 0f, 1f); } if ((Object)(object)OminousBeacon.Instance != (Object)null) { OminousBeacon.Instance.IsActive = false; } ResetLiveState(); } else { m_scanTimer += Time.deltaTime; float num = Mathf.Max(0.1f, OminousConfig.Data.ScanInterval); if (m_scanTimer >= num) { m_scanTimer = 0f; PerformScan(); } } } private void PerformScan() { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || (new Func<bool>(((Character)localPlayer).InIntro) != null && ((Character)localPlayer).InIntro())) { HasPlayer = false; IsEquipped = false; ActiveQuality = 1; if ((Object)(object)OminousBeacon.Instance != (Object)null) { OminousBeacon.Instance.IsActive = false; } ResetLiveState(); OminousAudio.Instance?.SetThreat(null, 0f, 1f); return; } HasPlayer = true; ItemData equippedSounder = OminousItem.GetEquippedSounder(localPlayer); bool flag = (IsEquipped = equippedSounder != null); ActiveQuality = ((equippedSounder == null) ? 1 : OminousItem.GetSounderQuality(equippedSounder)); if (OminousConfig.Data.RequireEquippedItem && !flag) { if ((Object)(object)OminousBeacon.Instance != (Object)null) { OminousBeacon.Instance.IsActive = false; } ResetLiveState(); OminousAudio.Instance?.SetThreat(null, 0f, 1f); m_wasInThreat = false; return; } if ((Object)(object)OminousBeacon.Instance != (Object)null) { OminousBeacon.Instance.IsActive = true; } Vector3 position = ((Component)localPlayer).transform.position; float num = 60f + (float)(ActiveQuality - 1) * 5f; if (OminousConfig.Data.Creatures != null) { for (int i = 0; i < OminousConfig.Data.Creatures.Count; i++) { CreatureOminousEntry creatureOminousEntry = OminousConfig.Data.Creatures[i]; if (creatureOminousEntry.Enabled && creatureOminousEntry.TriggerDistance > num) { num = creatureOminousEntry.TriggerDistance; } } } m_nearbyChars.Clear(); Character.GetCharactersInRange(position, num, m_nearbyChars); CreatureOminousEntry creatureOminousEntry2 = null; float num2 = -1f; float num3 = 0f; float activeCreatureDistance = 9999f; string activeCreaturePrefab = ""; for (int j = 0; j < m_nearbyChars.Count; j++) { Character val = m_nearbyChars[j]; if ((Object)(object)val == (Object)null || val.IsPlayer() || val.IsTamed() || val.IsDead()) { continue; } string text = ExtractCleanPrefabName(val); CreatureOminousEntry creatureOminousEntry3 = OminousConfig.FindEntry(text); if (creatureOminousEntry3 == null && !string.IsNullOrEmpty(val.m_name)) { creatureOminousEntry3 = OminousConfig.FindEntry(val.m_name); } if (creatureOminousEntry3 == null || !creatureOminousEntry3.Enabled) { continue; } int requiredTier = ((creatureOminousEntry3.RequiredTier > 0) ? creatureOminousEntry3.RequiredTier : OminousConfig.InferTierForCreature(text, creatureOminousEntry3.Biome)); if (OminousConfig.Data.RequireEquippedItem && !OminousItem.IsBiomeAttuned(equippedSounder, creatureOminousEntry3.Biome, requiredTier)) { continue; } float num4 = Vector3.Distance(position, ((Component)val).transform.position); if (!(num4 > creatureOminousEntry3.TriggerDistance)) { float num5 = Mathf.Clamp01(1f - (num4 - creatureOminousEntry3.MaxVolumeDistance) / Mathf.Max(1f, creatureOminousEntry3.TriggerDistance - creatureOminousEntry3.MaxVolumeDistance)); float num6 = (float)creatureOminousEntry3.Priority * 10f + num5 * 10f; if (num6 > num2) { num2 = num6; creatureOminousEntry2 = creatureOminousEntry3; num3 = num5; activeCreatureDistance = num4; activeCreaturePrefab = text; } } } if (creatureOminousEntry2 != null) { ActiveCreaturePrefab = activeCreaturePrefab; ActiveCreatureDistance = activeCreatureDistance; ActiveProximityFactor = num3; if (!m_wasInThreat && OminousConfig.Data.PingOnPerimeterEnter) { OminousBeacon.Instance?.PlayPing(); } m_wasInThreat = true; if ((Object)(object)OminousBeacon.Instance != (Object)null) { OminousBeacon.Instance.TensionFactor = num3; } float targetVolume = Mathf.Lerp(0.15f, 1f, num3) * creatureOminousEntry2.Volume * OminousConfig.Data.MasterVolume; float targetPitch = 1f; if (OminousConfig.Data.PitchScaling) { targetPitch = 1f + 0.15f * num3; } OminousAudio.Instance?.SetThreat(creatureOminousEntry2.Track, targetVolume, targetPitch); } else { m_wasInThreat = false; if ((Object)(object)OminousBeacon.Instance != (Object)null) { OminousBeacon.Instance.TensionFactor = 0f; } ResetLiveState(); OminousAudio.Instance?.SetThreat(null, 0f, 1f); } } private static string ExtractCleanPrefabName(Character c) { if ((Object)(object)c == (Object)null) { return ""; } string text = ((Object)c).name; int num = text.IndexOf("(Clone)", StringComparison.OrdinalIgnoreCase); if (num >= 0) { text = text.Substring(0, num); } return text.Trim(); } private void ResetLiveState() { ActiveCreaturePrefab = ""; ActiveCreatureDistance = 0f; ActiveProximityFactor = 0f; } } public class OminousWebGui { private readonly OminousPlugin m_plugin; private readonly int m_port; private HttpListener m_listener; private Thread m_thread; private volatile bool m_running; public bool IsRunning => m_running; public OminousWebGui(OminousPlugin plugin, int port) { m_plugin = plugin; m_port = port; } public void Start() { try { m_listener = new HttpListener(); m_listener.Prefixes.Add("http://127.0.0.1:" + m_port + "/"); m_listener.Start(); m_running = true; m_thread = new Thread(Loop) { IsBackground = true }; m_thread.Start(); Logger.LogInfo((object)("[Ominous] Web manager available at http://127.0.0.1:" + m_port + "/")); } catch (Exception ex) { m_running = false; Logger.LogWarning((object)("[Ominous] Could not start web manager: " + ex.Message)); } } public void Stop() { m_running = false; try { if (m_listener != null) { m_listener.Stop(); m_listener.Close(); } } catch { } m_listener = null; } private void Loop() { while (m_running && m_listener != null && m_listener.IsListening) { try { HttpListenerContext context = m_listener.GetContext(); Handle(context); } catch { } } } private void Handle(HttpListenerContext context) { try { switch (context.Request.Url.AbsolutePath) { case "/": case "/index.html": Write(context, "text/html; charset=utf-8", Page.Html); break; case "/state": HandleState(context); break; case "/apply": HandleApply(context); break; case "/audio": HandleAudio(context); break; default: context.Response.StatusCode = 404; Write(context, "text/plain", "Not Found"); break; } } catch (Exception ex) { try { context.Response.StatusCode = 500; Write(context, "text/plain", "Internal Error: " + ex.Message); } catch { } } } private void HandleState(HttpListenerContext context) { List<string> list = new List<string>(); try { if (Directory.Exists(OminousConfig.TracksDir)) { string[] files = Directory.GetFiles(OminousConfig.TracksDir); foreach (string path in files) { string text = Path.GetExtension(path).ToLowerInvariant(); if (text == ".wav" || text == ".mp3") { list.Add(Path.GetFileName(path)); } } } } catch { } string content = JsonConvert.SerializeObject((object)new { config = OminousConfig.Data, tracks = list, live = new { hasPlayer = ((Object)(object)OminousTracker.Instance != (Object)null && OminousTracker.Instance.HasPlayer), isEquipped = ((Object)(object)OminousTracker.Instance != (Object)null && OminousTracker.Instance.IsEquipped), activeQuality = ((!((Object)(object)OminousTracker.Instance != (Object)null)) ? 1 : OminousTracker.Instance.ActiveQuality), activeCreature = (((Object)(object)OminousTracker.Instance != (Object)null) ? OminousTracker.Instance.ActiveCreaturePrefab : ""), distance = (((Object)(object)OminousTracker.Instance != (Object)null) ? OminousTracker.Instance.ActiveCreatureDistance : 0f), proximityFactor = (((Object)(object)OminousTracker.Instance != (Object)null) ? OminousTracker.Instance.ActiveProximityFactor : 0f), activeTrack = (((Object)(object)OminousAudio.Instance != (Object)null) ? OminousAudio.Instance.ActiveTrack : ""), activeVolume = (((Object)(object)OminousAudio.Instance != (Object)null) ? OminousAudio.Instance.ActiveVolume : 0f), currentDucking = (((Object)(object)OminousAudio.Instance != (Object)null) ? OminousAudio.Instance.CurrentDucking : 0f) } }); Write(context, "application/json; charset=utf-8", content); } private void HandleApply(HttpListenerContext context) { if (context.Request.HttpMethod != "POST") { context.Response.StatusCode = 405; Write(context, "text/plain", "Method Not Allowed"); return; } string text; using (StreamReader streamReader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding)) { text = streamReader.ReadToEnd(); } OminousConfigData updated = JsonConvert.DeserializeObject<OminousConfigData>(text); if (updated != null) { m_plugin.Ask(delegate { OminousConfig.Data.Enabled = updated.Enabled; OminousConfig.Data.RequireEquippedItem = updated.RequireEquippedItem; OminousConfig.Data.EnableBeaconLight = updated.EnableBeaconLight; OminousConfig.Data.BeaconLightRange = updated.BeaconLightRange; OminousConfig.Data.BeaconBaseIntensity = updated.BeaconBaseIntensity; OminousConfig.Data.PingOnPerimeterEnter = updated.PingOnPerimeterEnter; OminousConfig.Data.MasterVolume = updated.MasterVolume; OminousConfig.Data.DuckingStrength = updated.DuckingStrength; OminousConfig.Data.PitchScaling = updated.PitchScaling; OminousConfig.Data.ScanInterval = updated.ScanInterval; OminousConfig.Data.Creatures = updated.Creatures ?? new List<CreatureOminousEntry>(); OminousConfig.Save(); m_plugin.ReloadTracks(); }); Write(context, "application/json", "{\"status\":\"ok\"}"); } else { context.Response.StatusCode = 400; Write(context, "text/plain", "Invalid Config Payload"); } } private void HandleAudio(HttpListenerContext context) { string text = context.Request.QueryString["file"]; if (string.IsNullOrEmpty(text)) { context.Response.StatusCode = 400; Write(context, "text/plain", "Missing file parameter"); return; } string fileName = Path.GetFileName(text); string path = Path.Combine(OminousConfig.TracksDir, fileName); if (!File.Exists(path)) { context.Response.StatusCode = 404; Write(context, "text/plain", "Audio file not found"); return; } string contentType = ((Path.GetExtension(fileName).ToLowerInvariant() == ".mp3") ? "audio/mpeg" : "audio/wav"); byte[] array = File.ReadAllBytes(path); context.Response.ContentType = contentType; context.Response.ContentLength64 = array.Length; context.Response.OutputStream.Write(array, 0, array.Length); context.Response.OutputStream.Close(); } private static void Write(HttpListenerContext context, string contentType, string content) { byte[] bytes = Encoding.UTF8.GetBytes(content); context.Response.ContentType = contentType; context.Response.ContentLength64 = bytes.Length; context.Response.OutputStream.Write(bytes, 0, bytes.Length); context.Response.OutputStream.Close(); } } public static class Page { private static string s_html; public static string Html { get { if (s_html == null) { s_html = LoadResource("Ominous.Page.html"); } return s_html; } } private static string LoadResource(string resourceName) { try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); if (stream == null) { return "<html><body><h1>Resource not found: " + resourceName + "</h1></body></html>"; } using StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); } catch (Exception ex) { return "<html><body><h1>Failed to load resource: " + ex.Message + "</h1></body></html>"; } } } [HarmonyPatch(typeof(MusicMan), "UpdateMusic")] public static class Patch_MusicMan_UpdateMusic { private static readonly FieldRef<MusicMan, AudioSource> s_musicSource = AccessTools.FieldRefAccess<MusicMan, AudioSource>("m_musicSource"); public static void Postfix(MusicMan __instance) { if ((Object)(object)OminousAudio.Instance == (Object)null || (Object)(object)__instance == (Object)null) { return; } float currentDucking = OminousAudio.Instance.CurrentDucking; if (currentDucking > 0.001f) { AudioSource val = s_musicSource.Invoke(__instance); if ((Object)(object)val != (Object)null) { val.volume *= Mathf.Clamp01(1f - currentDucking); } } } } }