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 LethalGargoyles v0.7.0
plugins/LethalGargoyles/DropDaDeuce.LethalGargoyles.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; 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 System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Coroner; using DropDaDeuce.LethalGargoyles.NetcodePatcher; using EnhancedMonsters.Utils; using GameNetcodeStuff; using HarmonyLib; using LethalGargoyles.src.Config; using LethalGargoyles.src.Enemy; using LethalGargoyles.src.Patch; using LethalGargoyles.src.Scrap; using LethalGargoyles.src.SoftDepends; using LethalGargoyles.src.Utility; using LethalLib.Modules; using Microsoft.CodeAnalysis; using NVorbis; using PathfindingLib.API.SmartPathfinding; using PathfindingLib.Utilities; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Networking; using UnityEngine.SceneManagement; [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("DropDaDeuce.LethalGargoyles")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.7.0.0")] [assembly: AssemblyInformationalVersion("0.7.0+decb0d8ae524aa7571f98698b2ac30bfa5b0f4d3")] [assembly: AssemblyProduct("LethalGargoyles")] [assembly: AssemblyTitle("DropDaDeuce.LethalGargoyles")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.7.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 LethalGargoyles { public static class PluginInfo { public const string PLUGIN_GUID = "DropDaDeuce.LethalGargoyles"; public const string PLUGIN_NAME = "LethalGargoyles"; public const string PLUGIN_VERSION = "0.7.0"; } } namespace LethalGargoyles.src { [BepInPlugin("DropDaDeuce.LethalGargoyles", "LethalGargoyles", "0.7.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger = null; internal static readonly Harmony harmony = new Harmony("LethalLib"); public static AssetBundle? ModAssets; public AudioClip? stepSound; public static Dictionary<string, List<string>> defaultAudioClipFilePaths = new Dictionary<string, List<string>>(); public static Plugin Instance { get; private set; } = null; internal static PluginConfig BoundConfig { get; private set; } = null; public bool IsCoronerLoaded { get; private set; } public bool IsEmployeeClassesLoaded { get; private set; } public bool IsEnhancedMonstersLoaded { get; private set; } public static string? CustomAudioFolderPath { get; private set; } [Conditional("DEBUG")] public void LogIfDebugBuild(string text) { Logger.LogInfo((object)text); } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config); IsCoronerLoaded = DepIsLoaded("com.elitemastereric.coroner"); IsEmployeeClassesLoaded = DepIsLoaded("Jade.EmployeeClasses"); IsEnhancedMonstersLoaded = DepIsLoaded("com.velddev.enhancedmonsters"); Instance = this; InitializeNetworkBehaviours(); string path = "gargoyleassets"; ModAssets = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), path)); if ((Object)(object)ModAssets == (Object)null) { Logger.LogError((object)"Failed to load custom assets."); return; } CustomAudioFolderPath = Path.Combine(Path.GetDirectoryName(Paths.ExecutablePath), "Lethal Gargoyles", "Custom Voice Lines"); if (!Directory.Exists(CustomAudioFolderPath)) { try { Directory.CreateDirectory(CustomAudioFolderPath); } catch (Exception arg) { Logger.LogError((object)$"Failed to create custom audio directory: {arg}"); return; } } Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Combat Dialog", "Attack")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Combat Dialog", "Hit")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - Activity")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - Aggro")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - Enemy")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - Gargoyle Death")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - General")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - Player Death")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - Prior Death", "Coroner")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - EmployeeClass")); Directory.CreateDirectory(Path.Combine(CustomAudioFolderPath, "Taunt - SteamIDs")); EnemyType val = ModAssets.LoadAsset<EnemyType>("LethalGargoyle"); TerminalNode val2 = ModAssets.LoadAsset<TerminalNode>("LethalGargoyleTN"); TerminalKeyword val3 = ModAssets.LoadAsset<TerminalKeyword>("LethalGargoyleTK"); NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab); Enemies.RegisterEnemy(val, BoundConfig.SpawnWeight.Value, (LevelTypes)(-1), val2, val3); harmony.PatchAll(); Logger.LogInfo((object)("Checking Soft Dependencies:\nCoroner Is Loaded? " + IsCoronerLoaded + "\nEmployeeClasses Is Loaded? " + IsEmployeeClassesLoaded + "\nEnhancedMonsters Is Loaded? " + IsEnhancedMonstersLoaded)); if (IsCoronerLoaded) { CoronerClass.Init(); } defaultAudioClipFilePaths = GetDefaultAudioClipFilePaths(); BoundConfig.InitializeAudioClipConfigs(defaultAudioClipFilePaths); if (BoundConfig.enableScrap.Value) { int value = BoundConfig.scrapWeight.Value; Item val4 = ModAssets.LoadAsset<Item>("Assets/ModAssets/LethalGargoyle/Scrap/GargoyleScrap.asset"); GargoyleStatue gargoyleStatue = val4.spawnPrefab.AddComponent<GargoyleStatue>(); ((GrabbableObject)gargoyleStatue).grabbable = true; ((GrabbableObject)gargoyleStatue).grabbableToEnemies = true; ((GrabbableObject)gargoyleStatue).itemProperties = val4; Utilities.FixMixerGroups(val4.spawnPrefab); NetworkPrefabs.RegisterNetworkPrefab(val4.spawnPrefab); Items.RegisterScrap(val4, value, (LevelTypes)(-1)); Logger.LogInfo((object)"Gargoyle Statue scrap is registered."); } stepSound = ModAssets.LoadAsset<AudioClip>("Assets/ModAssets/LethalGargoyle/Audio/sfx_Step.ogg"); Logger.LogInfo((object)"Plugin DropDaDeuce.LethalGargoyles is loaded!"); } private void OnEnable() { if (IsEnhancedMonstersLoaded) { EnhancedMonstersCompatibilityLayer.RegisterCustomMonsterEnemyData(); Logger.LogInfo((object)"Gargoyle has been registered with EnhancedMonsters."); } } private static void InitializeNetworkBehaviours() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { if (type.FullName == "LethalGargoyles.src.SoftDepends.CoronerClass" && !Instance.IsCoronerLoaded) { continue; } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { methodInfo.Invoke(null, null); } } } } private bool DepIsLoaded(string pGUID) { try { return Chainloader.PluginInfos.ContainsKey(pGUID); } catch { return false; } } private Dictionary<string, List<string>> GetDefaultAudioClipFilePaths() { Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>> { { "General", new List<string>() }, { "Aggro", new List<string>() }, { "Enemy", new List<string>() }, { "PlayerDeath", new List<string>() }, { "GargoyleDeath", new List<string>() }, { "PriorDeath", new List<string>() }, { "Attack", new List<string>() }, { "Hit", new List<string>() }, { "Activity", new List<string>() }, { "SteamIDs", new List<string>() } }; if (Instance.IsEmployeeClassesLoaded) { dictionary.Add("Class", new List<string>()); } foreach (KeyValuePair<string, List<string>> item in dictionary) { string key = item.Key; List<string> value = item.Value; FileInfo[] mP3Files = AudioManager.GetMP3Files(key, "Voice Lines"); FileInfo[] array = mP3Files; foreach (FileInfo fileInfo in array) { value.Add(fileInfo.FullName); } if (key == "PriorDeath" && Instance.IsCoronerLoaded) { FileInfo[] mP3Files2 = AudioManager.GetMP3Files("Coroner", "Voice Lines"); FileInfo[] array2 = mP3Files2; foreach (FileInfo fileInfo2 in array2) { value.Add(fileInfo2.FullName); } } if (Instance.IsEmployeeClassesLoaded && key == "Class") { FileInfo[] mP3Files3 = AudioManager.GetMP3Files("EmployeeClass", "Voice Lines"); FileInfo[] array3 = mP3Files3; foreach (FileInfo fileInfo3 in array3) { value.Add(fileInfo3.FullName); } } } return dictionary; } } } namespace LethalGargoyles.src.Utility { public class AudioManager : NetworkBehaviour { [CompilerGenerated] private sealed class <LoadAudioClip>d__30 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public string filePath; public string category; private UnityWebRequest <webRequest>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAudioClip>d__30(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <webRequest>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: { <>1__state = -1; string text = Path.GetExtension(filePath).ToLower(); AudioType val = ((!(text == ".ogg")) ? ((AudioType)0) : ((AudioType)14)); AudioType val2 = val; if ((int)val2 == 0) { Plugin.Logger.LogError((object)("Unsupported audio file format: " + filePath)); return false; } <webRequest>5__2 = UnityWebRequestMultimedia.GetAudioClip(filePath, val2); <>2__current = <webRequest>5__2.SendWebRequest(); <>1__state = 1; return true; } case 1: <>1__state = -1; if ((int)<webRequest>5__2.result == 3) { Plugin.Logger.LogError((object)<webRequest>5__2.error); } else { AudioClip content = DownloadHandlerAudioClip.GetContent(<webRequest>5__2); List<AudioClip> clipListByCategory = GetClipListByCategory(category); ((Object)content).name = Path.GetFileNameWithoutExtension(filePath); clipListByCategory.Add(content); Plugin.Logger.LogInfo((object)("Loaded clip: " + ((Object)content).name + " | Catagory: " + category)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LogClipCounts>d__20 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LogClipCounts>d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ProcessAudioClip>d__28 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public byte[] audioData; public string clipName; public string category; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ProcessAudioClip>d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (<>1__state != 0) { return false; } <>1__state = -1; VorbisReader val = new VorbisReader((Stream)new MemoryStream(audioData, writable: false), true); try { float[] array = new float[val.TotalSamples]; AudioClip val2 = AudioClip.Create(clipName, (int)(val.TotalSamples / val.Channels), val.Channels, val.SampleRate, false); int num = val.ReadSamples(array, 0, (int)val.TotalSamples); val2.SetData(array, 0); List<AudioClip> clipListByCategory = GetClipListByCategory(category); clipListByCategory.Add(val2); Plugin.Logger.LogInfo((object)("Clip Loaded: " + ((Object)val2).name)); return false; } finally { ((IDisposable)val)?.Dispose(); } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static List<AudioClip> tauntClips = new List<AudioClip>(); public static List<AudioClip> aggroClips = new List<AudioClip>(); public static List<AudioClip> enemyClips = new List<AudioClip>(); public static List<AudioClip> playerDeathClips = new List<AudioClip>(); public static List<AudioClip> deathClips = new List<AudioClip>(); public static List<AudioClip> priorDeathClips = new List<AudioClip>(); public static List<AudioClip> activityClips = new List<AudioClip>(); public static List<AudioClip> attackClips = new List<AudioClip>(); public static List<AudioClip> hitClips = new List<AudioClip>(); public static List<AudioClip> classClips = new List<AudioClip>(); public static List<AudioClip> playerClips = new List<AudioClip>(); public static AudioManager? Instance; private readonly Dictionary<ulong, bool> clientReady = new Dictionary<ulong, bool>(); public static Dictionary<string, List<string>> AudioClipFilePaths { get; private set; } = new Dictionary<string, List<string>>(); [Conditional("DEBUG")] private static void LogIfDebugBuild(string text) { Plugin.Logger.LogInfo((object)text); } public override void OnNetworkSpawn() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown ((NetworkBehaviour)this).OnNetworkSpawn(); Instance = this; NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("SendLGAudioClip", new HandleNamedMessageDelegate(OnReceivedMessage)); Plugin.Logger.LogInfo((object)"Registered message handler for 'SendLGAudioClip'"); if (((NetworkBehaviour)this).IsServer) { NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnectedCallback; NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnectedCallback; } else { Plugin.Logger.LogInfo((object)$"Connected to host with ID: {NetworkManager.Singleton.LocalClientId}"); } if (((NetworkBehaviour)this).IsHost) { Plugin.Logger.LogInfo((object)"Creating Audio Clip List"); LoadClipList(Plugin.defaultAudioClipFilePaths); LoadAudioClipsFromConfig(); } } public override void OnNetworkDespawn() { Plugin.Logger.LogInfo((object)"Clearing clip lists"); tauntClips.Clear(); aggroClips.Clear(); enemyClips.Clear(); playerDeathClips.Clear(); deathClips.Clear(); priorDeathClips.Clear(); activityClips.Clear(); attackClips.Clear(); hitClips.Clear(); classClips.Clear(); playerClips.Clear(); if (((NetworkBehaviour)this).IsServer) { NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnectedCallback; NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnectedCallback; } } [IteratorStateMachine(typeof(<LogClipCounts>d__20))] private IEnumerator LogClipCounts() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LogClipCounts>d__20(0); } private void OnClientConnectedCallback(ulong clientId) { Plugin.Logger.LogInfo((object)$"Client connected: {clientId}"); if (!clientReady.ContainsKey(clientId)) { clientReady.Add(clientId, value: true); } SendAudioClipsDelayed(clientId); } private void OnClientDisconnectedCallback(ulong clientId) { if (clientReady.ContainsKey(clientId)) { clientReady.Remove(clientId); } } public async void SendAudioClipsDelayed(ulong clientId) { bool isPlayerFullyLoaded = false; List<ulong> fullyLoadedPlayers = StartOfRound.Instance.fullyLoadedPlayers; CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10.0)); await Task.Run(delegate { while (!isPlayerFullyLoaded || !clientReady.ContainsKey(clientId)) { for (int i = 0; i < fullyLoadedPlayers.Count; i++) { if (fullyLoadedPlayers[i] == clientId) { isPlayerFullyLoaded = true; break; } } Task.Yield(); } }, cancellationTokenSource.Token); foreach (KeyValuePair<string, List<string>> audioClipFilePath in AudioClipFilePaths) { string category = audioClipFilePath.Key; List<string> value = audioClipFilePath.Value; GetClipListByCategory(category); foreach (string item in value) { string clipName = Path.GetFileNameWithoutExtension(item); byte[] audioData2; if (PluginConfig.AudioClipEnableConfig.TryGetValue(clipName, out ConfigEntry<bool> value2)) { if (!value2.Value) { continue; } audioData2 = AudioFileToByteArray(item); byte[] array = audioData2; if (array != null && array.Length > 512000) { Plugin.Logger.LogError((object)("Sending Clip(" + clipName + ") failed. Max clip size is 512000 bytes or 500KB")); break; } if (audioData2 != null) { await WaitForClientReady(clientId); if (!clientReady.ContainsKey(clientId)) { break; } await SendAudioClipToClient(clientId, audioData2, clipName, category); clientReady[clientId] = false; SetClientReadyClientRpc(isReady: false, clientId); Plugin.Logger.LogInfo((object)$"Sent Clip({clipName}) to ClientID({clientId})"); } continue; } audioData2 = AudioFileToByteArray(item); byte[] array2 = audioData2; if (array2 != null && array2.Length > 512000) { Plugin.Logger.LogError((object)("Sending Clip(" + clipName + ") failed. Max clip size is 512000 bytes or 500KB")); break; } if (audioData2 != null) { await WaitForClientReady(clientId); if (!clientReady.ContainsKey(clientId)) { break; } await SendAudioClipToClient(clientId, audioData2, clipName, category); clientReady[clientId] = false; SetClientReadyClientRpc(isReady: false, clientId); Plugin.Logger.LogInfo((object)$"Sent Clip({clipName}) to ClientID({clientId})"); } } } } private async Task WaitForClientReady(ulong clientId) { CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(5.0)); try { await Task.Run(async delegate { while (!clientReady[clientId]) { await Task.Delay(100, cts.Token); } }, cts.Token); } catch (OperationCanceledException) { if (!clientReady.ContainsKey(clientId)) { Plugin.Logger.LogWarning((object)$"Client {clientId} is disconnected."); return; } Plugin.Logger.LogWarning((object)$"Client {clientId} did not respond within the timeout, trying to send clip anyways."); clientReady[clientId] = true; } } private byte[]? AudioFileToByteArray(string filePath) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Invalid comparison between Unknown and I4 AudioType val = (AudioType)(Path.GetExtension(filePath).ToLower() switch { ".mp3" => 13, ".wav" => 20, ".ogg" => 14, _ => 0, }); if ((int)val == 0) { Plugin.Logger.LogError((object)("Unsupported audio file format: " + filePath)); return null; } UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(filePath, val); audioClip.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); UnityWebRequestAsyncOperation val2 = audioClip.SendWebRequest(); while (!((AsyncOperation)val2).isDone) { Task.Yield(); } if ((int)audioClip.result == 3) { Plugin.Logger.LogError((object)audioClip.error); return null; } return audioClip.downloadHandler.data; } private async Task SendAudioClipToClient(ulong clientId, byte[] audioData, string clipName, string category) { int num = audioData.Length + 200; FastBufferWriter writer = new FastBufferWriter(num, (Allocator)2, -1); try { ((FastBufferWriter)(ref writer)).WriteValueSafe(category, false); ((FastBufferWriter)(ref writer)).WriteValueSafe(clipName, false); if (((FastBufferWriter)(ref writer)).Capacity < audioData.Length) { Plugin.Logger.LogError((object)"Writer Capacity is less than clip size!"); return; } int num2 = audioData.Length; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num2, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteBytesSafe(audioData, audioData.Length, 0); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("SendLGAudioClip", clientId, writer, (NetworkDelivery)4); await Task.Yield(); } finally { ((IDisposable)(FastBufferWriter)(ref writer)).Dispose(); } } public void OnReceivedMessage(ulong clientId, FastBufferReader messagePayload) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsServer && !((NetworkBehaviour)this).IsHost) { SetClientReadyServerRpc(isReady: true, NetworkManager.Singleton.LocalClientId); string category = default(string); ((FastBufferReader)(ref messagePayload)).ReadValueSafe(ref category, false); string clipName = default(string); ((FastBufferReader)(ref messagePayload)).ReadValueSafe(ref clipName, false); int num = default(int); ((FastBufferReader)(ref messagePayload)).ReadValueSafe<int>(ref num, default(ForPrimitives)); byte[] audioData = new byte[num]; ((FastBufferReader)(ref messagePayload)).ReadBytesSafe(ref audioData, num, 0); ((MonoBehaviour)this).StartCoroutine(ProcessAudioClip(audioData, clipName, category)); } } [IteratorStateMachine(typeof(<ProcessAudioClip>d__28))] private IEnumerator ProcessAudioClip(byte[] audioData, string clipName, string category) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ProcessAudioClip>d__28(0) { audioData = audioData, clipName = clipName, category = category }; } private void LoadAudioClipsFromConfig() { foreach (KeyValuePair<string, List<string>> audioClipFilePath in AudioClipFilePaths) { string key = audioClipFilePath.Key; List<string> value = audioClipFilePath.Value; List<AudioClip> clipListByCategory = GetClipListByCategory(key); foreach (string item in value) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item); if (PluginConfig.AudioClipEnableConfig.TryGetValue(fileNameWithoutExtension, out ConfigEntry<bool> value2)) { if (value2.Value) { ((MonoBehaviour)this).StartCoroutine(LoadAudioClip(item, key)); } } else { ((MonoBehaviour)this).StartCoroutine(LoadAudioClip(item, key)); } } } } [IteratorStateMachine(typeof(<LoadAudioClip>d__30))] private IEnumerator LoadAudioClip(string filePath, string category) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAudioClip>d__30(0) { filePath = filePath, category = category }; } public static List<AudioClip> GetClipListByCategory(string category) { return category switch { "General" => tauntClips, "Aggro" => aggroClips, "Enemy" => enemyClips, "PlayerDeath" => playerDeathClips, "GargoyleDeath" => deathClips, "PriorDeath" => priorDeathClips, "Activity" => activityClips, "Class" => classClips, "Attack" => attackClips, "Hit" => hitClips, "SteamIDs" => playerClips, _ => throw new ArgumentException("Invalid audio clip category: " + category), }; } public void LoadClipList(Dictionary<string, List<string>> defaultAudioClipFilePaths) { AudioClipFilePaths = defaultAudioClipFilePaths; foreach (KeyValuePair<string, List<string>> audioClipFilePath in AudioClipFilePaths) { string key = audioClipFilePath.Key; List<string> value = audioClipFilePath.Value; FileInfo[] mP3Files = GetMP3Files(key, "Custom Voice Lines"); FileInfo[] array = mP3Files; foreach (FileInfo fileInfo in array) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); bool flag = false; for (int j = 0; j < value.Count; j++) { string fileNameWithoutExtension2 = Path.GetFileNameWithoutExtension(value[j]); if (fileNameWithoutExtension == fileNameWithoutExtension2) { value[j] = fileInfo.FullName; flag = true; break; } } if (!flag) { value.Add(fileInfo.FullName); } } if (key == "PriorDeath" && Plugin.Instance.IsCoronerLoaded) { FileInfo[] mP3Files2 = GetMP3Files("Coroner", "Voice Lines"); FileInfo[] mP3Files3 = GetMP3Files("Coroner", "Custom Voice Lines"); FileInfo[] array2 = mP3Files2; foreach (FileInfo fileInfo2 in array2) { value.Add(fileInfo2.FullName); } FileInfo[] array3 = mP3Files3; foreach (FileInfo fileInfo3 in array3) { string fileNameWithoutExtension3 = Path.GetFileNameWithoutExtension(fileInfo3.FullName); bool flag2 = false; for (int m = 0; m < value.Count; m++) { string fileNameWithoutExtension4 = Path.GetFileNameWithoutExtension(value[m]); if (fileNameWithoutExtension3 == fileNameWithoutExtension4) { value[m] = fileInfo3.FullName; flag2 = true; break; } } if (!flag2) { value.Add(fileInfo3.FullName); } } } if (!Plugin.Instance.IsEmployeeClassesLoaded || !(key == "Class")) { continue; } FileInfo[] mP3Files4 = GetMP3Files("EmployeeClass", "Voice Lines"); FileInfo[] mP3Files5 = GetMP3Files("EmployeeClass", "Custom Voice Lines"); FileInfo[] array4 = mP3Files4; foreach (FileInfo fileInfo4 in array4) { value.Add(fileInfo4.FullName); } FileInfo[] array5 = mP3Files5; foreach (FileInfo fileInfo5 in array5) { string fileNameWithoutExtension5 = Path.GetFileNameWithoutExtension(fileInfo5.FullName); bool flag3 = false; for (int num2 = 0; num2 < value.Count; num2++) { string fileNameWithoutExtension6 = Path.GetFileNameWithoutExtension(value[num2]); if (fileNameWithoutExtension5 == fileNameWithoutExtension6) { value[num2] = fileInfo5.FullName; flag3 = true; break; } } if (!flag3) { value.Add(fileInfo5.FullName); } } } } public static FileInfo[] GetMP3Files(string type, string folderName) { string text = ((folderName == "Voice Lines") ? Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location), folderName) : ((!(folderName == "Custom Voice Lines")) ? Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location), folderName) : Plugin.CustomAudioFolderPath)); string path = text; switch (type) { case "General": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - General")); return directoryInfo.GetFiles("*.*"); } case "Aggro": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Aggro")); return directoryInfo.GetFiles("*.*"); } case "Enemy": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Enemy")); return directoryInfo.GetFiles("*.*"); } case "PlayerDeath": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Player Death")); return directoryInfo.GetFiles("*.*"); } case "GargoyleDeath": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Gargoyle Death")); return directoryInfo.GetFiles("*.*"); } case "PriorDeath": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Prior Death")); return directoryInfo.GetFiles("*.*"); } case "Coroner": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Prior Death", "Coroner")); return directoryInfo.GetFiles("*.*"); } case "Class": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - EmployeeClass")); return directoryInfo.GetFiles("*.*"); } case "Activity": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - Activity")); return directoryInfo.GetFiles("*.*"); } case "Attack": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Combat Dialog", "Attack")); return directoryInfo.GetFiles("*.*"); } case "Hit": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Combat Dialog", "Hit")); return directoryInfo.GetFiles("*.*"); } case "SteamIDs": { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, "Taunt - SteamIDs")); return directoryInfo.GetFiles("*.*"); } default: return Array.Empty<FileInfo>(); } } [ClientRpc] private void SetClientReadyClientRpc(bool isReady, ulong clientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(2917554051u, val, (RpcDelivery)0); ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref isReady, default(ForPrimitives)); BytePacker.WriteValueBitPacked(val2, clientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 2917554051u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; if (clientReady.ContainsKey(NetworkManager.Singleton.LocalClientId) && NetworkManager.Singleton.LocalClientId == clientId) { clientReady[NetworkManager.Singleton.LocalClientId] = isReady; } } } [ServerRpc(RequireOwnership = false)] private void SetClientReadyServerRpc(bool isReady, ulong clientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val = default(ServerRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(1384767487u, val, (RpcDelivery)0); ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref isReady, default(ForPrimitives)); BytePacker.WriteValueBitPacked(val2, clientId); ((NetworkBehaviour)this).__endSendServerRpc(ref val2, 1384767487u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; if (clientReady.ContainsKey(clientId)) { clientReady[clientId] = isReady; } } } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(2917554051u, new RpcReceiveHandler(__rpc_handler_2917554051), "SetClientReadyClientRpc"); ((NetworkBehaviour)this).__registerRpc(1384767487u, new RpcReceiveHandler(__rpc_handler_1384767487), "SetClientReadyServerRpc"); ((NetworkBehaviour)this).__initializeRpcs(); } private static void __rpc_handler_2917554051(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { bool isReady = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref isReady, default(ForPrimitives)); ulong clientId = default(ulong); ByteUnpacker.ReadValueBitPacked(reader, ref clientId); target.__rpc_exec_stage = (__RpcExecStage)1; ((AudioManager)(object)target).SetClientReadyClientRpc(isReady, clientId); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_1384767487(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { bool isReady = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref isReady, default(ForPrimitives)); ulong clientId = default(ulong); ByteUnpacker.ReadValueBitPacked(reader, ref clientId); target.__rpc_exec_stage = (__RpcExecStage)1; ((AudioManager)(object)target).SetClientReadyServerRpc(isReady, clientId); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "AudioManager"; } } } namespace LethalGargoyles.src.SoftDepends { internal class CoronerClass { public static object? GargoyleDeath { get; private set; } public static object? GargoylePushDeath { get; private set; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void Init() { //IL_0005: 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) try { GargoyleDeath = API.Register("DeathEnemyLGargoyle"); GargoylePushDeath = API.Register("DeathEnemyGargoylePush"); Plugin.Logger.LogInfo((object)"Gargoyle causes of death registered with Coroner."); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Skipping Coroner initialization. Exception: {arg}"); } } internal static void CoronerSetCauseOfDeath(PlayerControllerB player, string deathType) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!(deathType == "Attack")) { if (deathType == "Push" && GargoylePushDeath != null) { SetCauseOfDeath((int)player.playerClientId, (AdvancedCauseOfDeath)GargoylePushDeath); } } else if (GargoyleDeath != null) { SetCauseOfDeath((int)player.playerClientId, (AdvancedCauseOfDeath)GargoyleDeath); } } internal static void SetCauseOfDeath(int playerId, AdvancedCauseOfDeath cause) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) Type type = typeof(Plugin).Assembly.GetType("Coroner.AdvancedDeathTracker"); if (type != null) { MethodInfo method = type.GetMethod("SetCauseOfDeath", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(int), typeof(AdvancedCauseOfDeath), typeof(bool) }, null); method?.Invoke(null, new object[3] { playerId, cause, true }); _ = method != null; } } internal static string? CoronerGetCauseOfDeath(PlayerControllerB player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) AdvancedCauseOfDeath? causeOfDeath = API.GetCauseOfDeath(player); if (causeOfDeath.HasValue) { AdvancedCauseOfDeath value = causeOfDeath.Value; return Regex.Replace(((AdvancedCauseOfDeath)(ref value)).GetLanguageTag(), "Death", ""); } return null; } } internal class EmployeeClassesClass { [Conditional("DEBUG")] private static void LogIfDebugBuild(string text) { Plugin.Logger.LogInfo((object)text); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static string? GetPlayerClass(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return null; } try { if (Chainloader.PluginInfos.TryGetValue("Jade.EmployeeClasses", out var value)) { Type type = ((object)value.Instance).GetType().Assembly.GetType("EmployeeClasses.Roles.RoleManager"); if (type != null) { Component component = ((Component)player).GetComponent(type); if ((Object)(object)component != (Object)null) { FieldInfo field = type.GetField("selectedRole", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { string text = (string)field.GetValue(component); if (text == null) { return null; } return text; } } } } } catch (Exception arg) { Plugin.Logger.LogError((object)$"Error getting player class from EmployeeClasses: {arg}"); return null; } return null; } } public static class EnhancedMonstersCompatibilityLayer { [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void RegisterCustomMonsterEnemyData() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) EnemyMetadata val = default(EnemyMetadata); ((EnemyMetadata)(ref val))..ctor(); val.MeshOffset = Vec3.op_Implicit(new Vector3(0f, 0f, 0f)); val.FloorRotation = Vec3.op_Implicit(new Vector3(0f, 90f, 0f)); val.HandRotation = Vec3.op_Implicit(new Vector3(0f, 90f, 0f)); val.AnimateOnDeath = false; EnemyMetadata val2 = val; EnemiesDataManager.RegisterEnemy("LethalGargoyle", true, 70, 90, 30f, "B", val2, false); } } } namespace LethalGargoyles.src.Scrap { internal class GargoyleStatue : GrabbableObject { [CompilerGenerated] private sealed class <PlayNoiseWhileTalking>d__15 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public GargoyleStatue <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayNoiseWhileTalking>d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown int num = <>1__state; GargoyleStatue gargoyleStatue = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)gargoyleStatue.scrapAudio != (Object)null && gargoyleStatue.scrapAudio.isPlaying) { RoundManager.Instance.PlayAudibleNoise(((Component)gargoyleStatue).transform.position, gargoyleStatue.scrapAudio.maxDistance / 1.2f, gargoyleStatue.scrapAudio.volume, 0, false, 0); <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private AudioSource? scrapAudio; private static int lastTaunt; private float distWarnSqr; private float dogCooldown; private bool dogHear; private float lastDogCheck; private static float lastDogTaunt; [Conditional("DEBUG")] private void LogIfDebugBuild(string text) { Plugin.Logger.LogInfo((object)text); } public override void Start() { ((GrabbableObject)this).Start(); scrapAudio = ((Component)this).GetComponentInParent<AudioSource>(); distWarnSqr = Plugin.BoundConfig.distWarn.Value; dogCooldown = Plugin.BoundConfig.dogCooldown.Value; dogHear = Plugin.BoundConfig.dogHear.Value; distWarnSqr *= distWarnSqr; lastDogTaunt = Time.time - dogCooldown; } public override void Update() { ((GrabbableObject)this).Update(); if ((Object)(object)scrapAudio != (Object)null && dogHear && Time.time - lastDogTaunt > dogCooldown && Time.time - lastDogCheck > 1f && !scrapAudio.isPlaying) { lastDogCheck = Time.time; if (DogNearStatue() && LethalGargoylesAI.ChooseRandomClip("taunt_enemy_Mouthdog", "Enemy", out string audioClip) && audioClip != null) { lastDogTaunt = Time.time; TauntClientRpc(audioClip, "enemy"); } } } private bool DogNearStatue() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies) { Vector3 val = ((Component)spawnedEnemy).transform.position - ((Component)this).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > distWarnSqr) && string.Equals(spawnedEnemy.enemyType.enemyName, "MouthDog", StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public override void ItemActivate(bool used, bool buttonDown = true) { ((GrabbableObject)this).ItemActivate(used, buttonDown); if (((NetworkBehaviour)this).IsServer && (Object)(object)scrapAudio != (Object)null && !scrapAudio.isPlaying) { ItemActivateServerRpc(used, buttonDown); } } [ServerRpc(RequireOwnership = false)] private void ItemActivateServerRpc(bool used, bool buttonDown) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val = default(ServerRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(3724832850u, val, (RpcDelivery)0); ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref used, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref buttonDown, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendServerRpc(ref val2, 3724832850u, val, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; GeneralTaunt(); } } } public void GeneralTaunt() { List<AudioClip> tauntClips = AudioManager.tauntClips; if ((Object)(object)base.playerHeldBy != (Object)null) { AudioClip val = LethalGargoylesAI.FindClip($"{base.playerHeldBy.playerSteamId}", AudioManager.playerClips); if ((Object)(object)val != (Object)null) { tauntClips.Add(val); } } if (tauntClips.Count > 0) { int num = Random.Range(0, tauntClips.Count); if (num == lastTaunt) { num++; } lastTaunt = num; TauntClientRpc(((Object)tauntClips[num]).name, "general"); } } [ClientRpc] private void TauntClientRpc(string clipName, string clipType) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_013d: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(3274531793u, val, (RpcDelivery)0); bool flag = clipName != null; ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val2)).WriteValueSafe(clipName, false); } bool flag2 = clipType != null; ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref flag2, default(ForPrimitives)); if (flag2) { ((FastBufferWriter)(ref val2)).WriteValueSafe(clipType, false); } ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 3274531793u, val, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; List<AudioClip> list = new List<AudioClip>(); switch (clipType) { case "general": list = AudioManager.tauntClips; break; case "enemy": list = AudioManager.enemyClips; break; case "aggro": list = AudioManager.aggroClips; break; case "death": list = AudioManager.deathClips; break; case "attack": list = AudioManager.attackClips; break; case "hit": list = AudioManager.hitClips; break; case "priordeath": list = AudioManager.priorDeathClips; break; case "playerdeath": list = AudioManager.playerDeathClips; break; case "class": list = AudioManager.classClips; break; case "activity": list = AudioManager.activityClips; break; case "steamids": list = AudioManager.playerClips; break; } AudioClip val3 = LethalGargoylesAI.FindClip(clipName, list); if (list.Count > 0 && (Object)(object)val3 != (Object)null && (Object)(object)scrapAudio != (Object)null) { scrapAudio.PlayOneShot(val3); if (dogHear) { ((MonoBehaviour)this).StartCoroutine(PlayNoiseWhileTalking()); } } } [IteratorStateMachine(typeof(<PlayNoiseWhileTalking>d__15))] private IEnumerator PlayNoiseWhileTalking() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayNoiseWhileTalking>d__15(0) { <>4__this = this }; } protected override void __initializeVariables() { ((GrabbableObject)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(3724832850u, new RpcReceiveHandler(__rpc_handler_3724832850), "ItemActivateServerRpc"); ((NetworkBehaviour)this).__registerRpc(3274531793u, new RpcReceiveHandler(__rpc_handler_3274531793), "TauntClientRpc"); ((GrabbableObject)this).__initializeRpcs(); } private static void __rpc_handler_3724832850(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { bool used = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref used, default(ForPrimitives)); bool buttonDown = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref buttonDown, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)1; ((GargoyleStatue)(object)target).ItemActivateServerRpc(used, buttonDown); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3274531793(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); string clipName = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref clipName, false); } bool flag2 = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag2, default(ForPrimitives)); string clipType = null; if (flag2) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref clipType, false); } target.__rpc_exec_stage = (__RpcExecStage)1; ((GargoyleStatue)(object)target).TauntClientRpc(clipName, clipType); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "GargoyleStatue"; } } } namespace LethalGargoyles.src.Patch { [HarmonyPatch(typeof(DoorLock), "OnTriggerStay")] public class HarmonyDoorPatch { private static readonly FieldInfo enemyDoorMeterField = typeof(DoorLock).GetField("enemyDoorMeter", BindingFlags.Instance | BindingFlags.NonPublic); [HarmonyPostfix] private static void PostFixOnTriggerStay(DoorLock __instance, Collider other) { if ((Object)(object)other == (Object)null || (Object)(object)((Component)other).GetComponent<EnemyAICollisionDetect>() == (Object)null || (Object)(object)((Component)other).GetComponent<EnemyAICollisionDetect>().mainScript == (Object)null || !(((Component)other).GetComponent<EnemyAICollisionDetect>().mainScript is LethalGargoylesAI lethalGargoylesAI)) { return; } if (enemyDoorMeterField != null) { float num = (float)enemyDoorMeterField.GetValue(__instance); if (num <= 0f && (Object)(object)lethalGargoylesAI.currentDoor == (Object)null) { lethalGargoylesAI.currentDoor = __instance; lethalGargoylesAI.lastDoorCloseTime = Time.time; } } else { Plugin.Logger.LogWarning((object)"enemyDoorMeter field not found in DoorLock."); } } } [HarmonyPatch(typeof(EnemyAI), "HitEnemy")] public class KillEnemyPatch { [HarmonyPostfix] private static void Postfix(EnemyAI __instance, PlayerControllerB? playerWhoHit) { if ((Object)(object)playerWhoHit != (Object)null) { ((MonoBehaviour)__instance).StartCoroutine(KillEnemyHelper.KillEnemy(__instance, playerWhoHit)); } } } public class KillEnemyHelper { [CompilerGenerated] private sealed class <KillEnemy>d__0 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public EnemyAI enemyAI; public PlayerControllerB playerWhoHit; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <KillEnemy>d__0(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; if (enemyAI.isEnemyDead) { LethalGargoylesAI.PlayerActivityTracker.UpdatePlayerActivity(playerWhoHit, LethalGargoylesAI.PlayerActivityTracker.PlayerActivityType.KilledEnemy, enemyAI.enemyType.enemyName); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [IteratorStateMachine(typeof(<KillEnemy>d__0))] public static IEnumerator KillEnemy(EnemyAI enemyAI, PlayerControllerB playerWhoHit) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <KillEnemy>d__0(0) { enemyAI = enemyAI, playerWhoHit = playerWhoHit }; } } [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectServerRpc")] public class GrabObjectServerRpcPatch { [HarmonyPostfix] public static void Postfix(PlayerControllerB __instance, ref NetworkObjectReference grabbedObject) { NetworkObject val = default(NetworkObject); if (!((NetworkBehaviour)__instance).IsServer || !((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null)) { return; } GrabbableObject componentInChildren = ((Component)val).GetComponentInChildren<GrabbableObject>(); if (componentInChildren != null) { string itemName = componentInChildren.itemProperties.itemName; if (LethalGargoylesAI.trackedItems.Contains(itemName)) { LethalGargoylesAI.PlayerActivityTracker.UpdatePlayerActivity(__instance, LethalGargoylesAI.PlayerActivityTracker.PlayerActivityType.PickedUpItem, componentInChildren.itemProperties.itemName); } } } } [HarmonyPatch(typeof(PlayerControllerB), "SetObjectAsNoLongerHeld")] public class SetObjectAsNoLongerHeldPatch { [HarmonyPostfix] public static void Postfix(PlayerControllerB __instance, GrabbableObject dropObject) { if (((NetworkBehaviour)__instance).IsServer) { string itemName = dropObject.itemProperties.itemName; if (LethalGargoylesAI.trackedItems.Contains(itemName)) { LethalGargoylesAI.PlayerActivityTracker.RemoveActivity(__instance, LethalGargoylesAI.PlayerActivityTracker.PlayerActivityType.PickedUpItem, itemName); } } } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] public class PlayerInFacilityPatch { private static readonly Dictionary<PlayerControllerB, float> playerEnterTimes = new Dictionary<PlayerControllerB, float>(); private static readonly Dictionary<PlayerControllerB, float> lastRanTimes = new Dictionary<PlayerControllerB, float>(); private const float MinimumTimeInFacility = 5f; private const float delay = 1f; [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { float value; float num = (lastRanTimes.TryGetValue(__instance, out value) ? value : 0f); if (!(Time.time - num > 1f)) { return; } if (__instance.isPlayerControlled && __instance.isInsideFactory && !__instance.isPlayerDead) { if (!playerEnterTimes.ContainsKey(__instance)) { playerEnterTimes[__instance] = Time.time; } else { float num2 = playerEnterTimes[__instance]; float num3 = Time.time - num2; if (num3 >= 300f) { LethalGargoylesAI.PlayerActivityTracker.UpdatePlayerActivity(__instance, LethalGargoylesAI.PlayerActivityTracker.PlayerActivityType.InFacility, "InFacilityTime", num3); } } } else { if (playerEnterTimes.ContainsKey(__instance)) { playerEnterTimes.Remove(__instance); } LethalGargoylesAI.PlayerActivityTracker.RemoveActivity(__instance, LethalGargoylesAI.PlayerActivityTracker.PlayerActivityType.InFacility); } lastRanTimes[__instance] = Time.time; } } [HarmonyPatch] public class NetworkObjectManager { public static GameObject? networkPrefab; [HarmonyPostfix] [HarmonyPatch(typeof(GameNetworkManager), "Start")] public static void Init() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (!((Object)(object)networkPrefab != (Object)null) && (Object)(object)Plugin.ModAssets != (Object)null) { networkPrefab = (GameObject)Plugin.ModAssets.LoadAsset("LGNetworkHandler"); networkPrefab.AddComponent<AudioManager>(); NetworkManager.Singleton.AddNetworkPrefab(networkPrefab); } } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "Awake")] public static void LoadClipsHostPostFix() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsHost && (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)) { GameObject val = Object.Instantiate<GameObject>(networkPrefab, Vector3.zero, Quaternion.identity); if (val != null) { val.GetComponent<NetworkObject>().Spawn(false); } } } } [HarmonyPatch(typeof(StartOfRound))] public static class GetDeathCauses { public static List<(string playerName, string causeOfDeath, string source)> previousRoundDeaths = new List<(string, string, string)>(); [HarmonyPostfix] [HarmonyPatch("WritePlayerNotes")] private static void PostFixWritePlayerNotes() { Plugin.Logger.LogInfo((object)"Getting Causes of Death."); previousRoundDeaths.Clear(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.isPlayerDead) { if (Plugin.Instance.IsCoronerLoaded) { string text = ((object)(CauseOfDeath)(ref val.causeOfDeath)).ToString() ?? "Unknown"; Plugin.Logger.LogInfo((object)("Vanilla caught " + val.playerUsername + "'s cause of death this round was " + text)); previousRoundDeaths.Add((val.playerUsername, text, "Vanilla")); text = CoronerClass.CoronerGetCauseOfDeath(val) ?? "Unknown"; Plugin.Logger.LogInfo((object)("Coroner caught " + val.playerUsername + "'s cause of death this round was " + text)); previousRoundDeaths.Add((val.playerUsername, text, "Coroner")); } else { string text = ((object)(CauseOfDeath)(ref val.causeOfDeath)).ToString() ?? "Unknown"; previousRoundDeaths.Add((val.playerUsername, text, "Vanilla")); Plugin.Logger.LogInfo((object)("Vanilla caught " + val.playerUsername + "'s cause of death this round was " + text)); } } } } } } namespace LethalGargoyles.src.Enemy { public class LethalGargoylesSFX : MonoBehaviour { public AudioSource? audioSource; public AudioClip? audioClip; public void PlayStep() { if (!((Object)(object)audioSource == (Object)null) && !((Object)(object)audioClip == (Object)null)) { audioSource.PlayOneShot(audioClip); } } } public class LethalGargoylesAI : EnemyAI, ISmartAI { private enum State { SearchingForPlayer, StealthyPursuit, GetOutOfSight, AggressivePursuit, Idle, PushTarget } public enum AnimState : byte { Idle, Walk, Chase, SwingAttack } public enum RelativeZone { Front, FrontRight, Right, BackRight, Back, BackLeft, Left, FrontLeft } public static class PlayerActivityTracker { public enum PlayerActivityType { KilledEnemy, PickedUpItem, InFacility } public class ActivityData { public string? Data { get; set; } public float TimeValue { get; set; } public float LastActivityTime { get; set; } } private static readonly Dictionary<PlayerControllerB, Dictionary<PlayerActivityType, ActivityData>> playerActivities = new Dictionary<PlayerControllerB, Dictionary<PlayerActivityType, ActivityData>>(); private static readonly Dictionary<PlayerControllerB, Dictionary<string, float>> playerTauntTimers = new Dictionary<PlayerControllerB, Dictionary<string, float>>(); public static void UpdatePlayerActivity(PlayerControllerB player, PlayerActivityType activityType, string? data = null, float timeValue = 0f) { if (!playerActivities.ContainsKey(player)) { playerActivities[player] = new Dictionary<PlayerActivityType, ActivityData>(); } playerActivities[player][activityType] = new ActivityData { Data = data, TimeValue = timeValue, LastActivityTime = Time.time }; } public static ActivityData GetPlayerActivity(PlayerControllerB player, PlayerActivityType activityType) { if (playerActivities.TryGetValue(player, out Dictionary<PlayerActivityType, ActivityData> value) && value.TryGetValue(activityType, out var value2)) { return value2; } return new ActivityData { Data = null, TimeValue = 0f, LastActivityTime = 0f }; } public static void RemoveActivity(PlayerControllerB player, PlayerActivityType activityType, string? dataValue = null) { if (!playerActivities.TryGetValue(player, out Dictionary<PlayerActivityType, ActivityData> value) || !value.ContainsKey(activityType)) { return; } if (dataValue != null) { if (value[activityType].Data == dataValue) { value.Remove(activityType); } } else { value.Remove(activityType); } if (value.Count == 0) { playerActivities.Remove(player); } } public static void ClearAllPlayerData() { playerActivities.Clear(); playerTauntTimers.Clear(); } public static float GetPlayerTauntTimer(PlayerControllerB player, string timerName) { if (!playerTauntTimers.TryGetValue(player, out Dictionary<string, float> value)) { value = new Dictionary<string, float> { { "lastLostTauntTime", Time.time - 61f }, { "lastGrabTauntTime", Time.time - 61f }, { "lastKillTauntTime", Time.time - 61f } }; playerTauntTimers[player] = value; } if (!value.TryGetValue(timerName, out var value2)) { value2 = (value[timerName] = Time.time - 61f); } return value2; } public static void UpdatePlayerTauntTimer(PlayerControllerB player, string timerName) { if (playerTauntTimers.ContainsKey(player)) { playerTauntTimers[player][timerName] = Time.time; } } } private struct KillTriggerInfo { public Transform T; public BoxCollider C; } [CompilerGenerated] private sealed class <DelayDoorClose>d__183 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DoorLock door; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayDoorClose>d__183(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; case 1: { <>1__state = -1; AnimatedObjectTrigger val = default(AnimatedObjectTrigger); if ((Object)(object)LGInstance != (Object)null && (Object)(object)door != (Object)null && ((Component)door).gameObject.TryGetComponent<AnimatedObjectTrigger>(ref val)) { val.TriggerAnimationNonPlayer(true, true, false); } DoorLock obj = door; if (obj != null) { obj.CloseDoorNonPlayerServerRpc(); } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PlayNoiseWhileTalking>d__212 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public LethalGargoylesAI <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayNoiseWhileTalking>d__212(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown int num = <>1__state; LethalGargoylesAI lethalGargoylesAI = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (((EnemyAI)lethalGargoylesAI).creatureVoice.isPlaying) { RoundManager.Instance.PlayAudibleNoise(((Component)lethalGargoylesAI).transform.position, ((EnemyAI)lethalGargoylesAI).creatureVoice.maxDistance / 3f, ((EnemyAI)lethalGargoylesAI).creatureVoice.volume, 0, false, 0); <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SetCauseOfDeathDelay>d__188 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PlayerControllerB player; public string deathType; public LethalGargoylesAI <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SetCauseOfDeathDelay>d__188(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; LethalGargoylesAI lethalGargoylesAI = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; if (player.isPlayerDead) { if (Plugin.Instance.IsCoronerLoaded) { CoronerClass.CoronerSetCauseOfDeath(player, deathType); } ((EnemyAI)lethalGargoylesAI).targetPlayer = null; lethalGargoylesAI.PlayVoice(AudioManager.playerDeathClips, "playerdeath"); lethalGargoylesAI.SwitchState(State.SearchingForPlayer); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly int TrigIdle = Animator.StringToHash("startIdle"); private static readonly int TrigWalk = Animator.StringToHash("startWalk"); private static readonly int TrigChase = Animator.StringToHash("startChase"); private static readonly int TrigSwingAttack = Animator.StringToHash("swingAttack"); private const float DEST_EPSILON_SQR = 0.01f; private const float REPATH_INTERVAL = 0.75f; private const float DEST_CHANGE_SQR = 1f; private const float TELEPORT_COOLDOWN = 10f; private const float TELEPORT_MIN_DIST_SQR = 2025f; private const float TELEPORT_RANGE_MIN = 10f; private const float TELEPORT_RANGE_MAX = 18f; private const int TELEPORT_ATTEMPTS = 10; private const float SlowMs = 2f; private const float AGGRO_EVAL_INTERVAL = 0.2f; private const float HIDE_EVAL_INTERVAL = 0.35f; public static readonly HashSet<string> trackedItems = new HashSet<string> { "Key", "Apparatus", "Comedy", "Tragedy", "Maneater" }; protected static ConcurrentDictionary<int, PlayerControllerB?> gargoyleTargets = new ConcurrentDictionary<int, PlayerControllerB>(); protected static ConcurrentDictionary<PlayerControllerB, ConcurrentDictionary<int, bool>> playerPushStates = new ConcurrentDictionary<PlayerControllerB, ConcurrentDictionary<int, bool>>(); private static readonly List<GameObject> cachedOutsideAINodes = new List<GameObject>(); private static readonly List<GameObject> cachedInsideAINodes = new List<GameObject>(); private static readonly List<GameObject> cachedAllAINodes = new List<GameObject>(); private static readonly List<LethalGargoylesAI> activeGargoyles = new List<LethalGargoylesAI>(); private static readonly List<Transform> cachedRailings = new List<Transform>(); private static int s_cachedRailingsSceneHandle = -1; private static readonly List<KillTriggerInfo> cachedKillTriggerInfos = new List<KillTriggerInfo>(); private static readonly int RailingMask = 1 << LayerMask.NameToLayer("Railing"); private static readonly Collider[] _tmpRailingColliders = (Collider[])(object)new Collider[16]; private static readonly Dictionary<RelativeZone, float> bufferDistances = new Dictionary<RelativeZone, float> { { RelativeZone.Front, 15f }, { RelativeZone.FrontRight, 12f }, { RelativeZone.Right, 10f }, { RelativeZone.BackRight, 6f }, { RelativeZone.Back, 3f }, { RelativeZone.BackLeft, 6f }, { RelativeZone.Left, 10f }, { RelativeZone.FrontLeft, 12f } }; private static int s_nextGargoyleSerial; private static readonly object PlayerPushStatesLock = new object(); private static int lastGenTaunt = -1; private static int lastAgrTaunt = -1; private static int lastGargoyleToSwitch = 0; private static float lastNodeCheckTime = 0f; public Transform turnCompass; public Transform attackArea; private int _gargoyleSerial; public int myID; private bool _smartRegistered; private SmartPathTask? pathingTask; private SmartPathDestination? activeDestination; private Vector3 _lastActiveDestination = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); private Vector3 _lastRequestedDest; private float _nextPathRequestTime; private float pathDelayTimer; private AnimatedObjectTrigger? currentDoorTrigger; private PlayerControllerB closestPlayer; private PlayerControllerB aggroPlayer; private PlayerControllerB? _lastTarget; private Vector3 cachedTargetPosition; private float distanceToPlayerSqr; private float distanceToClosestPlayerSqr; private bool isSeen; private bool canSeePlayer; private bool targetSeesGargoyle; private Transform? killTrigger; private float distToKillTriggerSqr; private float pushTimer; private int pushStage; private float targetTimer; private float _nextAggroEvalTime; private float playerCheckTimer; private int previousStateIndex; private float lastSeenCheckTime; private readonly Dictionary<RelativeZone, Vector3> RelativeZones = new Dictionary<RelativeZone, Vector3>(); private RelativeZone currentZone; private RelativeZone nextZoneRight; private RelativeZone nextZoneLeft; private float leftPathDist; private float rightPathDist; private float _nextZoneFailLogTime; private Vector3 lastCoverSearchPosition; private float coverSearchCooldown = 3f; private float lastCoverSearchTime = -10f; private List<Vector3> cachedCoverPoints = new List<Vector3>(); private float _nextHideEvalTime; public DoorLock? currentDoor; public float lastDoorCloseTime; private float baseSpeed; private float attackRangeSqr; private int attackDamage; private float aggroRangeSqr; private int minTaunt; private int maxTaunt; private float distWarnSqr; private float bufferDistSqr; private float awareDistSqr; private float idleDistanceSqr; private bool enablePush; private float randGenTauntTime; private float randAgrTauntTime; private float randEnemyTauntTime; private float lastGenTauntTime; private float lastAgrTauntTime; private float lastEnemyTauntTime; private float lastSteamIDTauntTime; private int genTauntCount; private string? lastEnemy; private string? _lastEnemyLogName; private float _nextEnemyLogTime; private float _nextActivityLogTime; private float _nextDoAiLogTime; private readonly float nodeCheckInterval = 5f; private float lastAttackTime; private readonly List<PlayerControllerB> validPlayers = new List<PlayerControllerB>(); private readonly List<LethalGargoylesAI> gargoyles = new List<LethalGargoylesAI>(); private readonly Dictionary<PlayerControllerB, string> playerClasses = new Dictionary<PlayerControllerB, string>(); private AnimState _lastAnim; private float _nextTeleportTime; public static LethalGargoylesAI? LGInstance { get; private set; } private string GargoyleTag => $"LG#{_gargoyleSerial}(agentId={myID}, netId={(((Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null) ? ((NetworkBehaviour)this).NetworkObject.NetworkObjectId : 0)})"; private static bool IsInvalidPos(Vector3 p) { return ((Vector3)(ref p)).sqrMagnitude < 0.0001f; } public override void Start() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).Start(); _gargoyleSerial = Interlocked.Increment(ref s_nextGargoyleSerial); myID = ((Object)base.agent).GetInstanceID(); SmartPathfinding.RegisterSmartAgent(base.agent); _smartRegistered = true; LGInstance = this; SetAnim(AnimState.Walk); SwitchState(State.SearchingForPlayer); ((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null); baseSpeed = Plugin.BoundConfig.baseSpeed.Value; attackDamage = Plugin.BoundConfig.attackDamage.Value; minTaunt = Plugin.BoundConfig.minTaunt.Value; maxTaunt = Plugin.BoundConfig.maxTaunt.Value; attackRangeSqr = Plugin.BoundConfig.attackRange.Value; attackRangeSqr *= attackRangeSqr; aggroRangeSqr = Plugin.BoundConfig.aggroRange.Value; aggroRangeSqr *= aggroRangeSqr; distWarnSqr = Plugin.BoundConfig.distWarn.Value; distWarnSqr *= distWarnSqr; idleDistanceSqr = Plugin.BoundConfig.idleDistance.Value; idleDistanceSqr *= idleDistanceSqr; bufferDistSqr = Plugin.BoundConfig.bufferDist.Value; bufferDistSqr *= bufferDistSqr; awareDistSqr = Plugin.BoundConfig.awareDist.Value; awareDistSqr *= awareDistSqr; enablePush = Plugin.BoundConfig.enablePush.Value; lastAttackTime = Time.time; pushTimer = Time.time; gargoyleTargets[myID] = base.targetPlayer; _lastTarget = base.targetPlayer; _nextAggroEvalTime = Time.time; AudioSource creatureVoice = base.creatureVoice; creatureVoice.maxDistance *= 3f; pathDelayTimer = Time.time; lastSteamIDTauntTime = Time.time - 91f; cachedOutsideAINodes.Clear(); GameObject[] outsideAINodes = RoundManager.Instance.outsideAINodes; foreach (GameObject val in outsideAINodes) { if ((Object)(object)val != (Object)null) { cachedOutsideAINodes.Add(val); } } cachedInsideAINodes.Clear(); GameObject[] insideAINodes = RoundManager.Instance.insideAINodes; foreach (GameObject val2 in insideAINodes) { if ((Object)(object)val2 != (Object)null) { cachedInsideAINodes.Add(val2); } } cachedAllAINodes.Clear(); GameObject[] allAINodes = base.allAINodes; foreach (GameObject val3 in allAINodes) { if ((Object)(object)val3 != (Object)null) { cachedAllAINodes.Add(val3); } } CacheKillTriggers(); playerClasses.Clear(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val4 in allPlayerScripts) { playerClasses[val4] = EmployeeClassesClass.GetPlayerClass(val4) ?? "Employee"; } activeGargoyles.Add(this); } public override void Update() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).Update(); cachedTargetPosition = (((Object)(object)base.targetPlayer != (Object)null) ? ((Component)base.targetPlayer).transform.position : ((Component)this).transform.position); if (base.isEnemyDead || StartOfRound.Instance.allPlayersDead || !((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh || !((NetworkBehaviour)this).IsOwner) { return; } Stopwatch stopwatch = Stopwatch.StartNew(); if ((Object)(object)_lastTarget != (Object)(object)base.targetPlayer) { gargoyleTargets[myID] = base.targetPlayer; _lastTarget = base.targetPlayer; } if (Time.time - lastNodeCheckTime > nodeCheckInterval) { float num = (float)stopwatch.Elapsed.TotalMilliseconds; CheckAndRefreshAINodes(); lastNodeCheckTime = Time.time; } float num2 = (float)stopwatch.Elapsed.TotalMilliseconds; HandleTargetPlayer(); if (Time.time - lastSeenCheckTime > 0.33f) { float num3 = (float)stopwatch.Elapsed.TotalMilliseconds; closestPlayer = ((EnemyAI)this).GetClosestPlayer(false, false, false); float num4; if (!((Object)(object)closestPlayer != (Object)null)) { num4 = 0f; } else { Vector3 val = ((Component)this).transform.position - ((Component)closestPlayer).transform.position; num4 = ((Vector3)(ref val)).sqrMagnitude; } distanceToClosestPlayerSqr = num4; isSeen = GargoyleIsSeen(((Component)this).transform); lastSeenCheckTime = Time.time; } float num5 = (float)stopwatch.Elapsed.TotalMilliseconds; HandlePushStage(); float num6 = (float)stopwatch.Elapsed.TotalMilliseconds; HandleBehaviorState(); if (base.currentBehaviourStateIndex != 4) { float num7 = (float)stopwatch.Elapsed.TotalMilliseconds; FollowSmartPath(); } stopwatch.Stop(); } public override void DoAIInterval() { //IL_0759: Unknown result type (might be due to invalid IL or missing references) //IL_0987: Unknown result type (might be due to invalid IL or missing references) //IL_0974: Unknown result type (might be due to invalid IL or missing references) //IL_0979: Unknown result type (might be due to invalid IL or missing references) //IL_097c: Unknown result type (might be due to invalid IL or missing references) //IL_0828: Unknown result type (might be due to invalid IL or missing references) //IL_0833: Unknown result type (might be due to invalid IL or missing references) //IL_0838: Unknown result type (might be due to invalid IL or missing references) //IL_083d: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_047d: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04e6: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Unknown result type (might be due to invalid IL or missing references) //IL_061b: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).DoAIInterval(); if (Time.time >= _nextDoAiLogTime) { _nextDoAiLogTime = Time.time + 3f; string text = StateToString(base.currentBehaviourStateIndex); string text2 = $"Owner={((NetworkBehaviour)this).IsOwner} Server={((NetworkBehaviour)this).IsServer} Spawned={(Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned}"; string text3 = (((Object)(object)base.targetPlayer == (Object)null) ? "Target=null" : $"Target={base.targetPlayer.playerUsername} id={base.targetPlayer.playerClientId} dead={base.targetPlayer.isPlayerDead} controlled={base.targetPlayer.isPlayerControlled} insideFactory={base.targetPlayer.isInsideFactory}"); string text4 = (((Object)(object)closestPlayer == (Object)null) ? "Closest=null" : $"Closest={closestPlayer.playerUsername} id={closestPlayer.playerClientId} dead={closestPlayer.isPlayerDead} insideFactory={closestPlayer.isInsideFactory}"); float num = (((Object)(object)base.targetPlayer != (Object)null) ? Mathf.Sqrt(distanceToPlayerSqr) : (-1f)); float num2 = (((Object)(object)closestPlayer != (Object)null) ? Mathf.Sqrt(distanceToClosestPlayerSqr) : (-1f)); string text5 = $"dist(target)={num:0.0}m dist(closest)={num2:0.0}m " + $"ranges: aware={Mathf.Sqrt(awareDistSqr):0.0} aggro={Mathf.Sqrt(aggroRangeSqr):0.0} idle={Mathf.Sqrt(idleDistanceSqr):0.0} atk={Mathf.Sqrt(attackRangeSqr):0.0} buffer={Mathf.Sqrt(bufferDistSqr):0.0}"; string text6 = $"seen={isSeen} targetSees={targetSeesGargoyle} canSee={canSeePlayer} " + $"push: enable={enablePush} stage={pushStage} timerIn={pushTimer - Time.time:0.0}s"; string text7 = string.Format("killTrigger={0} dist={1:0.0}m", ((Object)(object)killTrigger != (Object)null) ? ((Object)killTrigger).name : "null", (distToKillTriggerSqr == float.MaxValue) ? (-1f) : Mathf.Sqrt(distToKillTriggerSqr)); bool flag = false; if ((Object)(object)base.targetPlayer != (Object)null && playerPushStates.TryGetValue(base.targetPlayer, out ConcurrentDictionary<int, bool> value) && value.TryGetValue(myID, out var value2)) { flag = value2; } ConcurrentDictionary<int, bool> value3; string text8 = (((Object)(object)base.targetPlayer != (Object)null) ? $"pushMap: iAmPushing={flag} entries={(playerPushStates.TryGetValue(base.targetPlayer, out value3) ? value3.Count : 0)}" : "pushMap: n/a"); Vector3 position = ((Component)this).transform.position; Vector3 destination = base.agent.destination; Vector3 velocity = base.agent.velocity; string text9 = $"agent: enabled={((Behaviour)base.agent).enabled} onNavMesh={base.agent.isOnNavMesh} " + $"speed={base.agent.speed:0.00} angSpeed={base.agent.angularSpeed:0.0} stopDist={base.agent.stoppingDistance:0.00} " + $"hasPath={base.agent.hasPath} pending={base.agent.pathPending} status={base.agent.pathStatus} " + $"remDist={base.agent.remainingDistance:0.00} " + $"pos=({position.x:0.0},{position.y:0.0},{position.z:0.0}) dest=({destination.x:0.0},{destination.y:0.0},{destination.z:0.0}) vel=({velocity.x:0.0},{velocity.y:0.0},{velocity.z:0.0})"; if (pathingTask == null) { string text10 = "smartPath: task=null"; } else { bool isStarted = pathingTask.IsStarted; bool flag2 = isStarted && pathingTask.IsResultReady(0); string text11 = $"requested=({_lastRequestedDest.x:0.0},{_lastRequestedDest.y:0.0},{_lastRequestedDest.z:0.0})"; string text12 = $"lastActive=({_lastActiveDestination.x:0.0},{_lastActiveDestination.y:0.0},{_lastActiveDestination.z:0.0})"; string text13; if (!flag2) { text13 = "result=not-ready"; } else { SmartPathDestination? result = pathingTask.GetResult(0); if (!result.HasValue) { text13 = "result=null"; } else { SmartPathDestination value4 = result.Value; Vector3 position2 = ((SmartPathDestination)(ref value4)).Position; text13 = $"result: type={((SmartPathDestination)(ref value4)).Type} pos=({position2.x:0.0},{position2.y:0.0},{position2.z:0.0})"; } } string text10 = $"smartPath: started={isStarted} ready={flag2} {text11} {text12} {text13}"; } string text14 = (((Object)(object)currentDoor == (Object)null) ? "door=null" : $"door={((Object)currentDoor).name} locked={currentDoor.isLocked} trigCached={(Object)(object)currentDoorTrigger != (Object)null} trigBool={(Object)(object)currentDoorTrigger != (Object)null && currentDoorTrigger.boolValue} lastCloseAgo={Time.time - lastDoorCloseTime:0.00}s"); } if (base.isEnemyDead || StartOfRound.Instance.allPlayersDead) { if (StartOfRound.Instance.allPlayersDead) { ClearAllVariables(); } return; } _ = base.currentBehaviourStateIndex; _ = previousStateIndex; previousStateIndex = base.currentBehaviourStateIndex; if ((Object)(object)base.targetPlayer != (Object)null) { killTrigger = FindNearestKillTrigger(cachedTargetPosition); if (Time.time - playerCheckTimer > 3f) { ChangeTarget(); playerCheckTimer = Time.time; } } if ((Object)(object)LGInstance != (Object)null) { if ((Object)(object)currentDoorTrigger == (Object)null && (Object)(object)currentDoor != (Object)null) { currentDoorTrigger = ((Component)currentDoor).gameObject.GetComponent<AnimatedObjectTrigger>(); } if (Time.time - lastDoorCloseTime >= 0.75f && (Object)(object)currentDoor != (Object)null && !currentDoor.isLocked && (Object)(object)currentDoorTrigger != (Object)null && currentDoorTrigger.boolValue) { Vector3 val = ((Component)currentDoor).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude > ((base.currentBehaviourStateIndex == 4) ? 8f : 16f)) { ((MonoBehaviour)this).StartCoroutine(DelayDoorClose(currentDoor)); currentDoor = null; currentDoorTrigger = null; } } } switch (base.currentBehaviourStateIndex) { case 0: if (FoundClosestPlayerInRange()) { ((EnemyAI)this).StopSearch(base.currentSearch, true); SwitchState(State.StealthyPursuit); } if (base.agent.hasPath) { SetAnim(base.agent.hasPath ? AnimState.Walk : AnimState.Idle); } else { SetAnim(AnimState.Idle); } break; case 1: case 2: if (base.agent.hasPath) { SetAnim(AnimState.Walk); } else { SetAnim(AnimState.Idle); } break; case 4: SetAnim(AnimState.Idle); break; case 3: if (base.agent.hasPath) { SetAnim(AnimState.Chase); } else { SetAnim(AnimState.Idle); } break; case 5: if ((Time.time - targetTimer > 0.5f || !base.agent.hasPath) && (Object)(object)base.targetPlayer != (Object)null) { if (distanceToPlayerSqr <= idleDistanceSqr) { Vector3 targetPosition = GetTargetPosition(base.targetPlayer); SetSmartDestination(targetPosition); } else { SetSmartDestination(cachedTargetPosition); } targetTimer = Time.time; } if (base.agent.hasPath) { SetAnim(AnimState.Chase); } else { SetAnim(AnimState.Idle); } break; } } private void OnDisable() { CleanupSmartPathing(); } public override void OnDestroy()
plugins/LethalGargoyles/lib/NVorbis/NVorbis.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using NVorbis.Contracts; using NVorbis.Contracts.Ogg; using NVorbis.Ogg; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Andrew Ward")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Andrew Ward 2021")] [assembly: AssemblyDescription("A fully managed implementation of a Xiph.org Foundation Ogg Vorbis decoder.")] [assembly: AssemblyFileVersion("0.10.5.0")] [assembly: AssemblyInformationalVersion("0.10.5")] [assembly: AssemblyProduct("NVorbis")] [assembly: AssemblyTitle("NVorbis")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/NVorbis/NVorbis")] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("0.10.5.0")] namespace NVorbis { internal class Codebook : ICodebook { private class FastRange : IReadOnlyList<int>, IEnumerable<int>, IEnumerable, IReadOnlyCollection<int> { [ThreadStatic] private static FastRange _cachedRange; private int _start; private int _count; public int this[int index] { get { if (index > _count) { throw new ArgumentOutOfRangeException(); } return _start + index; } } public int Count => _count; internal static FastRange Get(int start, int count) { FastRange obj = _cachedRange ?? (_cachedRange = new FastRange()); obj._start = start; obj._count = count; return obj; } private FastRange() { } public IEnumerator<int> GetEnumerator() { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private int[] _lengths; private float[] _lookupTable; private IReadOnlyList<HuffmanListNode> _overflowList; private IReadOnlyList<HuffmanListNode> _prefixList; private int _prefixBitLength; private int _maxBits; public float this[int entry, int dim] => _lookupTable[entry * Dimensions + dim]; public int Dimensions { get; private set; } public int Entries { get; private set; } public int MapType { get; private set; } public void Init(IPacket packet, IHuffman huffman) { if (packet.ReadBits(24) != 5653314) { throw new InvalidDataException("Book header had invalid signature!"); } Dimensions = (int)packet.ReadBits(16); Entries = (int)packet.ReadBits(24); _lengths = new int[Entries]; InitTree(packet, huffman); InitLookupTable(packet); } private void InitTree(IPacket packet, IHuffman huffman) { int num = 0; bool flag; int num5; if (packet.ReadBit()) { int num2 = (int)packet.ReadBits(5) + 1; int num3 = 0; while (num3 < Entries) { int num4 = (int)packet.ReadBits(Utils.ilog(Entries - num3)); while (--num4 >= 0) { _lengths[num3++] = num2; } num2++; } num = 0; flag = false; num5 = num2; } else { num5 = -1; flag = packet.ReadBit(); for (int i = 0; i < Entries; i++) { if (!flag || packet.ReadBit()) { _lengths[i] = (int)packet.ReadBits(5) + 1; num++; } else { _lengths[i] = -1; } if (_lengths[i] > num5) { num5 = _lengths[i]; } } } if ((_maxBits = num5) > -1) { int[] array = null; if (flag && num >= Entries >> 2) { array = new int[Entries]; Array.Copy(_lengths, array, Entries); flag = false; } int num6 = (flag ? num : 0); int[] array2 = null; int[] array3 = null; if (!flag) { array3 = new int[Entries]; } else if (num6 != 0) { array = new int[num6]; array3 = new int[num6]; array2 = new int[num6]; } if (!ComputeCodewords(flag, array3, array, _lengths, Entries, array2)) { throw new InvalidDataException(); } IReadOnlyList<int> readOnlyList = array2; IReadOnlyList<int> value = readOnlyList ?? FastRange.Get(0, array3.Length); huffman.GenerateTable(value, array ?? _lengths, array3); _prefixList = huffman.PrefixTree; _prefixBitLength = huffman.TableBits; _overflowList = huffman.OverflowList; } } private bool ComputeCodewords(bool sparse, int[] codewords, int[] codewordLengths, int[] len, int n, int[] values) { int num = 0; uint[] array = new uint[32]; int i; for (i = 0; i < n && len[i] <= 0; i++) { } if (i == n) { return true; } AddEntry(sparse, codewords, codewordLengths, 0u, i, num++, len[i], values); for (int j = 1; j <= len[i]; j++) { array[j] = (uint)(1 << 32 - j); } for (int j = i + 1; j < n; j++) { int num2 = len[j]; if (num2 <= 0) { continue; } while (num2 > 0 && array[num2] == 0) { num2--; } if (num2 == 0) { return false; } uint num3 = array[num2]; array[num2] = 0u; AddEntry(sparse, codewords, codewordLengths, Utils.BitReverse(num3), j, num++, len[j], values); if (num2 != len[j]) { for (int num4 = len[j]; num4 > num2; num4--) { array[num4] = num3 + (uint)(1 << 32 - num4); } } } return true; } private void AddEntry(bool sparse, int[] codewords, int[] codewordLengths, uint huffCode, int symbol, int count, int len, int[] values) { if (sparse) { codewords[count] = (int)huffCode; codewordLengths[count] = len; values[count] = symbol; } else { codewords[symbol] = (int)huffCode; } } private void InitLookupTable(IPacket packet) { MapType = (int)packet.ReadBits(4); if (MapType == 0) { return; } float num = Utils.ConvertFromVorbisFloat32((uint)packet.ReadBits(32)); float num2 = Utils.ConvertFromVorbisFloat32((uint)packet.ReadBits(32)); int count = (int)packet.ReadBits(4) + 1; bool flag = packet.ReadBit(); int num3 = Entries * Dimensions; float[] array = new float[num3]; if (MapType == 1) { num3 = lookup1_values(); } uint[] array2 = new uint[num3]; for (int i = 0; i < num3; i++) { array2[i] = (uint)packet.ReadBits(count); } if (MapType == 1) { for (int j = 0; j < Entries; j++) { double num4 = 0.0; int num5 = 1; for (int k = 0; k < Dimensions; k++) { int num6 = j / num5 % num3; double num7 = (double)((float)array2[num6] * num2 + num) + num4; array[j * Dimensions + k] = (float)num7; if (flag) { num4 = num7; } num5 *= num3; } } } else { for (int l = 0; l < Entries; l++) { double num8 = 0.0; int num9 = l * Dimensions; for (int m = 0; m < Dimensions; m++) { double num10 = (double)((float)array2[num9] * num2 + num) + num8; array[l * Dimensions + m] = (float)num10; if (flag) { num8 = num10; } num9++; } } } _lookupTable = array; } private int lookup1_values() { int num = (int)Math.Floor(Math.Exp(Math.Log(Entries) / (double)Dimensions)); if (Math.Floor(Math.Pow(num + 1, Dimensions)) <= (double)Entries) { num++; } return num; } public int DecodeScalar(IPacket packet) { int index = (int)packet.TryPeekBits(_prefixBitLength, out var bitsRead); if (bitsRead == 0) { return -1; } HuffmanListNode huffmanListNode = _prefixList[index]; if (huffmanListNode != null) { packet.SkipBits(huffmanListNode.Length); return huffmanListNode.Value; } index = (int)packet.TryPeekBits(_maxBits, out var _); for (int i = 0; i < _overflowList.Count; i++) { huffmanListNode = _overflowList[i]; if (huffmanListNode.Bits == (index & huffmanListNode.Mask)) { packet.SkipBits(huffmanListNode.Length); return huffmanListNode.Value; } } return -1; } } public abstract class DataPacket : IPacket { [Flags] protected enum PacketFlags : byte { IsResync = 1, IsEndOfStream = 2, IsShort = 4, User0 = 8, User1 = 0x10, User2 = 0x20, User3 = 0x40, User4 = 0x80 } private ulong _bitBucket; private int _bitCount; private byte _overflowBits; private PacketFlags _packetFlags; private int _readBits; public int ContainerOverheadBits { get; set; } public long? GranulePosition { get; set; } public bool IsResync { get { return GetFlag(PacketFlags.IsResync); } set { SetFlag(PacketFlags.IsResync, value); } } public bool IsShort { get { return GetFlag(PacketFlags.IsShort); } private set { SetFlag(PacketFlags.IsShort, value); } } public bool IsEndOfStream { get { return GetFlag(PacketFlags.IsEndOfStream); } set { SetFlag(PacketFlags.IsEndOfStream, value); } } public int BitsRead => _readBits; public int BitsRemaining => TotalBits - _readBits; protected abstract int TotalBits { get; } private bool GetFlag(PacketFlags flag) { return _packetFlags.HasFlag(flag); } private void SetFlag(PacketFlags flag, bool value) { if (value) { _packetFlags |= flag; } else { _packetFlags &= (PacketFlags)(byte)(~(int)flag); } } protected abstract int ReadNextByte(); public virtual void Done() { } public virtual void Reset() { _bitBucket = 0uL; _bitCount = 0; _overflowBits = 0; _readBits = 0; } ulong IPacket.ReadBits(int count) { if (count == 0) { return 0uL; } int bitsRead; ulong result = TryPeekBits(count, out bitsRead); SkipBits(count); return result; } public ulong TryPeekBits(int count, out int bitsRead) { switch (count) { default: throw new ArgumentOutOfRangeException("count"); case 0: bitsRead = 0; return 0uL; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: break; } while (_bitCount < count) { int num = ReadNextByte(); if (num == -1) { bitsRead = _bitCount; return _bitBucket; } _bitBucket = (ulong)((long)(num & 0xFF) << _bitCount) | _bitBucket; _bitCount += 8; if (_bitCount > 64) { _overflowBits = (byte)(num >> 72 - _bitCount); } } ulong num2 = _bitBucket; if (count < 64) { num2 &= (ulong)((1L << count) - 1); } bitsRead = count; return num2; } public void SkipBits(int count) { if (count <= 0) { return; } if (_bitCount > count) { if (count > 63) { _bitBucket = 0uL; } else { _bitBucket >>= count; } if (_bitCount > 64) { int num = _bitCount - 64; _bitBucket |= (ulong)_overflowBits << _bitCount - count - num; if (num > count) { _overflowBits = (byte)(_overflowBits >> count); } } _bitCount -= count; _readBits += count; return; } if (_bitCount == count) { _bitBucket = 0uL; _bitCount = 0; _readBits += count; return; } count -= _bitCount; _readBits += _bitCount; _bitCount = 0; _bitBucket = 0uL; while (count > 8) { if (ReadNextByte() == -1) { count = 0; IsShort = true; break; } count -= 8; _readBits += 8; } if (count > 0) { int num2 = ReadNextByte(); if (num2 == -1) { IsShort = true; return; } _bitBucket = (ulong)(num2 >> count); _bitCount = 8 - count; _readBits += count; } } } public static class Extensions { public static int Read(this IPacket packet, byte[] buffer, int index, int count) { if (index < 0 || index >= buffer.Length) { throw new ArgumentOutOfRangeException("index"); } if (count < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } for (int i = 0; i < count; i++) { int bitsRead; byte b = (byte)packet.TryPeekBits(8, out bitsRead); if (bitsRead == 0) { return i; } buffer[index++] = b; packet.SkipBits(8); } return count; } public static byte[] ReadBytes(this IPacket packet, int count) { byte[] array = new byte[count]; int num = packet.Read(array, 0, count); if (num < count) { byte[] array2 = new byte[num]; Buffer.BlockCopy(array, 0, array2, 0, num); return array2; } return array; } public static bool ReadBit(this IPacket packet) { return packet.ReadBits(1) == 1; } public static byte PeekByte(this IPacket packet) { int bitsRead; return (byte)packet.TryPeekBits(8, out bitsRead); } public static byte ReadByte(this IPacket packet) { return (byte)packet.ReadBits(8); } public static short ReadInt16(this IPacket packet) { return (short)packet.ReadBits(16); } public static int ReadInt32(this IPacket packet) { return (int)packet.ReadBits(32); } public static long ReadInt64(this IPacket packet) { return (long)packet.ReadBits(64); } public static ushort ReadUInt16(this IPacket packet) { return (ushort)packet.ReadBits(16); } public static uint ReadUInt32(this IPacket packet) { return (uint)packet.ReadBits(32); } public static ulong ReadUInt64(this IPacket packet) { return packet.ReadBits(64); } public static void SkipBytes(this IPacket packet, int count) { packet.SkipBits(count * 8); } } internal class Factory : IFactory { public IHuffman CreateHuffman() { return new Huffman(); } public IMdct CreateMdct() { return new Mdct(); } public ICodebook CreateCodebook() { return new Codebook(); } public IFloor CreateFloor(IPacket packet) { return (int)packet.ReadBits(16) switch { 0 => new Floor0(), 1 => new Floor1(), _ => throw new InvalidDataException("Invalid floor type!"), }; } public IMapping CreateMapping(IPacket packet) { if (packet.ReadBits(16) != 0L) { throw new InvalidDataException("Invalid mapping type!"); } return new Mapping(); } public IMode CreateMode() { return new Mode(); } public IResidue CreateResidue(IPacket packet) { return (int)packet.ReadBits(16) switch { 0 => new Residue0(), 1 => new Residue1(), 2 => new Residue2(), _ => throw new InvalidDataException("Invalid residue type!"), }; } } internal class Floor0 : IFloor { private class Data : IFloorData { internal float[] Coeff; internal float Amp; public bool ExecuteChannel { get { if (ForceEnergy || Amp > 0f) { return !ForceNoEnergy; } return false; } } public bool ForceEnergy { get; set; } public bool ForceNoEnergy { get; set; } } private int _order; private int _rate; private int _bark_map_size; private int _ampBits; private int _ampOfs; private int _ampDiv; private ICodebook[] _books; private int _bookBits; private Dictionary<int, float[]> _wMap; private Dictionary<int, int[]> _barkMaps; public void Init(IPacket packet, int channels, int block0Size, int block1Size, ICodebook[] codebooks) { _order = (int)packet.ReadBits(8); _rate = (int)packet.ReadBits(16); _bark_map_size = (int)packet.ReadBits(16); _ampBits = (int)packet.ReadBits(6); _ampOfs = (int)packet.ReadBits(8); _books = new ICodebook[(int)packet.ReadBits(4) + 1]; if (_order < 1 || _rate < 1 || _bark_map_size < 1 || _books.Length == 0) { throw new InvalidDataException(); } _ampDiv = (1 << _ampBits) - 1; for (int i = 0; i < _books.Length; i++) { int num = (int)packet.ReadBits(8); if (num < 0 || num >= codebooks.Length) { throw new InvalidDataException(); } ICodebook codebook = codebooks[num]; if (codebook.MapType == 0 || codebook.Dimensions < 1) { throw new InvalidDataException(); } _books[i] = codebook; } _bookBits = Utils.ilog(_books.Length); _barkMaps = new Dictionary<int, int[]> { [block0Size] = SynthesizeBarkCurve(block0Size / 2), [block1Size] = SynthesizeBarkCurve(block1Size / 2) }; _wMap = new Dictionary<int, float[]> { [block0Size] = SynthesizeWDelMap(block0Size / 2), [block1Size] = SynthesizeWDelMap(block1Size / 2) }; } private int[] SynthesizeBarkCurve(int n) { float num = (float)_bark_map_size / toBARK(_rate / 2); int[] array = new int[n + 1]; for (int i = 0; i < n - 1; i++) { array[i] = Math.Min(_bark_map_size - 1, (int)Math.Floor(toBARK((float)_rate / 2f / (float)n * (float)i) * num)); } array[n] = -1; return array; } private static float toBARK(double lsp) { return (float)(13.1 * Math.Atan(0.00074 * lsp) + 2.24 * Math.Atan(1.85E-08 * lsp * lsp) + 0.0001 * lsp); } private float[] SynthesizeWDelMap(int n) { float num = (float)(Math.PI / (double)_bark_map_size); float[] array = new float[n]; for (int i = 0; i < n; i++) { array[i] = 2f * (float)Math.Cos(num * (float)i); } return array; } public IFloorData Unpack(IPacket packet, int blockSize, int channel) { Data data = new Data { Coeff = new float[_order + 1] }; data.Amp = packet.ReadBits(_ampBits); if (data.Amp > 0f) { Array.Clear(data.Coeff, 0, data.Coeff.Length); data.Amp = data.Amp / (float)_ampDiv * (float)_ampOfs; uint num = (uint)packet.ReadBits(_bookBits); if (num >= _books.Length) { data.Amp = 0f; return data; } ICodebook codebook = _books[num]; int i = 0; while (i < _order) { int num2 = codebook.DecodeScalar(packet); if (num2 == -1) { data.Amp = 0f; return data; } int num3 = 0; for (; i < _order; i++) { if (num3 >= codebook.Dimensions) { break; } data.Coeff[i] = codebook[num2, num3]; num3++; } } float num4 = 0f; int num5 = 0; while (num5 < _order) { int num6 = 0; while (num5 < _order && num6 < codebook.Dimensions) { data.Coeff[num5] += num4; num5++; num6++; } num4 = data.Coeff[num5 - 1]; } } return data; } public void Apply(IFloorData floorData, int blockSize, float[] residue) { if (!(floorData is Data data)) { throw new ArgumentException("Incorrect packet data!"); } int num = blockSize / 2; if (data.Amp > 0f) { int[] array = _barkMaps[blockSize]; float[] array2 = _wMap[blockSize]; int num2 = 0; for (num2 = 0; num2 < _order; num2++) { data.Coeff[num2] = 2f * (float)Math.Cos(data.Coeff[num2]); } num2 = 0; while (num2 < num) { int num3 = array[num2]; float num4 = 0.5f; float num5 = 0.5f; float num6 = array2[num3]; int i; for (i = 1; i < _order; i += 2) { num5 *= num6 - data.Coeff[i - 1]; num4 *= num6 - data.Coeff[i]; } if (i == _order) { num5 *= num6 - data.Coeff[i - 1]; num4 *= num4 * (4f - num6 * num6); num5 *= num5; } else { num4 *= num4 * (2f - num6); num5 *= num5 * (2f + num6); } num5 = data.Amp / (float)Math.Sqrt(num4 + num5) - (float)_ampOfs; num5 = (float)Math.Exp(num5 * 0.11512925f); residue[num2] *= num5; while (array[++num2] == num3) { residue[num2] *= num5; } } } else { Array.Clear(residue, 0, num); } } } internal class Floor1 : IFloor { private class Data : IFloorData { internal int[] Posts = new int[64]; internal int PostCount; public bool ExecuteChannel { get { if (ForceEnergy || PostCount > 0) { return !ForceNoEnergy; } return false; } } public bool ForceEnergy { get; set; } public bool ForceNoEnergy { get; set; } } private int[] _partitionClass; private int[] _classDimensions; private int[] _classSubclasses; private int[] _xList; private int[] _classMasterBookIndex; private int[] _hNeigh; private int[] _lNeigh; private int[] _sortIdx; private int _multiplier; private int _range; private int _yBits; private ICodebook[] _classMasterbooks; private ICodebook[][] _subclassBooks; private int[][] _subclassBookIndex; private static readonly int[] _rangeLookup = new int[4] { 256, 128, 86, 64 }; private static readonly int[] _yBitsLookup = new int[4] { 8, 7, 7, 6 }; private static readonly float[] inverse_dB_table = new float[256] { 1.0649863E-07f, 1.1341951E-07f, 1.2079015E-07f, 1.2863978E-07f, 1.369995E-07f, 1.459025E-07f, 1.5538409E-07f, 1.6548181E-07f, 1.7623574E-07f, 1.8768856E-07f, 1.998856E-07f, 2.128753E-07f, 2.2670913E-07f, 2.4144197E-07f, 2.5713223E-07f, 2.7384212E-07f, 2.9163792E-07f, 3.1059022E-07f, 3.307741E-07f, 3.5226967E-07f, 3.7516213E-07f, 3.995423E-07f, 4.255068E-07f, 4.5315863E-07f, 4.8260745E-07f, 5.1397E-07f, 5.4737063E-07f, 5.829419E-07f, 6.208247E-07f, 6.611694E-07f, 7.041359E-07f, 7.4989464E-07f, 7.98627E-07f, 8.505263E-07f, 9.057983E-07f, 9.646621E-07f, 1.0273513E-06f, 1.0941144E-06f, 1.1652161E-06f, 1.2409384E-06f, 1.3215816E-06f, 1.4074654E-06f, 1.4989305E-06f, 1.5963394E-06f, 1.7000785E-06f, 1.8105592E-06f, 1.9282195E-06f, 2.053526E-06f, 2.1869757E-06f, 2.3290977E-06f, 2.4804558E-06f, 2.6416496E-06f, 2.813319E-06f, 2.9961443E-06f, 3.1908505E-06f, 3.39821E-06f, 3.619045E-06f, 3.8542307E-06f, 4.1047006E-06f, 4.371447E-06f, 4.6555283E-06f, 4.958071E-06f, 5.280274E-06f, 5.623416E-06f, 5.988857E-06f, 6.3780467E-06f, 6.7925284E-06f, 7.2339453E-06f, 7.704048E-06f, 8.2047E-06f, 8.737888E-06f, 9.305725E-06f, 9.910464E-06f, 1.0554501E-05f, 1.1240392E-05f, 1.1970856E-05f, 1.2748789E-05f, 1.3577278E-05f, 1.4459606E-05f, 1.5399271E-05f, 1.6400005E-05f, 1.7465769E-05f, 1.8600793E-05f, 1.9809577E-05f, 2.1096914E-05f, 2.2467912E-05f, 2.3928002E-05f, 2.5482977E-05f, 2.7139005E-05f, 2.890265E-05f, 3.078091E-05f, 3.2781227E-05f, 3.4911533E-05f, 3.718028E-05f, 3.9596467E-05f, 4.2169668E-05f, 4.491009E-05f, 4.7828602E-05f, 5.0936775E-05f, 5.424693E-05f, 5.7772202E-05f, 6.152657E-05f, 6.552491E-05f, 6.9783084E-05f, 7.4317984E-05f, 7.914758E-05f, 8.429104E-05f, 8.976875E-05f, 9.560242E-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, 0.00015820454f, 0.00016848555f, 0.00017943469f, 0.00019109536f, 0.00020351382f, 0.0002167393f, 0.00023082423f, 0.00024582449f, 0.00026179955f, 0.00027881275f, 0.00029693157f, 0.00031622787f, 0.00033677815f, 0.00035866388f, 0.00038197188f, 0.00040679457f, 0.00043323037f, 0.0004613841f, 0.0004913675f, 0.00052329927f, 0.0005573062f, 0.0005935231f, 0.0006320936f, 0.0006731706f, 0.000716917f, 0.0007635063f, 0.00081312325f, 0.00086596457f, 0.00092223985f, 0.0009821722f, 0.0010459992f, 0.0011139743f, 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, 0.0019632196f, 0.0020908006f, 0.0022266726f, 0.0023713743f, 0.0025254795f, 0.0026895993f, 0.0028643848f, 0.0030505287f, 0.003248769f, 0.0034598925f, 0.0036847359f, 0.0039241905f, 0.0041792067f, 0.004450795f, 0.004740033f, 0.005048067f, 0.0053761187f, 0.005725489f, 0.0060975635f, 0.0064938175f, 0.0069158226f, 0.0073652514f, 0.007843887f, 0.008353627f, 0.008896492f, 0.009474637f, 0.010090352f, 0.01074608f, 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, 0.014722068f, 0.015678791f, 0.016697686f, 0.017782796f, 0.018938422f, 0.020169148f, 0.021479854f, 0.022875736f, 0.02436233f, 0.025945531f, 0.027631618f, 0.029427277f, 0.031339627f, 0.03337625f, 0.035545226f, 0.037855156f, 0.0403152f, 0.042935107f, 0.045725275f, 0.048696756f, 0.05186135f, 0.05523159f, 0.05882085f, 0.062643364f, 0.06671428f, 0.07104975f, 0.075666964f, 0.08058423f, 0.08582105f, 0.09139818f, 0.097337745f, 0.1036633f, 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, 0.14201812f, 0.15124726f, 0.16107617f, 0.1715438f, 0.18269168f, 0.19456401f, 0.20720787f, 0.22067343f, 0.23501402f, 0.25028655f, 0.26655158f, 0.28387362f, 0.3023213f, 0.32196787f, 0.34289113f, 0.36517414f, 0.3889052f, 0.41417846f, 0.44109413f, 0.4697589f, 0.50028646f, 0.53279793f, 0.5674221f, 0.6042964f, 0.64356697f, 0.6853896f, 0.72993004f, 0.777365f, 0.8278826f, 0.88168305f, 0.9389798f, 1f }; public void Init(IPacket packet, int channels, int block0Size, int block1Size, ICodebook[] codebooks) { int num = -1; _partitionClass = new int[(uint)packet.ReadBits(5)]; for (int i = 0; i < _partitionClass.Length; i++) { _partitionClass[i] = (int)packet.ReadBits(4); if (_partitionClass[i] > num) { num = _partitionClass[i]; } } _classDimensions = new int[++num]; _classSubclasses = new int[num]; _classMasterbooks = new ICodebook[num]; _classMasterBookIndex = new int[num]; _subclassBooks = new ICodebook[num][]; _subclassBookIndex = new int[num][]; for (int j = 0; j < num; j++) { _classDimensions[j] = (int)packet.ReadBits(3) + 1; _classSubclasses[j] = (int)packet.ReadBits(2); if (_classSubclasses[j] > 0) { _classMasterBookIndex[j] = (int)packet.ReadBits(8); _classMasterbooks[j] = codebooks[_classMasterBookIndex[j]]; } _subclassBooks[j] = new ICodebook[1 << _classSubclasses[j]]; _subclassBookIndex[j] = new int[_subclassBooks[j].Length]; for (int k = 0; k < _subclassBooks[j].Length; k++) { int num2 = (int)packet.ReadBits(8) - 1; if (num2 >= 0) { _subclassBooks[j][k] = codebooks[num2]; } _subclassBookIndex[j][k] = num2; } } _multiplier = (int)packet.ReadBits(2); _range = _rangeLookup[_multiplier]; _yBits = _yBitsLookup[_multiplier]; _multiplier++; int num3 = (int)packet.ReadBits(4); List<int> list = new List<int>(); list.Add(0); list.Add(1 << num3); for (int l = 0; l < _partitionClass.Length; l++) { int num4 = _partitionClass[l]; for (int m = 0; m < _classDimensions[num4]; m++) { list.Add((int)packet.ReadBits(num3)); } } _xList = list.ToArray(); _lNeigh = new int[list.Count]; _hNeigh = new int[list.Count]; _sortIdx = new int[list.Count]; _sortIdx[0] = 0; _sortIdx[1] = 1; for (int n = 2; n < _lNeigh.Length; n++) { _lNeigh[n] = 0; _hNeigh[n] = 1; _sortIdx[n] = n; for (int num5 = 2; num5 < n; num5++) { int num6 = _xList[num5]; if (num6 < _xList[n]) { if (num6 > _xList[_lNeigh[n]]) { _lNeigh[n] = num5; } } else if (num6 < _xList[_hNeigh[n]]) { _hNeigh[n] = num5; } } } for (int num7 = 0; num7 < _sortIdx.Length - 1; num7++) { for (int num8 = num7 + 1; num8 < _sortIdx.Length; num8++) { if (_xList[num7] == _xList[num8]) { throw new InvalidDataException(); } if (_xList[_sortIdx[num7]] > _xList[_sortIdx[num8]]) { int num9 = _sortIdx[num7]; _sortIdx[num7] = _sortIdx[num8]; _sortIdx[num8] = num9; } } } } public IFloorData Unpack(IPacket packet, int blockSize, int channel) { Data data = new Data(); if (packet.ReadBit()) { int num = 2; data.Posts[0] = (int)packet.ReadBits(_yBits); data.Posts[1] = (int)packet.ReadBits(_yBits); for (int i = 0; i < _partitionClass.Length; i++) { int num2 = _partitionClass[i]; int num3 = _classDimensions[num2]; int num4 = _classSubclasses[num2]; int num5 = (1 << num4) - 1; uint num6 = 0u; if (num4 > 0 && (num6 = (uint)_classMasterbooks[num2].DecodeScalar(packet)) == uint.MaxValue) { num = 0; break; } for (int j = 0; j < num3; j++) { ICodebook codebook = _subclassBooks[num2][num6 & num5]; num6 >>= num4; if (codebook != null && (data.Posts[num] = codebook.DecodeScalar(packet)) == -1) { num = 0; i = _partitionClass.Length; break; } num++; } } data.PostCount = num; } return data; } public void Apply(IFloorData floorData, int blockSize, float[] residue) { if (!(floorData is Data data)) { throw new ArgumentException("Incorrect packet data!", "packetData"); } int num = blockSize / 2; if (data.PostCount > 0) { bool[] array = UnwrapPosts(data); int num2 = 0; int num3 = data.Posts[0] * _multiplier; for (int i = 1; i < data.PostCount; i++) { int num4 = _sortIdx[i]; if (array[num4]) { int num5 = _xList[num4]; int num6 = data.Posts[num4] * _multiplier; if (num2 < num) { RenderLineMulti(num2, num3, Math.Min(num5, num), num6, residue); } num2 = num5; num3 = num6; } if (num2 >= num) { break; } } if (num2 < num) { RenderLineMulti(num2, num3, num, num3, residue); } } else { Array.Clear(residue, 0, num); } } private bool[] UnwrapPosts(Data data) { bool[] array = new bool[64]; array[0] = true; array[1] = true; int[] array2 = new int[64]; array2[0] = data.Posts[0]; array2[1] = data.Posts[1]; for (int i = 2; i < data.PostCount; i++) { int num = _lNeigh[i]; int num2 = _hNeigh[i]; int num3 = RenderPoint(_xList[num], array2[num], _xList[num2], array2[num2], _xList[i]); int num4 = data.Posts[i]; int num5 = _range - num3; int num6 = num3; int num7 = ((num5 >= num6) ? (num6 * 2) : (num5 * 2)); if (num4 != 0) { array[num] = true; array[num2] = true; array[i] = true; if (num4 >= num7) { if (num5 > num6) { array2[i] = num4 - num6 + num3; } else { array2[i] = num3 - num4 + num5 - 1; } } else if (num4 % 2 == 1) { array2[i] = num3 - (num4 + 1) / 2; } else { array2[i] = num3 + num4 / 2; } } else { array[i] = false; array2[i] = num3; } } for (int j = 0; j < data.PostCount; j++) { data.Posts[j] = array2[j]; } return array; } private int RenderPoint(int x0, int y0, int x1, int y1, int X) { int num = y1 - y0; int num2 = x1 - x0; int num3 = Math.Abs(num) * (X - x0) / num2; if (num < 0) { return y0 - num3; } return y0 + num3; } private void RenderLineMulti(int x0, int y0, int x1, int y1, float[] v) { int num = y1 - y0; int num2 = x1 - x0; int num3 = Math.Abs(num); int num4 = 1 - ((num >> 31) & 1) * 2; int num5 = num / num2; int num6 = x0; int num7 = y0; int num8 = -num2; v[x0] *= inverse_dB_table[y0]; num3 -= Math.Abs(num5) * num2; while (++num6 < x1) { num7 += num5; num8 += num3; if (num8 >= 0) { num8 -= num2; num7 += num4; } v[num6] *= inverse_dB_table[num7]; } } } internal class Huffman : IHuffman, IComparer<HuffmanListNode> { private const int MAX_TABLE_BITS = 10; public int TableBits { get; private set; } public IReadOnlyList<HuffmanListNode> PrefixTree { get; private set; } public IReadOnlyList<HuffmanListNode> OverflowList { get; private set; } public void GenerateTable(IReadOnlyList<int> values, int[] lengthList, int[] codeList) { HuffmanListNode[] array = new HuffmanListNode[lengthList.Length]; int num = 0; for (int i = 0; i < array.Length; i++) { array[i] = new HuffmanListNode { Value = values[i], Length = ((lengthList[i] <= 0) ? 99999 : lengthList[i]), Bits = codeList[i], Mask = (1 << lengthList[i]) - 1 }; if (lengthList[i] > 0 && num < lengthList[i]) { num = lengthList[i]; } } Array.Sort(array, 0, array.Length, this); int num2 = ((num > 10) ? 10 : num); List<HuffmanListNode> list = new List<HuffmanListNode>(1 << num2); List<HuffmanListNode> list2 = null; for (int j = 0; j < array.Length && array[j].Length < 99999; j++) { int length = array[j].Length; if (length > num2) { list2 = new List<HuffmanListNode>(array.Length - j); for (; j < array.Length && array[j].Length < 99999; j++) { list2.Add(array[j]); } continue; } int num3 = 1 << num2 - length; HuffmanListNode huffmanListNode = array[j]; for (int k = 0; k < num3; k++) { int num4 = (k << length) | huffmanListNode.Bits; while (list.Count <= num4) { list.Add(null); } list[num4] = huffmanListNode; } } while (list.Count < 1 << num2) { list.Add(null); } TableBits = num2; PrefixTree = list; OverflowList = list2; } int IComparer<HuffmanListNode>.Compare(HuffmanListNode x, HuffmanListNode y) { int num = x.Length - y.Length; if (num == 0) { return x.Bits - y.Bits; } return num; } } [Obsolete("Moved to NVorbis.Contracts.IContainerReader", true)] public interface IContainerReader : NVorbis.Contracts.IContainerReader, IDisposable { [Obsolete("Use Streams.Select(s => s.StreamSerial).ToArray() instead.", true)] int[] StreamSerials { get; } [Obsolete("No longer supported.", true)] int PagesRead { get; } [Obsolete("Moved to NewStreamCallback.", true)] event EventHandler<NewStreamEventArgs> NewStream; [Obsolete("Renamed to TryInit().", true)] bool Init(); [Obsolete("No longer supported.", true)] int GetTotalPageCount(); } [Obsolete("Moved to NVorbis.Contracts.IPacketProvider", true)] public interface IPacketProvider : NVorbis.Contracts.IPacketProvider { [Obsolete("Moved to per-stream IStreamStats instance on IStreamDecoder.Stats or VorbisReader.Stats.", true)] long ContainerBits { get; } [Obsolete("No longer supported.", true)] event EventHandler ParameterChange; [Obsolete("No longer supported.", true)] int GetTotalPageCount(); [Obsolete("Getting a packet by index is no longer supported.", true)] DataPacket GetPacket(int packetIndex); [Obsolete("Moved to long SeekTo(long, int, GetPacketGranuleCount)", true)] DataPacket FindPacket(long granulePos, Func<DataPacket, DataPacket, int> packetGranuleCountCallback); [Obsolete("Seeking to a specified packet is no longer supported. See SeekTo(...) instead.", true)] void SeekToPacket(DataPacket packet, int preRoll); } [Obsolete("Moved to NVorbis.Contracts.IStreamStats", true)] public interface IVorbisStreamStatus : IStreamStats { [Obsolete("No longer supported.", true)] TimeSpan PageLatency { get; } [Obsolete("No longer supported.", true)] TimeSpan PacketLatency { get; } [Obsolete("No longer supported.", true)] TimeSpan SecondLatency { get; } [Obsolete("No longer supported.", true)] int PagesRead { get; } [Obsolete("No longer supported.", true)] int TotalPages { get; } [Obsolete("Use IStreamDecoder.HasClipped instead. VorbisReader.HasClipped will return the same value for the stream it is handling.", true)] bool Clipped { get; } } internal class Mapping : IMapping { private IMdct _mdct; private int[] _couplingAngle; private int[] _couplingMangitude; private IFloor[] _submapFloor; private IResidue[] _submapResidue; private IFloor[] _channelFloor; private IResidue[] _channelResidue; public void Init(IPacket packet, int channels, IFloor[] floors, IResidue[] residues, IMdct mdct) { int num = 1; if (packet.ReadBit()) { num += (int)packet.ReadBits(4); } int num2 = 0; if (packet.ReadBit()) { num2 = (int)packet.ReadBits(8) + 1; } int count = Utils.ilog(channels - 1); _couplingAngle = new int[num2]; _couplingMangitude = new int[num2]; for (int i = 0; i < num2; i++) { int num3 = (int)packet.ReadBits(count); int num4 = (int)packet.ReadBits(count); if (num3 == num4 || num3 > channels - 1 || num4 > channels - 1) { throw new InvalidDataException("Invalid magnitude or angle in mapping header!"); } _couplingAngle[i] = num4; _couplingMangitude[i] = num3; } if (packet.ReadBits(2) != 0L) { throw new InvalidDataException("Reserved bits not 0 in mapping header."); } int[] array = new int[channels]; if (num > 1) { for (int j = 0; j < channels; j++) { array[j] = (int)packet.ReadBits(4); if (array[j] > num) { throw new InvalidDataException("Invalid channel mux submap index in mapping header!"); } } } _submapFloor = new IFloor[num]; _submapResidue = new IResidue[num]; for (int k = 0; k < num; k++) { packet.SkipBits(8); int num5 = (int)packet.ReadBits(8); if (num5 >= floors.Length) { throw new InvalidDataException("Invalid floor number in mapping header!"); } int num6 = (int)packet.ReadBits(8); if (num6 >= residues.Length) { throw new InvalidDataException("Invalid residue number in mapping header!"); } _submapFloor[k] = floors[num5]; _submapResidue[k] = residues[num6]; } _channelFloor = new IFloor[channels]; _channelResidue = new IResidue[channels]; for (int l = 0; l < channels; l++) { _channelFloor[l] = _submapFloor[array[l]]; _channelResidue[l] = _submapResidue[array[l]]; } _mdct = mdct; } public void DecodePacket(IPacket packet, int blockSize, int channels, float[][] buffer) { int num = blockSize >> 1; IFloorData[] array = new IFloorData[_channelFloor.Length]; bool[] array2 = new bool[_channelFloor.Length]; for (int i = 0; i < _channelFloor.Length; i++) { array[i] = _channelFloor[i].Unpack(packet, blockSize, i); array2[i] = !array[i].ExecuteChannel; Array.Clear(buffer[i], 0, num); } for (int j = 0; j < _couplingAngle.Length; j++) { if (array[_couplingAngle[j]].ExecuteChannel || array[_couplingMangitude[j]].ExecuteChannel) { array[_couplingAngle[j]].ForceEnergy = true; array[_couplingMangitude[j]].ForceEnergy = true; } } for (int k = 0; k < _submapFloor.Length; k++) { for (int l = 0; l < _channelFloor.Length; l++) { if (_submapFloor[k] != _channelFloor[l] || _submapResidue[k] != _channelResidue[l]) { array[l].ForceNoEnergy = true; } } _submapResidue[k].Decode(packet, array2, blockSize, buffer); } for (int num2 = _couplingAngle.Length - 1; num2 >= 0; num2--) { if (array[_couplingAngle[num2]].ExecuteChannel || array[_couplingMangitude[num2]].ExecuteChannel) { float[] array3 = buffer[_couplingMangitude[num2]]; float[] array4 = buffer[_couplingAngle[num2]]; for (int m = 0; m < num; m++) { float num3 = array3[m]; float num4 = array4[m]; float num5; float num6; if (num3 > 0f) { if (num4 > 0f) { num5 = num3; num6 = num3 - num4; } else { num6 = num3; num5 = num3 + num4; } } else if (num4 > 0f) { num5 = num3; num6 = num3 + num4; } else { num6 = num3; num5 = num3 - num4; } array3[m] = num5; array4[m] = num6; } } } for (int n = 0; n < _channelFloor.Length; n++) { if (array[n].ExecuteChannel) { _channelFloor[n].Apply(array[n], blockSize, buffer[n]); _mdct.Reverse(buffer[n], blockSize); } else { Array.Clear(buffer[n], num, num); } } } } internal class Mdct : IMdct { private class MdctImpl { private readonly int _n; private readonly int _n2; private readonly int _n4; private readonly int _n8; private readonly int _ld; private readonly float[] _a; private readonly float[] _b; private readonly float[] _c; private readonly ushort[] _bitrev; public MdctImpl(int n) { _n = n; _n2 = n >> 1; _n4 = _n2 >> 1; _n8 = _n4 >> 1; _ld = Utils.ilog(n) - 1; _a = new float[_n2]; _b = new float[_n2]; _c = new float[_n4]; int num; int num2 = (num = 0); while (num2 < _n4) { _a[num] = (float)Math.Cos((float)(4 * num2) * MathF.PI / (float)n); _a[num + 1] = (float)(0.0 - Math.Sin((float)(4 * num2) * MathF.PI / (float)n)); _b[num] = (float)Math.Cos((float)(num + 1) * MathF.PI / (float)n / 2f) * 0.5f; _b[num + 1] = (float)Math.Sin((float)(num + 1) * MathF.PI / (float)n / 2f) * 0.5f; num2++; num += 2; } num2 = (num = 0); while (num2 < _n8) { _c[num] = (float)Math.Cos((float)(2 * (num + 1)) * MathF.PI / (float)n); _c[num + 1] = (float)(0.0 - Math.Sin((float)(2 * (num + 1)) * MathF.PI / (float)n)); num2++; num += 2; } _bitrev = new ushort[_n8]; for (int i = 0; i < _n8; i++) { _bitrev[i] = (ushort)(Utils.BitReverse((uint)i, _ld - 3) << 2); } } internal void CalcReverse(float[] buffer) { float[] array = new float[_n2]; int num = _n2 - 2; int num2 = 0; int i = 0; for (int n = _n2; i != n; i += 4) { array[num + 1] = buffer[i] * _a[num2] - buffer[i + 2] * _a[num2 + 1]; array[num] = buffer[i] * _a[num2 + 1] + buffer[i + 2] * _a[num2]; num -= 2; num2 += 2; } i = _n2 - 3; while (num >= 0) { array[num + 1] = (0f - buffer[i + 2]) * _a[num2] - (0f - buffer[i]) * _a[num2 + 1]; array[num] = (0f - buffer[i + 2]) * _a[num2 + 1] + (0f - buffer[i]) * _a[num2]; num -= 2; num2 += 2; i -= 4; } float[] array2 = array; int num3 = _n2 - 8; int num4 = _n4; int num5 = 0; int num6 = _n4; int num7 = 0; while (num3 >= 0) { float num8 = array2[num4 + 1] - array2[num5 + 1]; float num9 = array2[num4] - array2[num5]; buffer[num6 + 1] = array2[num4 + 1] + array2[num5 + 1]; buffer[num6] = array2[num4] + array2[num5]; buffer[num7 + 1] = num8 * _a[num3 + 4] - num9 * _a[num3 + 5]; buffer[num7] = num9 * _a[num3 + 4] + num8 * _a[num3 + 5]; num8 = array2[num4 + 3] - array2[num5 + 3]; num9 = array2[num4 + 2] - array2[num5 + 2]; buffer[num6 + 3] = array2[num4 + 3] + array2[num5 + 3]; buffer[num6 + 2] = array2[num4 + 2] + array2[num5 + 2]; buffer[num7 + 3] = num8 * _a[num3] - num9 * _a[num3 + 1]; buffer[num7 + 2] = num9 * _a[num3] + num8 * _a[num3 + 1]; num3 -= 8; num6 += 4; num7 += 4; num4 += 4; num5 += 4; } int n2 = _n >> 4; int num10 = _n2 - 1; _ = _n4; step3_iter0_loop(n2, buffer, num10 - 0, -_n8); step3_iter0_loop(_n >> 4, buffer, _n2 - 1 - _n4, -_n8); int lim = _n >> 5; int num11 = _n2 - 1; _ = _n8; step3_inner_r_loop(lim, buffer, num11 - 0, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 2, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 3, -(_n >> 4), 16); int j; for (j = 2; j < _ld - 3 >> 1; j++) { int num12 = _n >> j + 2; int num13 = num12 >> 1; int num14 = 1 << j + 1; for (int k = 0; k < num14; k++) { step3_inner_r_loop(_n >> j + 4, buffer, _n2 - 1 - num12 * k, -num13, 1 << j + 3); } } for (; j < _ld - 6; j++) { int num15 = _n >> j + 2; int num16 = 1 << j + 3; int num17 = num15 >> 1; int num18 = _n >> j + 6; int n3 = 1 << j + 1; int num19 = _n2 - 1; int num20 = 0; for (int num21 = num18; num21 > 0; num21--) { step3_inner_s_loop(n3, buffer, num19, -num17, num20, num16, num15); num20 += num16 * 4; num19 -= 8; } } step3_inner_s_loop_ld654(_n >> 5, buffer, _n2 - 1, _n); int num22 = 0; int num23 = _n4 - 4; int num24 = _n2 - 4; while (num23 >= 0) { int num25 = _bitrev[num22]; array2[num24 + 3] = buffer[num25]; array2[num24 + 2] = buffer[num25 + 1]; array2[num23 + 3] = buffer[num25 + 2]; array2[num23 + 2] = buffer[num25 + 3]; num25 = _bitrev[num22 + 1]; array2[num24 + 1] = buffer[num25]; array2[num24] = buffer[num25 + 1]; array2[num23 + 1] = buffer[num25 + 2]; array2[num23] = buffer[num25 + 3]; num23 -= 4; num24 -= 4; num22 += 2; } int num26 = 0; int num27 = 0; int num28 = _n2 - 4; while (num27 < num28) { float num29 = array2[num27] - array2[num28 + 2]; float num30 = array2[num27 + 1] + array2[num28 + 3]; float num31 = _c[num26 + 1] * num29 + _c[num26] * num30; float num32 = _c[num26 + 1] * num30 - _c[num26] * num29; float num33 = array2[num27] + array2[num28 + 2]; float num34 = array2[num27 + 1] - array2[num28 + 3]; array2[num27] = num33 + num31; array2[num27 + 1] = num34 + num32; array2[num28 + 2] = num33 - num31; array2[num28 + 3] = num32 - num34; num29 = array2[num27 + 2] - array2[num28]; num30 = array2[num27 + 3] + array2[num28 + 1]; num31 = _c[num26 + 3] * num29 + _c[num26 + 2] * num30; num32 = _c[num26 + 3] * num30 - _c[num26 + 2] * num29; num33 = array2[num27 + 2] + array2[num28]; num34 = array2[num27 + 3] - array2[num28 + 1]; array2[num27 + 2] = num33 + num31; array2[num27 + 3] = num34 + num32; array2[num28] = num33 - num31; array2[num28 + 1] = num32 - num34; num26 += 4; num27 += 4; num28 -= 4; } int num35 = _n2 - 8; int num36 = _n2 - 8; int num37 = 0; int num38 = _n2 - 4; int num39 = _n2; int num40 = _n - 4; while (num36 >= 0) { float num41 = array[num36 + 6] * _b[num35 + 7] - array[num36 + 7] * _b[num35 + 6]; float num42 = (0f - array[num36 + 6]) * _b[num35 + 6] - array[num36 + 7] * _b[num35 + 7]; buffer[num37] = num41; buffer[num38 + 3] = 0f - num41; buffer[num39] = num42; buffer[num40 + 3] = num42; float num43 = array[num36 + 4] * _b[num35 + 5] - array[num36 + 5] * _b[num35 + 4]; float num44 = (0f - array[num36 + 4]) * _b[num35 + 4] - array[num36 + 5] * _b[num35 + 5]; buffer[num37 + 1] = num43; buffer[num38 + 2] = 0f - num43; buffer[num39 + 1] = num44; buffer[num40 + 2] = num44; num41 = array[num36 + 2] * _b[num35 + 3] - array[num36 + 3] * _b[num35 + 2]; num42 = (0f - array[num36 + 2]) * _b[num35 + 2] - array[num36 + 3] * _b[num35 + 3]; buffer[num37 + 2] = num41; buffer[num38 + 1] = 0f - num41; buffer[num39 + 2] = num42; buffer[num40 + 1] = num42; num43 = array[num36] * _b[num35 + 1] - array[num36 + 1] * _b[num35]; num44 = (0f - array[num36]) * _b[num35] - array[num36 + 1] * _b[num35 + 1]; buffer[num37 + 3] = num43; buffer[num38] = 0f - num43; buffer[num39 + 3] = num44; buffer[num40] = num44; num35 -= 8; num36 -= 8; num37 += 4; num39 += 4; num38 -= 4; num40 -= 4; } } private void step3_iter0_loop(int n, float[] e, int i_off, int k_off) { int num = i_off; int num2 = num + k_off; int num3 = 0; for (int num4 = n >> 2; num4 > 0; num4--) { float num5 = e[num] - e[num2]; float num6 = e[num - 1] - e[num2 - 1]; e[num] += e[num2]; e[num - 1] += e[num2 - 1]; e[num2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 1] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num5 = e[num - 2] - e[num2 - 2]; num6 = e[num - 3] - e[num2 - 3]; e[num - 2] += e[num2 - 2]; e[num - 3] += e[num2 - 3]; e[num2 - 2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 3] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num5 = e[num - 4] - e[num2 - 4]; num6 = e[num - 5] - e[num2 - 5]; e[num - 4] += e[num2 - 4]; e[num - 5] += e[num2 - 5]; e[num2 - 4] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 5] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num5 = e[num - 6] - e[num2 - 6]; num6 = e[num - 7] - e[num2 - 7]; e[num - 6] += e[num2 - 6]; e[num - 7] += e[num2 - 7]; e[num2 - 6] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 7] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num -= 8; num2 -= 8; } } private void step3_inner_r_loop(int lim, float[] e, int d0, int k_off, int k1) { int num = d0; int num2 = num + k_off; int num3 = 0; for (int num4 = lim >> 2; num4 > 0; num4--) { float num5 = e[num] - e[num2]; float num6 = e[num - 1] - e[num2 - 1]; e[num] += e[num2]; e[num - 1] += e[num2 - 1]; e[num2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 1] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num5 = e[num - 2] - e[num2 - 2]; num6 = e[num - 3] - e[num2 - 3]; e[num - 2] += e[num2 - 2]; e[num - 3] += e[num2 - 3]; e[num2 - 2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 3] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num5 = e[num - 4] - e[num2 - 4]; num6 = e[num - 5] - e[num2 - 5]; e[num - 4] += e[num2 - 4]; e[num - 5] += e[num2 - 5]; e[num2 - 4] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 5] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num5 = e[num - 6] - e[num2 - 6]; num6 = e[num - 7] - e[num2 - 7]; e[num - 6] += e[num2 - 6]; e[num - 7] += e[num2 - 7]; e[num2 - 6] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 7] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num -= 8; num2 -= 8; } } private void step3_inner_s_loop(int n, float[] e, int i_off, int k_off, int a, int a_off, int k0) { float num = _a[a]; float num2 = _a[a + 1]; float num3 = _a[a + a_off]; float num4 = _a[a + a_off + 1]; float num5 = _a[a + a_off * 2]; float num6 = _a[a + a_off * 2 + 1]; float num7 = _a[a + a_off * 3]; float num8 = _a[a + a_off * 3 + 1]; int num9 = i_off; int num10 = num9 + k_off; for (int num11 = n; num11 > 0; num11--) { float num12 = e[num9] - e[num10]; float num13 = e[num9 - 1] - e[num10 - 1]; e[num9] += e[num10]; e[num9 - 1] += e[num10 - 1]; e[num10] = num12 * num - num13 * num2; e[num10 - 1] = num13 * num + num12 * num2; num12 = e[num9 - 2] - e[num10 - 2]; num13 = e[num9 - 3] - e[num10 - 3]; e[num9 - 2] += e[num10 - 2]; e[num9 - 3] += e[num10 - 3]; e[num10 - 2] = num12 * num3 - num13 * num4; e[num10 - 3] = num13 * num3 + num12 * num4; num12 = e[num9 - 4] - e[num10 - 4]; num13 = e[num9 - 5] - e[num10 - 5]; e[num9 - 4] += e[num10 - 4]; e[num9 - 5] += e[num10 - 5]; e[num10 - 4] = num12 * num5 - num13 * num6; e[num10 - 5] = num13 * num5 + num12 * num6; num12 = e[num9 - 6] - e[num10 - 6]; num13 = e[num9 - 7] - e[num10 - 7]; e[num9 - 6] += e[num10 - 6]; e[num9 - 7] += e[num10 - 7]; e[num10 - 6] = num12 * num7 - num13 * num8; e[num10 - 7] = num13 * num7 + num12 * num8; num9 -= k0; num10 -= k0; } } private void step3_inner_s_loop_ld654(int n, float[] e, int i_off, int base_n) { int num = base_n >> 3; float num2 = _a[num]; int num3 = i_off; int num4 = num3 - 16 * n; while (num3 > num4) { float num5 = e[num3] - e[num3 - 8]; float num6 = e[num3 - 1] - e[num3 - 9]; e[num3] += e[num3 - 8]; e[num3 - 1] += e[num3 - 9]; e[num3 - 8] = num5; e[num3 - 9] = num6; num5 = e[num3 - 2] - e[num3 - 10]; num6 = e[num3 - 3] - e[num3 - 11]; e[num3 - 2] += e[num3 - 10]; e[num3 - 3] += e[num3 - 11]; e[num3 - 10] = (num5 + num6) * num2; e[num3 - 11] = (num6 - num5) * num2; num5 = e[num3 - 12] - e[num3 - 4]; num6 = e[num3 - 5] - e[num3 - 13]; e[num3 - 4] += e[num3 - 12]; e[num3 - 5] += e[num3 - 13]; e[num3 - 12] = num6; e[num3 - 13] = num5; num5 = e[num3 - 14] - e[num3 - 6]; num6 = e[num3 - 7] - e[num3 - 15]; e[num3 - 6] += e[num3 - 14]; e[num3 - 7] += e[num3 - 15]; e[num3 - 14] = (num5 + num6) * num2; e[num3 - 15] = (num5 - num6) * num2; iter_54(e, num3); iter_54(e, num3 - 8); num3 -= 16; } } private void iter_54(float[] e, int z) { float num = e[z] - e[z - 4]; float num2 = e[z] + e[z - 4]; float num3 = e[z - 2] + e[z - 6]; float num4 = e[z - 2] - e[z - 6]; e[z] = num2 + num3; e[z - 2] = num2 - num3; float num5 = e[z - 3] - e[z - 7]; e[z - 4] = num + num5; e[z - 6] = num - num5; float num6 = e[z - 1] - e[z - 5]; float num7 = e[z - 1] + e[z - 5]; float num8 = e[z - 3] + e[z - 7]; e[z - 1] = num7 + num8; e[z - 3] = num7 - num8; e[z - 5] = num6 - num4; e[z - 7] = num6 + num4; } } private const float M_PI = MathF.PI; private Dictionary<int, MdctImpl> _setupCache = new Dictionary<int, MdctImpl>(); public void Reverse(float[] samples, int sampleCount) { if (!_setupCache.TryGetValue(sampleCount, out var value)) { value = new MdctImpl(sampleCount); _setupCache[sampleCount] = value; } value.CalcReverse(samples); } } internal class Mode : IMode { private struct OverlapInfo { public int PacketStartIndex; public int PacketTotalLength; public int PacketValidLength; } private const float M_PI2 = MathF.PI / 2f; private int _channels; private bool _blockFlag; private int _blockSize; private IMapping _mapping; private float[][] _windows; private OverlapInfo[] _overlapInfo; public void Init(IPacket packet, int channels, int block0Size, int block1Size, IMapping[] mappings) { _channels = channels; _blockFlag = packet.ReadBit(); if (packet.ReadBits(32) != 0L) { throw new InvalidDataException("Mode header had invalid window or transform type!"); } int num = (int)packet.ReadBits(8); if (num >= mappings.Length) { throw new InvalidDataException("Mode header had invalid mapping index!"); } _mapping = mappings[num]; if (_blockFlag) { _blockSize = block1Size; _windows = new float[4][] { CalcWindow(block0Size, block1Size, block0Size), CalcWindow(block1Size, block1Size, block0Size), CalcWindow(block0Size, block1Size, block1Size), CalcWindow(block1Size, block1Size, block1Size) }; _overlapInfo = new OverlapInfo[4] { CalcOverlap(block0Size, block1Size, block0Size), CalcOverlap(block1Size, block1Size, block0Size), CalcOverlap(block0Size, block1Size, block1Size), CalcOverlap(block1Size, block1Size, block1Size) }; } else { _blockSize = block0Size; _windows = new float[1][] { CalcWindow(block0Size, block0Size, block0Size) }; } } private static float[] CalcWindow(int prevBlockSize, int blockSize, int nextBlockSize) { float[] array = new float[blockSize]; int num = prevBlockSize / 2; int num2 = nextBlockSize / 2; int num3 = blockSize / 4 - num / 2; int num4 = blockSize - blockSize / 4 - num2 / 2; for (int i = 0; i < num; i++) { float num5 = (float)Math.Sin(((double)i + 0.5) / (double)num * 1.5707963705062866); num5 *= num5; array[num3 + i] = (float)Math.Sin(num5 * (MathF.PI / 2f)); } for (int j = num3 + num; j < num4; j++) { array[j] = 1f; } for (int k = 0; k < num2; k++) { float num6 = (float)Math.Sin(((double)(num2 - k) - 0.5) / (double)num2 * 1.5707963705062866); num6 *= num6; array[num4 + k] = (float)Math.Sin(num6 * (MathF.PI / 2f)); } return array; } private static OverlapInfo CalcOverlap(int prevBlockSize, int blockSize, int nextBlockSize) { int num = prevBlockSize / 4; int num2 = nextBlockSize / 4; int packetStartIndex = blockSize / 4 - num; int num3 = blockSize / 4 * 3 + num2; int packetValidLength = num3 - num2 * 2; OverlapInfo result = default(OverlapInfo); result.PacketStartIndex = packetStartIndex; result.PacketValidLength = packetValidLength; result.PacketTotalLength = num3; return result; } private bool GetPacketInfo(IPacket packet, out int windowIndex, out int packetStartIndex, out int packetValidLength, out int packetTotalLength) { if (packet.IsShort) { windowIndex = 0; packetStartIndex = 0; packetValidLength = 0; packetTotalLength = 0; return false; } if (_blockFlag) { bool flag = packet.ReadBit(); bool flag2 = packet.ReadBit(); windowIndex = (flag ? 1 : 0) + (flag2 ? 2 : 0); OverlapInfo overlapInfo = _overlapInfo[windowIndex]; packetStartIndex = overlapInfo.PacketStartIndex; packetValidLength = overlapInfo.PacketValidLength; packetTotalLength = overlapInfo.PacketTotalLength; } else { windowIndex = 0; packetStartIndex = 0; packetValidLength = _blockSize / 2; packetTotalLength = _blockSize; } return true; } public bool Decode(IPacket packet, float[][] buffer, out int packetStartindex, out int packetValidLength, out int packetTotalLength) { if (GetPacketInfo(packet, out var windowIndex, out packetStartindex, out packetValidLength, out packetTotalLength)) { _mapping.DecodePacket(packet, _blockSize, _channels, buffer); float[] array = _windows[windowIndex]; for (int i = 0; i < _blockSize; i++) { for (int j = 0; j < _channels; j++) { buffer[j][i] *= array[i]; } } return true; } return false; } public int GetPacketSampleCount(IPacket packet) { GetPacketInfo(packet, out var _, out var packetStartIndex, out var packetValidLength, out var _); return packetValidLength - packetStartIndex; } } [Serializable] public class NewStreamEventArgs : EventArgs { public IStreamDecoder StreamDecoder { get; } public bool IgnoreStream { get; set; } public NewStreamEventArgs(IStreamDecoder streamDecoder) { StreamDecoder = streamDecoder ?? throw new ArgumentNullException("streamDecoder"); } } internal class Residue0 : IResidue { private int _channels; private int _begin; private int _end; private int _partitionSize; private int _classifications; private int _maxStages; private ICodebook[][] _books; private ICodebook _classBook; private int[] _cascade; private int[][] _decodeMap; private static int icount(int v) { int num = 0; while (v != 0) { num += v & 1; v >>= 1; } return num; } public virtual void Init(IPacket packet, int channels, ICodebook[] codebooks) { _begin = (int)packet.ReadBits(24); _end = (int)packet.ReadBits(24); _partitionSize = (int)packet.ReadBits(24) + 1; _classifications = (int)packet.ReadBits(6) + 1; _classBook = codebooks[(uint)packet.ReadBits(8)]; _cascade = new int[_classifications]; int num = 0; for (int i = 0; i < _classifications; i++) { int num2 = (int)packet.ReadBits(3); if (packet.ReadBit()) { _cascade[i] = ((int)packet.ReadBits(5) << 3) | num2; } else { _cascade[i] = num2; } num += icount(_cascade[i]); } int[] array = new int[num]; for (int j = 0; j < num; j++) { array[j] = (int)packet.ReadBits(8); if (codebooks[array[j]].MapType == 0) { throw new InvalidDataException(); } } int entries = _classBook.Entries; int num3 = _classBook.Dimensions; int num4 = 1; while (num3 > 0) { num4 *= _classifications; if (num4 > entries) { throw new InvalidDataException(); } num3--; } _books = new ICodebook[_classifications][]; num = 0; int num5 = 0; for (int k = 0; k < _classifications; k++) { int num6 = Utils.ilog(_cascade[k]); _books[k] = new ICodebook[num6]; if (num6 <= 0) { continue; } num5 = Math.Max(num5, num6); for (int l = 0; l < num6; l++) { if ((_cascade[k] & (1 << l)) > 0) { _books[k][l] = codebooks[array[num++]]; } } } _maxStages = num5; _decodeMap = new int[num4][]; for (int m = 0; m < num4; m++) { int num7 = m; int num8 = num4 / _classifications; _decodeMap[m] = new int[_classBook.Dimensions]; for (int n = 0; n < _classBook.Dimensions; n++) { int num9 = num7 / num8; num7 -= num9 * num8; num8 /= _classifications; _decodeMap[m][n] = num9; } } _channels = channels; } public virtual void Decode(IPacket packet, bool[] doNotDecodeChannel, int blockSize, float[][] buffer) { int num = ((_end < blockSize / 2) ? _end : (blockSize / 2)) - _begin; if (num <= 0 || Array.IndexOf(doNotDecodeChannel, value: false) == -1) { return; } int num2 = num / _partitionSize; int num3 = (num2 + _classBook.Dimensions - 1) / _classBook.Dimensions; int[,][] array = new int[_channels, num3][]; for (int i = 0; i < _maxStages; i++) { int j = 0; int num4 = 0; while (j < num2) { if (i == 0) { for (int k = 0; k < _channels; k++) { int num5 = _classBook.DecodeScalar(packet); if (num5 >= 0 && num5 < _decodeMap.Length) { array[k, num4] = _decodeMap[num5]; continue; } j = num2; i = _maxStages; break; } } int num6 = 0; for (; j < num2; j++) { if (num6 >= _classBook.Dimensions) { break; } int offset = _begin + j * _partitionSize; for (int l = 0; l < _channels; l++) { int num7 = array[l, num4][num6]; if ((_cascade[num7] & (1 << i)) != 0) { ICodebook codebook = _books[num7][i]; if (codebook != null && WriteVectors(codebook, packet, buffer, l, offset, _partitionSize)) { j = num2; i = _maxStages; break; } } } num6++; } num4++; } } } protected virtual bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize) { float[] array = residue[channel]; int num = partitionSize / codebook.Dimensions; int[] array2 = new int[num]; for (int i = 0; i < num; i++) { if ((array2[i] = codebook.DecodeScalar(packet)) == -1) { return true; } } for (int j = 0; j < codebook.Dimensions; j++) { int num2 = 0; while (num2 < num) { array[offset] += codebook[array2[num2], j]; num2++; offset++; } } return false; } } internal class Residue1 : Residue0 { protected override bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize) { float[] array = residue[channel]; int num = 0; while (num < partitionSize) { int num2 = codebook.DecodeScalar(packet); if (num2 == -1) { return true; } for (int i = 0; i < codebook.Dimensions; i++) { array[offset + num] += codebook[num2, i]; num++; } } return false; } } internal class Residue2 : Residue0 { private int _channels; public override void Init(IPacket packet, int channels, ICodebook[] codebooks) { _channels = channels; base.Init(packet, 1, codebooks); } public override void Decode(IPacket packet, bool[] doNotDecodeChannel, int blockSize, float[][] buffer) { base.Decode(packet, doNotDecodeChannel, blockSize * _channels, buffer); } protected override bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize) { int num = 0; offset /= _channels; int num2 = 0; while (num2 < partitionSize) { int num3 = codebook.DecodeScalar(packet); if (num3 == -1) { return true; } int num4 = 0; while (num4 < codebook.Dimensions) { residue[num][offset] += codebook[num3, num4]; if (++num == _channels) { num = 0; offset++; } num4++; num2++; } } return false; } } public sealed class StreamDecoder : IStreamDecoder, IDisposable { private NVorbis.Contracts.IPacketProvider _packetProvider; private IFactory _factory; private StreamStats _stats; private byte _channels; private int _sampleRate; private int _block0Size; private int _block1Size; private IMode[] _modes; private int _modeFieldBits; private string _vendor; private string[] _comments; private ITagData _tags; private long _currentPosition; private bool _hasClipped; private bool _hasPosition; private bool _eosFound; private float[][] _nextPacketBuf; private float[][] _prevPacketBuf; private int _prevPacketStart; private int _prevPacketEnd; private int _prevPacketStop; private static readonly byte[] PacketSignatureStream = new byte[11] { 1, 118, 111, 114, 98, 105, 115, 0, 0, 0, 0 }; private static readonly byte[] PacketSignatureComments = new byte[7] { 3, 118, 111, 114, 98, 105, 115 }; private static readonly byte[] PacketSignatureBooks = new byte[7] { 5, 118, 111, 114, 98, 105, 115 }; internal static Func<IFactory> CreateFactory { get; set; } = () => new Factory(); public int Channels => _channels; public int SampleRate => _sampleRate; public int UpperBitrate { get; private set; } public int NominalBitrate { get; private set; } public int LowerBitrate { get; private set; } public ITagData Tags => _tags ?? (_tags = new TagData(_vendor, _comments)); public TimeSpan TotalTime => TimeSpan.FromSeconds((double)TotalSamples / (double)_sampleRate); public long TotalSamples => (_packetProvider ?? throw new ObjectDisposedException("StreamDecoder")).GetGranuleCount(); public TimeSpan TimePosition { get { return TimeSpan.FromSeconds((double)_currentPosition / (double)_sampleRate); } set { SeekTo(value); } } public long SamplePosition { get { return _currentPosition; } set { SeekTo(value); } } public bool ClipSamples { get; set; } public bool HasClipped => _hasClipped; public bool IsEndOfStream { get { if (_eosFound) { return _prevPacketBuf == null; } return false; } } public IStreamStats Stats => _stats; public StreamDecoder(NVorbis.Contracts.IPacketProvider packetProvider) : this(packetProvider, new Factory()) { } internal StreamDecoder(NVorbis.Contracts.IPacketProvider packetProvider, IFactory factory) { _packetProvider = packetProvider ?? throw new ArgumentNullException("packetProvider"); _factory = factory ?? throw new ArgumentNullException("factory"); _stats = new StreamStats(); _currentPosition = 0L; ClipSamples = true; IPacket packet = _packetProvider.PeekNextPacket(); if (!ProcessHeaderPackets(packet)) { _packetProvider = null; packet.Reset(); throw GetInvalidStreamException(packet); } } private static Exception GetInvalidStreamException(IPacket packet) { try { ulong num = packet.ReadBits(64); if (num == 7233173838382854223L) { return new ArgumentException("Found OPUS bitstream."); } if ((num & 0xFF) == 127) { return new ArgumentException("Found FLAC bitstream."); } switch (num) { case 2314885909937746003uL: return new ArgumentException("Found Speex bitstream."); case 28254585843050854uL: return new ArgumentException("Found Skeleton metadata bitstream."); default: if ((num & 0xFFFFFFFFFFFF00L) == 27428895509214208L) { return new ArgumentException("Found Theora bitsream."); } return new ArgumentException("Could not find Vorbis data to decode."); } } finally { packet.Reset(); } } private bool ProcessHeaderPackets(IPacket packet) { if (!ProcessHeaderPacket(packet, LoadStreamHeader, delegate { _packetProvider.GetNextPacket().Done(); })) { return false; } if (!ProcessHeaderPacket(_packetProvider.GetNextPacket(), LoadComments, delegate(IPacket pkt) { pkt.Done(); })) { return false; } if (!ProcessHeaderPacket(_packetProvider.GetNextPacket(), LoadBooks, delegate(IPacket pkt) { pkt.Done(); })) { return false; } _currentPosition = 0L; ResetDecoder(); return true; } private static bool ProcessHeaderPacket(IPacket packet, Func<IPacket, bool> processAction, Action<IPacket> doneAction) { if (packet != null) { try { return processAction(packet); } finally { doneAction(packet); } } return false; } private static bool ValidateHeader(IPacket packet, byte[] expected) { for (int i = 0; i < expected.Length; i++) { if (expected[i] != packet.ReadBits(8)) { return false; } } return true; } private static string ReadString(IPacket packet) { int num = (int)packet.ReadBits(32); if (num == 0) { return string.Empty; } byte[] array = new byte[num]; if (packet.Read(array, 0, num) < num) { throw new InvalidDataException("Could not read full string!"); } return Encoding.UTF8.GetString(array); } private bool LoadStreamHeader(IPacket packet) { if (!ValidateHeader(packet, PacketSignatureStream)) { return false; } _channels = (byte)packet.ReadBits(8); _sampleRate = (int)packet.ReadBits(32); UpperBitrate = (int)packet.ReadBits(32); NominalBitrate = (int)packet.ReadBits(32); LowerBitrate = (int)packet.ReadBits(32); _block0Size = 1 << (int)packet.ReadBits(4); _block1Size = 1 << (int)packet.ReadBits(4); if (NominalBitrate == 0 && UpperBitrate > 0 && LowerBitrate > 0) { NominalBitrate = (UpperBitrate + LowerBitrate) / 2; } _stats.SetSampleRate(_sampleRate); _stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits); return true; } private bool LoadComments(IPacket packet) { if (!ValidateHeader(packet, PacketSignatureComments)) { return false; } _vendor = ReadString(packet); _comments = new string[packet.ReadBits(32)]; for (int i = 0; i < _comments.Length; i++) { _comments[i] = ReadString(packet); } _stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits); return true; } private bool LoadBooks(IPacket packet) { if (!ValidateHeader(packet, PacketSignatureBooks)) { return false; } IMdct mdct = _factory.CreateMdct(); IHuffman huffman = _factory.CreateHuffman(); ICodebook[] array = new ICodebook[packet.ReadBits(8) + 1]; for (int i = 0; i < array.Length; i++) { array[i] = _factory.CreateCodebook(); array[i].Init(packet, huffman); } int num = (int)packet.ReadBits(6) + 1; packet.SkipBits(16 * num); IFloor[] array2 = new IFloor[packet.ReadBits(6) + 1]; for (int j = 0; j < array2.Length; j++) { array2[j] = _factory.CreateFloor(packet); array2[j].Init(packet, _channels, _block0Size, _block1Size, array); } IResidue[] array3 = new IResidue[packet.ReadBits(6) + 1]; for (int k = 0; k < array3.Length; k++) { array3[k] = _factory.CreateResidue(packet); array3[k].Init(packet, _channels, array); } IMapping[] array4 = new IMapping[packet.ReadBits(6) + 1]; for (int l = 0; l < array4.Length; l++) { array4[l] = _factory.CreateMapping(packet); array4[l].Init(packet, _channels, array2, array3, mdct); } _modes = new IMode[packet.ReadBits(6) + 1]; for (int m = 0; m < _modes.Length; m++) { _modes[m] = _factory.CreateMode(); _modes[m].Init(packet, _channels, _block0Size, _block1Size, array4); } if (!packet.ReadBit()) { throw new InvalidDataException("Book packet did not end on correct bit!"); } _modeFieldBits = Utils.ilog(_modes.Length - 1); _stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits); return true; } private void ResetDecoder() { _prevPacketBuf = null; _prevPacketStart = 0; _prevPacketEnd = 0; _prevPacketStop = 0; _nextPacketBuf = null; _eosFound = false; _hasClipped = false; _hasPosition = false; } public int Read(Span<float> buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count % _channels != 0) { throw new ArgumentOutOfRangeException("count", "Must be a multiple of Channels!"); } if (_packetProvider == null) { throw new ObjectDisposedException("StreamDecoder"); } if (count == 0) { return 0; } int num = offset; int num2 = offset + count; while (num < num2) { if (_prevPacketStart == _prevPacketEnd) { if (_eosFound) { _nextPacketBuf = null; _prevPacketBuf = null; break; } if (!ReadNextPacket((num - offset) / _channels, out var samplePosition)) { _prevPacketEnd = _prevPacketStop; } if (samplePosition.HasValue && !_hasPosition) { _hasPosition = true; _currentPosition = samplePosition.Value - (_prevPacketEnd - _prevPacketStart) - (num - offset) / _channels; } } int num3 = Math.Min((num2 - num) / _channels, _prevPacketEnd - _prevPacketStart); if (num3 > 0) { num = ((!ClipSamples) ? (num + CopyBuffer(buffer, num, num3)) : (num + ClippingCopyBuffer(buffer, num, num3))); } } count = num - offset; _currentPosition += count / _channels; return count; } private int ClippingCopyBuffer(Span<float> target, int targetIndex, int count) { int num = targetIndex; while (count > 0) { for (int i = 0; i < _channels; i++) { target[num++] = Utils.ClipValue(_prevPacketBuf[i][_prevPacketStart], ref _hasClipped); } _prevPacketStart++; count--; } return num - targetIndex; } private int CopyBuffer(Span<float> target, int targetIndex, int count) { int num = targetIndex; while (count > 0) { for (int i = 0; i < _channels; i++) { target[num++] = _prevPacketBuf[i][_prevPacketStart]; } _prevPacketStart++; count--; } return num - targetIndex; } private bool ReadNextPacket(int bufferedSamples, out long? samplePosition) { int packetStartindex; int packetValidLength; int packetTotalLength; bool isEndOfStream; int bitsRead; int bitsRemaining; int containerOverheadBits; float[][] array = DecodeNextPacket(out packetStartindex, out packetValidLength, out packetTotalLength, out isEndOfStream, out samplePosition, out bitsRead, out bitsRemaining, out containerOverheadBits); _eosFound |= isEndOfStream; if (array == null) { _stats.AddPacket(0, bitsRead, bitsRemaining, containerOverheadBits); return false; } if (samplePosition.HasValue && isEndOfStream) { long num = _currentPosition + bufferedSamples + packetValidLength - packetStartindex; int num2 = (int)(samplePosition.Value - num); if (num2 < 0) { packetValidLength += num2; } } if (_prevPacketEnd > 0) { OverlapBuffers(_prevPacketBuf, array, _prevPacketStart, _prevPacketStop, packetStartindex, _channels); _prevPacketStart = packetStartindex; } else if (_prevPacketBuf == null) { _prevPacketStart = packetValidLength; } _stats.AddPacket(packetValidLength - _prevPacketStart, bitsRead, bitsRemaining, containerOverheadBits); _nextPacketBuf = _prevPacketBuf; _prevPacketEnd = packetValidLength; _prevPacketStop = packetTotalLength; _prevPacketBuf = array; return true; } private float[][] DecodeNextPacket(out int packetStartindex, out int packetValidLength, out int packetTotalLength, out bool isEndOfStream, out long? samplePosition, out int bitsRead, out int bitsRemaining, out int containerOverheadBits) { IPacket packet = null; try { if ((packet = _packetProvider.GetNextPacket()) == null) { isEndOfStream = true; } else { isEndOfStream = packet.IsEndOfStream; if (packet.IsResync) { _hasPosition = false; } containerOverheadBits = packet.ContainerOverheadBits; if (packet.ReadBit()) { bitsRemaining = packet.BitsRemaining + 1; } else { IMode mode = _modes[(uint)packet.ReadBits(_modeFieldBits)]; if (_nextPacketBuf == null) { _nextPacketBuf = new float[_channels][]; for (int i = 0; i < _channels; i++) { _nextPacketBuf[i] = new float[_block1Size]; } } if (mode.Decode(packet, _nextPacketBuf, out packetStartindex, out packetValidLength, out packetTotalLength)) { samplePosition = packet.GranulePosition; bitsRead = packet.BitsRead; bitsRemaining = packet.BitsRemaining; return _nextPacketBuf; } bitsRemaining = packet.BitsRead + packet.BitsRemaining; } } packetStartindex = 0; packetValidLength = 0; packetTotalLength = 0; samplePosition = null; bitsRead = 0; bitsRemaining = 0; containerOverheadBits = 0; return null; } finally { packet?.Done(); } } private static void OverlapBuffers(float[][] previous, float[][] next, int prevStart, int prevLen, int nextStart, int channels) { while (prevStart < prevLen) { for (int i = 0; i < channels; i++) { next[i][nextStart] += previous[i][prevStart]; } prevStart++; nextStart++; } } public void SeekTo(TimeSpan timePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { SeekTo((long)((double)SampleRate * timePosition.TotalSeconds), seekOrigin); } public void SeekTo(long samplePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { if (_packetProvider == null) { throw new ObjectDisposedException("StreamDecoder"); } if (!_packetProvider.CanSeek) { throw new InvalidOperationException("Seek is not supported by the Contracts.IPacketProvider instance."); } switch (seekOrigin) { case SeekOrigin.Current: samplePosition = SamplePosition - samplePosition; break; case SeekOrigin.End: samplePosition = TotalSamples - samplePosition; break; default: throw new ArgumentOutOfRangeException("seekOrigin"); case SeekOrigin.Begin: break; } if (samplePosition < 0) { throw new ArgumentOutOfRangeException("samplePosition"); } int num; if (samplePosition == 0L) { _packetProvider.SeekTo(0L, 0, GetPacketGranules); num = 0; } else { long num2 = _packetProvider.SeekTo(samplePosition, 1, GetPacketGranules); num = (int)(samplePosition - num2); } ResetDecoder(); _hasPosition = true; if (!ReadNextPacket(0, out var samplePosition2)) { _eosFound = true; if (_packetProvider.GetGranuleCount() != samplePosition) { throw new InvalidOperationException("Could not read pre-roll packet! Try seeking again prior to reading more samples."); } _prevPacketStart = _prevPacketStop; _currentPosition = samplePosition; return; } if (!ReadNextPacket(0, out samplePosition2)) { ResetDecoder(); _eosFound = true; throw new InvalidOperationException("Could not read pre-roll packet! Try seeking again prior to reading more samples."); } _prevPacketStart += num; _currentPosition = samplePosition; } private int GetPacketGranules(IPacket curPacket) { if (curPacket.IsResync) { return 0; } if (curPacket.ReadBit()) { return 0; } int num = (int)curPacket.ReadBits(_modeFieldBits); if (num < 0 || num >= _modes.Length) { return 0; } return _modes[num].GetPacketSampleCount(curPacket); } public void Dispose() { (_packetProvider as IDisposable)?.Dispose(); _packetProvider = null; } } internal class StreamStats : IStreamStats { private int _sampleRate; private readonly int[] _packetBits = new int[2]; private readonly int[] _packetSamples = new int[2]; private int _packetIndex; private long _totalSamples; private long _audioBits; private long _headerBits; private long _containerBits; private long _wasteBits; private object _lock = new object(); private int _packetCount; public int EffectiveBitRate { get { long totalSamples; long num; lock (_lock) { totalSamples = _totalSamples; num = _audioBits + _headerBits + _containerBits + _wasteBits; } if (totalSamples > 0) { return (int)((double)num / (double)totalSamples * (double)_sampleRate); } return 0; } } public int InstantBitRate { get { int num; int num2; lock (_lock) { num = _packetBits[0] + _packetBits[1]; num2 = _packetSamples[0] + _packetSamples[1]; } if (num2 > 0) { return (int)((double)num / (double)num2 * (double)_sampleRate); } return 0; } } public long ContainerBits => _containerBits; public long OverheadBits => _headerBits; public long AudioBits => _audioBits; public long WasteBits => _wasteBits; public int PacketCount => _packetCount; public void ResetStats() { lock (_lock) { _packetBits[0] = (_packetBits[1] = 0); _packetSamples[0] = (_packetSamples[1] = 0); _packetIndex = 0; _packetCount = 0; _audioBits = 0L; _totalSamples = 0L; _headerBits = 0L; _containerBits = 0L; _wasteBits = 0L; } } internal void SetSampleRate(int sampleRate) { lock (_lock) { _sampleRate = sampleRate; ResetStats(); } } internal void AddPacket(int samples, int bits, int waste, int container) { lock (_lock) { if (samples >= 0) { _audioBits += bits; _wasteBits += waste; _containerBits += container; _totalSamples += samples; _packetBits[_packetIndex] = bits + waste; _packetSamples[_packetIndex] = samples; if (++_packetIndex == 2) { _packetIndex = 0; } } else { _headerBits += bits; _wasteBits += waste; _containerBits += container; } } } } internal class TagData : ITagData { private static IReadOnlyList<string> s_emptyList = new List<string>(); private Dictionary<string, IReadOnlyList<string>> _tags; public IReadOnlyDictionary<string, IReadOnlyList<string>> All => _tags; public string EncoderVendor { get; } public string Title => GetTagSingle("TITLE"); public string Version => GetTagSingle("VERSION"); public string Album => GetTagSingle("ALBUM"); public string TrackNumber => GetTagSingle("TRACKNUMBER"); public string Artist => GetTagSingle("ARTIST"); public IReadOnlyList<string> Performers => GetTagMulti("PERFORMER"); public string Copyright => GetTagSingle("COPYRIGHT"); public string License => GetTagSingle("LICENSE"); public string Organization => GetTagSingle("ORGANIZATION"); public string Description => GetTagSingle("DESCRIPTION"); public IReadOnlyList<string> Genres => GetTagMulti("GENRE"); public IReadOnlyList<string> Dates => GetTagMulti("DATE"); public IReadOnlyList<string> Locations => GetTagMulti("LOCATION"); public string Contact => GetTagSingle("CONTACT"); public string Isrc => GetTagSingle("ISRC"); public TagData(string vendor, string[] comments) { EncoderVendor = vendor; Dictionary<string, IReadOnlyList<string>> dictionary = new Dictionary<string, IReadOnlyList<string>>(); for (int i = 0; i < comments.Length; i++) { string[] array = comments[i].Split(new char[1] { '=' }); if (array.Length == 1) { array = new string[2] { array[0], string.Empty }; } int num = array[0].IndexOf('['); if (num > -1) { array[1] = array[0].Substring(num + 1, array[0].Length - num - 2).ToUpper(CultureInfo.CurrentCulture) + ": " + array[1]; array[0] = array[0].Substring(0, num); } if (dictionary.TryGetValue(array[0].ToUpperInvariant(), out var value)) { ((List<string>)value).Add(array[1]); continue; } dictionary.Add(array[0].ToUpperInvariant(), new List<string> { array[1] }); } _tags = dictionary; } public string GetTagSingle(string key, bool concatenate = false) { IReadOnlyList<string> tagMulti = GetTagMulti(key); if (tagMulti.Count > 0) { if (concatenate) { return string.Join(Environment.NewLine, tagMulti.ToArray()); } return tagMulti[tagMulti.Count - 1]; } return string.Empty; } public IReadOnlyList<string> GetTagMulti(string key) { if (_tags.TryGetValue(key.ToUpperInvariant(), out var value)) { return value; } return s_emptyList; } } internal static class Utils { internal static int ilog(int x) { int num = 0; while (x > 0) { num++; x >>= 1; } return num; } internal static uint BitReverse(uint n) { return BitReverse(n, 32); } internal static uint BitReverse(uint n, int bits) { n = ((n & 0xAAAAAAAAu) >> 1) | ((n & 0x55555555) << 1); n = ((n & 0xCCCCCCCCu) >> 2) | ((n & 0x33333333) << 2); n = ((n & 0xF0F0F0F0u) >> 4) | ((n & 0xF0F0F0F) << 4); n = ((n & 0xFF00FF00u) >> 8) | ((n & 0xFF00FF) << 8); return ((n >> 16) | (n << 16)) >> 32 - bits; } internal static float ClipValue(float value, ref bool clipped) { if (value > MathF.PI * 113f / 355f) { clipped = true; return MathF.PI * 113f / 355f; } if (value < MathF.PI * -113f / 355f) { clipped = true; return MathF.PI * -113f / 355f; } return value; } internal static float ConvertFromVorbisFloat32(uint bits) { int num = (int)bits >> 31; double y = (int)(((bits & 0x7FE00000) >> 21) - 788); return (float)(((bits & 0x1FFFFF) ^ num) + (num & 1)) * (float)Math.Pow(2.0, y); } } public sealed class VorbisReader : IVorbisReader, IDisposable { private readonly List<IStreamDecoder> _decoders; private readonly NVorbis.Contracts.IContainerReader _containerReader; private readonly bool _closeOnDispose; private IStreamDecoder _streamDecoder; internal static Func<Stream, bool, NVorbis.Contracts.IContainerReader> CreateContainerReader { get; set; } = (Stream s, bool cod) => new ContainerReader(s, cod); internal static Func<NVorbis.Contracts.IPacketProvider, IStreamDecoder> CreateStreamDecoder { get; set; } = (NVorbis.Contracts.IPacketProvider pp) => new StreamDecoder(pp, new Factory()); public IReadOnlyList<IStreamDecoder> Streams => _decoders; public int Channels => _streamDecoder.Channels; public int SampleRate => _streamDecoder.SampleRate; public int UpperBitrate => _streamDecoder.UpperBitrate; public int NominalBitrate => _streamDecoder.NominalBitrate; public int LowerBitrate => _streamDecoder.LowerBitrate; public ITagData Tags => _streamDecoder.Tags; [Obsolete("Use .Tags.EncoderVendor instead.")] public string Vendor => _streamDecoder.Tags.EncoderVendor; [Obsolete("Use .Tags.All instead.")] public string[] Comments => _streamDecoder.Tags.All.SelectMany((KeyValuePair<string, IReadOnlyList<string>> k) => k.Value, (KeyValuePair<string, IReadOnlyList<string>> kvp, string Item) => kvp.Key + "=" + Item).ToArray(); [Obsolete("No longer supported. Will receive a new stream when parameters change.", true)] public bool IsParameterChange { get { throw new NotSupportedException(); } } public long ContainerOverheadBits => _containerReader?.ContainerBits ?? 0; public long ContainerWasteBits => _containerReader?.WasteBits ?? 0; public int StreamIndex => _decoders.IndexOf(_streamDecoder); [Obsolete("Use .Streams.Count instead.")] public int StreamCount => _decoders.Count; [Obsolete("Use VorbisReader.TimePosition instead.")] public TimeSpan DecodedTime { get { return _streamDecoder.TimePosition; } set { TimePosition = value; } } [Obsolete("Use VorbisReader.SamplePosition instead.")] public long DecodedPosition { get { return _streamDecoder.SamplePosition; } set { SamplePosition = value; } } public TimeSpan TotalTime => _streamDecoder.TotalTime; public long TotalSamples => _streamDecoder.TotalSamples; public TimeSpan TimePosition { get { return _streamDecoder.TimePosition; } set { _streamDecoder.TimePosition = value; } } public long SamplePosition { get { return _streamDecoder.SamplePosition; } set { _streamDecoder.SamplePosition = value; } } public bool IsEndOfStream => _streamDecoder.IsEndOfStream; public bool ClipSamples { get { return _streamDecoder.ClipSamples; } set { _streamDecoder.ClipSamples = value; } } public bool HasClipped => _streamDecoder.HasClipped; public IStreamStats StreamStats => _streamDecoder.Stats; [Obsolete("Use Streams[*].Stats instead.", true)] public IVorbisStreamStatus[] Stats { get { throw new NotSupportedException(); } } public event EventHandler<NewStreamEventArgs> NewStream; public VorbisReader(string fileName) : this(File.OpenRead(fileName)) { } public VorbisReader(Stream stream, bool closeOnDispose = true) { _decoders = new List<IStreamDecoder>(); NVorbis.Contracts.IContainerReader containerReader = CreateContainerReader(stream, closeOnDispose); containerReader.NewStreamCallback = ProcessNewStream; if (!containerReader.TryInit() || _decoders.Count == 0) { containerReader.NewStreamCallback = null; containerReader.Dispose(); if (closeOnDispose) { stream.Dispose(); } throw new ArgumentException("Could not load the specified container!", "containerReader"); } _closeOnDispose = closeOnDispose; _containerReader = containerReader; _streamDecoder = _decoders[0]; } [Obsolete("Use \"new StreamDecoder(Contracts.IPacketProvider)\" and the container's NewStreamCallback or Streams property instead.", true)] public VorbisReader(NVorbis.Contracts.IContainerReader containerReader) { throw new NotSupportedException(); } [Obsolete("Use \"new StreamDecoder(Contracts.IPacketProvider)\" instead.", true)] public VorbisReader(NVorbis.Contracts.IPacketProvider packetProvider) { throw new NotSupportedException(); } private bool ProcessNewStream(NVorbis.Contracts.IPacketProvider packetProvider) { IStreamDecoder streamDecoder = CreateStreamDecoder(packetProvider); streamDecoder.ClipSamples = true; NewStreamEventArgs newStreamEventArgs = new NewStreamEventArgs(streamDecoder); this.NewStream?.Invoke(this, newStreamEventArgs); if (!newStreamEventArgs.IgnoreStream) { _decoders.Add(streamDecoder); return true; } return false; } public void Dispose() { if (_decoders != null) { foreach (IStreamDecoder decoder in _decoders) { decoder.Dispose(); } _decoders.Clear(); } if (_containerReader != null) { _containerReader.NewStreamCallback = null; if (_closeOnDispose) { _containerReader.Dispose(); } } } public bool FindNextStream() { if (_containerReader == null) { return false; } return _containerReader.FindNextStream(); } public bool SwitchStreams(int index) { if (index < 0 || index >= _decoders.Count) { throw new ArgumentOutOfRangeException("index"); } IStreamDecoder streamDecoder = _decoders[index]; IStreamDecoder streamDecoder2 = _streamDecoder; if (streamDecoder == streamDecoder2) { return false; } streamDecoder.ClipSamples = streamDecoder2.ClipSamples; _streamDecoder = streamDecoder; if (streamDecoder.Channels == streamDecoder2.Channels) { return streamDecoder.SampleRate != streamDecoder2.SampleRate; } return true; } public void SeekTo(TimeSpan timePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { _streamDecoder.SeekTo(timePosition, seekOrigin); } public void SeekTo(long samplePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { _streamDecoder.SeekTo(samplePosition, seekOrigin); } public int ReadSamples(float[] buffer, int offset, int count) { count -= count % _streamDecoder.Channels; if (count > 0) { return _streamDecoder.Read(buffer, offset, count); } return 0; } public int ReadSamples(Span<float> buffer) { int count = buffer.Length - buffer.Length % _streamDecoder.Channels; if (!buffer.IsEmpty) { return _streamDecoder.Read(buffer, 0, count); } return 0; } [Obsolete("No longer needed.", true)] public void ClearParameterChange() { throw new NotSupportedException(); } } } namespace NVorbis.Ogg { public sealed class ContainerReader : NVorbis.Contracts.IContainerReader, IDisposable { private IPageReader _reader; private List<WeakReference<NVorbis.Contracts.IPacketProvider>> _packetProviders; private bool _foundStream; internal static Func<Stream, bool, Func<NVorbis.Contracts.IPacketProvider, bool>, IPageReader> CreatePageReader { get; set; } = (Stream s, bool cod, Func<NVorbis.Contracts.IPacketProvider, bool> cb) => new PageReader(s, cod, cb); internal static Func<Stream, bool, Func<NVorbis.Contracts.IPacketProvider, bool>, IPageReader> CreateForwardOnlyPageReader { get; set; } = (Stream s, bool cod, Func<NVorbis.Contracts.IPacketProvider, bool> cb) => new ForwardOnlyPageReader(s, cod, cb); public NewStreamHandler NewStreamCallback { get; set; } public bool CanSeek { get; } public long WasteBits => _reader.WasteBits; public long ContainerBits => _reader.ContainerBits; public IReadOnlyList<NVorbis.Contracts.IPacketProvider> GetStreams() { List<NVorbis.Contracts.IPacketProvider> list = new List<NVorbis.Contracts.IPacketProvider>(_packetProviders.Count); for (int i = 0; i < _packetProviders.Count; i++) { if (_packetProviders[i].TryGetTarget(out var target)) { list.Add(target); continue; } list.RemoveAt(i); i--; } return list; } public ContainerReader(Stream stream, bool closeOnDispose) { if (stream == null) { throw new ArgumentNullException("stream"); } _packetProviders = new List<WeakReference<NVorbis.Contracts.IPacketProvider>>(); if (stream.CanSeek) { _reader = CreatePageReader(stream, closeOnDispose, ProcessNewStream); CanSeek = true; } else { _reader = CreateForwardOnlyPageReader(stream, closeOnDispose, ProcessNewStream); } } public bool TryInit() { return FindNextStream(); } public bool FindNextStream() { _reader.Lock(); try { _foundStream = false; while (_reader.ReadNextPage()) { if (_foundStream) { return true; } } return false; } finally { _reader.Release(); } } private bool ProcessNewStream(NVorbis.Contracts.IPacketProvider packetProvider) { bool flag = _reader.Release(); try { NewStreamHandler newStreamCallback = NewStreamCallback; if (newStreamCallback == null || newStreamCallback(packetProvider)) { _packetProviders.Add(new WeakReference<NVorbis.Contracts.IPacketProvider>(packetProvider)); _foundStream = true; return true; } return false; } finally { if (flag) { _reader.Lock(); } } } public void Dispose() { _reader?.Dispose(); _reader = null; } } internal class Crc : ICrc { private const uint CRC32_POLY = 79764919u; private static readonly uint[] s_crcTable; private uint _crc; static Crc() { s_crcTable = new uint[256]; for (uint num = 0u; num < 256; num++) { uint num2 = num << 24; for (int i = 0; i < 8; i++) { num2 = (num2 << 1) ^ ((num2 >= 2147483648u) ? 79764919u : 0u); } s_crcTable[num] = num2; } } public Crc() { Reset(); } public void Reset() { _crc = 0u; } public void Update(int nextVal) { _crc = (_crc << 8) ^ s_crcTable[nextVal ^ (_crc >> 24)]; } public bool Test(uint checkCrc) { return _crc == checkCrc; } } internal class ForwardOnlyPacketProvider : DataPacket, IForwardOnlyPacketProvider, NVorbis.Contracts.IPacketProvider { private int _lastSeqNo; private readonly Queue<(byte[] buf, bool isResync)> _pageQueue = new Queue<(byte[], bool)>(); private readonly IPageReader _reader; private byte[] _pageBuf; private int _packetIndex; private bool _isEndOfStream; private int _dataStart; private bool _lastWasPeek; private Memory<byte> _packetBuf; private int _dataIndex; public bool CanSeek => false; public int StreamSerial { get; } protected override int TotalBits => _packetBuf.Length * 8; public ForwardOnlyPacketProvider(IPageReader reader, int streamSerial) { _reader = reader; StreamSerial = streamSerial; _packetIndex = int.MaxValue; } public bool AddPage(byte[] buf, bool isResync) { if ((buf[5] & 2u) != 0) { if (_isEndOfStream) { return false; } isResync = true; _lastSeqNo = BitConverter.ToInt32(buf, 18); } else { int num = BitConverter.ToInt32(buf, 18); isResync |= num != _lastSeqNo + 1; _lastSeqNo = num; } int num2 = 0; for (int i = 0; i < buf[26]; i++) { num2 += buf[27 + i]; } if (num2 == 0) { return false; } _pageQueue.Enqueue((buf, isResync)); return true; } public void SetEndOfStream() { _isEndOfStream = true; } public IPacket GetNextPacket() { if (_packetBuf.Length > 0) { if (!_lastWasPeek) { throw new InvalidOperationException("Must call Done() on previous packet first."); } _lastWasPeek = false; return this; } _lastWasPeek = false; if (GetPacket()) { return this; } return null; } public IPacket PeekNextPacket() { if (_packetBuf.Length > 0) { if (!_lastWasPeek) { throw new InvalidOperationException("Must call Done() on previous packet first."); } return this; } _lastWasPeek = true; if (GetPacket()) { return this; } return null; } private bool GetPacket() { byte[] pageBuf; bool isResync; int packetIndex; bool isContinuation; bool isContinued; int dataStart; if (_pageBuf != null && _packetIndex < 27 + _pageBuf[26]) { pageBuf = _pageBuf; isResync = false; dataStart = _dataStart; packetIndex = _packetIndex; isContinuation = false; isContinued = pageBuf[26 + pageBuf[26]] == byte.MaxValue; } else if (!ReadNextPage(out pageBuf, out isResync, out dataStart, out packetIndex, out isContinuation, out isContinued)) { return false; } int num = dataStart; bool flag = packetIndex == 27; if (isContinuation && flag) { isResync = true; num += GetPacketLength(pageBuf, ref packetIndex); if (packetIndex == 27 + pageBuf[26]) { return GetPacket(); } } if (!flag) { num = 0; } int packetLength = GetPacketLength(pageBuf, ref packetIndex); Memory<byte> memory = new Memory<byte>(pageBuf, dataStart, packetLength); dataStart += packetLength; bool flag2 = packetIndex == 27 + pageBuf[26]; if (isContinued) { if (flag2) { flag2 = false; } else { int packetIndex2 = packetIndex; GetPacketLength(pageBuf, ref packetIndex2); flag2 = packetIndex2 == 27 + pageBuf[26]; } } bool flag3 = false; long? granulePosition = null; if (flag2) { granulePosition = BitConverter.ToInt64(pageBuf, 6); if ((pageBuf[5] & 4u) != 0 || (_isEndOfStream && _pageQueue.Count == 0)) { flag3 = true; } } else { while (isContinued && packetIndex == 27 + pageBuf[26] && ReadNextPage(out pageBuf, out isResync, out dataStart, out packetIndex, out isContinuation, out isContinued) && !isResync && isContinuation) { num += 27 + pageBuf[26]; Memory<byte> memory2 = memory; int packetLength2 = GetPacketLength(pageBuf, ref packetIndex); memory = new Memory<byte>(new byte[memory2.Length + packetLength2]); memory2.CopyTo(memory); new Memory<byte>(pageBuf, dataStart, packetLength2).CopyTo(memory.Slice(memory2.Length)); dataStart += packetLength2; } } base.IsResync = isResync; base.GranulePosition = granulePosition; base.IsEndOfStream = flag3; base.ContainerOverheadBits = num * 8; _pageBuf = pageBuf; _dataStart = dataStart; _packetIndex = packetIndex; _packetBuf = memory; _isEndOfStream |= flag3; Reset(); return true; } private bool ReadNextPage(out byte[] pageBuf, out bool isResync, out int dataStart, out int packetIndex, out bool isContinuation, out bool isContinued) { while (_pageQueue.Count == 0) { if (_isEndOfStream || !_reader.ReadNextPage()) { pageBuf = null; isResync = false; dataStart = 0; packetIndex = 0; isContinuation = false; isContinued = false; return false; } } (byte[], bool) tuple = _pageQueue.Dequeue(); pageBuf = tuple.Item1; isResync = tuple.Item2; dataStart = pageBuf[26] + 27; packetIndex = 27; isContinuation = (pageBuf[5] & 1) != 0; isContinued = pageBuf[26 + pageBuf[26]] == byte.MaxValue; return true; } private int GetPacketLength(byte[] pageBuf, ref int packetIndex) { int num = 0;