

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()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;