Decompiled source of Sailwind Radio v1.5.13
BepInEx/plugins/SailwindRadio/SailwindRadio.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using NLayer; using SailwindRadio.Acoustics; using SailwindRadio.Audio; using SailwindRadio.Library; using SailwindRadio.Models; using SailwindRadio.Persistence; using SailwindRadio.Physical; using SailwindRadio.Playback; using SailwindRadio.Shops; using SailwindRadio.UI; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("SailwindRadio")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.5.13.0")] [assembly: AssemblyInformationalVersion("1.5.13")] [assembly: AssemblyProduct("SailwindRadio")] [assembly: AssemblyTitle("SailwindRadio")] [assembly: AssemblyVersion("1.5.13.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SailwindRadio { public enum DeviceRole { Radio, SmallSpeaker, Speaker, Woofer } public static class DeviceKind { public const int Count = 16; public const int Walnut = 0; public const int AlAnkh = 1; public const int Aestrin = 2; public const int Emerald = 3; public const int WalnutRadio = 0; public const int WalnutSmallSpeaker = 1; public const int WalnutSpeaker = 2; public const int WalnutWoofer = 3; public const int MaximumStack = 6; public static bool IsValid(int kind) { if (kind >= 0) { return kind < 16; } return false; } public static DeviceRole Role(int kind) { return (DeviceRole)(kind & 3); } public static int Family(int kind) { return kind >> 2; } public static bool IsWalnut(int kind) { return Family(kind) == 0; } public static int Of(int family, DeviceRole role) { return (int)(family * 4 + role); } public static bool CanStack(int bottom, int top) { if (IsValid(bottom) && IsValid(top) && Family(bottom) == Family(top) && IsCabinet(bottom)) { if (!IsCabinet(top)) { return Role(top) == DeviceRole.Radio; } return true; } return false; } private static bool IsCabinet(int kind) { if (Role(kind) != DeviceRole.Speaker) { return Role(kind) == DeviceRole.Woofer; } return true; } } [BepInPlugin("local.sailwind.radio", "Sailwind Radio", "1.5.13")] [BepInProcess("Sailwind.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "local.sailwind.radio"; public const string Version = "1.5.13"; private static Plugin instance; private Harmony harmony; private RadioWorldService world; private RadioAcousticsService acoustics; private RadioShopService shops; private ConfigEntry<string> musicFolders; private ConfigEntry<bool> continueWhileSleeping; private ConfigEntry<float> mechanismVolume; private ConfigEntry<bool> songHover; private ConfigEntry<bool> logDisplayTiming; private LibraryScanner library; private RadioMenus menus; private Task<List<AudioApplication>> applicationList; private RadioPlaybackSet<RadioItemController> radios; private readonly HashSet<RadioItemController> seen = new HashSet<RadioItemController>(); private readonly List<RadioItemController> removed = new List<RadioItemController>(); private bool ready; private bool applicationPaused; private bool focused = true; private bool onlyLoading; private bool Suspended { get { if (!Loading) { return Paused; } return true; } } private static bool Loading { get { if (GameState.playing && !GameState.currentlyLoading) { return GameState.loadingScenes > 0; } return true; } } private bool Paused { get { if ((!GameState.sleeping || continueWhileSleeping.Value) && (!(Time.timeScale <= 0f) || (GameState.sleeping && continueWhileSleeping.Value)) && !AudioListener.pause && !applicationPaused) { if (!focused) { return !Application.runInBackground; } return false; } return true; } } private void Awake() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Expected O, but got Unknown instance = this; try { musicFolders = ((BaseUnityPlugin)this).Config.Bind<string>("Music", "MusicFolders", "", "Music folders separated by |. Each folder is one collection including all its subfolders. Example: D:\\Music | E:\\Sailing Music"); continueWhileSleeping = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ContinueWhileSleeping", false, "Keep music playing while the player sleeps. Loading still suspends playback."); ConfigEntry<float> appVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "AppVolume", 1f, new ConfigDescription("Volume multiplier for apps playing through a radio, such as Spotify or a browser. 1 plays an app as loud as its own volume allows. Raise it to bring an app up to your music without turning the app itself up. Loud peaks are smoothly limited instead of clipping.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>())); ApplicationRing.Boost = appVolume.Value; appVolume.SettingChanged += delegate { ApplicationRing.Boost = appVolume.Value; }; BindFalloff("RadioFalloff", "the radio's built-in speaker", RadioSpeakerProfile.BuiltIn); BindFalloff("SmallSpeakerFalloff", "Small Speakers", RadioSpeakerProfile.Small); BindFalloff("SpeakerFalloff", "Speakers", RadioSpeakerProfile.Normal); BindFalloff("WooferFalloff", "Woofers and Turbo Wolfers", RadioSpeakerProfile.TurboWoofer); mechanismVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "MechanismVolume", 0.2f, new ConfigDescription("Volume of the regional radio display mechanisms, from silent at 0 to full at 1. Game volume also applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); songHover = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowSongOnHover", false, "Show the current song's title and artist when looking at a radio."); logDisplayTiming = ((BaseUnityPlugin)this).Config.Bind<bool>("Development", "LogDisplayTiming", false, "Log regional display timing, mesh updates and allocations every 10 seconds for performance checks."); RemoveRetiredSettings(); harmony = new Harmony("local.sailwind.radio"); MediaFoundationSupport.Detect(); LibraryPaths.MediaFoundationFormats = MediaFoundationSupport.Enabled; ((BaseUnityPlugin)this).Logger.LogInfo((object)MediaFoundationSupport.Summary); ApplicationAudioSupport.Detect(Path.Combine(Paths.ConfigPath, "SailwindRadio.held-volumes.txt"), Warn); ((BaseUnityPlugin)this).Logger.LogInfo((object)ApplicationAudioSupport.Summary); acoustics = new RadioAcousticsService(); library = new LibraryScanner(); radios = new RadioPlaybackSet<RadioItemController>((RadioItemController item, RadioState state) => new RadioPlayback((MonoBehaviour)(object)this, state, Warn), AttachEngine, delegate(RadioItemController item) { if (Object.op_Implicit((Object)(object)item) && item.State.Powered) { item.TogglePower(); } }, Warn); menus = new RadioMenus(); DisplayTiming.Configure(() => logDisplayTiming.Value, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); }); world = new RadioWorldService(harmony, Warn, new DisplaySoundBank(() => mechanismVolume.Value, Warn)); world.BeforeSave += CapturePositions; world.ActionRequested += HandleAction; world.RadioReplaced += delegate(RadioItemController from, RadioItemController to) { radios.Move(from, to); }; shops = new RadioShopService(world, Warn); menus.CollectionsChanged += SelectCollections; menus.ApplicationChosen += ChooseApplication; library.RequestScan(musicFolders.Value); InstallSuspendBoundary(typeof(StartMenu), "GameToSettings"); InstallSuspendBoundary(typeof(Sleep), "FallAsleep"); ready = true; int num = 0; string[] array = (musicFolders.Value ?? "").Split(new char[1] { '|' }); for (int num2 = 0; num2 < array.Length; num2++) { if (!string.IsNullOrWhiteSpace(array[num2])) { num++; } } ((BaseUnityPlugin)this).Logger.LogInfo((object)((num == 0) ? "Sailwind Radio 1.5.13 ready. Set MusicFolders in the Radio config file to load music." : ("Sailwind Radio 1.5.13 ready with " + num + ((num == 1) ? " music folder." : " music folders.")))); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Radio initialization failed: " + ex)); Shutdown(); ((Behaviour)this).enabled = false; } } private void BindFalloff(string key, string output, RadioSpeakerProfile profile) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown ConfigEntry<float> entry = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", key, profile.DefaultRadius, new ConfigDescription("How far " + output + " can be heard, in metres." + ((profile == RadioSpeakerProfile.BuiltIn) ? "" : (" They join a playing radio up to " + 50f + " m away whatever this is set to.")), (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 50f), Array.Empty<object>())); profile.SetRadius(entry.Value); entry.SettingChanged += delegate { profile.SetRadius(entry.Value); }; } private void RemoveRetiredSettings() { ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Development", "SpawnRadio", "", "Retired developer spawn shortcut."); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val).Definition); ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "SpawnDefaultRevision", 0, "Retired spawn shortcut migration marker."); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val2).Definition); ConfigEntry<string> val3 = ((BaseUnityPlugin)this).Config.Bind<string>("Music", "MusicFile", "", "Retired single-file music setting."); bool num = !string.IsNullOrWhiteSpace(val3.Value) && string.IsNullOrWhiteSpace(musicFolders.Value); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val3).Definition); ConfigEntry<bool> val4 = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "StormInterferenceEnabled", true, "Retired interference setting."); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val4).Definition); ConfigEntry<float> val5 = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "StormInterferenceStrength", 0.35f, "Retired interference setting."); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val5).Definition); ConfigEntry<bool> val6 = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ContinueWhilePaused", false, "Retired pause setting."); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val6).Definition); ConfigEntry<float> val7 = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "PageHoldSeconds", 4f, "Retired page hold setting."); ((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val7).Definition); ((BaseUnityPlugin)this).Config.Save(); if (num) { Warn("MusicFile has been retired. Set MusicFolders to a folder containing your music."); } } private void InstallSuspendBoundary(Type type, string name) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0087: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, Type.EmptyTypes, (Type[])null); if (methodInfo == null) { Warn("Immediate radio pause hook unavailable for " + type.Name + "." + name + ". Game state pause checks remain active."); } else { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "ReleaseControlBoundary", (Type[])null), new HarmonyMethod(typeof(Plugin), "SuspendBoundary", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void ReleaseControlBoundary() { if (Object.op_Implicit((Object)(object)instance) && instance.ready) { instance.ReleaseRadioControls(); } } private static void SuspendBoundary() { if (Object.op_Implicit((Object)(object)instance) && instance.ready && instance.Suspended) { instance.SuspendNow(); } } private void Update() { if (!ready) { return; } try { acoustics.Tick(); world.Tick(); TickShops(); SynchronizePlayback(); LibrarySnapshot snapshot = library.Snapshot; if (library.Poll()) { foreach (string item in library.Snapshot.WarningsSince(snapshot)) { Warn(item); } radios.SetSnapshot(library.Snapshot); if (Object.op_Implicit((Object)(object)menus.CollectionRadio)) { ShowCollections(menus.CollectionRadio); } } menus.Tick(); PollApplications(); bool paused = Paused; onlyLoading = !paused && Loading; bool suspended = paused || onlyLoading; radios.Tick(Time.realtimeSinceStartup, world.ActiveRadioId, (RadioItemController item) => Object.op_Implicit((Object)(object)item) ? item.InstanceId : 0, TickPlayback, suspended); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Radio stopped after a runtime error: " + ex)); Shutdown(); ((Behaviour)this).enabled = false; } } private void SynchronizePlayback() { seen.Clear(); IReadOnlyList<RadioItemController> items = world.Items; for (int i = 0; i < items.Count; i++) { RadioItemController radioItemController = items[i]; if (Object.op_Implicit((Object)(object)radioItemController) && radioItemController.State.Role == DeviceRole.Radio) { seen.Add(radioItemController); radios.Add(radioItemController, radioItemController.State); } } removed.Clear(); foreach (RadioItemController key in radios.Keys) { if (!Object.op_Implicit((Object)(object)key) || !seen.Contains(key)) { removed.Add(key); } } foreach (RadioItemController item in removed) { radios.Remove(item); } } private void AttachEngine(RadioItemController item, RadioPlayback engine) { if (!Object.op_Implicit((Object)(object)item)) { return; } if (engine == null) { item.CapturePosition = null; item.SuspendPlayback = null; item.ForgetPlayback(); return; } item.CapturePosition = delegate { radios.Capture(item); }; item.SuspendPlayback = delegate { radios.Run(item, delegate(RadioPlayback current, RadioQueue queue) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) current.Tick(item.VisualAudioPosition, suspended: true); }, rethrow: true); }; } private void TickShops() { if (shops == null) { return; } try { shops.Tick(); } catch (Exception ex) { Warn("Radio shops stopped after an error: " + ex.Message); RadioShopService radioShopService = shops; shops = null; try { radioShopService.Dispose(); } catch (Exception ex2) { Warn("Could not release radio shops: " + ex2.Message); } } } private bool HeardFromHead(DeviceVessel vessel) { if (acoustics.HeadKnown) { return DeviceVessels.OnPlayerBoat(vessel); } return false; } private bool ShouldMuffle(bool audible, float volume, Vector3 position, RadioSpeakerProfile profile, bool fromHead) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //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_0042: 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) if (!audible || volume <= 0f || profile == null) { return false; } Vector3 val = ((fromHead && acoustics.HeadKnown) ? acoustics.HeadPosition : acoustics.ListenerPosition); Vector3 val2 = position - val; return ((Vector3)(ref val2)).sqrMagnitude <= profile.Radius * profile.Radius; } private float Muffling(RadioItemController device, bool audible, float volume, Vector3 position, bool carried, RadioSpeakerProfile profile, bool fromHead) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (acoustics.ListenerKnown) { if (!ShouldMuffle(audible, volume, position, profile, fromHead)) { return acoustics.LastObstruction((Component)(object)device); } return acoustics.ObstructionAt((Component)(object)device, position, carried, fromHead); } return 0f; } private void TickPlayback(RadioItemController item, RadioPlayback engine, RadioQueue queue, bool suspended) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0116: 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) if (!Object.op_Implicit((Object)(object)item)) { return; } DevicePlacement devicePlacement = item.Place(); Vector3 val = devicePlacement.SoundPosition; bool flag = HeardFromHead(devicePlacement.Vessel); if (devicePlacement.Carried && acoustics.ListenerKnown) { val = acoustics.ListenerPosition; } bool audible = engine.Audible(suspended); float obstruction = Muffling(item, audible, item.State.Volume * item.State.LocalVolume, val, devicePlacement.Carried, RadioSpeakerProfile.BuiltIn, flag); item.HearFromHead(flag, acoustics.HeadPosition); engine.SetAcoustics(flag ? acoustics.HeadPosition : acoustics.ListenerPosition, acoustics.ListenerKnown, obstruction, flag); engine.SetCarried(devicePlacement.Carried); engine.BeginEndpoints(); if (item.InstanceId == world.ActiveRadioId && item.State.Powered) { ConnectSpeakers(devicePlacement.Vessel, engine, devicePlacement.VisualPosition, flag, audible, item.State.Volume); } engine.EndEndpoints(); engine.Tick(val, suspended, suspended && !onlyLoading); if (!suspended && item.State.Powered && !item.State.Paused) { bool num; if (!engine.LoadFailed) { if (!engine.TrackEnded) { goto IL_0186; } num = queue.TrackEnded(); } else { num = queue.TrackFailed(engine.FailedPath); } if (num) { engine.SetTrack(item.State.TrackPath); } } goto IL_0186; IL_0186: engine.PreloadTrack((item.InstanceId == world.ActiveRadioId && item.State.Powered) ? queue.PeekNext() : ""); AudioApplication playingApplication = engine.PlayingApplication; if (playingApplication != null) { MediaControls.Track applicationTrack = engine.ApplicationTrack; bool flag2 = applicationTrack != null && applicationTrack.Title.Length > 0; item.SetTrackInfo(flag2 ? applicationTrack.Title : playingApplication.Label, flag2 ? applicationTrack.Artist : "", flag2 ? applicationTrack.Album : "", item.State.Powered && songHover.Value); } else { TrackInfo trackInfo = library.Snapshot.GetTrackInfo(item.State.TrackPath); item.SetTrackInfo(trackInfo.Title, trackInfo.Artist, trackInfo.Album, engine.NamesTrack && songHover.Value); } } private void ConnectSpeakers(DeviceVessel sourceVessel, RadioPlayback engine, Vector3 devicePosition, bool fromHead, bool audible, float masterVolume) { //IL_0056: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) foreach (RadioItemController item in world.Items) { if (Object.op_Implicit((Object)(object)item) && item.State.Role != DeviceRole.Radio && item.State.SpeakerEnabled) { DevicePlacement devicePlacement = item.Place(); if (DeviceVessels.CanConnect(sourceVessel, devicePlacement.Vessel, devicePosition, devicePlacement.VisualPosition)) { Vector3 position = ((devicePlacement.Carried && acoustics.ListenerKnown) ? acoustics.ListenerPosition : devicePlacement.SoundPosition); float num = ((item.State.Role == DeviceRole.Woofer) ? 1f : item.State.Volume); float obstruction = Muffling(item, audible, masterVolume * num, position, devicePlacement.Carried, RadioSpeakerProfile.ForKind(item.State.Kind), fromHead); engine.SetEndpoint(item.InstanceId, position, devicePlacement.Carried, item.State.Kind, num, item.State.Bass, obstruction); } } } } private void HandleAction(RadioItemController item, RadioAction action) { if (!ready || !Object.op_Implicit((Object)(object)item) || item.State.Role != DeviceRole.Radio) { return; } if (action == RadioAction.Power) { if (item.State.Powered) { library.RequestScan(musicFolders.Value); } } else if (action == RadioAction.Collections) { ShowCollections(item); ListApplications(item); } else { if (action == RadioAction.PlayPause && !item.State.Powered) { return; } radios.Run(item, delegate(RadioPlayback engine, RadioQueue queue) { bool flag = false; bool flag2 = engine.PlayingApplication != null; switch (action) { case RadioAction.PlayPause: if (!flag2 || item.State.Paused || !engine.SendToApplication(MediaControls.Command.PlayPause)) { engine.CapturePosition(); item.State.Paused = !item.State.Paused; if (item.State.Paused) { item.SuspendPlayback?.Invoke(); } } break; case RadioAction.Previous: if (flag2) { engine.SendToApplication(MediaControls.Command.Previous); } else { flag = queue.Previous(); } break; case RadioAction.Next: if (flag2) { engine.SendToApplication(MediaControls.Command.Next); } else { flag = queue.Next(); } break; case RadioAction.Shuffle: flag = queue.SetShuffle(!item.State.Shuffle); break; } if (flag) { engine.SetTrack(item.State.TrackPath); } }); } } private void ShowCollections(RadioItemController item) { if (!Object.op_Implicit((Object)(object)item)) { return; } List<CollectionChoice> list = new List<CollectionChoice>(); HashSet<string> hashSet = new HashSet<string>(item.State.SelectedCollections ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase); foreach (MusicCollection collection in library.Snapshot.Collections) { list.Add(new CollectionChoice(collection.Id, collection.Label, hashSet.Contains(collection.Id))); } menus.ShowCollections(item, list); } private void SelectCollections(RadioItemController item, string[] selected) { if (!Object.op_Implicit((Object)(object)item)) { return; } radios.Run(item, delegate(RadioPlayback engine, RadioQueue queue) { if (queue.SetCollections(library.Snapshot, selected)) { engine.SetTrack(item.State.TrackPath); } }); } private void ListApplications(RadioItemController item) { if (!ApplicationAudioSupport.Enabled) { menus.ShowApplications(PlayingApplication(item), null, ApplicationAudioSupport.Summary); return; } menus.ShowApplications(PlayingApplication(item), null, "Looking for applications playing sound"); if (applicationList != null) { return; } applicationList = Task.Run(delegate { using (new ComCalls.Apartment()) { return AudioApplications.List(); } }); } private void PollApplications() { if (applicationList == null || !applicationList.IsCompleted) { return; } Task<List<AudioApplication>> task = applicationList; applicationList = null; RadioItemController collectionRadio = menus.CollectionRadio; if (task.IsFaulted) { Warn("Could not list applications: " + task.Exception.GetBaseException().Message); if (Object.op_Implicit((Object)(object)collectionRadio)) { menus.ShowApplications(PlayingApplication(collectionRadio), null, "Could not list applications"); } } else if (Object.op_Implicit((Object)(object)collectionRadio)) { menus.ShowApplications(PlayingApplication(collectionRadio), task.Result, (task.Result.Count == 0) ? "No other application is playing sound. Start your music app and open this menu again." : null); } } private AudioApplication PlayingApplication(RadioItemController item) { AudioApplication playing = null; radios.Run(item, delegate(RadioPlayback engine, RadioQueue queue) { playing = engine.PlayingApplication; }); return playing; } private void ChooseApplication(RadioItemController item, AudioApplication application) { if (Object.op_Implicit((Object)(object)item)) { radios.Run(item, delegate(RadioPlayback engine, RadioQueue queue) { engine.SetApplication(application); }); } } private void OnGUI() { if (ready) { menus?.Draw(); } } private void CapturePositions() { radios?.ForEachEngine(delegate(RadioItemController item, RadioPlayback engine) { engine.CapturePosition(); }, "Could not capture a radio position"); } private void SuspendNow() { bool paused = Paused; radios?.ForEachEngine(delegate(RadioItemController item, RadioPlayback engine) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)item)) { engine.Tick(item.VisualAudioPosition, suspended: true, paused); } }, "Could not suspend a radio"); } private void ReleaseRadioControls() { menus?.Close(); foreach (RadioItemController item in world?.Items ?? Array.Empty<RadioItemController>()) { if (Object.op_Implicit((Object)(object)item)) { try { item.ReleaseControls(); } catch (Exception ex) { Warn("Could not release radio controls: " + ex.Message); } } } } private void OnApplicationPause(bool pause) { applicationPaused = pause; if (pause) { ReleaseRadioControls(); } if (pause && ready) { SuspendNow(); } } private void OnApplicationFocus(bool focus) { focused = focus; acoustics?.Invalidate(); if (!focus) { ReleaseRadioControls(); } if (!focus && !Application.runInBackground && ready) { SuspendNow(); } } private void Warn(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } private void OnDisable() { Shutdown(); } private void OnDestroy() { Shutdown(); } private void Shutdown() { ready = false; ReleaseRadioControls(); CapturePositions(); radios?.Clear(); library?.Dispose(); library = null; menus?.Dispose(); menus = null; try { shops?.Dispose(); } catch (Exception ex) { Warn("Could not release radio shops: " + ex.Message); } shops = null; try { world?.Dispose(); } catch (Exception ex2) { Warn("Could not release radio item hooks: " + ex2.Message); } world = null; acoustics?.Dispose(); acoustics = null; try { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } catch (Exception ex3) { Warn("Could not remove radio hooks: " + ex3.Message); } harmony = null; if ((Object)(object)instance == (Object)(object)this) { instance = null; } } } [Serializable] public sealed class RadioState { public int Kind; public float Bass = 0.5f; public float LocalVolume = 1f; public bool SpeakerEnabled = true; public bool Shuffle; public bool CollectionsInitialized; public string[] SelectedCollections = Array.Empty<string>(); public string TrackPath = ""; public double PositionSeconds; public bool Powered; public bool Paused; public float Volume = 0.5f; public RadioState Stacked; public DeviceRole Role => DeviceKind.Role(Kind); public List<RadioState> Above() { List<RadioState> list = new List<RadioState>(); for (RadioState stacked = Stacked; stacked != null; stacked = stacked.Stacked) { list.Add(stacked); } return list; } public static RadioState NewDevice(int kind) { return new RadioState { Kind = kind, Volume = ((DeviceKind.Role(kind) == DeviceRole.Radio) ? 0.5f : 0.75f), TrackPath = "" }; } } } namespace SailwindRadio.UI { internal sealed class MenuInputLease { private Object character; private Object controller; private Object crosshair; private bool crosshairActive; private bool mouseLook; private bool cursorVisible; private CursorLockMode cursorLock; internal bool Owned { get; private set; } internal static bool GameplayAvailable { get { if (GameState.playing && !GameState.currentlyLoading && GameState.loadingScenes == 0 && !GameState.justStarted && !GameState.sleeping && !Object.op_Implicit((Object)(object)GameState.inBed) && !BoatCamera.on) { return Time.timeScale > 0f; } return false; } } internal bool Acquire() { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if (Owned) { return true; } if (!GameplayAvailable || !Application.isFocused || GameState.inCursorMenu || !Object.op_Implicit((Object)(object)Refs.charController) || !Object.op_Implicit((Object)(object)Refs.ovrController) || !Object.op_Implicit((Object)(object)Refs.mouseCrosshair) || !((Collider)Refs.charController).enabled || !((Behaviour)Refs.ovrController).enabled) { return false; } character = (Object)(object)Refs.charController; controller = (Object)(object)Refs.ovrController; crosshair = (Object)(object)Refs.mouseCrosshair; crosshairActive = Refs.mouseCrosshair.activeSelf; mouseLook = MouseLook.MouseLookIsEnabled(); cursorVisible = Cursor.visible; cursorLock = Cursor.lockState; Owned = true; MouseLook.ToggleMouseLook(false); MouseLook.ToggleMouseLookAndCursor(false); ((Collider)Refs.charController).enabled = false; ((Behaviour)Refs.ovrController).enabled = false; Refs.mouseCrosshair.SetActive(false); return true; } internal void Release() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (!Owned) { return; } Owned = false; if (!GameState.currentlyLoading && GameState.playing && !GameState.sleeping && !Object.op_Implicit((Object)(object)GameState.inBed)) { if (Object.op_Implicit((Object)(object)Refs.charController) && (Object)(object)Refs.charController == character) { ((Collider)Refs.charController).enabled = true; } if (Object.op_Implicit((Object)(object)Refs.ovrController) && (Object)(object)Refs.ovrController == controller) { ((Behaviour)Refs.ovrController).enabled = true; } if ((Object)(object)Refs.charController == character && (Object)(object)Refs.ovrController == controller) { MouseLook.ToggleMouseLook(mouseLook); MouseLook.ToggleMouseLookAndCursor(true); Cursor.visible = cursorVisible; Cursor.lockState = cursorLock; if (!BoatCamera.on && Object.op_Implicit((Object)(object)Refs.mouseCrosshair) && (Object)(object)Refs.mouseCrosshair == crosshair) { Refs.mouseCrosshair.SetActive(crosshairActive); } } } character = (controller = (crosshair = null)); } } public sealed class CollectionChoice { public readonly string Id; public readonly string Label; public readonly bool Selected; public CollectionChoice(string id, string label, bool selected) { Id = id; Label = label; Selected = selected; } } public sealed class RadioMenus : IDisposable { private readonly MenuInputLease lease = new MenuInputLease(); private readonly List<CollectionChoice> choices = new List<CollectionChoice>(); private readonly Dictionary<string, bool> selected = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); private readonly List<AudioApplication> applications = new List<AudioApplication>(); private AudioApplication playing; private string applicationNote; private Vector2 scroll; private bool disposed; public bool IsOpen => lease.Owned; public RadioItemController CollectionRadio { get; private set; } public event Action<RadioItemController, string[]> CollectionsChanged; public event Action<RadioItemController, AudioApplication> ApplicationChosen; public void ShowApplications(AudioApplication current, IReadOnlyList<AudioApplication> available, string note) { playing = current; applicationNote = note; applications.Clear(); if (available != null) { applications.AddRange(available); } } public void ShowCollections(RadioItemController radio, IReadOnlyList<CollectionChoice> available) { //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) if (disposed || !Object.op_Implicit((Object)(object)radio) || radio.State.Role != DeviceRole.Radio) { return; } if (!IsOpen || !((Object)(object)CollectionRadio == (Object)(object)radio)) { Close(); radio.ReleaseControls(); if (!lease.Acquire()) { return; } selected.Clear(); scroll = Vector2.zero; } CollectionRadio = radio; choices.Clear(); if (available == null) { return; } foreach (CollectionChoice item in available) { if (item != null && !string.IsNullOrEmpty(item.Id)) { choices.Add(item); if (!selected.ContainsKey(item.Id)) { selected.Add(item.Id, item.Selected); } } } } public void Tick() { if (IsOpen) { if (!MenuInputLease.GameplayAvailable || !Application.isFocused || !GameState.inCursorMenu || Input.GetKeyDown((KeyCode)27)) { Close(); } else if (Object.op_Implicit((Object)(object)CollectionRadio) && (!CollectionRadio.IsPlacedForControls || !CollectionRadio.EnsureOwned() || !CollectionRadio.WithinMenuReach)) { Close(); } else if (!Object.op_Implicit((Object)(object)CollectionRadio)) { Close(); } } } public void Draw() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (IsOpen) { float num = Mathf.Min(440, Screen.width - 24); float num2 = Mathf.Min(520, Screen.height - 24); GUILayout.Window(194043, new Rect(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2), new WindowFunction(DrawWindow), "Radio music", Array.Empty<GUILayoutOption>()); } } private void DrawWindow(int id) { //IL_0021: 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_004f: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)CollectionRadio)) { GUILayout.Label("Choose which music collections this radio plays", Array.Empty<GUILayoutOption>()); scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height((float)Mathf.Min(370, Screen.height - 160)) }); if (choices.Count == 0) { GUILayout.Label("No collections available yet", Array.Empty<GUILayoutOption>()); } foreach (CollectionChoice choice in choices) { selected[choice.Id] = GUILayout.Toggle(selected[choice.Id], choice.Label ?? choice.Id, Array.Empty<GUILayoutOption>()); } DrawApplications(); GUILayout.EndScrollView(); if (GUILayout.Button("Apply", Array.Empty<GUILayoutOption>())) { RadioItemController collectionRadio = CollectionRadio; List<string> list = new List<string>(); foreach (CollectionChoice choice2 in choices) { if (selected[choice2.Id] && !list.Contains(choice2.Id)) { list.Add(choice2.Id); } } Close(); this.CollectionsChanged?.Invoke(collectionRadio, list.ToArray()); } } if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>())) { Close(); } } private void DrawApplications() { GUILayout.Space(12f); GUILayout.Label((playing != null) ? ("Playing " + playing.Label + " through the radio") : "Or play an application through the radio", Array.Empty<GUILayoutOption>()); bool flag = playing != null && GUILayout.Button("Back to music", Array.Empty<GUILayoutOption>()); AudioApplication arg = null; if (applicationNote != null) { GUILayout.Label(applicationNote, Array.Empty<GUILayoutOption>()); } foreach (AudioApplication application in applications) { if (!application.Same(playing) && GUILayout.Button(application.Label, Array.Empty<GUILayoutOption>())) { flag = true; arg = application; } } if (flag) { RadioItemController collectionRadio = CollectionRadio; Close(); this.ApplicationChosen?.Invoke(collectionRadio, arg); } } public void Close() { lease.Release(); CollectionRadio = null; choices.Clear(); selected.Clear(); applications.Clear(); playing = null; applicationNote = null; } public void Dispose() { if (!disposed) { Close(); disposed = true; } } } } namespace SailwindRadio.Shops { internal static class NativeShopContract { internal static readonly FieldInfo KeeperRegion = typeof(Shopkeeper).GetField("parentRegion", BindingFlags.Instance | BindingFlags.NonPublic); internal static readonly FieldInfo KeeperEconomy = typeof(Shopkeeper).GetField("economy", BindingFlags.Instance | BindingFlags.NonPublic); internal static readonly FieldInfo KeeperHome = typeof(Shopkeeper).GetField("homePos", BindingFlags.Instance | BindingFlags.NonPublic); internal static readonly FieldInfo KeeperShop = typeof(Shopkeeper).GetField("shop", BindingFlags.Instance | BindingFlags.NonPublic); internal static readonly FieldInfo AreaKeeper = typeof(ShopArea).GetField("keeper", BindingFlags.Instance | BindingFlags.NonPublic); internal static bool KeeperReady(ShopArea area) { Shopkeeper shopkeeper = area.GetShopkeeper(); if (!Object.op_Implicit((Object)(object)shopkeeper)) { return false; } if (KeeperRegion?.GetValue(shopkeeper) is Region) { return KeeperShop?.GetValue(shopkeeper) == area; } return false; } } internal static class RadioShopCatalog { internal static readonly DeviceRole[] StockRoles = new DeviceRole[7] { DeviceRole.Woofer, DeviceRole.Speaker, DeviceRole.Speaker, DeviceRole.Radio, DeviceRole.Radio, DeviceRole.SmallSpeaker, DeviceRole.SmallSpeaker }; internal static int StallFamily(int island) { if (!RadioStalls.TryGet(island, out var stall)) { return 0; } return stall.Family; } internal static int StockKind(int island, int slot) { return DeviceKind.Of(StallFamily(island), StockRoles[slot]); } internal static int BasePrice(int kind) { if (!DeviceKind.IsValid(kind)) { return 0; } return DeviceKind.Role(kind) switch { DeviceRole.Speaker => 1579, DeviceRole.SmallSpeaker => 526, DeviceRole.Radio => 789, _ => 2632, }; } } internal static class RadioShopPlacement { internal static bool TryStand(IslandSceneryScene scenery, out Vector3 position, out Quaternion rotation, out string reason) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_0043: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); rotation = Quaternion.identity; reason = "not an authored capital scene"; if (!Object.op_Implicit((Object)(object)scenery) || !RadioStalls.TryGet(scenery.parentIslandIndex, out var stall)) { return false; } Vector3 val = ((Component)scenery).transform.TransformPoint(stall.SceneryAnchor); rotation = ((Component)scenery).transform.rotation * Quaternion.Euler(0f, stall.Yaw, 0f); float height; bool flag = Ground(val, out height); bool flag2 = stall.SettlesOnSupport && flag && height <= val.y + 0.02f && height >= val.y - 0.3f; position = new Vector3(val.x, (flag2 ? height : (val.y + 0.02f)) + stall.GroundVisualOffset, val.z); string text = (flag ? "" : "no level static ground at the authored anchor"); if (flag && !flag2 && Mathf.Abs(height - val.y) > 0.15f) { text = Append(text, "nearby support height differs from authored height by " + (height - val.y)); } bool flag3 = false; float[] array = new float[4] { -1.1f, 1.1f, 1.39f, 2.21f }; foreach (float num in array) { float[] array2 = new float[2] { -0.39f, 0.39f }; foreach (float num2 in array2) { if (!Ground(position + rotation * new Vector3(num, 0f, num2), out var height2) || Mathf.Abs(height2 - position.y) > 0.045f) { flag3 = true; } } } if (flag3) { text = Append(text, "uneven or missing ground beneath the display"); } Vector3 envelopeHalf = RadioStandLayout.EnvelopeHalf; if (stall.WideCounter) { envelopeHalf.x += 0.15f; } string text2 = Blocker(position + rotation * RadioStandLayout.EnvelopeCenter, envelopeHalf, rotation); if (text2 != null) { text = Append(text, "display footprint overlaps " + text2); } text2 = Blocker(position + rotation * new Vector3(0.55f, 0.91f, -1.02f), new Vector3(1.8f, 0.85f, 0.38f), rotation); if (text2 != null) { text = Append(text, "customer approach overlaps " + text2); } reason = text; return true; } private static string Append(string previous, string message) { if (previous.Length != 0) { return previous + ", " + message; } return message; } private static bool Ground(Vector3 expected, out float height) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) height = 0f; RaycastHit val = default(RaycastHit); if (!Physics.Raycast(expected + Vector3.up, Vector3.down, ref val, 3f, -1, (QueryTriggerInteraction)1) || !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider) || ((RaycastHit)(ref val)).normal.y < 0.5f || Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody) || Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<ShipItem>()) || Mathf.Abs(((RaycastHit)(ref val)).point.y - expected.y) > 1.5f) { return false; } height = ((RaycastHit)(ref val)).point.y; return true; } private static string Blocker(Vector3 center, Vector3 half, Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapBox(center, half, rotation, -1, (QueryTriggerInteraction)2); foreach (Collider val in array) { if (Object.op_Implicit((Object)(object)val) && val.enabled && (!val.isTrigger || Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<ShipItem>()))) { return ((Object)val).name; } } return null; } } internal sealed class RadioShopService : IDisposable { private sealed class Slot { internal int Kind; internal int Index; internal ShopRestock Clock = new ShopRestock(); internal GameObject Anchor; internal RadioShopStock Stock; } private sealed class Vendor { internal IslandSceneryScene Scenery; internal ShopArea Area; internal Slot[] Slots; internal RadioShopStand Stand; internal GameObject OwnedNpc; internal Shopkeeper Template; internal Collider[] MerchantTriggers; internal bool DisplayShown; internal bool InitialStockAttempted; internal float StageReadyAt = -1f; internal float NextStockAttempt; internal float NextBuildAttempt; internal bool FoundWhileStarting; internal readonly HashSet<string> ReportedReasons = new HashSet<string>(); } private static RadioShopService active; private readonly RadioWorldService world; private readonly Action<string> warn; private readonly Harmony harmony = new Harmony("local.sailwind.radio.shops"); private readonly List<Vendor> vendors = new List<Vendor>(); private SaveLoadManager session; private const float SafetyScanSeconds = 30f; private const float BuildRetrySeconds = 0.5f; private const float InPlaceDistance = 0.03f; private const float NativeStockDistance = 500f; private bool sessionScanned; private float nextSafetyScan; private bool disposed; private bool supported; internal RadioShopService(RadioWorldService world, Action<string> warn) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Expected O, but got Unknown if (active != null) { throw new InvalidOperationException("Radio shops already active"); } this.world = world; this.warn = warn ?? ((Action<string>)delegate { }); active = this; SceneManager.sceneLoaded += SceneLoaded; try { MethodInfo method = typeof(ShipItem).GetMethod("EnterBoat", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(Collider) }, null); MethodInfo method2 = typeof(Shopkeeper).GetMethod("GetPrice", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(ShipItem) }, null); if (method == null || method2 == null || method.ReturnType != typeof(void) || method2.ReturnType != typeof(int)) { throw new MissingMethodException("Native shop purchase methods changed"); } harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(RadioShopService), "BeforeEnterBoat", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)method2, new HarmonyMethod(typeof(RadioShopService), "BeforePrice", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo method3 = typeof(ShopArea).GetMethod("OnTriggerEnter", BindingFlags.Instance | BindingFlags.NonPublic); MethodInfo method4 = typeof(Shopkeeper).GetMethod("OnTriggerEnter", BindingFlags.Instance | BindingFlags.NonPublic); if (method3 == null || method4 == null) { throw new MissingMethodException("Native shop trigger methods changed"); } harmony.Patch((MethodBase)method3, new HarmonyMethod(typeof(RadioShopService), "BeforeAreaEnter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)method4, new HarmonyMethod(typeof(RadioShopService), "BeforeKeeperEnter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); supported = true; } catch (Exception ex) { harmony.UnpatchSelf(); this.warn("Radio shop stock unavailable: " + ex.Message); } } internal void Tick() { if (disposed) { return; } if ((Object)(object)session != (Object)(object)SaveLoadManager.instance || GameState.currentlyLoading) { Clear(); session = SaveLoadManager.instance; } if (GameState.currentlyLoading || !Object.op_Implicit((Object)(object)session) || !GameState.playing || GameState.loadingScenes > 0) { return; } if (!sessionScanned || Time.unscaledTime >= nextSafetyScan) { ScanScenery(); } for (int num = vendors.Count - 1; num >= 0; num--) { Vendor vendor = vendors[num]; if (!Object.op_Implicit((Object)(object)vendor.Scenery)) { Clear(vendor); vendors.RemoveAt(num); } else { if (world.ReadyToStageShop && vendor.StageReadyAt < 0f) { vendor.StageReadyAt = Time.unscaledTime; } if (!Object.op_Implicit((Object)(object)vendor.Stand) || !Object.op_Implicit((Object)(object)vendor.Area)) { Build(vendor); } if (Object.op_Implicit((Object)(object)vendor.Stand) && Object.op_Implicit((Object)(object)vendor.Area) && (world.ReadyToStageShop || !vendor.DisplayShown)) { Update(vendor); } } } } private void SceneLoaded(Scene scene, LoadSceneMode mode) { if (disposed) { return; } GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { if (Object.op_Implicit((Object)(object)val)) { IslandSceneryScene[] componentsInChildren = val.GetComponentsInChildren<IslandSceneryScene>(); foreach (IslandSceneryScene scenery in componentsInChildren) { ObserveScenery(scenery); } } } } private void ScanScenery() { sessionScanned = true; nextSafetyScan = Time.unscaledTime + 30f; IslandSceneryScene[] array = Object.FindObjectsOfType<IslandSceneryScene>(); foreach (IslandSceneryScene scenery in array) { ObserveScenery(scenery); } } private void ObserveScenery(IslandSceneryScene scenery) { if (!Object.op_Implicit((Object)(object)scenery) || !RadioStandLayout.TryAnchor(scenery.parentIslandIndex, out var _, out var _)) { return; } foreach (Vendor vendor2 in vendors) { if ((Object)(object)vendor2.Scenery == (Object)(object)scenery) { return; } } Vendor vendor = new Vendor { Scenery = scenery, Slots = new Slot[RadioShopCatalog.StockRoles.Length], FoundWhileStarting = GameState.justStarted }; for (int i = 0; i < vendor.Slots.Length; i++) { vendor.Slots[i] = new Slot { Kind = RadioShopCatalog.StockKind(scenery.parentIslandIndex, i), Index = i }; } vendors.Add(vendor); } private void Build(Vendor vendor) { if (!(Time.unscaledTime < vendor.NextBuildAttempt)) { vendor.NextBuildAttempt = Time.unscaledTime + 0.5f; if (Object.op_Implicit((Object)(object)vendor.Stand)) { TryMerchant(vendor); } else if (InPlace(vendor.Scenery)) { TryDisplay(vendor); } } } private static bool InPlace(IslandSceneryScene scenery) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) Transform[] islands = Refs.islands; int parentIslandIndex = scenery.parentIslandIndex; if (islands == null || parentIslandIndex < 0 || parentIslandIndex >= islands.Length || !Object.op_Implicit((Object)(object)islands[parentIslandIndex])) { return false; } Vector3 val = ((Component)scenery).transform.position - islands[parentIslandIndex].position; return ((Vector3)(ref val)).sqrMagnitude < 0.0009f; } private void Update(Vendor vendor) { //IL_01b2: Unknown result type (might be due to invalid IL or missing references) if (vendor.MerchantTriggers != null) { Collider[] merchantTriggers = vendor.MerchantTriggers; foreach (Collider val in merchantTriggers) { if (Object.op_Implicit((Object)(object)val) && val.enabled) { val.enabled = false; } } } bool flag = world.ReadyToStageShop && ReadyToStock(vendor); bool flag2 = ((Component)vendor.Area.GetShopkeeper()).gameObject.activeInHierarchy && (vendor.Area.openAtNight || (Object.op_Implicit((Object)(object)Sun.sun) && Sun.sun.localTime >= 7f && Sun.sun.localTime <= 18f)); bool saleReady = SaleReady(vendor, flag2); bool flag3 = false; Slot[] slots = vendor.Slots; foreach (Slot slot in slots) { slot.Clock.Tick(Time.deltaTime); if (slot.Clock.Occupied && (!Object.op_Implicit((Object)(object)slot.Stock) || slot.Stock.Purchased || ((Component)slot.Stock).GetComponent<ShipItem>().sold)) { slot.Clock.Removed(); slot.Stock = null; if (Object.op_Implicit((Object)(object)slot.Anchor)) { Object.Destroy((Object)(object)slot.Anchor); } slot.Anchor = null; } if (Object.op_Implicit((Object)(object)slot.Stock)) { ProtectStock(slot.Stock); ((Component)slot.Stock).gameObject.SetActive(StockVisible(vendor, slot.Stock, flag2, saleReady)); } else if (flag && slot.Clock.Ready && SpawnsHere(vendor, SlotPosition(vendor, slot)) && (!vendor.InitialStockAttempted || !(Time.unscaledTime < vendor.NextStockAttempt))) { flag3 = true; TryStock(vendor, slot); } } if (flag3) { vendor.InitialStockAttempted = true; vendor.NextStockAttempt = Time.unscaledTime + 5f; } if (!vendor.DisplayShown && (flag || (vendor.StageReadyAt >= 0f && Time.unscaledTime - vendor.StageReadyAt >= 5f))) { vendor.DisplayShown = true; vendor.Stand.SetVisible(visible: true); SetNpcVisible(vendor.OwnedNpc, visible: true); SphereCollider val2 = (Object.op_Implicit((Object)(object)vendor.OwnedNpc) ? vendor.OwnedNpc.GetComponent<SphereCollider>() : null); if (Object.op_Implicit((Object)(object)val2)) { ((Collider)val2).enabled = true; } saleReady = SaleReady(vendor, flag2); } else if (!vendor.DisplayShown || !flag2) { return; } slots = vendor.Slots; foreach (Slot slot2 in slots) { if (Object.op_Implicit((Object)(object)slot2.Stock)) { ((Component)slot2.Stock).gameObject.SetActive(StockVisible(vendor, slot2.Stock, flag2, saleReady)); } } } private bool SaleReady(Vendor vendor, bool open) { if (open && vendor.DisplayShown && world.ReadyForShop) { return PurchaseEnvironmentReady(vendor); } return false; } private static bool StockVisible(Vendor vendor, RadioShopStock stock, bool open, bool saleReady) { if (!saleReady) { if (open && vendor.DisplayShown) { return KeepStockActive(stock); } return false; } return true; } private void TryDisplay(Vendor vendor) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!RadioShopPlacement.TryStand(vendor.Scenery, out var position, out var rotation, out var reason)) { ReportSetupFailure(vendor, reason); return; } try { vendor.Stand = RadioShopStand.Create(((Component)vendor.Scenery).transform, position, rotation, vendor.Scenery.parentIslandIndex); vendor.Stand.SetVisible(visible: false); Physics.SyncTransforms(); TryMerchant(vendor); } catch (Exception ex) { Clear(vendor); for (int i = 0; i < vendor.Slots.Length; i++) { vendor.Slots[i] = new Slot { Kind = RadioShopCatalog.StockKind(vendor.Scenery.parentIslandIndex, i), Index = i }; } ReportSetupFailure(vendor, ex.Message); } } private void TryMerchant(Vendor vendor) { try { CreateMerchant(vendor); } catch (Exception ex) { if (Object.op_Implicit((Object)(object)vendor.Area)) { Object.Destroy((Object)(object)((Component)vendor.Area).gameObject); } if (Object.op_Implicit((Object)(object)vendor.OwnedNpc)) { Object.Destroy((Object)(object)vendor.OwnedNpc); } vendor.Area = null; vendor.OwnedNpc = null; vendor.MerchantTriggers = null; if (Object.op_Implicit((Object)(object)vendor.Stand) && vendor.StageReadyAt >= 0f && Time.unscaledTime - vendor.StageReadyAt >= 10f) { vendor.DisplayShown = true; vendor.Stand.SetVisible(visible: true); if (Time.unscaledTime - vendor.StageReadyAt >= 60f) { ReportSetupFailure(vendor, "its merchant is unavailable (" + ex.Message + ")"); } } } } private static void CreateMerchant(Vendor vendor) { //IL_0015: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Expected O, but got Unknown //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; GameObject val2 = null; try { Shopkeeper val3 = FindNativeMerchant(vendor.Scenery, ((Component)vendor.Stand).transform.position); if (!Object.op_Implicit((Object)(object)val3)) { throw new MissingComponentException("native shopkeeper template is not loaded yet"); } val2 = Object.Instantiate<GameObject>(((Component)val3).gameObject, ((Component)vendor.Scenery).transform); val2.SetActive(false); ((Object)val2).name = "Radio shopkeeper"; val2.transform.position = ((Component)vendor.Stand).transform.TransformPoint(RadioStandLayout.MerchantOffset); val2.transform.rotation = ((Component)vendor.Stand).transform.rotation * Quaternion.Euler(0f, 180f, 0f); Shopkeeper component = val2.GetComponent<Shopkeeper>(); if (!Object.op_Implicit((Object)(object)component)) { throw new MissingComponentException("native shopkeeper clone lost Shopkeeper"); } vendor.MerchantTriggers = ConfigureMerchantTriggers(val2, vendor.Scenery.parentIslandIndex); SphereCollider component2 = val2.GetComponent<SphereCollider>(); if (Object.op_Implicit((Object)(object)component2)) { ((Collider)component2).enabled = vendor.DisplayShown; } FieldInfo keeperHome = NativeShopContract.KeeperHome; if (keeperHome == null || keeperHome.FieldType != typeof(Transform)) { throw new MissingFieldException("Shopkeeper.homePos changed"); } keeperHome.SetValue(component, val2.transform); FieldInfo keeperRegion = NativeShopContract.KeeperRegion; if (keeperRegion == null || keeperRegion.FieldType != typeof(Region)) { throw new MissingFieldException("Shopkeeper.parentRegion changed"); } object? value = keeperRegion.GetValue(val3); keeperRegion.SetValue(component, (value is Region) ? value : null); vendor.Template = val3; val = new GameObject("Radio merchant area"); val.SetActive(false); val.transform.SetParent(((Component)vendor.Stand).transform, false); val.transform.localPosition = Vector3.zero; val.transform.position = ((Component)vendor.Stand).transform.position; Rigidbody obj = val.AddComponent<Rigidbody>(); obj.isKinematic = true; obj.useGravity = false; BoxCollider obj2 = val.AddComponent<BoxCollider>(); ((Collider)obj2).isTrigger = true; obj2.center = new Vector3(0f, 1.15f, 0f); obj2.size = new Vector3(2.65f, 2.3f, 1.5f); ShopArea val4 = val.AddComponent<ShopArea>(); FieldInfo areaKeeper = NativeShopContract.AreaKeeper; if (areaKeeper == null || areaKeeper.FieldType != typeof(Shopkeeper)) { throw new MissingFieldException("ShopArea.keeper changed"); } areaKeeper.SetValue(val4, component); component.RegisterShop(val4); val4.itemsForSale = new List<ShipItem>(); vendor.Area = val4; vendor.OwnedNpc = val2; SetNpcVisible(val2, vendor.DisplayShown); val2.SetActive(true); val.SetActive(true); } catch { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } if (Object.op_Implicit((Object)(object)val2)) { Object.Destroy((Object)(object)val2); } throw; } } private static void SetNpcVisible(GameObject npc, bool visible) { if (Object.op_Implicit((Object)(object)npc)) { Renderer[] componentsInChildren = npc.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = visible; } } } private static Collider[] ConfigureMerchantTriggers(GameObject npc, int islandIndex) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) List<Collider> list = new List<Collider>(); bool flag = false; RadioStall stall; float num = (RadioStalls.TryGet(islandIndex, out stall) ? stall.SaleRadius : 1.75f); Collider[] componentsInChildren = npc.GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (!val.isTrigger) { continue; } if ((Object)(object)((Component)val).transform == (Object)(object)npc.transform) { SphereCollider val2 = (SphereCollider)(object)((val is SphereCollider) ? val : null); if (val2 != null && !flag) { val2.radius = Mathf.Min(val2.radius, num); flag = true; continue; } } val.enabled = false; list.Add(val); } if (!flag) { throw new MissingComponentException("native shopkeeper root sale trigger contract changed"); } return list.ToArray(); } private static Shopkeeper FindNativeMerchant(IslandSceneryScene scenery, Vector3 standPosition) { //IL_0057: 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) Shopkeeper result = null; float num = 30f; Shopkeeper[] componentsInChildren = ((Component)scenery).GetComponentsInChildren<Shopkeeper>(true); foreach (Shopkeeper val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && (Object)(object)((Component)val).transform.parent == (Object)(object)((Component)scenery).transform && NativeKeeperName(((Object)val).name) && Object.op_Implicit((Object)(object)((Component)val).GetComponent<Renderer>())) { float num2 = Vector3.Distance(standPosition, ((Component)val).transform.position); if (num2 < num) { result = val; num = num2; } } } return result; } private static bool NativeKeeperName(string name) { if (string.Equals(name, "shopkeeper", StringComparison.OrdinalIgnoreCase)) { return true; } int result; if (name != null && name.StartsWith("shopkeeper (", StringComparison.OrdinalIgnoreCase) && name.EndsWith(")", StringComparison.Ordinal)) { return int.TryParse(name.Substring("shopkeeper (".Length, name.Length - "shopkeeper (".Length - 1), out result); } return false; } private void ReportSetupFailure(Vendor vendor, string reason) { if (vendor.ReportedReasons.Add(reason)) { warn("Radio shop at " + ((Object)vendor.Scenery).name + " could not be set up: " + reason); } } private static Vector3 SlotPosition(Vendor vendor, Slot slot) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) return ((Component)vendor.Stand).transform.TransformPoint(RadioStandLayout.Slot(vendor.Scenery.parentIslandIndex, slot.Index, vendor.Stand.UsesNativeGoldRockCounter)); } private static bool SpawnsHere(Vendor vendor, Vector3 position) { //IL_002d: 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) if (!GameState.justStarted && (!vendor.FoundWhileStarting || vendor.InitialStockAttempted)) { if (Object.op_Implicit((Object)(object)Camera.main)) { return Vector3.Distance(((Component)Camera.main).transform.position, position) < 500f; } return false; } return true; } private void TryStock(Vendor vendor, Slot slot) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0056: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) if (!ReadyToStock(vendor)) { return; } Vector3 position = SlotPosition(vendor, slot); Quaternion rotation = ((Component)vendor.Stand).transform.rotation; GameObject val = null; RadioItemController radioItemController = null; try { val = new GameObject("Radio shop stock anchor"); val.SetActive(false); val.transform.SetParent(((Component)vendor.Stand).transform, false); val.transform.position = position; val.transform.rotation = rotation; Vector3 lossyScale = val.transform.parent.lossyScale; val.transform.localScale = new Vector3(1f / lossyScale.x, 1f / lossyScale.y, 1f / lossyScale.z); ShopItemSpawner obj = val.AddComponent<ShopItemSpawner>(); ((Behaviour)obj).enabled = false; obj.priceMult = 1f; MeshRenderer component = val.GetComponent<MeshRenderer>(); if (!Object.op_Implicit((Object)(object)component)) { throw new MissingComponentException("Native shop spawner renderer was not created"); } ((Renderer)component).enabled = false; val.SetActive(true); radioItemController = world.CreateShopStock(val.transform, position, rotation, slot.Kind); if (!Object.op_Implicit((Object)(object)radioItemController)) { Object.Destroy((Object)(object)val); return; } RadioShopStock radioShopStock = ((Component)radioItemController).gameObject.AddComponent<RadioShopStock>(); radioShopStock.Service = this; radioShopStock.Shop = vendor.Area; radioShopStock.Controller = radioItemController; radioShopStock.Anchor = val.transform; ((Component)radioItemController).GetComponent<ShipItem>().AddToShop(vendor.Area); radioItemController.SetShopStock(stock: true); slot.Anchor = val; slot.Stock = radioShopStock; slot.Clock.Spawned(); ((Component)radioShopStock).gameObject.SetActive(false); Physics.SyncTransforms(); } catch (Exception ex) { if (Object.op_Implicit((Object)(object)radioItemController)) { vendor.Area.itemsForSale.Remove(((Component)radioItemController).GetComponent<ShipItem>()); Object.Destroy((Object)(object)((Component)radioItemController).gameObject); } if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } ReportSetupFailure(vendor, ex.Message); } } private bool ReadyToStock(Vendor vendor) { if (!supported || !Object.op_Implicit((Object)(object)vendor.Area)) { return false; } Shopkeeper shopkeeper = vendor.Area.GetShopkeeper(); if (!Object.op_Implicit((Object)(object)shopkeeper)) { return false; } if (Object.op_Implicit((Object)(object)KeeperRegion(vendor)) && NativeShopContract.KeeperEconomy?.GetValue(shopkeeper) != null) { return NativeShopContract.KeeperReady(vendor.Area); } return false; } private static Region KeeperRegion(Vendor vendor) { Shopkeeper shopkeeper = vendor.Area.GetShopkeeper(); object? obj = NativeShopContract.KeeperRegion?.GetValue(shopkeeper); Region val = (Region)((obj is Region) ? obj : null); if (Object.op_Implicit((Object)(object)vendor.Template)) { object? obj2 = NativeShopContract.KeeperRegion?.GetValue(vendor.Template); Region val2 = (Region)((obj2 is Region) ? obj2 : null); if (val2 != null && Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)val) { NativeShopContract.KeeperRegion.SetValue(shopkeeper, val2); val = val2; } } return val; } private bool PurchaseEnvironmentReady(Vendor vendor) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected I4, but got Unknown if (!ReadyToStock(vendor) || vendor.Area.itemsForSale == null) { return false; } int num = (int)KeeperRegion(vendor).portRegion; if (num >= 0 && PlayerGold.currency != null && PlayerGold.currency.Length > num && PlayerReputation.retailDiscounts != null && PlayerReputation.retailDiscounts.Length > num && Object.op_Implicit((Object)(object)CurrencyMarket.instance) && Object.op_Implicit((Object)(object)UISoundPlayer.instance) && Object.op_Implicit((Object)(object)BuyItemUI.instance) && Object.op_Implicit((Object)(object)DayLogs.instance) && DayLogs.instance.dayLogs != null && DayLogs.instance.dayLogs.Length > num && DayLogs.instance.dayLogs[num] != null) { return Object.op_Implicit((Object)(object)MoneyNotification.instance); } return false; } private static bool BeforeAreaEnter(ShopArea __instance, Collider other) { if (active == null) { return true; } Shopkeeper val = (Object.op_Implicit((Object)(object)other) ? ((Component)other).GetComponentInParent<Shopkeeper>() : null); ShipItem val2 = (Object.op_Implicit((Object)(object)other) ? ((Component)other).GetComponentInParent<ShipItem>() : null); RadioShopStock radioShopStock = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<RadioShopStock>() : null); bool flag = Object.op_Implicit((Object)(object)radioShopStock) && radioShopStock.Service == active && (!radioShopStock.Purchased || !val2.sold); if (!active.Owns(__instance)) { if (!Object.op_Implicit((Object)(object)val) || !active.Owns(val)) { return !flag; } return false; } if (Object.op_Implicit((Object)(object)val)) { return (Object)(object)val == (Object)(object)__instance.GetShopkeeper(); } if (Object.op_Implicit((Object)(object)val2) && (!Object.op_Implicit((Object)(object)radioShopStock) || !radioShopStock.Purchased || !val2.sold)) { if (flag) { return (Object)(object)radioShopStock.Shop == (Object)(object)__instance; } return false; } return true; } private static bool BeforeKeeperEnter(Shopkeeper __instance, Collider other) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (active == null) { return true; } ShipItem val = (Object.op_Implicit((Object)(object)other) ? ((Component)other).GetComponentInParent<ShipItem>() : null); RadioShopStock radioShopStock = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<RadioShopStock>() : null); bool flag = Object.op_Implicit((Object)(object)radioShopStock) && radioShopStock.Service == active && (!radioShopStock.Purchased || !val.sold); if (!active.Owns(__instance)) { return !flag; } if (!Object.op_Implicit((Object)(object)val)) { return true; } if (flag) { if (Object.op_Implicit((Object)(object)radioShopStock.Shop)) { return (Object)(object)radioShopStock.Shop.GetShopkeeper() == (Object)(object)__instance; } return false; } foreach (Vendor vendor in active.vendors) { if (Object.op_Implicit((Object)(object)vendor.OwnedNpc) && (Object)(object)vendor.OwnedNpc.GetComponent<Shopkeeper>() == (Object)(object)__instance) { return val.sold && Object.op_Implicit((Object)(object)((PickupableItem)val).held) && active.world.ReadyForShop && active.ReadyToStock(vendor) && Object.op_Implicit((Object)(object)Camera.main) && Vector3.Distance(((Component)Camera.main).transform.position, ((Component)vendor.Stand).transform.position) <= 3.25f; } } return false; } private bool Owns(ShopArea area) { foreach (Vendor vendor in vendors) { if ((Object)(object)vendor.Area == (Object)(object)area) { return true; } } return false; } private bool Owns(Shopkeeper keeper) { foreach (Vendor vendor in vendors) { if (Object.op_Implicit((Object)(object)vendor.OwnedNpc) && (Object)(object)vendor.OwnedNpc.GetComponent<Shopkeeper>() == (Object)(object)keeper) { return true; } } return false; } private static bool KeepStockActive(RadioShopStock stock) { ShipItem component = ((Component)stock).GetComponent<ShipItem>(); BoxCollider component2 = ((Component)stock).GetComponent<BoxCollider>(); if (Object.op_Implicit((Object)(object)component)) { if (!Object.op_Implicit((Object)(object)((PickupableItem)component).held)) { if (Object.op_Implicit((Object)(object)component2)) { return !((Collider)component2).enabled; } return false; } return true; } return false; } private static void ProtectStock(RadioShopStock stock) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) ShipItem component = ((Component)stock).GetComponent<ShipItem>(); if (Object.op_Implicit((Object)(object)component) && !component.sold && !stock.Purchased && Object.op_Implicit((Object)(object)stock.Anchor)) { if (Object.op_Implicit((Object)(object)stock.Shop) && stock.Shop.itemsForSale != null && !stock.Shop.itemsForSale.Contains(component)) { stock.Shop.itemsForSale.Add(component); } if ((Object)(object)((Component)component).transform.parent != (Object)(object)stock.Anchor) { ((Component)component).transform.SetParent(stock.Anchor, true); } if (Object.op_Implicit((Object)(object)((PickupableItem)component).held) && Vector3.Distance(((Component)component).transform.position, stock.Anchor.position) > 1.8f) { component.ReturnToShopPos(); } } } private static void BeforePrice(ShipItem item) { RadioShopStock radioShopStock = (Object.op_Implicit((Object)(object)item) ? ((Component)item).GetComponent<RadioShopStock>() : null); if (Object.op_Implicit((Object)(object)radioShopStock)) { ProtectStock(radioShopStock); } } private static bool BeforeEnterBoat(ShipItem __instance) { if (!__instance.sold) { return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RadioShopStock>()); } return true; } private static void Clear(Vendor vendor) { Slot[] slots = vendor.Slots; foreach (Slot slot in slots) { if (Object.op_Implicit((Object)(object)slot.Stock) && !((Component)slot.Stock).GetComponent<ShipItem>().sold) { if (Object.op_Implicit((Object)(object)vendor.Area)) { vendor.Area.itemsForSale.Remove(((Component)slot.Stock).GetComponent<ShipItem>()); } Object.Destroy((Object)(object)((Component)slot.Stock).gameObject); } if (Object.op_Implicit((Object)(object)slot.Anchor)) { Object.Destroy((Object)(object)slot.Anchor); } } if (Object.op_Implicit((Object)(object)vendor.Stand)) { Object.Destroy((Object)(object)((Component)vendor.Stand).gameObject); } if (Object.op_Implicit((Object)(object)vendor.Area)) { Object.Destroy((Object)(object)((Component)vendor.Area).gameObject); } if (Object.op_Implicit((Object)(object)vendor.OwnedNpc)) { Object.Destroy((Object)(object)vendor.OwnedNpc); } vendor.Stand = null; vendor.Area = null; vendor.OwnedNpc = null; vendor.MerchantTriggers = null; vendor.DisplayShown = false; vendor.InitialStockAttempted = false; vendor.StageReadyAt = -1f; vendor.NextStockAttempt = 0f; } private void Clear() { foreach (Vendor vendor in vendors) { Clear(vendor); } vendors.Clear(); sessionScanned = false; } public void Dispose() { if (!disposed) { disposed = true; SceneManager.sceneLoaded -= SceneLoaded; Clear(); harmony.UnpatchSelf(); if (active == this) { active = null; } } } } internal sealed class RadioShopStand : MonoBehaviour { private Material wood; private Material platformWood; private Material canvas; private Material roofWood; private readonly List<Renderer> structureRenderers = new List<Renderer>(); private readonly List<Collider> structureColliders = new List<Collider>(); internal bool UsesNativeGoldRockCounter { get; private set; } internal void SetVisible(bool visible) { foreach (Renderer structureRenderer in structureRenderers) { if (Object.op_Implicit((Object)(object)structureRenderer)) { structureRenderer.enabled = visible; } } foreach (Collider structureCollider in structureColliders) { if (Object.op_Implicit((Object)(object)structureCollider)) { structureCollider.enabled = visible; } } } internal static RadioShopStand Create(Transform scenery, Vector3 position, Quaternion rotation, int island) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_004e: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_073b: Unknown result type (might be due to invalid IL or missing references) //IL_074f: Unknown result type (might be due to invalid IL or missing references) //IL_0773: Unknown result type (might be due to invalid IL or missing references) //IL_0792: Unknown result type (might be due to invalid IL or missing references) //IL_07a6: Unknown result type (might be due to invalid IL or missing references) //IL_07ca: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_065a: Unknown result type (might be due to invalid IL or missing references) //IL_066e: Unknown result type (might be due to invalid IL or missing references) //IL_0692: Unknown result type (might be due to invalid IL or missing references) //IL_06bf: Unknown result type (might be due to invalid IL or missing references) //IL_06d3: Unknown result type (might be due to invalid IL or missing references) //IL_06fc: Unknown result type (might be due to invalid IL or missing references) //IL_0710: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Unknown result type (might be due to invalid IL or missing references) //IL_05fe: Unknown result type (might be due to invalid IL or missing references) //IL_060f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Radio merchant display"); try { val.transform.SetParent(scenery, false); val.transform.position = position; val.transform.rotation = rotation; Vector3 lossyScale = scenery.lossyScale; val.transform.localScale = new Vector3(1f / lossyScale.x, 1f / lossyScale.y, 1f / lossyScale.z); RadioShopStand radioShopStand = val.AddComponent<RadioShopStand>(); Shader val2 = Shader.Find("Standard"); if (!Object.op_Implicit((Object)(object)val2)) { throw new InvalidOperationException("Display stand shader unavailable"); } Material val3 = new Material(val2); Color color; switch (island) { default: color = new Color(0.39f, 0.24f, 0.15f); break; case 15: case 25: color = new Color(0.37f, 0.29f, 0.23f); break; case 9: color = new Color(0.31f, 0.18f, 0.14f); break; } val3.color = color; radioShopStand.wood = val3; radioShopStand.wood.SetFloat("_Glossiness", 0.16f); if (island == 9) { radioShopStand.platformWood = new Material(val2) { color = new Color(0.34f, 0.23f, 0.18f) }; radioShopStand.platformWood.SetFloat("_Glossiness", 0.1f); radioShopStand.roofWood = new Material(val2) { color = new Color(0.25f, 0.14f, 0.11f) }; radioShopStand.roofWood.SetFloat("_Glossiness", 0.1f); } radioShopStand.canvas = new Material(val2) { color = ((island == 9) ? new Color(0.36f, 0.2f, 0.16f) : new Color(0.42f, 0.21f, 0.15f)) }; radioShopStand.canvas.SetFloat("_Glossiness", 0.05f); if (!(radioShopStand.UsesNativeGoldRockCounter = island == 1 && radioShopStand.NativeGoldRockStall(scenery))) { radioShopStand.Board("Flat display top", new Vector3(0f, 0.78f, 0f), new Vector3(2.36f, 0.075f, 1.13f)); radioShopStand.Board("Front retaining lip", new Vector3(0f, 0.78f, -0.55f), new Vector3(2.38f, 0.09f, 0.055f)); radioShopStand.Board("Rear retaining lip", new Vector3(0f, 0.78f, 0.55f), new Vector3(2.38f, 0.09f, 0.055f)); for (int i = -1; i <= 1; i += 2) { radioShopStand.Board("Side retaining lip", new Vector3((float)i * 1.17f, 0.78f, 0f), new Vector3(0.055f, 0.09f, 1.1f)); } for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { radioShopStand.Board("Wooden leg", new Vector3((float)j * 1.06f, 0.38f, (float)k * 0.44f), new Vector3(0.105f, 0.76f, 0.105f)); } } radioShopStand.Board("Rear brace", new Vector3(0f, 0.37f, 0.45f), new Vector3(2.2f, 0.09f, 0.08f)); radioShopStand.Board("Front brace", new Vector3(0f, 0.26f, -0.45f), new Vector3(2.2f, 0.09f, 0.08f)); } if (island == 9 && !radioShopStand.NativeDragonCliffsDeck(scenery)) { for (int l = -5; l <= 7; l++) { radioShopStand.Board("Dragon Cliffs platform plank", new Vector3((float)l * 0.33f, -0.045f, 0.7f), new Vector3(0.31f, 0.09f, 3.8f), radioShopStand.platformWood); } for (int m = -1; m <= 1; m += 2) { radioShopStand.Board("Platform cross beam", new Vector3(0.33f, -0.13f, 0.7f + (float)m * 1.8f), new Vector3(4.28f, 0.15f, 0.1f), radioShopStand.platformWood); } for (int n = -5; n <= 7; n++) { radioShopStand.Board("Rear Dragon Cliffs platform plank", new Vector3((float)n * 0.33f, -0.045f, 4.9f), new Vector3(0.31f, 0.09f, 3.8f), radioShopStand.platformWood); } for (int num = 4; num <= 16; num++) { radioShopStand.Board("Left Dragon Cliffs platform plank", new Vector3((float)num * 0.33f, -0.05f, 0.7f), new Vector3(0.31f, 0.09f, 3.8f), radioShopStand.platformWood); } for (int num2 = -1; num2 <= 1; num2 += 2) { radioShopStand.Board("Left platform cross beam", new Vector3(3.2f, -0.135f, 0.7f + (float)num2 * 1.8f), new Vector3(4.2f, 0.15f, 0.1f), radioShopStand.platformWood); } } bool flag2 = island == 9 && radioShopStand.NativeDragonCliffsVisual(scenery, "east_market_roof", "east_market_roof", "Dragon Cliffs native canopy", new Vector3(0f, 2.05f, 0.1875f), 0.65f, solid: false); if ((island == 9 && !flag2) || island == 15) { float num3 = ((island == 9) ? 0.1875f : 0f); for (int num4 = -1; num4 <= 1; num4 += 2) { for (int num5 = -1; num5 <= 1; num5 += 2) { float num6 = ((island == 9) ? ((num5 < 0) ? 2.36f : 2.66f) : 2.5f); radioShopStand.Board("Canopy post", new Vector3((float)num4 * 1.34f, num6 / 2f, 0.35f + (float)num5 * 1.05f + num3), new Vector3(0.065f, num6, 0.065f)); } } if (island == 9) { for (int num7 = -1; num7 <= 1; num7++) { radioShopStand.Board("Dragon Cliffs canvas roof panel", new Vector3((float)num7 * 0.98f, 2.53f, 0.35f + num3), new Vector3(0.99f, 0.04f, 2.45f), radioShopStand.canvas).transform.localRotation = Quaternion.Euler(-7f, 0f, 0f); } radioShopStand.Board("Dragon Cliffs hanging front fabric", new Vector3(0f, 2.29f, -0.88f + num3), new Vector3(2.9f, 0.18f, 0.045f), radioShopStand.canvas); radioShopStand.Board("Dragon Cliffs front wood rail", new Vector3(0f, 2.39f, -0.88f + num3), new Vector3(2.9f, 0.075f, 0.065f), radioShopStand.roofWood); } else { radioShopStand.Board("Canvas canopy left", new Vector3(-0.72f, 2.52f, 0.35f), new Vector3(1.5f, 0.055f, 2.35f), radioShopStand.canvas).transform.localRotation = Quaternion.Euler(0f, 0f, 7f); radioShopStand.Board("Canvas canopy right", new Vector3(0.72f, 2.52f, 0.35f), new Vector3(1.5f, 0.055f, 2.35f), radioShopStand.canvas).transform.localRotation = Quaternion.Euler(0f, 0f, -7f); } } return radioShopStand; } catch { Object.Destroy((Object)(object)val); throw; } } private GameObject Board(string name, Vector3 center, Vector3 size, Material material = null) { //IL_0026: 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) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = name; val.transform.SetParent(((Component)this).transform, false); val.transform.localPosition = center; val.transform.localScale = size; Renderer component = val.GetComponent<Renderer>(); component.sharedMaterial = (Object.op_Implicit((Object)(object)material) ? material : wood); structureRenderers.Add(component); structureColliders.Add(val.GetComponent<Collider>()); return val; } private bool NativeGoldRockStall(Transform scenery) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) MeshFilter val = null; MeshRenderer val2 = null; float num = 30f; MeshFilter[] componentsInChildren = ((Component)scenery).GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val3 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.sharedMesh) || ((Object)val3).name != "market_stall (2)" || ((Object)val3.sharedMesh).name != "market_stall_001") { continue; } MeshRenderer component = ((Component)val3).GetComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)component) && ((Renderer)component).sharedMaterials.Length == 1 && Object.op_Implicit((Object)(object)((Renderer)component).sharedMaterials[0]) && !(((Object)((Renderer)component).sharedMaterials[0]).name != "buildings_A_paint")) { float num2 = Vector3.Distance(((Component)val3).transform.position, ((Component)this).transform.position); if (!(num2 >= num)) { val = val3; val2 = component; num = num2; } } } if (!Object.op_Implicit((Object)(object)val)) { return false; } GameObject val4 = new GameObject("Gold Rock native covered market stall"); val4.transform.SetParent(((Component)this).transform, false); val4.transform.localRotation = Quaternion.Euler(0f, 181f, 0f) * Quaternion.LookRotation(Vector3.up, Vector3.left); val4.transform.localScale = ((Component)val).transform.lossyScale; val4.transform.localPosition = new Vector3(0f, 1.045f, 0.24f); val4.AddComponent<MeshFilter>().sharedMesh = val.sharedMesh; MeshRenderer val5 = val4.AddComponent<MeshRenderer>(); ((Renderer)val5).sharedMaterials = ((Renderer)val2).sharedMaterials; structureRenderers.Add((Renderer)(object)val5); Support("Gold Rock front plank support", new Vector3(0f, 0.86f, -0.4625f), new Vector3(2.52f, 0.06f, 0.315f), 0f); Support("Gold Rock middle plank support", new Vector3(0f, 0.89f, 0.02f), new Vector3(2.7f, 0.06f, 0.65f), -2.6f); Support("Gold Rock rear plank
BepInEx/plugins/SailwindRadio/NLayer.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; using NLayer.Decoder; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Mark Heath, Andrew Ward")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Fully Managed MPEG 1 & 2 Decoder for Layers 1, 2, & 3")] [assembly: AssemblyFileVersion("1.16.0.0")] [assembly: AssemblyInformationalVersion("1.16.0+c88b0d8abfa15c1e506106931ea8410170dc6326")] [assembly: AssemblyProduct("NLayer")] [assembly: AssemblyTitle("NLayer")] [assembly: AssemblyVersion("1.16.0.0")] namespace NLayer { public enum MpegVersion { Unknown = 0, Version1 = 10, Version2 = 20, Version25 = 25 } public enum MpegLayer { Unknown, LayerI, LayerII, LayerIII } public enum MpegChannelMode { Stereo, JointStereo, DualChannel, Mono } public enum StereoMode { Both, LeftOnly, RightOnly, DownmixToMono } public interface IMpegFrame { int SampleRate { get; } int SampleRateIndex { get; } int FrameLength { get; } int BitRate { get; } MpegVersion Version { get; } MpegLayer Layer { get; } MpegChannelMode ChannelMode { get; } int ChannelModeExtension { get; } int SampleCount { get; } int BitRateIndex { get; } bool IsCopyrighted { get; } bool HasCrc { get; } bool IsCorrupted { get; } void Reset(); int ReadBits(int bitCount); } public class MpegFile : IDisposable { private Stream _stream; private bool _closeStream; private bool _eofFound; private MpegStreamReader _reader; private MpegFrameDecoder _decoder; private object _seekLock = new object(); private long _position; private float[] _readBuf = new float[2304]; private int _readBufLen; private int _readBufOfs; public int SampleRate => _reader.SampleRate; public int Channels => _reader.Channels; public bool CanSeek => _reader.CanSeek; public long Length => _reader.SampleCount * _reader.Channels * 4; public TimeSpan Duration { get { long sampleCount = _reader.SampleCount; if (sampleCount == -1) { return TimeSpan.Zero; } return TimeSpan.FromSeconds((double)sampleCount / (double)_reader.SampleRate); } } public long Position { get { return _position; } set { if (!_reader.CanSeek) { throw new InvalidOperationException("Cannot Seek!"); } if (value < 0) { throw new ArgumentOutOfRangeException("value"); } long num = value / 4 / _reader.Channels; int num2 = 0; if (num >= _reader.FirstFrameSampleCount) { num2 = _reader.FirstFrameSampleCount; num -= num2; } lock (_seekLock) { long num3 = _reader.SeekTo(num); if (num3 == -1) { throw new ArgumentOutOfRangeException("value"); } _decoder.Reset(); if (num2 != 0) { _decoder.DecodeFrame(_reader.NextFrame(), _readBuf, 0); num3 += num2; } _position = num3 * 4 * _reader.Channels; _eofFound = false; _readBufOfs = (_readBufLen = 0); } } } public TimeSpan Time { get { return TimeSpan.FromSeconds((double)_position / 4.0 / (double)_reader.Channels / (double)_reader.SampleRate); } set { Position = (long)(value.TotalSeconds * (double)_reader.SampleRate * (double)_reader.Channels * 4.0); } } public StereoMode StereoMode { get { return _decoder.StereoMode; } set { _decoder.StereoMode = value; } } public MpegFile(string fileName) { Init(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), closeStream: true); } public MpegFile(Stream stream) { Init(stream, closeStream: false); } private void Init(Stream stream, bool closeStream) { _stream = stream; _closeStream = closeStream; _reader = new MpegStreamReader(_stream); _decoder = new MpegFrameDecoder(); } public void Dispose() { if (_closeStream) { _stream.Dispose(); _closeStream = false; } } public void SetEQ(float[] eq) { _decoder.SetEQ(eq); } public int ReadSamples(byte[] buffer, int index, int count) { if (index < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("index"); } count -= count % 4; return ReadSamplesImpl(buffer, index, count, 32); } public int ReadSamples(float[] buffer, int index, int count) { if (index < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("index"); } return ReadSamplesImpl(buffer, index * 4, count * 4, 32) / 4; } public int ReadSamplesInt16(byte[] buffer, int index, int count) { if (index < 0 || index + count > buffer.Length * 2) { throw new ArgumentOutOfRangeException("index"); } return ReadSamplesImpl(buffer, index, count, 16) * 2 / 4; } public int ReadSamplesInt8(byte[] buffer, int index, int count) { if (index < 0 || index + count > buffer.Length * 4) { throw new ArgumentOutOfRangeException("index"); } return ReadSamplesImpl(buffer, index, count, 8) / 4; } private int ReadSamplesImpl(Array buffer, int index, int count, int bitDepth) { int num = 0; lock (_seekLock) { while (count > 0) { if (_readBufLen > _readBufOfs) { int num2 = _readBufLen - _readBufOfs; if (num2 > count) { num2 = count; } if (bitDepth == 32) { Buffer.BlockCopy(_readBuf, _readBufOfs, buffer, index, num2); } else { for (int i = 0; i < num2 / 4; i++) { switch (bitDepth) { case 8: buffer.SetValue((byte)Math.Round(127.5f * _readBuf[_readBufOfs / 4 + i] + 127.5f), index / 4 + i); break; case 16: { int num3 = (int)Math.Round(32767.5f * _readBuf[_readBufOfs / 4 + i] - 0.5f); if (num3 < 0) { num3 += 65536; } buffer.SetValue((byte)(num3 % 256), 2 * (index / 4 + i)); buffer.SetValue((byte)(num3 / 256), 2 * (index / 4 + i) + 1); break; } } } } num += num2; count -= num2; index += num2; _position += num2; _readBufOfs += num2; if (_readBufOfs == _readBufLen) { _readBufLen = 0; } } if (_readBufLen != 0) { continue; } if (_eofFound) { break; } MpegFrame mpegFrame = _reader.NextFrame(); if (mpegFrame == null) { _eofFound = true; break; } try { _readBufLen = _decoder.DecodeFrame(mpegFrame, _readBuf, 0) * 4; _readBufOfs = 0; } catch (InvalidDataException) { _decoder.Reset(); _readBufOfs = (_readBufLen = 0); } catch (EndOfStreamException) { _eofFound = true; break; } finally { mpegFrame.ClearBuffer(); } } } return num; } } public class MpegFrameDecoder { private LayerIDecoder _layerIDecoder; private LayerIIDecoder _layerIIDecoder; private LayerIIIDecoder _layerIIIDecoder; private float[] _eqFactors; private float[] _ch0; private float[] _ch1; public StereoMode StereoMode { get; set; } public MpegFrameDecoder() { _ch0 = new float[1152]; _ch1 = new float[1152]; } public void SetEQ(float[] eq) { if (eq != null) { float[] array = new float[32]; for (int i = 0; i < eq.Length; i++) { array[i] = (float)Math.Pow(2.0, eq[i] / 6f); } _eqFactors = array; } else { _eqFactors = null; } } public int DecodeFrame(IMpegFrame frame, byte[] dest, int destOffset) { if (frame == null) { throw new ArgumentNullException("frame"); } if (dest == null) { throw new ArgumentNullException("dest"); } if (destOffset % 4 != 0) { throw new ArgumentException("Must be an even multiple of 4", "destOffset"); } if ((dest.Length - destOffset) / 4 < ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) * frame.SampleCount) { throw new ArgumentException("Buffer not large enough! Must be big enough to hold the frame's entire output. This is up to 9,216 bytes.", "dest"); } return DecodeFrameImpl(frame, dest, destOffset / 4) * 4; } public int DecodeFrame(IMpegFrame frame, float[] dest, int destOffset) { if (frame == null) { throw new ArgumentNullException("frame"); } if (dest == null) { throw new ArgumentNullException("dest"); } if (dest.Length - destOffset < ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) * frame.SampleCount) { throw new ArgumentException("Buffer not large enough! Must be big enough to hold the frame's entire output. This is up to 2,304 elements.", "dest"); } return DecodeFrameImpl(frame, dest, destOffset); } private int DecodeFrameImpl(IMpegFrame frame, Array dest, int destOffset) { frame.Reset(); LayerDecoderBase layerDecoderBase = null; switch (frame.Layer) { case MpegLayer.LayerI: if (_layerIDecoder == null) { _layerIDecoder = new LayerIDecoder(); } layerDecoderBase = _layerIDecoder; break; case MpegLayer.LayerII: if (_layerIIDecoder == null) { _layerIIDecoder = new LayerIIDecoder(); } layerDecoderBase = _layerIIDecoder; break; case MpegLayer.LayerIII: if (_layerIIIDecoder == null) { _layerIIIDecoder = new LayerIIIDecoder(); } layerDecoderBase = _layerIIIDecoder; break; } if (layerDecoderBase != null) { layerDecoderBase.SetEQ(_eqFactors); layerDecoderBase.StereoMode = StereoMode; int num = layerDecoderBase.DecodeFrame(frame, _ch0, _ch1); if (frame.ChannelMode == MpegChannelMode.Mono) { Buffer.BlockCopy(_ch0, 0, dest, destOffset * 4, num * 4); } else { for (int i = 0; i < num; i++) { Buffer.BlockCopy(_ch0, i * 4, dest, destOffset * 4, 4); destOffset++; Buffer.BlockCopy(_ch1, i * 4, dest, destOffset * 4, 4); destOffset++; } num *= 2; } return num; } return 0; } public void Reset() { if (_layerIDecoder != null) { _layerIDecoder.ResetForSeek(); } if (_layerIIDecoder != null) { _layerIIDecoder.ResetForSeek(); } if (_layerIIIDecoder != null) { _layerIIIDecoder.ResetForSeek(); } } } } namespace NLayer.Decoder { internal class BitReservoir { private byte[] _buf = new byte[8192]; private int _start; private int _end = -1; private int _bitsLeft; private long _bitsRead; public int BitsAvailable { get { if (_bitsLeft > 0) { return (_end + _buf.Length - _start) % _buf.Length * 8 + _bitsLeft; } return 0; } } public long BitsRead => _bitsRead; private static int GetSlots(IMpegFrame frame) { int num = frame.FrameLength - 4; if (frame.HasCrc) { num -= 2; } if (frame.Version == MpegVersion.Version1 && frame.ChannelMode != MpegChannelMode.Mono) { return num - 32; } if (frame.Version > MpegVersion.Version1 && frame.ChannelMode == MpegChannelMode.Mono) { return num - 9; } return num - 17; } public bool AddBits(IMpegFrame frame, int overlap) { int end = _end; int num = GetSlots(frame); while (--num >= 0) { int num2 = frame.ReadBits(8); if (num2 == -1) { throw new InvalidDataException("Frame did not have enough bytes!"); } _buf[++_end] = (byte)num2; if (_end == _buf.Length - 1) { _end = -1; } } _bitsLeft = 8; if (end == -1) { return overlap == 0; } if ((end + 1 - _start + _buf.Length) % _buf.Length >= overlap) { _start = (end + 1 - overlap + _buf.Length) % _buf.Length; return true; } _start = end + overlap; return false; } public int GetBits(int count) { int readCount; int result = TryPeekBits(count, out readCount); if (readCount < count) { throw new InvalidDataException("Reservoir did not have enough bytes!"); } SkipBits(count); return result; } public int Get1Bit() { if (_bitsLeft == 0) { throw new InvalidDataException("Reservoir did not have enough bytes!"); } _bitsLeft--; _bitsRead++; int result = (_buf[_start] >> _bitsLeft) & 1; if (_bitsLeft == 0 && (_start = (_start + 1) % _buf.Length) != _end + 1) { _bitsLeft = 8; } return result; } public int TryPeekBits(int count, out int readCount) { if (count < 0 || count > 32) { throw new ArgumentOutOfRangeException("count", "Must return between 0 and 32 bits!"); } if (_bitsLeft == 0 || count == 0) { readCount = 0; return 0; } int num = _buf[_start]; if (count < _bitsLeft) { num >>= _bitsLeft - count; num &= (1 << count) - 1; readCount = count; return num; } num &= (1 << _bitsLeft) - 1; count -= _bitsLeft; readCount = _bitsLeft; int num2 = _start; while (count > 0 && (num2 = (num2 + 1) % _buf.Length) != _end + 1) { int num3 = Math.Min(count, 8); num <<= num3; num |= _buf[num2] >> (8 - num3) % 8; count -= num3; readCount += num3; } return num; } public void SkipBits(int count) { if (count > 0) { if (count > BitsAvailable) { throw new ArgumentOutOfRangeException("count"); } int num = 8 - _bitsLeft + count; _start = (num / 8 + _start) % _buf.Length; _bitsLeft = 8 - num % 8; _bitsRead += count; } } public void RewindBits(int count) { _bitsLeft += count; _bitsRead -= count; while (_bitsLeft > 8) { _start--; _bitsLeft -= 8; } while (_start < 0) { _start += _buf.Length; } } public void FlushBits() { if (_bitsLeft < 8) { SkipBits(_bitsLeft); } } public void Reset() { _start = 0; _end = -1; _bitsLeft = 0; } } internal abstract class FrameBase { private static int _totalAllocation; private MpegStreamReader _reader; private byte[] _savedBuffer; internal static int TotalAllocation => Interlocked.CompareExchange(ref _totalAllocation, 0, 0); internal long Offset { get; private set; } internal int Length { get; set; } internal bool Validate(long offset, MpegStreamReader reader) { Offset = offset; _reader = reader; int num = Validate(); if (num > 0) { Length = num; return true; } return false; } protected int Read(int offset, byte[] buffer) { return Read(offset, buffer, 0, buffer.Length); } protected int Read(int offset, byte[] buffer, int index, int count) { if (_savedBuffer != null) { if (index < 0 || index + count > buffer.Length) { return 0; } if (offset < 0 || offset >= _savedBuffer.Length) { return 0; } if (offset + count > _savedBuffer.Length) { count = _savedBuffer.Length - index; } Array.Copy(_savedBuffer, offset, buffer, index, count); return count; } return _reader.Read(Offset + offset, buffer, index, count); } protected int ReadByte(int offset) { if (_savedBuffer != null) { if (offset < 0) { throw new ArgumentOutOfRangeException(); } if (offset >= _savedBuffer.Length) { return -1; } return _savedBuffer[offset]; } return _reader.ReadByte(Offset + offset); } protected abstract int Validate(); internal void SaveBuffer() { _savedBuffer = new byte[Length]; _reader.Read(Offset, _savedBuffer, 0, Length); Interlocked.Add(ref _totalAllocation, Length); } internal void ClearBuffer() { Interlocked.Add(ref _totalAllocation, -Length); _savedBuffer = null; } internal virtual void Parse() { } } internal class Huffman { private class HuffmanListNode { internal byte Value; internal int Length; internal int Bits; internal int Mask; internal HuffmanListNode Next; } private static readonly byte[][,] _codeTables; private static readonly float[] _floatLookup; private static HuffmanListNode[] _llCache; private static int[] _llCacheMaxBits; private static readonly int[] LIN_BITS; static Huffman() { _codeTables = new byte[17][,] { new byte[7, 2] { { 2, 1 }, { 0, 0 }, { 2, 1 }, { 0, 16 }, { 2, 1 }, { 0, 1 }, { 0, 17 } }, new byte[17, 2] { { 2, 1 }, { 0, 0 }, { 4, 1 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 2, 1 }, { 0, 17 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 33 }, { 2, 1 }, { 0, 18 }, { 2, 1 }, { 0, 2 }, { 0, 34 } }, new byte[17, 2] { { 4, 1 }, { 2, 1 }, { 0, 0 }, { 0, 1 }, { 2, 1 }, { 0, 17 }, { 2, 1 }, { 0, 16 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 33 }, { 2, 1 }, { 0, 18 }, { 2, 1 }, { 0, 2 }, { 0, 34 } }, new byte[31, 2] { { 2, 1 }, { 0, 0 }, { 4, 1 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 2, 1 }, { 0, 17 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 34 }, { 0, 48 }, { 2, 1 }, { 0, 3 }, { 0, 19 }, { 2, 1 }, { 0, 49 }, { 2, 1 }, { 0, 50 }, { 2, 1 }, { 0, 35 }, { 0, 51 } }, new byte[31, 2] { { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 0 }, { 0, 16 }, { 0, 17 }, { 6, 1 }, { 2, 1 }, { 0, 1 }, { 2, 1 }, { 0, 32 }, { 0, 33 }, { 6, 1 }, { 2, 1 }, { 0, 18 }, { 2, 1 }, { 0, 2 }, { 0, 34 }, { 4, 1 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 4, 1 }, { 2, 1 }, { 0, 48 }, { 0, 50 }, { 2, 1 }, { 0, 35 }, { 2, 1 }, { 0, 3 }, { 0, 51 } }, new byte[71, 2] { { 2, 1 }, { 0, 0 }, { 4, 1 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 8, 1 }, { 2, 1 }, { 0, 17 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 0, 33 }, { 18, 1 }, { 6, 1 }, { 2, 1 }, { 0, 18 }, { 2, 1 }, { 0, 34 }, { 0, 48 }, { 4, 1 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 4, 1 }, { 2, 1 }, { 0, 3 }, { 0, 50 }, { 2, 1 }, { 0, 35 }, { 0, 4 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 64 }, { 0, 65 }, { 2, 1 }, { 0, 20 }, { 2, 1 }, { 0, 66 }, { 0, 36 }, { 12, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 51 }, { 0, 67 }, { 0, 80 }, { 4, 1 }, { 2, 1 }, { 0, 52 }, { 0, 5 }, { 0, 81 }, { 6, 1 }, { 2, 1 }, { 0, 21 }, { 2, 1 }, { 0, 82 }, { 0, 37 }, { 4, 1 }, { 2, 1 }, { 0, 68 }, { 0, 53 }, { 4, 1 }, { 2, 1 }, { 0, 83 }, { 0, 84 }, { 2, 1 }, { 0, 69 }, { 0, 85 } }, new byte[71, 2] { { 6, 1 }, { 2, 1 }, { 0, 0 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 2, 1 }, { 0, 17 }, { 4, 1 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 14, 1 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 2, 1 }, { 0, 34 }, { 4, 1 }, { 2, 1 }, { 0, 48 }, { 0, 3 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 2, 1 }, { 0, 64 }, { 0, 4 }, { 2, 1 }, { 0, 65 }, { 2, 1 }, { 0, 20 }, { 0, 66 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 36 }, { 2, 1 }, { 0, 51 }, { 0, 80 }, { 4, 1 }, { 2, 1 }, { 0, 67 }, { 0, 52 }, { 0, 81 }, { 6, 1 }, { 2, 1 }, { 0, 21 }, { 2, 1 }, { 0, 5 }, { 0, 82 }, { 6, 1 }, { 2, 1 }, { 0, 37 }, { 2, 1 }, { 0, 68 }, { 0, 53 }, { 2, 1 }, { 0, 83 }, { 2, 1 }, { 0, 69 }, { 2, 1 }, { 0, 84 }, { 0, 85 } }, new byte[71, 2] { { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 0 }, { 0, 16 }, { 2, 1 }, { 0, 1 }, { 0, 17 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 33 }, { 2, 1 }, { 0, 18 }, { 2, 1 }, { 0, 2 }, { 0, 34 }, { 12, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 48 }, { 0, 3 }, { 0, 49 }, { 2, 1 }, { 0, 19 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 65 }, { 0, 20 }, { 4, 1 }, { 2, 1 }, { 0, 64 }, { 0, 51 }, { 2, 1 }, { 0, 66 }, { 0, 36 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 4 }, { 0, 80 }, { 0, 67 }, { 2, 1 }, { 0, 52 }, { 0, 81 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 21 }, { 0, 82 }, { 2, 1 }, { 0, 37 }, { 0, 68 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 5 }, { 0, 84 }, { 0, 83 }, { 2, 1 }, { 0, 53 }, { 2, 1 }, { 0, 69 }, { 0, 85 } }, new byte[127, 2] { { 2, 1 }, { 0, 0 }, { 4, 1 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 10, 1 }, { 2, 1 }, { 0, 17 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 28, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 34 }, { 0, 48 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 3 }, { 0, 50 }, { 2, 1 }, { 0, 35 }, { 0, 64 }, { 4, 1 }, { 2, 1 }, { 0, 65 }, { 0, 20 }, { 4, 1 }, { 2, 1 }, { 0, 4 }, { 0, 51 }, { 2, 1 }, { 0, 66 }, { 0, 36 }, { 28, 1 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 80 }, { 0, 5 }, { 0, 96 }, { 2, 1 }, { 0, 97 }, { 0, 22 }, { 12, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 67 }, { 0, 52 }, { 0, 81 }, { 2, 1 }, { 0, 21 }, { 2, 1 }, { 0, 82 }, { 0, 37 }, { 4, 1 }, { 2, 1 }, { 0, 38 }, { 0, 54 }, { 0, 113 }, { 20, 1 }, { 8, 1 }, { 2, 1 }, { 0, 23 }, { 4, 1 }, { 2, 1 }, { 0, 68 }, { 0, 83 }, { 0, 6 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 53 }, { 0, 69 }, { 0, 98 }, { 2, 1 }, { 0, 112 }, { 2, 1 }, { 0, 7 }, { 0, 100 }, { 14, 1 }, { 4, 1 }, { 2, 1 }, { 0, 114 }, { 0, 39 }, { 6, 1 }, { 2, 1 }, { 0, 99 }, { 2, 1 }, { 0, 84 }, { 0, 85 }, { 2, 1 }, { 0, 70 }, { 0, 115 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 55 }, { 0, 101 }, { 2, 1 }, { 0, 86 }, { 0, 116 }, { 6, 1 }, { 2, 1 }, { 0, 71 }, { 2, 1 }, { 0, 102 }, { 0, 117 }, { 4, 1 }, { 2, 1 }, { 0, 87 }, { 0, 118 }, { 2, 1 }, { 0, 103 }, { 0, 119 } }, new byte[127, 2] { { 6, 1 }, { 2, 1 }, { 0, 0 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 8, 1 }, { 2, 1 }, { 0, 17 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 0, 18 }, { 24, 1 }, { 8, 1 }, { 2, 1 }, { 0, 33 }, { 2, 1 }, { 0, 34 }, { 2, 1 }, { 0, 48 }, { 0, 3 }, { 4, 1 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 4, 1 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 4, 1 }, { 2, 1 }, { 0, 64 }, { 0, 4 }, { 2, 1 }, { 0, 65 }, { 0, 20 }, { 30, 1 }, { 16, 1 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 66 }, { 0, 36 }, { 4, 1 }, { 2, 1 }, { 0, 51 }, { 0, 67 }, { 0, 80 }, { 4, 1 }, { 2, 1 }, { 0, 52 }, { 0, 81 }, { 0, 97 }, { 6, 1 }, { 2, 1 }, { 0, 22 }, { 2, 1 }, { 0, 6 }, { 0, 38 }, { 2, 1 }, { 0, 98 }, { 2, 1 }, { 0, 21 }, { 2, 1 }, { 0, 5 }, { 0, 82 }, { 16, 1 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 37 }, { 0, 68 }, { 0, 96 }, { 2, 1 }, { 0, 99 }, { 0, 54 }, { 4, 1 }, { 2, 1 }, { 0, 112 }, { 0, 23 }, { 0, 113 }, { 16, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 7 }, { 0, 100 }, { 0, 114 }, { 2, 1 }, { 0, 39 }, { 4, 1 }, { 2, 1 }, { 0, 83 }, { 0, 53 }, { 2, 1 }, { 0, 84 }, { 0, 69 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 70 }, { 0, 115 }, { 2, 1 }, { 0, 55 }, { 2, 1 }, { 0, 101 }, { 0, 86 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 85 }, { 0, 87 }, { 0, 116 }, { 2, 1 }, { 0, 71 }, { 0, 102 }, { 4, 1 }, { 2, 1 }, { 0, 117 }, { 0, 118 }, { 2, 1 }, { 0, 103 }, { 0, 119 } }, new byte[127, 2] { { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 2, 1 }, { 0, 17 }, { 2, 1 }, { 0, 0 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 16, 1 }, { 4, 1 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 4, 1 }, { 2, 1 }, { 0, 34 }, { 0, 49 }, { 2, 1 }, { 0, 19 }, { 2, 1 }, { 0, 48 }, { 2, 1 }, { 0, 3 }, { 0, 64 }, { 26, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 2, 1 }, { 0, 65 }, { 0, 51 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 20 }, { 0, 66 }, { 2, 1 }, { 0, 36 }, { 2, 1 }, { 0, 4 }, { 0, 80 }, { 4, 1 }, { 2, 1 }, { 0, 67 }, { 0, 52 }, { 2, 1 }, { 0, 81 }, { 0, 21 }, { 28, 1 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 82 }, { 0, 37 }, { 2, 1 }, { 0, 83 }, { 0, 53 }, { 4, 1 }, { 2, 1 }, { 0, 96 }, { 0, 22 }, { 0, 97 }, { 4, 1 }, { 2, 1 }, { 0, 98 }, { 0, 38 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 5 }, { 0, 6 }, { 0, 68 }, { 2, 1 }, { 0, 84 }, { 0, 69 }, { 18, 1 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 99 }, { 0, 54 }, { 4, 1 }, { 2, 1 }, { 0, 112 }, { 0, 7 }, { 0, 113 }, { 4, 1 }, { 2, 1 }, { 0, 23 }, { 0, 100 }, { 2, 1 }, { 0, 70 }, { 0, 114 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 39 }, { 2, 1 }, { 0, 85 }, { 0, 115 }, { 2, 1 }, { 0, 55 }, { 0, 86 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 101 }, { 0, 116 }, { 2, 1 }, { 0, 71 }, { 0, 102 }, { 4, 1 }, { 2, 1 }, { 0, 117 }, { 0, 87 }, { 2, 1 }, { 0, 118 }, { 2, 1 }, { 0, 103 }, { 0, 119 } }, new byte[511, 2] { { 2, 1 }, { 0, 0 }, { 6, 1 }, { 2, 1 }, { 0, 16 }, { 2, 1 }, { 0, 1 }, { 0, 17 }, { 28, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 34 }, { 0, 48 }, { 2, 1 }, { 0, 3 }, { 0, 49 }, { 6, 1 }, { 2, 1 }, { 0, 19 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 4, 1 }, { 2, 1 }, { 0, 64 }, { 0, 4 }, { 0, 65 }, { 70, 1 }, { 28, 1 }, { 14, 1 }, { 6, 1 }, { 2, 1 }, { 0, 20 }, { 2, 1 }, { 0, 51 }, { 0, 66 }, { 4, 1 }, { 2, 1 }, { 0, 36 }, { 0, 80 }, { 2, 1 }, { 0, 67 }, { 0, 52 }, { 4, 1 }, { 2, 1 }, { 0, 81 }, { 0, 21 }, { 4, 1 }, { 2, 1 }, { 0, 5 }, { 0, 82 }, { 2, 1 }, { 0, 37 }, { 2, 1 }, { 0, 68 }, { 0, 83 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 96 }, { 0, 6 }, { 2, 1 }, { 0, 97 }, { 0, 22 }, { 4, 1 }, { 2, 1 }, { 0, 128 }, { 0, 8 }, { 0, 129 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 53 }, { 0, 98 }, { 2, 1 }, { 0, 38 }, { 0, 84 }, { 4, 1 }, { 2, 1 }, { 0, 69 }, { 0, 99 }, { 2, 1 }, { 0, 54 }, { 0, 112 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 7 }, { 0, 85 }, { 0, 113 }, { 2, 1 }, { 0, 23 }, { 2, 1 }, { 0, 39 }, { 0, 55 }, { 72, 1 }, { 24, 1 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 24 }, { 0, 130 }, { 2, 1 }, { 0, 40 }, { 4, 1 }, { 2, 1 }, { 0, 100 }, { 0, 70 }, { 0, 114 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 132 }, { 0, 72 }, { 2, 1 }, { 0, 144 }, { 0, 9 }, { 2, 1 }, { 0, 145 }, { 0, 25 }, { 24, 1 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 115 }, { 0, 101 }, { 2, 1 }, { 0, 86 }, { 0, 116 }, { 4, 1 }, { 2, 1 }, { 0, 71 }, { 0, 102 }, { 0, 131 }, { 6, 1 }, { 2, 1 }, { 0, 56 }, { 2, 1 }, { 0, 117 }, { 0, 87 }, { 2, 1 }, { 0, 146 }, { 0, 41 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 103 }, { 0, 133 }, { 2, 1 }, { 0, 88 }, { 0, 57 }, { 2, 1 }, { 0, 147 }, { 2, 1 }, { 0, 73 }, { 0, 134 }, { 6, 1 }, { 2, 1 }, { 0, 160 }, { 2, 1 }, { 0, 104 }, { 0, 10 }, { 2, 1 }, { 0, 161 }, { 0, 26 }, { 68, 1 }, { 24, 1 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 162 }, { 0, 42 }, { 4, 1 }, { 2, 1 }, { 0, 149 }, { 0, 89 }, { 2, 1 }, { 0, 163 }, { 0, 58 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 74 }, { 0, 150 }, { 2, 1 }, { 0, 176 }, { 0, 11 }, { 2, 1 }, { 0, 177 }, { 0, 27 }, { 20, 1 }, { 8, 1 }, { 2, 1 }, { 0, 178 }, { 4, 1 }, { 2, 1 }, { 0, 118 }, { 0, 119 }, { 0, 148 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 135 }, { 0, 120 }, { 0, 164 }, { 4, 1 }, { 2, 1 }, { 0, 105 }, { 0, 165 }, { 0, 43 }, { 12, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 90 }, { 0, 136 }, { 0, 179 }, { 2, 1 }, { 0, 59 }, { 2, 1 }, { 0, 121 }, { 0, 166 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 106 }, { 0, 180 }, { 0, 192 }, { 4, 1 }, { 2, 1 }, { 0, 12 }, { 0, 152 }, { 0, 193 }, { 60, 1 }, { 22, 1 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 28 }, { 2, 1 }, { 0, 137 }, { 0, 181 }, { 2, 1 }, { 0, 91 }, { 0, 194 }, { 4, 1 }, { 2, 1 }, { 0, 44 }, { 0, 60 }, { 4, 1 }, { 2, 1 }, { 0, 182 }, { 0, 107 }, { 2, 1 }, { 0, 196 }, { 0, 76 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 168 }, { 0, 138 }, { 2, 1 }, { 0, 208 }, { 0, 13 }, { 2, 1 }, { 0, 209 }, { 2, 1 }, { 0, 75 }, { 2, 1 }, { 0, 151 }, { 0, 167 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 195 }, { 2, 1 }, { 0, 122 }, { 0, 153 }, { 4, 1 }, { 2, 1 }, { 0, 197 }, { 0, 92 }, { 0, 183 }, { 4, 1 }, { 2, 1 }, { 0, 29 }, { 0, 210 }, { 2, 1 }, { 0, 45 }, { 2, 1 }, { 0, 123 }, { 0, 211 }, { 52, 1 }, { 28, 1 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 61 }, { 0, 198 }, { 4, 1 }, { 2, 1 }, { 0, 108 }, { 0, 169 }, { 2, 1 }, { 0, 154 }, { 0, 212 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 184 }, { 0, 139 }, { 2, 1 }, { 0, 77 }, { 0, 199 }, { 4, 1 }, { 2, 1 }, { 0, 124 }, { 0, 213 }, { 2, 1 }, { 0, 93 }, { 0, 224 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 225 }, { 0, 30 }, { 4, 1 }, { 2, 1 }, { 0, 14 }, { 0, 46 }, { 0, 226 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 227 }, { 0, 109 }, { 2, 1 }, { 0, 140 }, { 0, 228 }, { 4, 1 }, { 2, 1 }, { 0, 229 }, { 0, 186 }, { 0, 240 }, { 38, 1 }, { 16, 1 }, { 4, 1 }, { 2, 1 }, { 0, 241 }, { 0, 31 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 170 }, { 0, 155 }, { 0, 185 }, { 2, 1 }, { 0, 62 }, { 2, 1 }, { 0, 214 }, { 0, 200 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 78 }, { 2, 1 }, { 0, 215 }, { 0, 125 }, { 2, 1 }, { 0, 171 }, { 2, 1 }, { 0, 94 }, { 0, 201 }, { 6, 1 }, { 2, 1 }, { 0, 15 }, { 2, 1 }, { 0, 156 }, { 0, 110 }, { 2, 1 }, { 0, 242 }, { 0, 47 }, { 32, 1 }, { 16, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 216 }, { 0, 141 }, { 0, 63 }, { 6, 1 }, { 2, 1 }, { 0, 243 }, { 2, 1 }, { 0, 230 }, { 0, 202 }, { 2, 1 }, { 0, 244 }, { 0, 79 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 187 }, { 0, 172 }, { 2, 1 }, { 0, 231 }, { 0, 245 }, { 4, 1 }, { 2, 1 }, { 0, 217 }, { 0, 157 }, { 2, 1 }, { 0, 95 }, { 0, 232 }, { 30, 1 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 111 }, { 2, 1 }, { 0, 246 }, { 0, 203 }, { 4, 1 }, { 2, 1 }, { 0, 188 }, { 0, 173 }, { 0, 218 }, { 8, 1 }, { 2, 1 }, { 0, 247 }, { 4, 1 }, { 2, 1 }, { 0, 126 }, { 0, 127 }, { 0, 142 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 158 }, { 0, 174 }, { 0, 204 }, { 2, 1 }, { 0, 248 }, { 0, 143 }, { 18, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 219 }, { 0, 189 }, { 2, 1 }, { 0, 234 }, { 0, 249 }, { 4, 1 }, { 2, 1 }, { 0, 159 }, { 0, 235 }, { 2, 1 }, { 0, 190 }, { 2, 1 }, { 0, 205 }, { 0, 250 }, { 14, 1 }, { 4, 1 }, { 2, 1 }, { 0, 221 }, { 0, 236 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 233 }, { 0, 175 }, { 0, 220 }, { 2, 1 }, { 0, 206 }, { 0, 251 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 191 }, { 0, 222 }, { 2, 1 }, { 0, 207 }, { 0, 238 }, { 4, 1 }, { 2, 1 }, { 0, 223 }, { 0, 239 }, { 2, 1 }, { 0, 255 }, { 2, 1 }, { 0, 237 }, { 2, 1 }, { 0, 253 }, { 2, 1 }, { 0, 252 }, { 0, 254 } }, new byte[511, 2] { { 16, 1 }, { 6, 1 }, { 2, 1 }, { 0, 0 }, { 2, 1 }, { 0, 16 }, { 0, 1 }, { 2, 1 }, { 0, 17 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 50, 1 }, { 16, 1 }, { 6, 1 }, { 2, 1 }, { 0, 34 }, { 2, 1 }, { 0, 48 }, { 0, 49 }, { 6, 1 }, { 2, 1 }, { 0, 19 }, { 2, 1 }, { 0, 3 }, { 0, 64 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 14, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 4 }, { 0, 20 }, { 0, 65 }, { 4, 1 }, { 2, 1 }, { 0, 51 }, { 0, 66 }, { 2, 1 }, { 0, 36 }, { 0, 67 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 52 }, { 2, 1 }, { 0, 80 }, { 0, 5 }, { 2, 1 }, { 0, 81 }, { 0, 21 }, { 4, 1 }, { 2, 1 }, { 0, 82 }, { 0, 37 }, { 4, 1 }, { 2, 1 }, { 0, 68 }, { 0, 83 }, { 0, 97 }, { 90, 1 }, { 36, 1 }, { 18, 1 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 53 }, { 2, 1 }, { 0, 96 }, { 0, 6 }, { 2, 1 }, { 0, 22 }, { 0, 98 }, { 4, 1 }, { 2, 1 }, { 0, 38 }, { 0, 84 }, { 2, 1 }, { 0, 69 }, { 0, 99 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 54 }, { 2, 1 }, { 0, 112 }, { 0, 7 }, { 2, 1 }, { 0, 113 }, { 0, 85 }, { 4, 1 }, { 2, 1 }, { 0, 23 }, { 0, 100 }, { 2, 1 }, { 0, 114 }, { 0, 39 }, { 24, 1 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 70 }, { 0, 115 }, { 2, 1 }, { 0, 55 }, { 0, 101 }, { 4, 1 }, { 2, 1 }, { 0, 86 }, { 0, 128 }, { 2, 1 }, { 0, 8 }, { 0, 116 }, { 4, 1 }, { 2, 1 }, { 0, 129 }, { 0, 24 }, { 2, 1 }, { 0, 130 }, { 0, 40 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 71 }, { 0, 102 }, { 2, 1 }, { 0, 131 }, { 0, 56 }, { 4, 1 }, { 2, 1 }, { 0, 117 }, { 0, 87 }, { 2, 1 }, { 0, 132 }, { 0, 72 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 144 }, { 0, 25 }, { 0, 145 }, { 4, 1 }, { 2, 1 }, { 0, 146 }, { 0, 118 }, { 2, 1 }, { 0, 103 }, { 0, 41 }, { 92, 1 }, { 36, 1 }, { 18, 1 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 133 }, { 0, 88 }, { 4, 1 }, { 2, 1 }, { 0, 9 }, { 0, 119 }, { 0, 147 }, { 4, 1 }, { 2, 1 }, { 0, 57 }, { 0, 148 }, { 2, 1 }, { 0, 73 }, { 0, 134 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 104 }, { 2, 1 }, { 0, 160 }, { 0, 10 }, { 2, 1 }, { 0, 161 }, { 0, 26 }, { 4, 1 }, { 2, 1 }, { 0, 162 }, { 0, 42 }, { 2, 1 }, { 0, 149 }, { 0, 89 }, { 26, 1 }, { 14, 1 }, { 6, 1 }, { 2, 1 }, { 0, 163 }, { 2, 1 }, { 0, 58 }, { 0, 135 }, { 4, 1 }, { 2, 1 }, { 0, 120 }, { 0, 164 }, { 2, 1 }, { 0, 74 }, { 0, 150 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 105 }, { 0, 176 }, { 0, 177 }, { 4, 1 }, { 2, 1 }, { 0, 27 }, { 0, 165 }, { 0, 178 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 90 }, { 0, 43 }, { 2, 1 }, { 0, 136 }, { 0, 151 }, { 2, 1 }, { 0, 179 }, { 2, 1 }, { 0, 121 }, { 0, 59 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 106 }, { 0, 180 }, { 2, 1 }, { 0, 75 }, { 0, 193 }, { 4, 1 }, { 2, 1 }, { 0, 152 }, { 0, 137 }, { 2, 1 }, { 0, 28 }, { 0, 181 }, { 80, 1 }, { 34, 1 }, { 16, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 91 }, { 0, 44 }, { 0, 194 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 11 }, { 0, 192 }, { 0, 166 }, { 2, 1 }, { 0, 167 }, { 0, 122 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 195 }, { 0, 60 }, { 4, 1 }, { 2, 1 }, { 0, 12 }, { 0, 153 }, { 0, 182 }, { 4, 1 }, { 2, 1 }, { 0, 107 }, { 0, 196 }, { 2, 1 }, { 0, 76 }, { 0, 168 }, { 20, 1 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 138 }, { 0, 197 }, { 4, 1 }, { 2, 1 }, { 0, 208 }, { 0, 92 }, { 0, 209 }, { 4, 1 }, { 2, 1 }, { 0, 183 }, { 0, 123 }, { 2, 1 }, { 0, 29 }, { 2, 1 }, { 0, 13 }, { 0, 45 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 210 }, { 0, 211 }, { 4, 1 }, { 2, 1 }, { 0, 61 }, { 0, 198 }, { 2, 1 }, { 0, 108 }, { 0, 169 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 154 }, { 0, 184 }, { 0, 212 }, { 4, 1 }, { 2, 1 }, { 0, 139 }, { 0, 77 }, { 2, 1 }, { 0, 199 }, { 0, 124 }, { 68, 1 }, { 34, 1 }, { 18, 1 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 213 }, { 0, 93 }, { 4, 1 }, { 2, 1 }, { 0, 224 }, { 0, 14 }, { 0, 225 }, { 4, 1 }, { 2, 1 }, { 0, 30 }, { 0, 226 }, { 2, 1 }, { 0, 170 }, { 0, 46 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 185 }, { 0, 155 }, { 2, 1 }, { 0, 227 }, { 0, 214 }, { 4, 1 }, { 2, 1 }, { 0, 109 }, { 0, 62 }, { 2, 1 }, { 0, 200 }, { 0, 140 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 228 }, { 0, 78 }, { 2, 1 }, { 0, 215 }, { 0, 125 }, { 4, 1 }, { 2, 1 }, { 0, 229 }, { 0, 186 }, { 2, 1 }, { 0, 171 }, { 0, 94 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 201 }, { 0, 156 }, { 2, 1 }, { 0, 241 }, { 0, 31 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 240 }, { 0, 110 }, { 0, 242 }, { 2, 1 }, { 0, 47 }, { 0, 230 }, { 38, 1 }, { 18, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 216 }, { 0, 243 }, { 2, 1 }, { 0, 63 }, { 0, 244 }, { 6, 1 }, { 2, 1 }, { 0, 79 }, { 2, 1 }, { 0, 141 }, { 0, 217 }, { 2, 1 }, { 0, 187 }, { 0, 202 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 172 }, { 0, 231 }, { 2, 1 }, { 0, 126 }, { 0, 245 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 157 }, { 0, 95 }, { 2, 1 }, { 0, 232 }, { 0, 142 }, { 2, 1 }, { 0, 246 }, { 0, 203 }, { 34, 1 }, { 18, 1 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 15 }, { 0, 174 }, { 0, 111 }, { 2, 1 }, { 0, 188 }, { 0, 218 }, { 4, 1 }, { 2, 1 }, { 0, 173 }, { 0, 247 }, { 2, 1 }, { 0, 127 }, { 0, 233 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 158 }, { 0, 204 }, { 2, 1 }, { 0, 248 }, { 0, 143 }, { 4, 1 }, { 2, 1 }, { 0, 219 }, { 0, 189 }, { 2, 1 }, { 0, 234 }, { 0, 249 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 159 }, { 0, 220 }, { 2, 1 }, { 0, 205 }, { 0, 235 }, { 4, 1 }, { 2, 1 }, { 0, 190 }, { 0, 250 }, { 2, 1 }, { 0, 175 }, { 0, 221 }, { 14, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 236 }, { 0, 206 }, { 0, 251 }, { 4, 1 }, { 2, 1 }, { 0, 191 }, { 0, 237 }, { 2, 1 }, { 0, 222 }, { 0, 252 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 207 }, { 0, 253 }, { 0, 238 }, { 4, 1 }, { 2, 1 }, { 0, 223 }, { 0, 254 }, { 2, 1 }, { 0, 239 }, { 0, 255 } }, new byte[511, 2] { { 2, 1 }, { 0, 0 }, { 6, 1 }, { 2, 1 }, { 0, 16 }, { 2, 1 }, { 0, 1 }, { 0, 17 }, { 42, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 2, 1 }, { 0, 33 }, { 0, 18 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 34 }, { 2, 1 }, { 0, 48 }, { 0, 3 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 4, 1 }, { 2, 1 }, { 0, 64 }, { 0, 4 }, { 0, 65 }, { 6, 1 }, { 2, 1 }, { 0, 20 }, { 2, 1 }, { 0, 51 }, { 0, 66 }, { 4, 1 }, { 2, 1 }, { 0, 36 }, { 0, 80 }, { 2, 1 }, { 0, 67 }, { 0, 52 }, { 138, 1 }, { 40, 1 }, { 16, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 5 }, { 0, 21 }, { 0, 81 }, { 4, 1 }, { 2, 1 }, { 0, 82 }, { 0, 37 }, { 4, 1 }, { 2, 1 }, { 0, 68 }, { 0, 53 }, { 0, 83 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 96 }, { 0, 6 }, { 0, 97 }, { 2, 1 }, { 0, 22 }, { 0, 98 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 38 }, { 0, 84 }, { 2, 1 }, { 0, 69 }, { 0, 99 }, { 4, 1 }, { 2, 1 }, { 0, 54 }, { 0, 112 }, { 0, 113 }, { 40, 1 }, { 18, 1 }, { 8, 1 }, { 2, 1 }, { 0, 23 }, { 2, 1 }, { 0, 7 }, { 2, 1 }, { 0, 85 }, { 0, 100 }, { 4, 1 }, { 2, 1 }, { 0, 114 }, { 0, 39 }, { 4, 1 }, { 2, 1 }, { 0, 70 }, { 0, 101 }, { 0, 115 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 55 }, { 2, 1 }, { 0, 86 }, { 0, 8 }, { 2, 1 }, { 0, 128 }, { 0, 129 }, { 6, 1 }, { 2, 1 }, { 0, 24 }, { 2, 1 }, { 0, 116 }, { 0, 71 }, { 2, 1 }, { 0, 130 }, { 2, 1 }, { 0, 40 }, { 0, 102 }, { 24, 1 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 131 }, { 0, 56 }, { 2, 1 }, { 0, 117 }, { 0, 132 }, { 4, 1 }, { 2, 1 }, { 0, 72 }, { 0, 144 }, { 0, 145 }, { 6, 1 }, { 2, 1 }, { 0, 25 }, { 2, 1 }, { 0, 9 }, { 0, 118 }, { 2, 1 }, { 0, 146 }, { 0, 41 }, { 14, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 133 }, { 0, 88 }, { 2, 1 }, { 0, 147 }, { 0, 57 }, { 4, 1 }, { 2, 1 }, { 0, 160 }, { 0, 10 }, { 0, 26 }, { 8, 1 }, { 2, 1 }, { 0, 162 }, { 2, 1 }, { 0, 103 }, { 2, 1 }, { 0, 87 }, { 0, 73 }, { 6, 1 }, { 2, 1 }, { 0, 148 }, { 2, 1 }, { 0, 119 }, { 0, 134 }, { 2, 1 }, { 0, 161 }, { 2, 1 }, { 0, 104 }, { 0, 149 }, { 220, 1 }, { 126, 1 }, { 50, 1 }, { 26, 1 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 42 }, { 2, 1 }, { 0, 89 }, { 0, 58 }, { 2, 1 }, { 0, 163 }, { 2, 1 }, { 0, 135 }, { 0, 120 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 164 }, { 0, 74 }, { 2, 1 }, { 0, 150 }, { 0, 105 }, { 4, 1 }, { 2, 1 }, { 0, 176 }, { 0, 11 }, { 0, 177 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 27 }, { 0, 178 }, { 2, 1 }, { 0, 43 }, { 2, 1 }, { 0, 165 }, { 0, 90 }, { 6, 1 }, { 2, 1 }, { 0, 179 }, { 2, 1 }, { 0, 166 }, { 0, 106 }, { 4, 1 }, { 2, 1 }, { 0, 180 }, { 0, 75 }, { 2, 1 }, { 0, 12 }, { 0, 193 }, { 30, 1 }, { 14, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 181 }, { 0, 194 }, { 0, 44 }, { 4, 1 }, { 2, 1 }, { 0, 167 }, { 0, 195 }, { 2, 1 }, { 0, 107 }, { 0, 196 }, { 8, 1 }, { 2, 1 }, { 0, 29 }, { 4, 1 }, { 2, 1 }, { 0, 136 }, { 0, 151 }, { 0, 59 }, { 4, 1 }, { 2, 1 }, { 0, 209 }, { 0, 210 }, { 2, 1 }, { 0, 45 }, { 0, 211 }, { 18, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 30 }, { 0, 46 }, { 0, 226 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 121 }, { 0, 152 }, { 0, 192 }, { 2, 1 }, { 0, 28 }, { 2, 1 }, { 0, 137 }, { 0, 91 }, { 14, 1 }, { 6, 1 }, { 2, 1 }, { 0, 60 }, { 2, 1 }, { 0, 122 }, { 0, 182 }, { 4, 1 }, { 2, 1 }, { 0, 76 }, { 0, 153 }, { 2, 1 }, { 0, 168 }, { 0, 138 }, { 6, 1 }, { 2, 1 }, { 0, 13 }, { 2, 1 }, { 0, 197 }, { 0, 92 }, { 4, 1 }, { 2, 1 }, { 0, 61 }, { 0, 198 }, { 2, 1 }, { 0, 108 }, { 0, 154 }, { 88, 1 }, { 86, 1 }, { 36, 1 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 139 }, { 0, 77 }, { 2, 1 }, { 0, 199 }, { 0, 124 }, { 4, 1 }, { 2, 1 }, { 0, 213 }, { 0, 93 }, { 2, 1 }, { 0, 224 }, { 0, 14 }, { 8, 1 }, { 2, 1 }, { 0, 227 }, { 4, 1 }, { 2, 1 }, { 0, 208 }, { 0, 183 }, { 0, 123 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 169 }, { 0, 184 }, { 0, 212 }, { 2, 1 }, { 0, 225 }, { 2, 1 }, { 0, 170 }, { 0, 185 }, { 24, 1 }, { 10, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 155 }, { 0, 214 }, { 0, 109 }, { 2, 1 }, { 0, 62 }, { 0, 200 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 140 }, { 0, 228 }, { 0, 78 }, { 4, 1 }, { 2, 1 }, { 0, 215 }, { 0, 229 }, { 2, 1 }, { 0, 186 }, { 0, 171 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 156 }, { 0, 230 }, { 4, 1 }, { 2, 1 }, { 0, 110 }, { 0, 216 }, { 2, 1 }, { 0, 141 }, { 0, 187 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 231 }, { 0, 157 }, { 2, 1 }, { 0, 232 }, { 0, 142 }, { 4, 1 }, { 2, 1 }, { 0, 203 }, { 0, 188 }, { 0, 158 }, { 0, 241 }, { 2, 1 }, { 0, 31 }, { 2, 1 }, { 0, 15 }, { 0, 47 }, { 66, 1 }, { 56, 1 }, { 2, 1 }, { 0, 242 }, { 52, 1 }, { 50, 1 }, { 20, 1 }, { 8, 1 }, { 2, 1 }, { 0, 189 }, { 2, 1 }, { 0, 94 }, { 2, 1 }, { 0, 125 }, { 0, 201 }, { 6, 1 }, { 2, 1 }, { 0, 202 }, { 2, 1 }, { 0, 172 }, { 0, 126 }, { 4, 1 }, { 2, 1 }, { 0, 218 }, { 0, 173 }, { 0, 204 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 174 }, { 2, 1 }, { 0, 219 }, { 0, 220 }, { 2, 1 }, { 0, 205 }, { 0, 190 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 235 }, { 0, 237 }, { 0, 238 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 217 }, { 0, 234 }, { 0, 233 }, { 2, 1 }, { 0, 222 }, { 4, 1 }, { 2, 1 }, { 0, 221 }, { 0, 236 }, { 0, 206 }, { 0, 63 }, { 0, 240 }, { 4, 1 }, { 2, 1 }, { 0, 243 }, { 0, 244 }, { 2, 1 }, { 0, 79 }, { 2, 1 }, { 0, 245 }, { 0, 95 }, { 10, 1 }, { 2, 1 }, { 0, 255 }, { 4, 1 }, { 2, 1 }, { 0, 246 }, { 0, 111 }, { 2, 1 }, { 0, 247 }, { 0, 127 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 143 }, { 2, 1 }, { 0, 248 }, { 0, 249 }, { 4, 1 }, { 2, 1 }, { 0, 159 }, { 0, 250 }, { 0, 175 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 251 }, { 0, 191 }, { 2, 1 }, { 0, 252 }, { 0, 207 }, { 4, 1 }, { 2, 1 }, { 0, 253 }, { 0, 223 }, { 2, 1 }, { 0, 254 }, { 0, 239 } }, new byte[512, 2] { { 60, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 0 }, { 0, 16 }, { 2, 1 }, { 0, 1 }, { 0, 17 }, { 14, 1 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 32 }, { 0, 2 }, { 0, 33 }, { 2, 1 }, { 0, 18 }, { 2, 1 }, { 0, 34 }, { 2, 1 }, { 0, 48 }, { 0, 3 }, { 14, 1 }, { 4, 1 }, { 2, 1 }, { 0, 49 }, { 0, 19 }, { 4, 1 }, { 2, 1 }, { 0, 50 }, { 0, 35 }, { 4, 1 }, { 2, 1 }, { 0, 64 }, { 0, 4 }, { 0, 65 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 20 }, { 0, 51 }, { 2, 1 }, { 0, 66 }, { 0, 36 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 67 }, { 0, 52 }, { 0, 81 }, { 6, 1 }, { 4, 1 }, { 2, 1 }, { 0, 80 }, { 0, 5 }, { 0, 21 }, { 2, 1 }, { 0, 82 }, { 0, 37 }, { 250, 1 }, { 98, 1 }, { 34, 1 }, { 18, 1 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 68 }, { 0, 83 }, { 2, 1 }, { 0, 53 }, { 2, 1 }, { 0, 96 }, { 0, 6 }, { 4, 1 }, { 2, 1 }, { 0, 97 }, { 0, 22 }, { 2, 1 }, { 0, 98 }, { 0, 38 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 84 }, { 0, 69 }, { 2, 1 }, { 0, 99 }, { 0, 54 }, { 4, 1 }, { 2, 1 }, { 0, 113 }, { 0, 85 }, { 2, 1 }, { 0, 100 }, { 0, 70 }, { 32, 1 }, { 14, 1 }, { 6, 1 }, { 2, 1 }, { 0, 114 }, { 2, 1 }, { 0, 39 }, { 0, 55 }, { 2, 1 }, { 0, 115 }, { 4, 1 }, { 2, 1 }, { 0, 112 }, { 0, 7 }, { 0, 23 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 101 }, { 0, 86 }, { 4, 1 }, { 2, 1 }, { 0, 128 }, { 0, 8 }, { 0, 129 }, { 4, 1 }, { 2, 1 }, { 0, 116 }, { 0, 71 }, { 2, 1 }, { 0, 24 }, { 0, 130 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 40 }, { 0, 102 }, { 2, 1 }, { 0, 131 }, { 0, 56 }, { 4, 1 }, { 2, 1 }, { 0, 117 }, { 0, 87 }, { 2, 1 }, { 0, 132 }, { 0, 72 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 145 }, { 0, 25 }, { 2, 1 }, { 0, 146 }, { 0, 118 }, { 4, 1 }, { 2, 1 }, { 0, 103 }, { 0, 41 }, { 2, 1 }, { 0, 133 }, { 0, 88 }, { 92, 1 }, { 34, 1 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 147 }, { 0, 57 }, { 2, 1 }, { 0, 148 }, { 0, 73 }, { 4, 1 }, { 2, 1 }, { 0, 119 }, { 0, 134 }, { 2, 1 }, { 0, 104 }, { 0, 161 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 162 }, { 0, 42 }, { 2, 1 }, { 0, 149 }, { 0, 89 }, { 4, 1 }, { 2, 1 }, { 0, 163 }, { 0, 58 }, { 2, 1 }, { 0, 135 }, { 2, 1 }, { 0, 120 }, { 0, 74 }, { 22, 1 }, { 12, 1 }, { 4, 1 }, { 2, 1 }, { 0, 164 }, { 0, 150 }, { 4, 1 }, { 2, 1 }, { 0, 105 }, { 0, 177 }, { 2, 1 }, { 0, 27 }, { 0, 165 }, { 6, 1 }, { 2, 1 }, { 0, 178 }, { 2, 1 }, { 0, 90 }, { 0, 43 }, { 2, 1 }, { 0, 136 }, { 0, 179 }, { 16, 1 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 144 }, { 2, 1 }, { 0, 9 }, { 0, 160 }, { 2, 1 }, { 0, 151 }, { 0, 121 }, { 4, 1 }, { 2, 1 }, { 0, 166 }, { 0, 106 }, { 0, 180 }, { 12, 1 }, { 6, 1 }, { 2, 1 }, { 0, 26 }, { 2, 1 }, { 0, 10 }, { 0, 176 }, { 2, 1 }, { 0, 59 }, { 2, 1 }, { 0, 11 }, { 0, 192 }, { 4, 1 }, { 2, 1 }, { 0, 75 }, { 0, 193 }, { 2, 1 }, { 0, 152 }, { 0, 137 }, { 67, 1 }, { 34, 1 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 28 }, { 0, 181 }, { 2, 1 }, { 0, 91 }, { 0, 194 }, { 4, 1 }, { 2, 1 }, { 0, 44 }, { 0, 167 }, { 2, 1 }, { 0, 122 }, { 0, 195 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 60 }, { 2, 1 }, { 0, 12 }, { 0, 208 }, { 2, 1 }, { 0, 182 }, { 0, 107 }, { 4, 1 }, { 2, 1 }, { 0, 196 }, { 0, 76 }, { 2, 1 }, { 0, 153 }, { 0, 168 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 138 }, { 0, 197 }, { 2, 1 }, { 0, 92 }, { 0, 209 }, { 4, 1 }, { 2, 1 }, { 0, 183 }, { 0, 123 }, { 2, 1 }, { 0, 29 }, { 0, 210 }, { 9, 1 }, { 4, 1 }, { 2, 1 }, { 0, 45 }, { 0, 211 }, { 2, 1 }, { 0, 61 }, { 0, 198 }, { 85, 250 }, { 4, 1 }, { 2, 1 }, { 0, 108 }, { 0, 169 }, { 2, 1 }, { 0, 154 }, { 0, 212 }, { 32, 1 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 184 }, { 0, 139 }, { 2, 1 }, { 0, 77 }, { 0, 199 }, { 4, 1 }, { 2, 1 }, { 0, 124 }, { 0, 213 }, { 2, 1 }, { 0, 93 }, { 0, 225 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 30 }, { 0, 226 }, { 2, 1 }, { 0, 170 }, { 0, 185 }, { 4, 1 }, { 2, 1 }, { 0, 155 }, { 0, 227 }, { 2, 1 }, { 0, 214 }, { 0, 109 }, { 20, 1 }, { 10, 1 }, { 6, 1 }, { 2, 1 }, { 0, 62 }, { 2, 1 }, { 0, 46 }, { 0, 78 }, { 2, 1 }, { 0, 200 }, { 0, 140 }, { 4, 1 }, { 2, 1 }, { 0, 228 }, { 0, 215 }, { 4, 1 }, { 2, 1 }, { 0, 125 }, { 0, 171 }, { 0, 229 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 186 }, { 0, 94 }, { 2, 1 }, { 0, 201 }, { 2, 1 }, { 0, 156 }, { 0, 110 }, { 8, 1 }, { 2, 1 }, { 0, 230 }, { 2, 1 }, { 0, 13 }, { 2, 1 }, { 0, 224 }, { 0, 14 }, { 4, 1 }, { 2, 1 }, { 0, 216 }, { 0, 141 }, { 2, 1 }, { 0, 187 }, { 0, 202 }, { 74, 1 }, { 2, 1 }, { 0, 255 }, { 64, 1 }, { 58, 1 }, { 32, 1 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 172 }, { 0, 231 }, { 2, 1 }, { 0, 126 }, { 0, 217 }, { 4, 1 }, { 2, 1 }, { 0, 157 }, { 0, 232 }, { 2, 1 }, { 0, 142 }, { 0, 203 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 188 }, { 0, 218 }, { 2, 1 }, { 0, 173 }, { 0, 233 }, { 4, 1 }, { 2, 1 }, { 0, 158 }, { 0, 204 }, { 2, 1 }, { 0, 219 }, { 0, 189 }, { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 234 }, { 0, 174 }, { 2, 1 }, { 0, 220 }, { 0, 205 }, { 4, 1 }, { 2, 1 }, { 0, 235 }, { 0, 190 }, { 2, 1 }, { 0, 221 }, { 0, 236 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 206 }, { 0, 237 }, { 2, 1 }, { 0, 222 }, { 0, 238 }, { 0, 15 }, { 4, 1 }, { 2, 1 }, { 0, 240 }, { 0, 31 }, { 0, 241 }, { 4, 1 }, { 2, 1 }, { 0, 242 }, { 0, 47 }, { 2, 1 }, { 0, 243 }, { 0, 63 }, { 18, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 244 }, { 0, 79 }, { 2, 1 }, { 0, 245 }, { 0, 95 }, { 4, 1 }, { 2, 1 }, { 0, 246 }, { 0, 111 }, { 2, 1 }, { 0, 247 }, { 2, 1 }, { 0, 127 }, { 0, 143 }, { 10, 1 }, { 4, 1 }, { 2, 1 }, { 0, 248 }, { 0, 249 }, { 4, 1 }, { 2, 1 }, { 0, 159 }, { 0, 175 }, { 0, 250 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 251 }, { 0, 191 }, { 2, 1 }, { 0, 252 }, { 0, 207 }, { 4, 1 }, { 2, 1 }, { 0, 253 }, { 0, 223 }, { 2, 1 }, { 0, 254 }, { 0, 239 } }, new byte[31, 2] { { 2, 1 }, { 0, 0 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 8 }, { 0, 4 }, { 2, 1 }, { 0, 1 }, { 0, 2 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 12 }, { 0, 10 }, { 2, 1 }, { 0, 3 }, { 0, 6 }, { 6, 1 }, { 2, 1 }, { 0, 9 }, { 2, 1 }, { 0, 5 }, { 0, 7 }, { 4, 1 }, { 2, 1 }, { 0, 14 }, { 0, 13 }, { 2, 1 }, { 0, 15 }, { 0, 11 } }, new byte[31, 2] { { 16, 1 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 0 }, { 0, 1 }, { 2, 1 }, { 0, 2 }, { 0, 3 }, { 4, 1 }, { 2, 1 }, { 0, 4 }, { 0, 5 }, { 2, 1 }, { 0, 6 }, { 0, 7 }, { 8, 1 }, { 4, 1 }, { 2, 1 }, { 0, 8 }, { 0, 9 }, { 2, 1 }, { 0, 10 }, { 0, 11 }, { 4, 1 }, { 2, 1 }, { 0, 12 }, { 0, 13 }, { 2, 1 }, { 0, 14 }, { 0, 15 } } }; _llCache = new HuffmanListNode[_codeTables.Length]; _llCacheMaxBits = new int[_codeTables.Length]; LIN_BITS = new int[32] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 8, 10, 13, 4, 5, 6, 7, 8, 9, 11, 13 }; _floatLookup = new float[8207]; for (int i = 0; i < 8207; i++) { _floatLookup[i] = (float)Math.Pow(i, 1.3333333333333333); } } internal static void Decode(BitReservoir br, int table, out float x, out float y) { if (table == 0 || table == 4 || table == 14) { x = (y = 0f); return; } byte num = DecodeSymbol(br, table); int num2 = num >> 4; int num3 = num & 0xF; int num4 = LIN_BITS[table]; if (num4 > 0 && num2 == 15) { num2 += br.GetBits(num4); } if (num2 != 0 && br.Get1Bit() != 0) { x = 0f - _floatLookup[num2]; } else { x = _floatLookup[num2]; } if (num4 > 0 && num3 == 15) { num3 += br.GetBits(num4); } if (num3 != 0 && br.Get1Bit() != 0) { y = 0f - _floatLookup[num3]; } else { y = _floatLookup[num3]; } } internal static void Decode(BitReservoir br, int table, out float x, out float y, out float v, out float w) { byte num = DecodeSymbol(br, table); v = (w = (x = (y = 0f))); if ((num & 8u) != 0) { if (br.Get1Bit() == 1) { v = 0f - _floatLookup[1]; } else { v = _floatLookup[1]; } } if ((num & 4u) != 0) { if (br.Get1Bit() == 1) { w = 0f - _floatLookup[1]; } else { w = _floatLookup[1]; } } if ((num & 2u) != 0) { if (br.Get1Bit() == 1) { x = 0f - _floatLookup[1]; } else { x = _floatLookup[1]; } } if (((uint)num & (true ? 1u : 0u)) != 0) { if (br.Get1Bit() == 1) { y = 0f - _floatLookup[1]; } else { y = _floatLookup[1]; } } } private static byte DecodeSymbol(BitReservoir br, int table) { int maxBits; HuffmanListNode huffmanListNode = GetNode(table, out maxBits); int readCount; int num = br.TryPeekBits(maxBits, out readCount); if (readCount < maxBits) { num <<= maxBits - readCount; } while (huffmanListNode != null && huffmanListNode.Length <= readCount) { if ((num & huffmanListNode.Mask) == huffmanListNode.Bits) { br.SkipBits(huffmanListNode.Length); break; } huffmanListNode = huffmanListNode.Next; } if (huffmanListNode != null && huffmanListNode.Length <= readCount) { return huffmanListNode.Value; } return 0; } private static HuffmanListNode GetNode(int table, out int maxBits) { int num = table; if (num > 16) { num = ((num > 31) ? (num - 17) : ((num < 24) ? 13 : 14)); } else { if (num > 13) { num--; } if (num > 3) { num--; } num--; } if (_llCache[num] == null) { _llCache[num] = InitTable(_codeTables[num], out maxBits); _llCacheMaxBits[num] = maxBits; } else { maxBits = _llCacheMaxBits[num]; } return _llCache[num]; } private static HuffmanListNode InitTable(byte[,] tree, out int maxBits) { List<byte> list = new List<byte>(); List<int> list2 = new List<int>(); List<int> list3 = new List<int>(); int length = tree.GetLength(0); for (int i = 0; i < length; i++) { if (tree[i, 0] == 0) { int num = 0; int item = 0; int num2 = i; do { num2 = FindPreviousNode(tree, num2, out var bit); num |= bit << item++; } while (num2 > 0); list.Add(tree[i, 1]); list2.Add(item); list3.Add(num); } } return BuildLinkedList(list, list2, list3, out maxBits); } private static int FindPreviousNode(byte[,] tree, int idx, out int bit) { for (int num = idx - 1; num >= 0; num--) { if (tree[num, 0] != 0) { for (int i = 0; i < 2; i++) { if (num + tree[num, i] != idx) { continue; } if (tree[num, i] >= 250) { int result = FindPreviousNode(tree, num, out bit); if (bit != i) { throw new InvalidOperationException(); } return result; } bit = i; return num; } } } throw new InvalidOperationException(); } private static HuffmanListNode BuildLinkedList(List<byte> values, List<int> lengthList, List<int> codeList, out int maxBits) { HuffmanListNode[] array = new HuffmanListNode[lengthList.Count]; maxBits = lengthList.Max(); for (int j = 0; j < array.Length; j++) { int num = maxBits - lengthList[j]; array[j] = new HuffmanListNode { Value = values[j], Length = lengthList[j], Bits = codeList[j] << num, Mask = (1 << lengthList[j]) - 1 << num }; } Array.Sort(array, (HuffmanListNode i1, HuffmanListNode i2) => i1.Length - i2.Length); for (int k = 1; k < array.Length && array[k].Length < 99999; k++) { array[k - 1].Next = array[k]; } return array[0]; } } internal class ID3Frame : FrameBase { private int _version; internal int Version { get { if (_version == 0) { return 1; } return _version; } } internal static ID3Frame TrySync(uint syncMark) { if ((syncMark & 0xFFFFFF00u) == 1229206272) { return new ID3Frame { _version = 2 }; } if ((syncMark & 0xFFFFFF00u) == 1413564160) { if ((syncMark & 0xFF) == 43) { return new ID3Frame { _version = 1 }; } return new ID3Frame { _version = 0 }; } return null; } private ID3Frame() { } protected override int Validate() { switch (_version) { case 2: { byte[] array = new byte[7]; if (Read(3, array) == 7) { byte b; switch (array[0]) { case 2: b = 63; break; case 3: b = 31; break; case 4: b = 15; break; default: return -1; } int num = (array[3] << 21) | (array[4] << 14) | (array[5] << 7) | array[6]; if (((array[2] & b) | (array[3] & 0x80) | (array[4] & 0x80) | (array[5] & 0x80) | (array[6] & 0x80)) == 0 && array[1] != byte.MaxValue) { return num + 10; } } break; } case 1: return 355; case 0: return 128; } return -1; } internal override void Parse() { switch (_version) { case 2: ParseV2(); break; case 1: ParseV1Enh(); break; case 0: ParseV1(3); break; } } private void ParseV1(int offset) { } private void ParseV1Enh() { ParseV1(230); } private void ParseV2() { } internal void Merge(ID3Frame newFrame) { } } internal abstract class LayerDecoderBase { protected const int SBLIMIT = 32; private const float INV_SQRT_2 = 0.70710677f; private static float[] DEWINDOW_TABLE = new float[512] { 0f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -3.0518E-05f, -3.0518E-05f, -3.0518E-05f, -3.0518E-05f, -4.5776E-05f, -4.5776E-05f, -6.1035E-05f, -6.1035E-05f, -7.6294E-05f, -7.6294E-05f, -9.1553E-05f, -0.000106812f, -0.000106812f, -0.00012207f, -0.000137329f, -0.000152588f, -0.000167847f, -0.000198364f, -0.000213623f, -0.000244141f, -0.000259399f, -0.000289917f, -0.000320435f, -0.000366211f, -0.000396729f, -0.000442505f, -0.000473022f, -0.000534058f, -0.000579834f, -0.00062561f, -0.000686646f, -0.000747681f, -0.000808716f, -0.00088501f, -0.000961304f, -0.001037598f, -0.001113892f, -0.001205444f, -0.001296997f, -0.00138855f, -0.001480103f, -0.001586914f, -0.001693726f, -0.001785278f, -0.001907349f, -0.00201416f, -0.002120972f, -0.002243042f, -0.002349854f, -0.002456665f, -0.002578735f, -0.002685547f, -0.002792358f, -0.00289917f, -0.002990723f, -0.003082275f, -0.003173828f, 0.003250122f, 0.003326416f, 0.003387451f, 0.003433228f, 0.003463745f, 0.003479004f, 0.003479004f, 0.003463745f, 0.003417969f, 0.003372192f, 0.00328064f, 0.003173828f, 0.003051758f, 0.002883911f, 0.002700806f, 0.002487183f, 0.002227783f, 0.001937866f, 0.001617432f, 0.001266479f, 0.000869751f, 0.000442505f, -3.0518E-05f, -0.000549316f, -0.001098633f, -0.001693726f, -0.002334595f, -0.003005981f, -0.003723145f, -0.004486084f, -0.0052948f, -0.006118774f, -0.007003784f, -0.007919312f, -0.008865356f, -0.009841919f, -0.010848999f, -0.011886597f, -0.012939453f, -0.014022827f, -0.01512146f, -0.016235352f, -0.017349243f, -0.018463135f, -0.019577026f, -0.020690918f, -0.02178955f, -0.022857666f, -0.023910522f, -0.024932861f, -0.025909424f, -0.02684021f, -0.02772522f, -0.028533936f, -0.029281616f, -0.029937744f, -0.030532837f, -0.03100586f, -0.03138733f, -0.031661987f, -0.031814575f, -0.031845093f, -0.03173828f, -0.03147888f, 0.031082153f, 0.030517578f, 0.029785156f, 0.028884888f, 0.027801514f, 0.026535034f, 0.02508545f, 0.023422241f, 0.021575928f, 0.01953125f, 0.01725769f, 0.014801025f, 0.012115479f, 0.009231567f, 0.006134033f, 0.002822876f, -0.000686646f, -0.004394531f, -0.00831604f, -0.012420654f, -0.016708374f, -0.0211792f, -0.025817871f, -0.03060913f, -0.03555298f, -0.040634155f, -0.045837402f, -0.051132202f, -0.056533813f, -0.06199646f, -0.06752014f, -0.07305908f, -0.07862854f, -0.08418274f, -0.08970642f, -0.09516907f, -0.10054016f, -0.1058197f, -0.110946655f, -0.11592102f, -0.12069702f, -0.1252594f, -0.12956238f, -0.1335907f, -0.13729858f, -0.14067078f, -0.14367676f, -0.1462555f, -0.14842224f, -0.15011597f, -0.15130615f, -0.15196228f, -0.15206909f, -0.15159607f, -0.15049744f, -0.1487732f, -0.1463623f, -0.14326477f, -0.13945007f, -0.1348877f, -0.12957764f, -0.12347412f, -0.11657715f, -0.1088562f, 0.10031128f, 0.090927124f, 0.08068848f, 0.06959534f, 0.057617188f, 0.044784546f, 0.031082153f, 0.01651001f, 0.001068115f, -0.015228271f, -0.03237915f, -0.050354004f, -0.06916809f, -0.088775635f, -0.10916138f, -0.13031006f, -0.15220642f, -0.17478943f, -0.19805908f, -0.22198486f, -0.24650574f, -0.2715912f, -0.2972107f, -0.32331848f, -0.34986877f, -0.37680054f, -0.40408325f, -0.43165588f, -0.45947266f, -0.48747253f, -0.51560974f, -0.54382324f, -0.57203674f, -0.6002197f, -0.6282959f, -0.6562195f, -0.6839142f, -0.71131897f, -0.7383728f, -0.7650299f, -0.791214f, -0.816864f, -0.84194946f, -0.8663635f, -0.89009094f, -0.9130554f, -0.9351959f, -0.95648193f, -0.9768524f, -0.99624634f, -1.0146179f, -1.0319366f, -1.0481567f, -1.0632172f, -1.0771179f, -1.0897827f, -1.1012115f, -1.1113739f, -1.120224f, -1.1277466f, -1.1339264f, -1.1387634f, -1.1422119f, -1.1442871f, 1.144989f, 1.1442871f, 1.1422119f, 1.1387634f, 1.1339264f, 1.1277466f, 1.120224f, 1.1113739f, 1.1012115f, 1.0897827f, 1.0771179f, 1.0632172f, 1.0481567f, 1.0319366f, 1.0146179f, 0.99624634f, 0.9768524f, 0.95648193f, 0.9351959f, 0.9130554f, 0.89009094f, 0.8663635f, 0.84194946f, 0.816864f, 0.791214f, 0.7650299f, 0.7383728f, 0.71131897f, 0.6839142f, 0.6562195f, 0.6282959f, 0.6002197f, 0.57203674f, 0.54382324f, 0.51560974f, 0.48747253f, 0.45947266f, 0.43165588f, 0.40408325f, 0.37680054f, 0.34986877f, 0.32331848f, 0.2972107f, 0.2715912f, 0.24650574f, 0.22198486f, 0.19805908f, 0.17478943f, 0.15220642f, 0.13031006f, 0.10916138f, 0.088775635f, 0.06916809f, 0.050354004f, 0.03237915f, 0.015228271f, -0.001068115f, -0.01651001f, -0.031082153f, -0.044784546f, -0.057617188f, -0.06959534f, -0.08068848f, -0.090927124f, 0.10031128f, 0.1088562f, 0.11657715f, 0.12347412f, 0.12957764f, 0.1348877f, 0.13945007f, 0.14326477f, 0.1463623f, 0.1487732f, 0.15049744f, 0.15159607f, 0.15206909f, 0.15196228f, 0.15130615f, 0.15011597f, 0.14842224f, 0.1462555f, 0.14367676f, 0.14067078f, 0.13729858f, 0.1335907f, 0.12956238f, 0.1252594f, 0.12069702f, 0.11592102f, 0.110946655f, 0.1058197f, 0.10054016f, 0.09516907f, 0.08970642f, 0.08418274f, 0.07862854f, 0.07305908f, 0.06752014f, 0.06199646f, 0.056533813f, 0.051132202f, 0.045837402f, 0.040634155f, 0.03555298f, 0.03060913f, 0.025817871f, 0.0211792f, 0.016708374f, 0.012420654f, 0.00831604f, 0.004394531f, 0.000686646f, -0.002822876f, -0.006134033f, -0.009231567f, -0.012115479f, -0.014801025f, -0.01725769f, -0.01953125f, -0.021575928f, -0.023422241f, -0.02508545f, -0.026535034f, -0.027801514f, -0.028884888f, -0.029785156f, -0.030517578f, 0.031082153f, 0.03147888f, 0.03173828f, 0.031845093f, 0.031814575f, 0.031661987f, 0.03138733f, 0.03100586f, 0.030532837f, 0.029937744f, 0.029281616f, 0.028533936f, 0.02772522f, 0.02684021f, 0.025909424f, 0.024932861f, 0.023910522f, 0.022857666f, 0.02178955f, 0.020690918f, 0.019577026f, 0.018463135f, 0.017349243f, 0.016235352f, 0.01512146f, 0.014022827f, 0.012939453f, 0.011886597f, 0.010848999f, 0.009841919f, 0.008865356f, 0.007919312f, 0.007003784f, 0.006118774f, 0.0052948f, 0.004486084f, 0.003723145f, 0.003005981f, 0.002334595f, 0.001693726f, 0.001098633f, 0.000549316f, 3.0518E-05f, -0.000442505f, -0.000869751f, -0.001266479f, -0.001617432f, -0.001937866f, -0.002227783f, -0.002487183f, -0.002700806f, -0.002883911f, -0.003051758f, -0.003173828f, -0.00328064f, -0.003372192f, -0.003417969f, -0.003463745f, -0.003479004f, -0.003479004f, -0.003463745f, -0.003433228f, -0.003387451f, -0.003326416f, 0.003250122f, 0.003173828f, 0.003082275f, 0.002990723f, 0.00289917f, 0.002792358f, 0.002685547f, 0.002578735f, 0.002456665f, 0.002349854f, 0.002243042f, 0.002120972f, 0.00201416f, 0.001907349f, 0.001785278f, 0.001693726f, 0.001586914f, 0.001480103f, 0.00138855f, 0.001296997f, 0.001205444f, 0.001113892f, 0.001037598f, 0.000961304f, 0.00088501f, 0.000808716f, 0.000747681f, 0.000686646f, 0.00062561f, 0.000579834f, 0.000534058f, 0.000473022f, 0.000442505f, 0.000396729f, 0.000366211f, 0.000320435f, 0.000289917f, 0.000259399f, 0.000244141f, 0.000213623f, 0.000198364f, 0.000167847f, 0.000152588f, 0.000137329f, 0.00012207f, 0.000106812f, 0.000106812f, 9.1553E-05f, 7.6294E-05f, 7.6294E-05f, 6.1035E-05f, 6.1035E-05f, 4.5776E-05f, 4.5776E-05f, 3.0518E-05f, 3.0518E-05f, 3.0518E-05f, 3.0518E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f }; private static float[] SYNTH_COS64_TABLE = new float[31] { 0.500603f, 0.5024193f, 0.50547093f, 0.5097956f, 0.5154473f, 0.5224986f, 0.5310426f, 0.5411961f, 0.5531039f, 0.56694406f, 0.582935f, 0.6013449f, 0.6225041f, 0.6468218f, 0.6748083f, 0.70710677f, 0.7445363f, 0.7881546f, 0.8393496f, 0.8999762f, 0.9725682f, 1.0606776f, 1.1694399f, 1.306563f, 1.4841646f, 1.7224472f, 2.057781f, 2.5629156f, 3.4076085f, 5.1011486f, 10.190008f }; private List<float[]> _synBuf = new List<float[]>(2); private List<int> _bufOffset = new List<int>(2); private float[] _eq; private float[] ippuv = new float[512]; private float[] ei32 = new float[16]; private float[] eo32 = new float[16]; private float[] oi32 = new float[16]; private float[] oo32 = new float[16]; private float[] ei16 = new float[8]; private float[] eo16 = new float[8]; private float[] oi16 = new float[8]; private float[] oo16 = new float[8]; private float[] ei8 = new float[4]; private float[] tmp8 = new float[6]; private float[] oi8 = new float[4]; private float[] oo8 = new float[4]; internal StereoMode StereoMode { get; set; } internal LayerDecoderBase() { StereoMode = StereoMode.Both; } internal abstract int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1); internal void SetEQ(float[] eq) { if (eq == null || eq.Length == 32) { _eq = eq; } } internal virtual void ResetForSeek() { _synBuf.Clear(); _bufOffset.Clear(); } protected void InversePolyPhase(int channel, float[] data) { GetBufAndOffset(channel, out var synBuf, out var k); if (_eq != null) { for (int i = 0; i < 32; i++) { data[i] *= _eq[i]; } } DCT32(data, synBuf, k); BuildUVec(ippuv, synBuf, k); DewindowOutput(ippuv, data); } private void GetBufAndOffset(int channel, out float[] synBuf, out int k) { while (_synBuf.Count <= channel) { _synBuf.Add(new float[1024]); } while (_bufOffset.Count <= channel) { _bufOffset.Add(0); } synBuf = _synBuf[channel]; k = _bufOffset[channel]; k = (k - 32) & 0x1FF; _bufOffset[channel] = k; } private void DCT32(float[] _in, float[] _out, int k) { for (int i = 0; i < 16; i++) { ei32[i] = _in[i] + _in[31 - i]; oi32[i] = (_in[i] - _in[31 - i]) * SYNTH_COS64_TABLE[2 * i]; } DCT16(ei32, eo32); DCT16(oi32, oo32); for (int i = 0; i < 15; i++) { _out[2 * i + k] = eo32[i]; _out[2 * i + 1 + k] = oo32[i] + oo32[i + 1]; } _out[30 + k] = eo32[15]; _out[31 + k] = oo32[15]; } private void DCT16(float[] _in, float[] _out) { float num = _in[0]; float num2 = _in[15]; ei16[0] = num + num2; oi16[0] = (num - num2) * SYNTH_COS64_TABLE[1]; num = _in[1]; num2 = _in[14]; ei16[1] = num + num2; oi16[1] = (num - num2) * SYNTH_COS64_TABLE[5]; num = _in[2]; num2 = _in[13]; ei16[2] = num + num2; oi16[2] = (num - num2) * SYNTH_COS64_TABLE[9]; num = _in[3]; num2 = _in[12]; ei16[3] = num + num2; oi16[3] = (num - num2) * SYNTH_COS64_TABLE[13]; num = _in[4]; num2 = _in[11]; ei16[4] = num + num2; oi16[4] = (num - num2) * SYNTH_COS64_TABLE[17]; num = _in[5]; num2 = _in[10]; ei16[5] = num + num2; oi16[5] = (num - num2) * SYNTH_COS64_TABLE[21]; num = _in[6]; num2 = _in[9]; ei16[6] = num + num2; oi16[6] = (num - num2) * SYNTH_COS64_TABLE[25]; num = _in[7]; num2 = _in[8]; ei16[7] = num + num2; oi16[7] = (num - num2) * SYNTH_COS64_TABLE[29]; DCT8(ei16, eo16); DCT8(oi16, oo16); _out[0] = eo16[0]; _out[1] = oo16[0] + oo16[1]; _out[2] = eo16[1]; _out[3] = oo16[1] + oo16[2]; _out[4] = eo16[2]; _out[5] = oo16[2] + oo16[3]; _out[6] = eo16[3]; _out[7] = oo16[3] + oo16[4]; _out[8] = eo16[4]; _out[9] = oo16[4] + oo16[5]; _out[10] = eo16[5]; _out[11] = oo16[5] + oo16[6]; _out[12] = eo16[6]; _out[13] = oo16[6] + oo16[7]; _out[14] = eo16[7]; _out[15] = oo16[7]; } private void DCT8(float[] _in, float[] _out) { ei8[0] = _in[0] + _in[7]; ei8[1] = _in[3] + _in[4]; ei8[2] = _in[1] + _in[6]; ei8[3] = _in[2] + _in[5]; tmp8[0] = ei8[0] + ei8[1]; tmp8[1] = ei8[2] + ei8[3]; tmp8[2] = (ei8[0] - ei8[1]) * SYNTH_COS64_TABLE[7]; tmp8[3] = (ei8[2] - ei8[3]) * SYNTH_COS64_TABLE[23]; tmp8[4] = (tmp8[2] - tmp8[3]) * 0.70710677f; _out[0] = tmp8[0] + tmp8[1]; _out[2] = tmp8[2] + tmp8[3] + tmp8[4]; _out[4] = (tmp8[0] - tmp8[1]) * 0.70710677f; _out[6] = tmp8[4]; oi8[0] = (_in[0] - _in[7]) * SYNTH_COS64_TABLE[3]; oi8[1] = (_in[1] - _in[6]) * SYNTH_COS64_TABLE[11]; oi8[2] = (_in[2] - _in[5]) * SYNTH_COS64_TABLE[19]; oi8[3] = (_in[3] - _in[4]) * SYNTH_COS64_TABLE[27]; tmp8[0] = oi8[0] + oi8[3]; tmp8[1] = oi8[1] + oi8[2]; tmp8[2] = (oi8[0] - oi8[3]) * SYNTH_COS64_TABLE[7]; tmp8[3] = (oi8[1] - oi8[2]) * SYNTH_COS64_TABLE[23]; tmp8[4] = tmp8[2] + tmp8[3]; tmp8[5] = (tmp8[2] - tmp8[3]) * 0.70710677f; oo8[0] = tmp8[0] + tmp8[1]; oo8[1] = tmp8[4] + tmp8[5]; oo8[2] = (tmp8[0] - tmp8[1]) * 0.70710677f; oo8[3] = tmp8[5]; _out[1] = oo8[0] + oo8[1]; _out[3] = oo8[1] + oo8[2]; _out[5] = oo8[2] + oo8[3]; _out[7] = oo8[3]; } private void BuildUVec(float[] u_vec, float[] cur_synbuf, int k) { int num = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 16; j++) { u_vec[num + j] = cur_synbuf[k + j + 16]; u_vec[num + j + 17] = 0f - cur_synbuf[k + 31 - j]; } k = (k + 32) & 0x1FF; for (int j = 0; j < 16; j++) { u_vec[num + j + 32] = 0f - cur_synbuf[k + 16 - j]; u_vec[num + j + 48] = 0f - cur_synbuf[k + j]; } u_vec[num + 16] = 0f; k = (k + 32) & 0x1FF; num += 64; } } private void DewindowOutput(float[] u_vec, float[] samples) { for (int i = 0; i < 512; i++) { u_vec[i] *= DEWINDOW_TABLE[i]; } for (int j = 0; j < 32; j++) { float num = u_vec[j]; num += u_vec[j + 32]; num += u_vec[j + 64]; num += u_vec[j + 96]; num += u_vec[j + 128]; num += u_vec[j + 160]; num += u_vec[j + 192]; num += u_vec[j + 224]; num += u_vec[j + 256]; num += u_vec[j + 288]; num += u_vec[j + 320]; num += u_vec[j + 352]; num += u_vec[j + 384]; num += u_vec[j + 416]; num += u_vec[j + 448]; num += u_vec[j + 480]; u_vec[j] = num; } for (int k = 0; k < 32; k++) { samples[k] = u_vec[k]; } } } internal class LayerIDecoder : LayerIIDecoderBase { private static readonly int[] _rateTable = new int[32]; private static readonly int[][] _allocLookupTable = new int[1][] { new int[17] { 4, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } }; internal static bool GetCRC(MpegFrame frame, ref uint crc) { return LayerIIDecoderBase.GetCRC(frame, _rateTable, _allocLookupTable, readScfsiBits: false, ref crc); } internal LayerIDecoder() : base(_allocLookupTable, 1) { } protected override int[] GetRateTable(IMpegFrame frame) { return _rateTable; } protected override void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels) { } } internal class LayerIIDecoder : LayerIIDecoderBase { private static readonly int[][] _rateLookupTable = new int[5][] { new int[27] { 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, new int[30] { 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, new int[8] { 4, 4, 5, 5, 5, 5, 5, 5 }, new int[12] { 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, new int[30] { 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 } }; private static readonly int[][] _allocLookupTable = new int[8][] { new int[5] { 2, 0, -5, -7, 16 }, new int[9] { 3, 0, -5, -7, 3, -10, 4, 5, 16 }, new int[17] { 4, 0, -5, -7, 3, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }, new int[17] { 4, 0, -5, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, new int[17] { 4, 0, -5, -7, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, new int[9] { 3, 0, -5, -7, -10, 4, 5, 6, 9 }, new int[17] { 4, 0, -5, -7, 3, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, new int[5] { 2, 0, -5, -7, 3 } }; internal static bool GetCRC(MpegFrame frame, ref uint crc) { return LayerIIDecoderBase.GetCRC(frame, SelectTable(frame), _allocLookupTable, readScfsiBits: true, ref crc); } private static int[] SelectTable(IMpegFrame frame) { int num = frame.BitRate / ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) / 1000; if (frame.Version == MpegVersion.Version1) { if ((num >= 56 && num <= 80) || (frame.SampleRate == 48000 && num >= 56)) { return _rateLookupTable[0]; } if (frame.SampleRate != 48000 && num >= 96) { return _rateLookupTable[1]; } if (frame.SampleRate != 32000 && num <= 48) { return _rateLookupTable[2]; } return _rateLookupTable[3]; } return _rateLookupTable[4]; } internal LayerIIDecoder() : base(_allocLookupTable, 3) { } protected override int[] GetRateTable(IMpegFrame frame) { return SelectTable(frame); } protected override void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels) { for (int i = 0; i < 30; i++) { for (int j = 0; j < channels; j++) { if (scfsi[j][i] == 2) { scfsi[j][i] = frame.ReadBits(2); } } } } } internal abstract class LayerIIDecoderBase : LayerDecoderBase { protected const int SSLIMIT = 12; private static readonly float[] _groupedC = new float[5] { 0f, 0f, 1.3333334f, 1.6f, 1.7777778f }; private static readonly float[] _groupedD = new float[5] { 0f, 0f, -0.5f, -0.5f, -0.5f }; private static readonly float[] _C = new float[17] { 0f, 0f, 1.3333334f, 1.1428572f, 1.0666667f, 1.032258f, 1.0158731f, 1.007874f, 1.0039216f, 1.0019569f, 1.0009775f, 1.0004885f, 1.0002443f, 1.0001221f, 1.000061f, 1.0000305f, 1.0000153f }; private static readonly float[] _D = new float[17] { 0f, 0f, -0.5f, -0.75f, -0.875f, -0.9375f, -31f / 32f, -63f / 64f, -127f / 128f, -0.99609375f, -0.9980469f, -0.99902344f, -0.9995117f, -0.99975586f, -0.9998779f, -0.99993896f, -0.9999695f }; private static readonly float[] _denormalMultiplier = new float[64] { 2f, 1.587401f, 1.2599211f, 1f, 0.7937005f, 0.62996054f, 0.5f, 0.39685026f, 0.31498027f, 0.25f, 0.19842513f, 0.15749013f, 0.125f, 0.099212565f, 0.07874507f, 0.0625f, 0.049606282f, 0.039372534f, 1f / 32f, 0.024803141f, 0.019686267f, 1f / 64f, 0.012401571f, 0.009843133f, 1f / 128f, 0.0062007853f, 0.0049215667f, 0.00390625f, 0.0031003926f, 0.0024607833f, 0.001953125f, 0.0015501963f, 0.0012303917f, 0.0009765625f, 0.00077509816f, 0.00061519584f, 0.00048828125f, 0.00038754908f, 0.00030759792f, 0.00024414062f, 0.00019377454f, 0.00015379896f, 0.00012207031f, 9.688727E-05f, 7.689948E-05f, 6.1035156E-05f, 4.8443635E-05f, 3.844974E-05f, 3.0517578E-05f, 2.4221818E-05f, 1.922487E-05f, 1.5258789E-05f, 1.2110909E-05f, 9.612435E-06f, 7.6293945E-06f, 6.0554544E-06f, 4.8062175E-06f, 3.8146973E-06f, 3.0277272E-06f, 2.4031087E-06f, 1.9073486E-06f, 1.5138636E-06f, 1.2015544E-06f, 9.536743E-07f }; private int _channels; private int _jsbound; private int _granuleCount; private int[][] _allocLookupTable; private int[][] _scfsi; private int[][] _samples; private int[][][] _scalefac; private float[] _polyPhaseBuf; private int[][] _allocation; protected static bool GetCRC(MpegFrame frame, int[] rateTable, int[][] allocLookupTable, bool readScfsiBits, ref uint crc) { int num = 0; int num2 = rateTable.Length; int num3 = num2; if (frame.ChannelMode == MpegChannelMode.JointStereo) { num3 = frame.ChannelModeExtension * 4 + 4; } int num4 = ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2); int i; for (i = 0; i < num3; i++) { int num5 = allocLookupTable[rateTable[i]][0]; for (int j = 0; j < num4; j++) { int num6 = frame.ReadBits(num5); if (num6 > 0) { num += 2; } MpegFrame.UpdateCRC(num6, num5, ref crc); } } for (; i < num2; i++) { int num7 = allocLookupTable[rateTable[i]][0]; int num8 = frame.ReadBits(num7); if (num8 > 0) { num += num4 * 2; } MpegFrame.UpdateCRC(num8, num7, ref crc); } if (readScfsiBits) { while (num >= 2) { MpegFrame.UpdateCRC(frame.ReadBits(2), 2, ref crc); num -= 2; } } return true; } protected LayerIIDecoderBase(int[][] allocLookupTable, int granuleCount) { _allocLookupTable = allocLookupTable; _granuleCount = granuleCount; _allocation = new int[2][] { new int[32], new int[32] }; _scfsi = new int[2][] { new int[32], new int[32] }; _samples = new int[2][] { new int[384 * _granuleCount], new int[384 * _granuleCount] }; _scalefac = new int[2][][] { new int[3][], new int[3][] }; for (int i = 0; i < 3; i++) { _scalefac[0][i] = new int[32]; _scalefac[1][i] = new int[32]; } _polyPhaseBuf = new float[32]; } internal override int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1) { InitFrame(frame); int[] rateTable = GetRateTable(frame); ReadAllocation(frame, rateTable); for (int i = 0; i < _scfsi[0].Length; i++) { _scfsi[0][i] = ((_allocation[0][i] != 0) ? 2 : (-1)); _scfsi[1][i] = ((_allocation[1][i] != 0) ? 2 : (-1)); } ReadScaleFactorSelection(frame, _scfsi, _channels); ReadScaleFactors(frame); ReadSamples(frame); return DecodeSamples(ch0, ch1); } private void InitFrame(IMpegFrame frame) { switch (frame.ChannelMode) { case MpegChannelMode.Mono: _channels = 1; _jsbound = 32; break; case MpegChannelMode.JointStereo: _channels = 2; _jsbound = frame.ChannelModeExtension * 4 + 4; break; default: _channels = 2; _jsbound = 32; break; } } protected abstract int[] GetRateTable(IMpegFrame frame); private void ReadAllocation(IMpegFrame frame, int[] rateTable) { int num = rateTable.Length; if (_jsbound > num) { _jsbound = num; } Array.Clear(_allocation[0], 0, 32); Array.Clear(_allocation[1], 0, 32); int i; for (i = 0; i < _jsbound; i++) { int[] array = _allocLookupTable[rateTable[i]]; int bitCount = array[0]; for (int j = 0; j < _channels; j++) { _allocation[j][i] = array[frame.ReadBits(bitCount) + 1]; } } for (; i < num; i++) { int[] array2 = _allocLookupTable[rateTable[i]]; _allocation[0][i] = (_allocation[1][i] = array2[frame.ReadBits(array2[0]) + 1]); } } protected abstract void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels); private void ReadScaleFactors(IMpegFrame frame) { for (int i = 0; i < 32; i++) { for (int j = 0; j < _channels; j++) { switch (_scfsi[j][i]) { case 0: _scalefac[j][0][i] = frame.ReadBits(6); _scalefac[j][1][i] = frame.ReadBits(6); _scalefac[j][2][i] = frame.ReadBits(6); break; case 1: _scalefac[j][0][i] = (_scalefac[j][1][i] = frame.ReadBits(6)); _scalefac[j][2][i] = frame.ReadBits(6); break; case 2: _scalefac[j][0][i] = (_scalefac[j][1][i] = (_scalefac[j][2][i] = frame.ReadBits(6))); break; case 3: _scalefac[j][0][i] = frame.ReadBits(6); _scalefac[j][1][i] = (_scalefac[j][2][i] = frame.ReadBits(6)); break; default: _scalefac[j][0][i] = 63; _scalefac[j][1][i] = 63; _scalefac[j][2][i] = 63; break; } } } } private void ReadSamples(IMpegFrame frame) { int num = 0; int num2 = 0; while (num < 12) { int num3 = 0; while (num3 < 32) { for (int i = 0; i < _channels; i++) { if (i == 0 || num3 < _jsbound) { int num4 = _allocation[i][num3]; if (num4 != 0) { if (num4 < 0) { int num5 = frame.ReadBits(-num4); int num6 = (1 << -num4 / 2 + -num4 % 2 - 1) + 1; _samples[i][num2] = num5 % num6; num5 /= num6; _samples[i][num2 + 32] = num5 % num6; _samples[i][num2 + 64] = num5 / num6; } else { for (int j = 0; j < _granuleCount; j++) { _samples[i][num2 + 32 * j] = frame.ReadBits(num4); } } } else { for (int k = 0; k < _granuleCount; k++) { _samples[i][num2 + 32 * k] = 0; } } } else { for (int l = 0; l < _granuleCount; l++) { _samples[1][num2 + 32 * l] = _samples[0][num2 + 32 * l]; } } } num3++; num2++; } num++; num2 += 32 * (_granuleCount - 1); } } private int DecodeSamples(float[] ch0, float[] ch1) { float[][] array = new float[2][]; int num = 0; int num2 = _channels - 1; if (_channels == 1 || base.StereoMode == StereoMode.LeftOnly) { array[0] = ch0; num2 = 0; } else if (base.StereoMode == StereoMode.RightOnly) { array[1] = ch0; num = 1; } else { array[0] = ch0; array[1] = ch1; } int num3 = 0; for (int i = num; i <= num2; i++) { num3 = 0; for (int j = 0; j < _granuleCount; j++) { for (int k = 0; k < 12; k++) { int num4 = 0; while (num4 < 32) { int num5 = _allocation[i][num4]; if (num5 != 0) { float[] array2; float[] array3; if (num5 < 0) { num5 = -num5 / 2 + -num5 % 2 - 1; array2 = _groupedC; array3 = _groupedD; } else { array2 = _C; array3 = _D; } _polyPhaseBuf[num4] = array2[num5] * ((float)(_samples[i][num3] << 16 - num5) / 32768f + array3[num5]) * _denormalMultiplier[_scalefac[i][j][num4]]; } else { _polyPhaseBuf[num4] = 0f; } num4++; num3++; } InversePolyPhase(i, _polyPhaseBuf); Array.Copy(_polyPhaseBuf, 0, array[i], num3 - 32, 32); } } } if (_channels == 2 && base.StereoMode == StereoMode.DownmixToMono) { for (int l = 0; l < num3; l++) { ch0[l] = (ch0[l] + ch1[l]) / 2f; } } return num3; } } internal sealed class LayerIIIDecoder : LayerDecoderBase { private class HybridMDCT { private const float PI = MathF.PI; private static float[][] _swin; private static float[] icos72_table; private List<float[]> _prevBlock; private List<float[]> _nextBlock; private float[] _imdctTemp = new float[18]; private float[] _imdctResult = new float[36]; private const float sqrt32 = 0.8660254f; static HybridMDCT() { icos72_table = new float[35] { 0.50047636f, 0.5019099f, 0.5043145f, 0.5077133f, 0.51213974f, 0.5176381f, 0.5242646f, 0.5320889f, 0.5411961f, 0.55168897f, 0.56369096f, 0.57735026f, 0.59284455f, 0.61038727f, 0.6302362f, 0.65270364f, 0.67817086f, 0.70710677f, 0.7400936f, 0.7778619f, 0.8213398f, 0.8717234f, 0.9305795f, 1f, 1.0828403f, 1.1831008f, 1.306563f, 1.4619021f, 1.6627548f, 1.9318516f, 2.3101132f, 2.8793852f, 3.830649f, 5.7368565f, 11.462792f }; _swin = new float[4][] { new float[36], new float[36], new float[36], new float[36] }; for (int i = 0; i < 36; i++) { _swin[0][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5)); } for (int i = 0; i < 18; i++) { _swin[1][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5)); } for (int i = 18; i < 24; i++) { _swin[1][i] = 1f; } for (int i = 24; i < 30; i++) { _swin[1][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5 - 18.0)); } for (int i = 30; i < 36; i++) { _swin[1][i] = 0f; } for (int i = 0; i < 6; i++) { _swin[3][i] = 0f; } for (int i = 6; i < 12; i++) { _swin[3][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5 - 6.0)); } for (int i = 12; i < 18; i++) { _swin[3][i] = 1f; } for (int i = 18; i < 36; i++) { _swin[3][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5)); } for (int i = 0; i < 12; i++) { _swin[2][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5)); } for (int i = 12; i < 36; i++) { _swin[2][i] = 0f; } } internal HybridMDCT() { _prevBlock = new List<float[]>(); _nextBlock = new List<float[]>(); } internal void Reset() { _prevBlock.Clear(); _nextBlock.Clear(); } private void GetPrevBlock(int channel, out float[] prevBlock, out float[] nextBlock) { while (_prevBlock.Count <= channel) { _prevBlock.Add(new float[576]); } while (_nextBlock.Count <= channel) { _nextBlock.Add(new float[576]); } prevBlock = _prevBlock[channel]; nextBlock = _nextBlock[channel]; _nextBlock[channel] = prevBlock; _prevBlock[channel] = nextBlock; } internal void Apply(float[] fsIn, int channel, int blockType, bool doMixed) { GetPrevBlock(channel, out var prevBlock, out var nextBlock); int sbStart = 0; if (doMixed) { LongImpl(fsIn, 0, 2, nextBlock, 0); sbStart = 2; } if (blockType == 2) { ShortImpl(fsIn, sbStart, nextBlock); } else { LongImpl(fsIn, sbStart, 32, nextBlock, blockType); } for (int i = 0; i < 576; i++) { fsIn[i] += prevBlock[i]; } } private void LongImpl(float[] fsIn, int sbStart, int sbLimit, float[] nextblck, int blockType) { int i = sbStart; int num = sbStart * 18; for (; i < sbLimit; i++) { Array.Copy(fsIn, num, _imdctTemp, 0, 18); LongIMDCT(_imdctTemp, _imdctResult); float[] array = _swin[blockType]; int j; for (j = 0; j < 18; j++) { fsIn[num++] = _imdctResult[j] * array[j]; } num -= 18; for (; j < 36; j++) { nextblck[num++] = _imdctResult[j] * array[j]; } } } private static void LongIMDCT(float[] invec, float[] outvec) { float[] array = new float[17]; float[] array2 = new float[18]; float[] array3 = new float[9]; float[] array4 = new float[9]; float[] array5 = new float[9]; float[] array6 = new float[9]; int i; for (i = 0; i < 17; i++) { array[i] = invec[i] + invec[i + 1]; } array3[0] = invec[0]; array4[0] = array[0]; int num = 0; i = 1; while (i < 9) { array3[i] = array[num + 1]; array4[i] = array[num] + array[num + 2]; i++; num += 2; } imdct_9pt(array3, array5); imdct_9pt(array4, array6); for (i = 0; i < 9; i++) { array6[i] *= ICOS36_A(i); array2[i] = (array5[i] + array6[i]) * ICOS72_A(i); } for (; i < 18; i++) { array2[i] = (array5[17 - i] - array6[17 - i]) * ICOS72_A(i); } outvec[0] = array2[9]; outvec[1] = array2[10]; outvec[2] = array2[11]; outvec[3] = array2[12]; outvec[4] = array2[13]; outvec[5] = array2[14]; outvec[6] = array2[15]; outvec[7] = array2[16]; outvec[8] = array2[17]; outvec[9] = 0f - array2[17]; outvec[10] = 0f - array2[16]; outvec[11] = 0f - array2[15]; outvec[12] = 0f - array2[14]; outvec[13] = 0f - array2[13]; outvec[14] = 0f - array2[12]; outvec[15] = 0f - array2[11]; outvec[16] = 0f - array2[10]; outvec[17] = 0f - array2[9]; outvec[35] = (outvec[18] = 0f - array2[8]); outvec[34] = (outvec[19] = 0f - array2[7]); outvec[33] = (outvec[20] = 0f - array2[6]); outvec[32] = (outvec[21] = 0f - array2[5]); outvec[31] = (outvec[22] = 0f - array2[4]); outvec[30] = (outvec[23] = 0f - array2[3]); outvec[29] = (outvec[24] = 0f - array2[2]); outvec[28] = (outvec[25] = 0f - array2[1]); outvec[27] = (outvec[26] = 0f - array2[0]); } private static float ICOS72_A(int i) { return icos72_table[2 * i]; } private static float ICOS36_A(int i) { return icos72_table[4 * i + 1]; } private static void imdct_9pt(float[] invec, float[] outvec) { float[] array = new float[5]; float[] array2 = new float[4]; float num = invec[6] / 2f + invec[0]; float num2 = invec[0] - invec[6]; float num3 = invec[2] - invec[4] - invec[8]; array[0] = num + invec[2] * 0.9396926f + invec[4] * 0.76604444f + invec[8] * 0.17364818f; array[1] = num3 / 2f + num2; array[2] = num - invec[2] * 0.17364818f - invec[4] * 0.9396926f + invec[8] * 0.76604444f; array[3] = num - invec[2] * 0.76604444f + invec[4] * 0.17364818f - invec[8] * 0.9396926f; array[4] = num2 - num3; float num4 = invec[1] + invec[3]; float num5 = invec[3] + invec[5]; num = (invec[5] + invec[7]) * 0.5f + invec[1]; array2[0] = num + num4 * 0.9396926f + num5 * 0.76604444f; array2[1] = (invec[1] - invec[5]) * 1.5f - invec[7]; array2[2] = num - num4 * 0.17364818f - num5 * 0.9396926f; array2[3] = num - num4 * 0.76604444f + num5 * 0.17364818f; array2[0] += invec[7] * 0.17364818f; array2[1] -= invec[7] * 0.5f; array2[2] += invec[7] * 0.76604444f; array2[3] -= invec[7] * 0.9396926f; array2[0] *= 0.5077133f; array2[1] *= 0.57735026f; array2[2] *= 0.7778619f; array2[3] *= 1.4619021f; for (int i = 0; i < 4; i++) { outvec[i] = array[i] + array2[i]; } outvec[4] = array[4]; for (int i = 5; i < 9; i++) { outvec[i] = array[8 - i] - array2[8 - i]; } } private void ShortImpl(float[] fsIn, int sbStart, float[] nextblck) { _ = _swin[2]; int num = sbStart; int num2 = sbStart * 18; while (num < 32) { int i = 0; int num3 = 0; for (; i < 3; i++) { int num4 = num2 + i; for (int j = 0; j < 6; j++) { _imdctTemp[num3 + j] = fsIn[num4]; num4 += 3; } num3 += 6; } Array.Clear(fsIn, num2, 6); ShortIMDCT(_imdctTemp, 0, _imdctResult); Array.Copy(_imdctResult, 0, fsIn, num2 + 6, 12); ShortIMDCT(_imdct