using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.AvatarFramework; using Il2CppScheduleOne.AvatarFramework.Animation; using Il2CppScheduleOne.AvatarFramework.Emotions; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Economy; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.Messaging; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.NPCs.Actions; using Il2CppScheduleOne.NPCs.Behaviour; using Il2CppScheduleOne.NPCs.Relation; using Il2CppScheduleOne.Police; using Il2CppScheduleOne.UI.Compass; using Il2CppScheduleOne.Vision; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using IllegalRave.Gltf; using IllegalRave.Gltf.Data; using IllegalRave.Gltf.Processing; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using NLayer; using NLayer.Decoder; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Illegal Rave")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: MelonInfo(typeof(RaveMod), "Illegal Rave", "1.0.10", "Virtunerd", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: AssemblyFileVersion("1.0.10")] [assembly: AssemblyInformationalVersion("1.0.10")] [assembly: AssemblyVersion("1.0.10.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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; } } } internal static class GlbAssetProvider { private const uint GLB_MAGIC = 1179937895u; internal static byte[] GetDjBooth() { return ReadResource("rave.assets.glb.djbooth.glb"); } internal static byte[] GetDjDan() { return ReadResource("rave.assets.glb.djdan.glb"); } internal static byte[] GetDjGirl() { return ReadResource("rave.assets.glb.djgirl.glb"); } internal static byte[] GetDjCutChemist() { return ReadResource("rave.assets.glb.djcutchemist.glb"); } internal static byte[] GetDjLudapimp() { return ReadResource("rave.assets.glb.djludapimp.glb"); } internal static byte[] GetFlyer() { return ReadResource("rave.assets.glb.flyer.glb"); } internal static byte[] GetTripods() { return ReadResource("rave.assets.glb.tripods.glb"); } internal static byte[] GetLetsGo() { return ReadResource("rave.assets.glb.letsgo.glb"); } private static byte[] ReadResource(string name) { Assembly assembly = typeof(GlbAssetProvider).Assembly; using (Stream stream = assembly.GetManifestResourceStream(name + ".br")) { if (stream != null) { byte[] array = DecompressGlb(stream); if (array != null) { return array; } RaveMod.Logger.Error("Embedded asset '" + name + ".br' could not be decompressed."); return null; } } using Stream stream2 = assembly.GetManifestResourceStream(name); if (stream2 == null) { return null; } using MemoryStream memoryStream = new MemoryStream((int)stream2.Length); stream2.CopyTo(memoryStream); return memoryStream.ToArray(); } private static byte[] DecompressGlb(Stream compressed) { using BrotliStream stream = new BrotliStream(compressed, CompressionMode.Decompress); byte[] array = new byte[12]; if (!ReadExactly(stream, array, 0, array.Length)) { return null; } if (BitConverter.ToUInt32(array, 0) != 1179937895) { return null; } uint num = BitConverter.ToUInt32(array, 8); if (num < 12 || num > int.MaxValue) { return null; } byte[] array2 = new byte[num]; Buffer.BlockCopy(array, 0, array2, 0, array.Length); if (!ReadExactly(stream, array2, array.Length, (int)num - array.Length)) { return null; } return array2; } private static bool ReadExactly(Stream stream, byte[] buffer, int offset, int count) { while (count > 0) { int num = stream.Read(buffer, offset, count); if (num <= 0) { return false; } offset += num; count -= num; } return true; } } public static class LetsGoObjectController { private static GameObject _prefab; private static GameObject _instance; private static bool _cacheFailed; private const string GO_NAME = "LetsGoObject"; private static readonly Vector3 CORE_POSITION = new Vector3(-170.12f, -2.94f, 85.17f); private static readonly Vector3 PULTV2_LOCAL_POSITION = new Vector3(0.028f, 1.809f, 0.258f); private static readonly Vector3 OFFSET = new Vector3(-3.9f, -0.95f, -0.5f); private static readonly Quaternion ROTATION = Quaternion.Euler(0f, 90f, 0f); internal static Vector3 GetSpawnPosition() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) return CORE_POSITION + OFFSET; } internal static Quaternion GetSpawnRotation() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) return ROTATION; } internal static Vector3 GetPultWorldPosition() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) return GetSpawnPosition() + GetSpawnRotation() * PULTV2_LOCAL_POSITION; } internal static void SpawnObject() { //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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) if (_cacheFailed) { return; } try { if ((Object)(object)_prefab == (Object)null) { byte[] letsGo = GlbAssetProvider.GetLetsGo(); if (letsGo == null) { Debug.LogError(Object.op_Implicit("[LetsGo] GLB data null")); _cacheFailed = true; return; } GltfImporter gltfImporter = new GltfImporter().SetName("LetsGoObject").ImportAnimations(import: false).SetScale(1f); _prefab = gltfImporter.Load(letsGo); } if (!((Object)(object)_instance != (Object)null)) { Vector3 spawnPosition = GetSpawnPosition(); RaveMod.Logger.Msg($"[LetsGo] Spawn at ({spawnPosition.x:F2}, {spawnPosition.y:F2}, {spawnPosition.z:F2})"); _instance = Object.Instantiate(_prefab, spawnPosition, ROTATION); ((Object)_instance).name = "LetsGoObject"; _instance.isStatic = true; SetupColliders(_instance); RaveMod.Logger.Msg($"[LetsGo] Final Position: {spawnPosition}"); Instance logger = RaveMod.Logger; DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(19, 1); defaultInterpolatedStringHandler.AppendLiteral("[LetsGo] Rotation: "); Quaternion rOTATION = ROTATION; defaultInterpolatedStringHandler.AppendFormatted(((Quaternion)(ref rOTATION)).eulerAngles); logger.Msg(defaultInterpolatedStringHandler.ToStringAndClear()); } } catch (Exception ex) { Debug.LogError(Object.op_Implicit("[LetsGo] Spawn failed: " + ex)); _cacheFailed = true; } } internal static void SetupColliders(GameObject root) { int num = 0; foreach (Transform componentsInChild in root.GetComponentsInChildren(true)) { if (!((Object)componentsInChild).name.StartsWith("COL_", StringComparison.OrdinalIgnoreCase)) { continue; } MeshFilter component = ((Component)componentsInChild).GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null) { RaveMod.Logger.Warning("[LetsGo] Collider node '" + ((Object)componentsInChild).name + "' has no mesh – skipped"); continue; } MeshCollider val = ((Component)componentsInChild).gameObject.GetComponent() ?? ((Component)componentsInChild).gameObject.AddComponent(); val.sharedMesh = component.sharedMesh; val.convex = false; MeshRenderer component2 = ((Component)componentsInChild).GetComponent(); if ((Object)(object)component2 != (Object)null) { ((Renderer)component2).enabled = false; } num++; RaveMod.Logger.Msg("[LetsGo] Collider attached: " + ((Object)componentsInChild).name); } RaveMod.Logger.Msg($"[LetsGo] SetupColliders done – {num} collider(s) added"); } internal static void Cleanup() { if ((Object)(object)_instance != (Object)null) { Object.Destroy((Object)(object)_instance); _instance = null; } } } public sealed class RaveAudioController { private struct PendingClip { internal string TrackPath; internal float[] Samples; internal int SampleRate; internal int Channels; } private const int VISUAL_SPEAKER_COUNT = 4; private const float SPEAKER_RADIUS = 2.5f; private static GameObject[] _speakerVisuals; private static GameObject _audioObject; private static List _stageAudioObjects = new List(); private static AudioSource _audioSource; private static bool _isPlaying = false; private static bool _isPaused = false; private const int STAGE_SYNC_TOLERANCE_SAMPLES = 441; private const int MAX_CACHE_SIZE = 50; private static Dictionary _clipCache = new Dictionary(); private static LinkedList _cacheOrder = new LinkedList(); private static Dictionary _mutedSources = new Dictionary(); private static AudioSource[] _cachedVanillaSources; private static float _vanillaScanTimer = 0f; private const float VANILLA_SCAN_INTERVAL = 10f; private static readonly object _pendingLock = new object(); private static readonly Queue _pendingClips = new Queue(); private static volatile int _backgroundDecodeCount = 0; private static volatile bool _waitingForTrack = false; private static string _waitingTrackPath = null; private RaveAudioController() { } internal static void SpawnSpeaker() { //IL_002c: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Expected O, but got Unknown //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) try { DestroyStageAudioObjects(); _audioObject = null; _audioSource = null; _speakerVisuals = null; _isPlaying = false; _isPaused = false; DestroyStaleObjects(); Vector3 musicPosition = RaveLocationManager.MusicPosition; _audioObject = new GameObject("RaveSpeaker_Audio"); _audioObject.transform.position = musicPosition; _audioSource = _audioObject.AddComponent(); _audioSource.spatialBlend = 1f; _audioSource.rolloffMode = (AudioRolloffMode)2; _audioSource.dopplerLevel = 0f; _audioSource.loop = false; _audioSource.volume = RaveConfig.MusicVolume.Value; _audioSource.playOnAwake = false; if (RaveLocationManager.IsUnderground) { _audioSource.minDistance = 3f; _audioSource.maxDistance = 20f; _audioSource.spread = 360f; AnimationCurve val = new AnimationCurve(); val.AddKey(0f, 1f); val.AddKey(3f, 1f); val.AddKey(8f, 0.6f); val.AddKey(14f, 0.15f); val.AddKey(18f, 0.02f); val.AddKey(20f, 0f); _audioSource.SetCustomCurve((AudioSourceCurveType)0, val); } else { _audioSource.minDistance = 5f; _audioSource.maxDistance = 60f; _audioSource.spread = 180f; AnimationCurve val2 = new AnimationCurve(); val2.AddKey(0f, 1f); val2.AddKey(5f, 1f); val2.AddKey(15f, 0.7f); val2.AddKey(30f, 0.3f); val2.AddKey(45f, 0.06f); val2.AddKey(55f, 0.01f); val2.AddKey(60f, 0f); _audioSource.SetCustomCurve((AudioSourceCurveType)0, val2); } _speakerVisuals = (GameObject[])(object)new GameObject[4]; Vector3 val3 = default(Vector3); for (int i = 0; i < 4; i++) { float num = (float)Math.PI / 2f * (float)i; ((Vector3)(ref val3))..ctor(musicPosition.x + Mathf.Cos(num) * 2.5f, musicPosition.y, musicPosition.z + Mathf.Sin(num) * 2.5f); GameObject val4 = new GameObject($"RaveSpeaker_{i}"); val4.transform.position = val3; _speakerVisuals[i] = val4; GameObject val5 = GameObject.CreatePrimitive((PrimitiveType)3); val5.transform.SetParent(val4.transform); val5.transform.localPosition = new Vector3(0f, 0.5f, 0f); val5.transform.localScale = new Vector3(0.8f, 1.2f, 0.6f); Vector3 val6 = musicPosition - val3; val6.y = 0f; if (Vector3.Dot(val6, val6) > 0.01f) { val4.transform.rotation = Quaternion.LookRotation(val6); } Collider component = val5.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = val5.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.material.color = new Color(0.1f, 0.1f, 0.1f); } } ScanVanillaAudioSources(); if (RaveLocationManager.IsStageActive) { TrySpawnStageAudioSources(); } } catch (Exception ex) { RaveMod.Logger.Error("Error creating audio system: " + ex.Message); } } private static void TrySpawnStageAudioSources() { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: 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_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) try { DestroyStageAudioObjects(); GameObject val = GameObject.Find("SmallFestivalStage"); List<(Vector3, string)> list = new List<(Vector3, string)>(); if ((Object)(object)val != (Object)null) { foreach (Transform componentsInChild in val.GetComponentsInChildren(false)) { string name = ((Object)componentsInChild).name; if (name != null) { string text = name.ToLowerInvariant(); bool flag = text.StartsWith("col_speaker"); bool flag2 = text.StartsWith("h") && text.Contains("ngeboxen"); bool flag3 = text == "kleinebox"; bool flag4 = text.StartsWith("funktion"); if (flag || flag2 || flag3 || flag4) { list.Add((componentsInChild.position, name)); } } } } if (list.Count == 0) { if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] No stage speaker nodes found — stage audio skipped (main source only)."); } return; } AnimationCurve val2 = new AnimationCurve(); val2.AddKey(0f, 1f); val2.AddKey(3f, 1f); val2.AddKey(10f, 0.6f); val2.AddKey(20f, 0.2f); val2.AddKey(35f, 0.02f); val2.AddKey(40f, 0f); foreach (var item3 in list) { Vector3 item = item3.Item1; string item2 = item3.Item2; GameObject val3 = new GameObject("RaveSpeaker_Stage_" + item2); val3.transform.position = item; AudioSource val4 = val3.AddComponent(); val4.spatialBlend = 1f; val4.rolloffMode = (AudioRolloffMode)2; val4.dopplerLevel = 0f; val4.loop = false; val4.volume = RaveConfig.MusicVolume.Value * 0.25f; val4.playOnAwake = false; val4.minDistance = 3f; val4.maxDistance = 40f; val4.spread = 140f; val4.SetCustomCurve((AudioSourceCurveType)0, val2); _stageAudioObjects.Add(val3); RaveMod.Logger.Msg($"[Stage] AudioSource spawned: {item2} at ({item.x:F1},{item.y:F1},{item.z:F1})"); } } catch (Exception ex) { RaveMod.Logger.Warning("[Stage] AudioSource spawn failed: " + ex.Message); } } internal static void PreloadAudio() { try { RavePlaylistManager.Initialize(); if (RavePlaylistManager.TrackCount == 0) { RaveMod.Logger.Warning("No tracks in playlist, pre-loading skipped."); return; } _clipCache.Clear(); _cacheOrder.Clear(); _waitingForTrack = false; _waitingTrackPath = null; lock (_pendingLock) { _pendingClips.Clear(); } string text = RavePlaylistManager.AllTrackPaths[0]; if (File.Exists(text)) { LogTrackSizeWarning(text); BackgroundDecodeTrack(text); RaveMod.Logger.Msg("First track queued for background decode: " + Path.GetFileNameWithoutExtension(text)); } RaveMod.Logger.Msg($"Playlist initialized: {RavePlaylistManager.TrackCount} tracks (async loading)."); } catch (Exception ex) { RaveMod.Logger.Error("PreloadAudio error: " + ex.Message); } } internal static void StartMusic() { if (!((Object)(object)_audioSource == (Object)null)) { if (RavePlaylistManager.TrackCount == 0) { RaveMod.Logger.Warning("No tracks in playlist, rave runs without music."); } else { LoadAndPlayNextTrack(); } } } internal static void StopMusic() { _isPaused = false; if (_isPlaying && (Object)(object)_audioSource != (Object)null) { try { _audioSource.Stop(); } catch { } _isPlaying = false; } if (_stageAudioObjects.Count <= 0) { return; } try { foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { AudioSource component = stageAudioObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.Stop(); } } } } catch { } } private static void SyncStageAudioSource(AudioClip clip) { if (_stageAudioObjects.Count == 0 || (Object)(object)clip == (Object)null || (Object)(object)_audioSource == (Object)null) { return; } try { int timeSamples = _audioSource.timeSamples; foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { AudioSource component = stageAudioObject.GetComponent(); if (!((Object)(object)component == (Object)null)) { component.clip = clip; component.volume = RaveConfig.MusicVolume.Value * 0.25f; component.timeSamples = timeSamples; component.Play(); } } } } catch (Exception ex) { RaveMod.Logger.Warning("[Stage] SyncStageAudioSource failed: " + ex.Message); } } private static void PausePlayback() { if ((Object)(object)_audioSource != (Object)null) { try { _audioSource.Pause(); } catch { } } foreach (GameObject stageAudioObject in _stageAudioObjects) { if ((Object)(object)stageAudioObject == (Object)null) { continue; } try { AudioSource component = stageAudioObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.Pause(); } } catch { } } } private static void UnPausePlayback() { if ((Object)(object)_audioSource != (Object)null) { try { _audioSource.UnPause(); } catch { } } foreach (GameObject stageAudioObject in _stageAudioObjects) { if ((Object)(object)stageAudioObject == (Object)null) { continue; } try { AudioSource component = stageAudioObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.UnPause(); } } catch { } } ResyncStageToMain(); } private static void ResyncStageToMain() { if (_stageAudioObjects.Count == 0 || (Object)(object)_audioSource == (Object)null) { return; } try { AudioClip clip = _audioSource.clip; if ((Object)(object)clip == (Object)null) { return; } int timeSamples = _audioSource.timeSamples; if (timeSamples < 0 || timeSamples >= clip.samples) { return; } foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { AudioSource component = stageAudioObject.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.clip == (Object)null) && component.isPlaying && timeSamples < component.clip.samples && Mathf.Abs(component.timeSamples - timeSamples) > 441) { component.timeSamples = timeSamples; } } } } catch (Exception ex) { RaveMod.Logger.Warning("[Stage] ResyncStageToMain failed: " + ex.Message); } } private static void DestroyStageAudioObjects() { if (_stageAudioObjects.Count == 0) { return; } foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { try { Object.DestroyImmediate((Object)(object)stageAudioObject); } catch { } } } _stageAudioObjects.Clear(); } private static void CacheClip(string trackPath, AudioClip clip) { if (trackPath == null || (Object)(object)clip == (Object)null) { return; } if (_clipCache.ContainsKey(trackPath)) { _cacheOrder.Remove(trackPath); _cacheOrder.AddLast(trackPath); return; } while (_clipCache.Count >= 50 && _cacheOrder.Count > 0) { string value = _cacheOrder.First.Value; _cacheOrder.RemoveFirst(); if ((Object)(object)_audioSource != (Object)null && _clipCache.ContainsKey(value) && (Object)(object)_clipCache[value] == (Object)(object)_audioSource.clip) { _cacheOrder.AddLast(value); break; } _clipCache.Remove(value); } ((Object)clip).hideFlags = (HideFlags)32; _clipCache[trackPath] = clip; _cacheOrder.AddLast(trackPath); } private static AudioClip GetCachedClip(string trackPath) { if (trackPath == null) { return null; } if (_clipCache.TryGetValue(trackPath, out var value) && (Object)(object)value != (Object)null) { _cacheOrder.Remove(trackPath); _cacheOrder.AddLast(trackPath); return value; } return null; } internal static void UpdateAudio() { if ((Object)(object)_audioSource == (Object)null) { return; } if (Time.timeScale == 0f) { if (_isPlaying && !_isPaused) { PausePlayback(); _isPaused = true; } return; } if (_isPaused) { UnPausePlayback(); _isPaused = false; } if (_isPlaying) { _audioSource.volume = RaveConfig.MusicVolume.Value; if (_stageAudioObjects.Count > 0) { float volume = RaveConfig.MusicVolume.Value * 0.25f; foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { AudioSource component = stageAudioObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.volume = volume; } } } } } ProcessPendingClips(); if (_isPlaying && !_audioSource.isPlaying && !_audioSource.loop) { LoadAndPlayNextTrack(); } _vanillaScanTimer += Time.deltaTime; if (_vanillaScanTimer >= 10f) { _vanillaScanTimer = 0f; ScanVanillaAudioSources(); } MuteVanillaMusicInRadius(); } private static void LoadAndPlayNextTrack() { if (_waitingForTrack) { return; } int trackCount = RavePlaylistManager.TrackCount; int num = 0; while (num < trackCount) { num++; try { string nextTrack = RavePlaylistManager.GetNextTrack(); if (nextTrack == null) { RaveMod.Logger.Warning("No more tracks available."); _isPlaying = false; return; } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(nextTrack); AudioClip cachedClip = GetCachedClip(nextTrack); if ((Object)(object)cachedClip != (Object)null && (Object)(object)_audioSource != (Object)null) { _audioSource.clip = cachedClip; _audioSource.volume = RaveConfig.MusicVolume.Value; _audioSource.Play(); SyncStageAudioSource(cachedClip); _isPlaying = true; _isPaused = false; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Now playing: " + fileNameWithoutExtension); } TriggerLookAhead(); } else { LogTrackSizeWarning(nextTrack); _waitingTrackPath = nextTrack; _waitingForTrack = true; BackgroundDecodeTrack(nextTrack); RaveMod.Logger.Msg("Track not cached — background decoding: " + fileNameWithoutExtension); } return; } catch (Exception ex) { RaveMod.Logger.Error("Audio loading error: " + ex.Message); } } RaveMod.Logger.Warning("No playable tracks found."); _isPlaying = false; } private static AudioClip LoadWavFromFile(string filePath) { try { byte[] array = File.ReadAllBytes(filePath); if (array.Length < 44) { return null; } int num = BitConverter.ToInt16(array, 22); int num2 = BitConverter.ToInt32(array, 24); int num3 = BitConverter.ToInt16(array, 34); int i; int num4; for (i = 12; i < array.Length - 8; i += 8 + num4) { string text = Encoding.ASCII.GetString(array, i, 4); num4 = BitConverter.ToInt32(array, i + 4); if (text == "data") { i += 8; break; } } if (i >= array.Length) { return null; } int num5 = array.Length - i; int num6 = num3 switch { 16 => num5 / 2, 24 => num5 / 3, _ => num5 / (num3 / 8), }; float[] array2 = new float[num6]; switch (num3) { case 16: { for (int k = 0; k < num6; k++) { int num9 = i + k * 2; if (num9 + 1 >= array.Length) { break; } short num10 = BitConverter.ToInt16(array, num9); array2[k] = (float)num10 / 32768f; } break; } case 24: { for (int j = 0; j < num6; j++) { int num7 = i + j * 3; if (num7 + 2 >= array.Length) { break; } int num8 = array[num7] | (array[num7 + 1] << 8) | (array[num7 + 2] << 16); if ((num8 & 0x800000) != 0) { num8 |= -16777216; } array2[j] = (float)num8 / 8388608f; } break; } } AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(filePath), num6 / num, num, num2, false); val.SetData(Il2CppStructArray.op_Implicit(array2), 0); return val; } catch (Exception ex) { RaveMod.Logger.Error("WAV loading error: " + ex.Message); return null; } } private static AudioClip LoadMp3WithNLayer(string filePath) { try { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); using MpegFile mpegFile = new MpegFile(filePath); int sampleRate = mpegFile.SampleRate; int channels = mpegFile.Channels; if (sampleRate <= 0 || channels <= 0) { RaveMod.Logger.Warning($"Invalid MP3 metadata: {fileNameWithoutExtension} (Rate={sampleRate}, Ch={channels})"); return null; } long num = (long)(mpegFile.Duration.TotalSeconds * (double)sampleRate * (double)channels) + 4096; if (num > int.MaxValue) { num = 2147483647L; } float[] array = new float[(int)num]; int num2 = 0; while (true) { if (num2 >= array.Length) { float[] array2 = new float[array.Length * 2]; Array.Copy(array, array2, num2); array = array2; } int num3 = mpegFile.ReadSamples(array, num2, array.Length - num2); if (num3 <= 0) { break; } num2 += num3; } if (num2 == 0) { RaveMod.Logger.Warning("NLayer returned no samples: " + fileNameWithoutExtension); return null; } float[] array3; if (num2 == array.Length) { array3 = array; } else { array3 = new float[num2]; Array.Copy(array, array3, num2); } int num4 = num2 / channels; AudioClip val = AudioClip.Create(fileNameWithoutExtension, num4, channels, sampleRate, false); val.SetData(Il2CppStructArray.op_Implicit(array3), 0); return val; } catch (Exception ex) { RaveMod.Logger.Error("MP3 decoding failed: " + ex.Message); return null; } } private static void DecodeWavToSamples(string filePath, out float[] samples, out int sampleRate, out int channels) { samples = null; sampleRate = 0; channels = 0; byte[] array = File.ReadAllBytes(filePath); if (array.Length < 44) { return; } channels = BitConverter.ToInt16(array, 22); sampleRate = BitConverter.ToInt32(array, 24); int num = BitConverter.ToInt16(array, 34); int i; int num2; for (i = 12; i < array.Length - 8; i += 8 + num2) { string text = Encoding.ASCII.GetString(array, i, 4); num2 = BitConverter.ToInt32(array, i + 4); if (text == "data") { i += 8; break; } } if (i >= array.Length) { return; } int num3 = array.Length - i; int num4 = num switch { 16 => num3 / 2, 24 => num3 / 3, _ => num3 / (num / 8), }; samples = new float[num4]; switch (num) { case 16: { for (int k = 0; k < num4; k++) { int num7 = i + k * 2; if (num7 + 1 >= array.Length) { break; } short num8 = BitConverter.ToInt16(array, num7); samples[k] = (float)num8 / 32768f; } break; } case 24: { for (int j = 0; j < num4; j++) { int num5 = i + j * 3; if (num5 + 2 >= array.Length) { break; } int num6 = array[num5] | (array[num5 + 1] << 8) | (array[num5 + 2] << 16); if ((num6 & 0x800000) != 0) { num6 |= -16777216; } samples[j] = (float)num6 / 8388608f; } break; } } } private static void DecodeMp3ToSamples(string filePath, out float[] samples, out int sampleRate, out int channels) { samples = null; sampleRate = 0; channels = 0; using MpegFile mpegFile = new MpegFile(filePath); sampleRate = mpegFile.SampleRate; channels = mpegFile.Channels; if (sampleRate <= 0 || channels <= 0) { return; } long num = (long)(mpegFile.Duration.TotalSeconds * (double)sampleRate * (double)channels) + 4096; if (num > int.MaxValue) { num = 2147483647L; } float[] array = new float[(int)num]; int num2 = 0; while (true) { if (num2 >= array.Length) { float[] array2 = new float[array.Length * 2]; Array.Copy(array, array2, num2); array = array2; } int num3 = mpegFile.ReadSamples(array, num2, array.Length - num2); if (num3 <= 0) { break; } num2 += num3; } if (num2 != 0) { if (num2 == array.Length) { samples = array; return; } samples = new float[num2]; Array.Copy(array, samples, num2); } } private static void BackgroundDecodeTrack(string trackPath) { if (trackPath == null || _clipCache.ContainsKey(trackPath) || _backgroundDecodeCount >= 2) { return; } lock (_pendingLock) { foreach (PendingClip pendingClip in _pendingClips) { if (pendingClip.TrackPath == trackPath) { return; } } } Interlocked.Increment(ref _backgroundDecodeCount); ThreadPool.QueueUserWorkItem(delegate { try { string fullPath = Path.GetFullPath(trackPath); string text = Path.GetExtension(trackPath).ToLower(); float[] samples; int sampleRate; int channels; if (text == ".mp3") { DecodeMp3ToSamples(fullPath, out samples, out sampleRate, out channels); } else { if (!(text == ".wav")) { return; } DecodeWavToSamples(fullPath, out samples, out sampleRate, out channels); } if (samples == null || samples.Length == 0 || sampleRate <= 0 || channels <= 0) { return; } PendingClip item = default(PendingClip); item.TrackPath = trackPath; item.Samples = samples; item.SampleRate = sampleRate; item.Channels = channels; lock (_pendingLock) { _pendingClips.Enqueue(item); } } catch (Exception ex) { RaveMod.Logger.Warning("Background decode error: " + ex.Message); } finally { Interlocked.Decrement(ref _backgroundDecodeCount); } }); } private static void ProcessPendingClips() { PendingClip pendingClip; lock (_pendingLock) { if (_pendingClips.Count == 0) { return; } pendingClip = _pendingClips.Dequeue(); } if (_clipCache.ContainsKey(pendingClip.TrackPath)) { return; } try { int num = pendingClip.Samples.Length / pendingClip.Channels; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pendingClip.TrackPath); AudioClip val = AudioClip.Create(fileNameWithoutExtension, num, pendingClip.Channels, pendingClip.SampleRate, false); val.SetData(Il2CppStructArray.op_Implicit(pendingClip.Samples), 0); CacheClip(pendingClip.TrackPath, val); if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Background-decoded and cached: {fileNameWithoutExtension} ({val.length:F0}s)"); } if (_waitingForTrack && _waitingTrackPath == pendingClip.TrackPath && (Object)(object)_audioSource != (Object)null) { _audioSource.clip = val; _audioSource.volume = RaveConfig.MusicVolume.Value; _audioSource.Play(); SyncStageAudioSource(val); _isPlaying = true; _isPaused = false; _waitingForTrack = false; _waitingTrackPath = null; RaveMod.Logger.Msg("Now playing (async loaded): " + fileNameWithoutExtension); TriggerLookAhead(); } } catch (Exception ex) { if (_waitingForTrack && _waitingTrackPath == pendingClip.TrackPath) { _waitingForTrack = false; _waitingTrackPath = null; } RaveMod.Logger.Warning("ProcessPendingClips error: " + ex.Message); } } private static void TriggerLookAhead() { string text = RavePlaylistManager.PeekNextTrack(); if (text != null) { BackgroundDecodeTrack(text); } } private static void LogTrackSizeWarning(string trackPath) { try { long length = new FileInfo(trackPath).Length; if (length > 52428800) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(trackPath); float value = (float)length / 1048576f; RaveMod.Logger.Warning($"Large audio file: {fileNameWithoutExtension} ({value:F0} MB). Very long tracks use a lot of RAM. Consider shorter files (<15 min)."); } } catch { } } private static void ScanVanillaAudioSources() { try { AudioSource[] array = Il2CppArrayBase.op_Implicit(Object.FindObjectsOfType()); if (array == null) { _cachedVanillaSources = null; return; } HashSet hashSet = new HashSet(); foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { AudioSource component = stageAudioObject.GetComponent(); if ((Object)(object)component != (Object)null) { hashSet.Add(component); } } } List list = new List(); foreach (AudioSource val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)_audioSource) && !hashSet.Contains(val)) { list.Add(val); } } _cachedVanillaSources = list.ToArray(); if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Vanilla AudioSources scanned: {_cachedVanillaSources.Length} found"); } } catch (Exception ex) { _cachedVanillaSources = null; RaveMod.Logger.Warning("ScanVanillaAudioSources error: " + ex.Message); } } private static void MuteVanillaMusicInRadius() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) try { if (_cachedVanillaSources == null) { return; } Vector3 centerPosition = RaveLocationManager.CenterPosition; float value = RaveConfig.EventRadius.Value; float num = value * value; int num2 = 0; for (int i = 0; i < _cachedVanillaSources.Length; i++) { AudioSource val = _cachedVanillaSources[i]; if ((Object)(object)val == (Object)null) { continue; } Vector3 val2 = ((Component)val).transform.position - centerPosition; float num3 = Vector3.Dot(val2, val2); if (num3 <= num) { if (!_mutedSources.ContainsKey(val) && val.volume > 0f) { _mutedSources[val] = val.volume; val.volume = 0f; num2++; } } else if (_mutedSources.ContainsKey(val)) { val.volume = _mutedSources[val]; _mutedSources.Remove(val); } } if (num2 > 0 && RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] {num2} neue Vanilla-AudioSources stummgeschaltet (gesamt: {_mutedSources.Count})"); } } catch (Exception ex) { RaveMod.Logger.Warning("MuteVanillaMusicInRadius error: " + ex.Message); } } private static void RestoreMutedSources() { foreach (KeyValuePair mutedSource in _mutedSources) { try { if ((Object)(object)mutedSource.Key != (Object)null) { mutedSource.Key.volume = mutedSource.Value; } } catch { } } _mutedSources.Clear(); } internal static void RelocateToPosition(Vector3 newCenter) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_audioObject != (Object)null) { _audioObject.transform.position = newCenter; } if (_speakerVisuals == null) { return; } Vector3 val = default(Vector3); for (int i = 0; i < _speakerVisuals.Length; i++) { if (!((Object)(object)_speakerVisuals[i] == (Object)null)) { float num = (float)Math.PI / 2f * (float)i; ((Vector3)(ref val))..ctor(newCenter.x + Mathf.Cos(num) * 2.5f, newCenter.y, newCenter.z + Mathf.Sin(num) * 2.5f); _speakerVisuals[i].transform.position = val; Vector3 val2 = newCenter - val; val2.y = 0f; if (Vector3.Dot(val2, val2) > 0.01f) { _speakerVisuals[i].transform.rotation = Quaternion.LookRotation(val2); } } } } catch (Exception ex) { RaveMod.Logger.Error("RelocateAudio error: " + ex.Message); } } internal static void Cleanup() { StopMusic(); RestoreMutedSources(); if ((Object)(object)_audioObject != (Object)null) { Object.DestroyImmediate((Object)(object)_audioObject); _audioObject = null; } DestroyStageAudioObjects(); if (_speakerVisuals != null) { for (int i = 0; i < _speakerVisuals.Length; i++) { if ((Object)(object)_speakerVisuals[i] != (Object)null) { Object.DestroyImmediate((Object)(object)_speakerVisuals[i]); } } _speakerVisuals = null; } RavePlaylistManager.Cleanup(); _audioSource = null; _isPlaying = false; _isPaused = false; _cachedVanillaSources = null; _vanillaScanTimer = 0f; lock (_pendingLock) { _pendingClips.Clear(); } } private static void DestroyStaleObjects() { try { GameObject[] array = Il2CppArrayBase.op_Implicit(Object.FindObjectsOfType()); if (array == null) { return; } foreach (GameObject val in array) { if ((Object)(object)val == (Object)null || ((Object)val).name == null || !((Object)val).name.StartsWith("RaveSpeaker")) { continue; } bool flag = (Object)(object)val == (Object)(object)_audioObject; if (!flag && _speakerVisuals != null) { for (int j = 0; j < _speakerVisuals.Length; j++) { if ((Object)(object)val == (Object)(object)_speakerVisuals[j]) { flag = true; break; } } } if (!flag) { flag = _stageAudioObjects.Contains(val); } if (!flag) { Object.DestroyImmediate((Object)(object)val); } } } catch (Exception ex) { RaveMod.Logger.Warning("Audio DestroyStaleObjects error: " + ex.Message); } } } public sealed class RaveCompassController { [HarmonyPatch(typeof(CompassManager), "LateUpdate")] private static class CompassExtendedRangePatch { [HarmonyPostfix] private static void Postfix(CompassManager __instance) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) try { if (_compassElement == null || (Object)(object)_compassElement.TargetTransform == (Object)null || !_compassElement.Visible) { return; } Transform cam = __instance.cam; if (!((Object)(object)cam == (Object)null)) { Vector3 position = cam.position; Vector3 position2 = _compassElement.TargetTransform.position; float num = Vector3.Distance(position, position2); if (!(num > 300f)) { float num2 = default(float); float num3 = default(float); __instance.GetCompassData(position2, ref num2, ref num3); float fullAlphaRange = __instance.FullAlphaRange; float alpha = ((!(num <= fullAlphaRange)) ? Mathf.Lerp(1f, 0.15f, (num - fullAlphaRange) / (300f - fullAlphaRange)) : 1f); _compassElement.Group.alpha = alpha; _compassElement.Rect.anchoredPosition = new Vector2(num2, 0f); ((TMP_Text)_compassElement.DistanceLabel).text = Mathf.CeilToInt(num) + "m"; ((Component)_compassElement.Rect).gameObject.SetActive(true); } } } catch (Exception) { } } } private static GameObject _anchorGO; private static GameObject _contentGO; private static Element _compassElement; private static Sprite _iconSprite; private const string ANCHOR_NAME = "RaveCompassAnchor"; private const string RESOURCE_NAME = "rave.assets.Graffiti_TLH.png"; private const float EXTENDED_RANGE = 300f; private const float MIN_ALPHA = 0.15f; private RaveCompassController() { } private static bool EnsureIconLoaded() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_iconSprite != (Object)null) { return true; } try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("rave.assets.Graffiti_TLH.png"); if (stream == null) { RaveMod.Logger.Error("Compass icon not found: rave.assets.Graffiti_TLH.png"); return false; } byte[] array; using (MemoryStream memoryStream = new MemoryStream((int)stream.Length)) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, Il2CppStructArray.op_Implicit(array))) { RaveMod.Logger.Error("Compass icon could not be loaded as Texture2D."); return false; } ((Texture)val).filterMode = (FilterMode)1; _iconSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } catch (Exception ex) { RaveMod.Logger.Error("Error loading compass icon: " + ex.Message); return false; } return true; } internal static void Show() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_008d: 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_00f7: Unknown result type (might be due to invalid IL or missing references) try { if (!EnsureIconLoaded()) { return; } CompassManager instance = Singleton.Instance; if ((Object)(object)instance == (Object)null) { RaveMod.Logger.Warning("CompassManager not found, no compass icon."); return; } Hide(); _anchorGO = new GameObject("RaveCompassAnchor"); _anchorGO.transform.position = RaveLocationManager.CenterPosition; Object.DontDestroyOnLoad((Object)(object)_anchorGO); _contentGO = new GameObject("RaveCompassContent"); RectTransform val = _contentGO.AddComponent(); val.sizeDelta = instance.ElementContentSize * 2.5f; Image val2 = _contentGO.AddComponent(); val2.sprite = _iconSprite; val2.preserveAspect = true; _compassElement = instance.AddElement(_anchorGO.transform, val, true); if (_compassElement != null) { ((Transform)val).localScale = new Vector3(2.5f, 2.5f, 1f); } else { RaveMod.Logger.Warning("CompassManager.AddElement returned null."); } } catch (Exception ex) { RaveMod.Logger.Error("Error showing compass icon: " + ex.Message); } } internal static void Hide() { try { if (_compassElement != null && (Object)(object)_anchorGO != (Object)null) { CompassManager instance = Singleton.Instance; if ((Object)(object)instance != (Object)null) { instance.RemoveElement(_anchorGO.transform, true); } _compassElement = null; } if ((Object)(object)_contentGO != (Object)null) { Object.Destroy((Object)(object)_contentGO); _contentGO = null; } if ((Object)(object)_anchorGO != (Object)null) { Object.Destroy((Object)(object)_anchorGO); _anchorGO = null; } } catch (Exception ex) { RaveMod.Logger.Warning("Error removing compass icon: " + ex.Message); } } internal static void Cleanup() { Hide(); } } public sealed class RaveConfig { internal sealed class FixedEntry { internal T Value { get; } internal FixedEntry(T v) { Value = v; } } private const string RuntimeStateFileName = "runtime_state.cfg"; private const string StateDataFileName = "rave_state.dat"; private const string StateDataHeader = "IllegalRaveStateV1"; private const long MaxStateDataFileBytes = 16384L; internal static MelonPreferences_Category Category; internal static MelonPreferences_Entry SmallFestivalStageEnabled; internal static MelonPreferences_Entry RaveStartTime; internal const bool EndOnSleep = true; internal const int FirstMessageTime = 2300; internal static readonly FixedEntry EventRadius = new FixedEntry(60f); internal static readonly FixedEntry DebugCoordinates = new FixedEntry(v: false); private static readonly string CustomLocationsFile = Path.Combine("UserData", "Rave", "locations.cfg"); private static readonly string RuntimeStateFile = Path.Combine("UserData", "Rave", "runtime_state.cfg"); private static readonly string StateDataFile = Path.Combine("UserData", "Rave", "rave_state.dat"); private static string _customLocationsData = ""; private static bool _resumeRaveActive; private static int _resumeRaveDay = -1; private static string _resumePresetName = ""; private static bool _resumeBookedDjStateCaptured; private static bool _resumeDjDanBooked; private static bool _resumeDjGirlBooked; private static bool _resumeDjCutChemistBooked; private static bool _resumeDjLudapimpBooked; internal static MelonPreferences_Entry CustomRaveLocation; internal static MelonPreferences_Entry PresetTriggerChanceEnabled; private static MelonPreferences_Entry[] _customSlots; internal static MelonPreferences_Entry MusicVolume; internal static MelonPreferences_Entry LampCount; internal static MelonPreferences_Entry StrobeSpeed; internal static MelonPreferences_Entry LightIntensity; internal static MelonPreferences_Entry LightRange; internal static MelonPreferences_Entry StrobeEnabled; internal static MelonPreferences_Entry StrobeInterval; internal static MelonPreferences_Entry StrobeDuration; internal static MelonPreferences_Entry LampColorR; internal static MelonPreferences_Entry LampColorG; internal static MelonPreferences_Entry LampColorB; internal static MelonPreferences_Entry LampRotation; internal static bool DJDanBooked; internal static bool DJGirlBooked; internal static bool DJCutChemistBooked; internal static bool DJLudapimpBooked; internal static MelonPreferences_Entry BundleDebugLogging; internal static MelonPreferences_Entry NPCCount; internal static MelonPreferences_Entry DanceSpeed; internal static MelonPreferences_Entry DanceRadius; internal static int SecondMessageTime { get { int value = RaveStartTime.Value; int num = value / 100; int num2 = value % 100; num2 -= 5; if (num2 < 0) { num2 += 60; num--; } if (num < 0) { num += 24; } return num * 100 + num2; } } internal static string CustomLocationsValue { get { return _customLocationsData; } set { _customLocationsData = value ?? ""; SaveCustomLocations(); } } private RaveConfig() { } internal static void Initialize() { Category = MelonPreferences.CreateCategory("Illegal Rave: Settings", "Rave Settings Update"); SmallFestivalStageEnabled = Category.CreateEntry("SmallFestivalStageEnabled", true, "Enable Small Rave Stage (Parkinglot only - trigger 100%)", (string)null, false, false, (ValueValidator)null, (string)null); RaveStartTime = Category.CreateEntry("RaveStartTime", 400, "Rave Start Time (HHMM)", "When the rave starts (100 = 01:00 to 400 = 04:00).", false, false, (ValueValidator)null, (string)null); LoadStateData(); CustomRaveLocation = Category.CreateEntry("CustomRaveLocation", 0, "Custom Rave", "Custom location slot (1-3). 0=use a random preset location.", false, false, (ValueValidator)null, (string)null); PresetTriggerChanceEnabled = Category.CreateEntry("PresetTriggerChanceEnabled", false, "Rave Trigger Chance", "Preset nights use the 30% trigger chance. When disabled, preset nights always happen. Custom locations (1-3) always trigger 100%.", false, false, (ValueValidator)null, (string)null); _customSlots = new MelonPreferences_Entry[3]; string[] slotCoordinates = GetSlotCoordinates(); for (int i = 0; i < _customSlots.Length; i++) { string text = ((slotCoordinates[i] != null) ? "saved" : "free"); _customSlots[i] = Category.CreateEntry($"Custom{i + 1}", text, $"Custom{i + 1}", slotCoordinates[i] ?? "", false, false, (ValueValidator)null, (string)null); _customSlots[i].Value = text; } MusicVolume = Category.CreateEntry("MusicVolume", 0.7f, "Music Volume", "Rave music volume (0.0 - 1.5)", false, false, (ValueValidator)null, (string)null); LampCount = Category.CreateEntry("LampCount", 6, "Lamp Count", "Number of standing lamps placed around the rave", false, false, (ValueValidator)null, (string)null); StrobeSpeed = Category.CreateEntry("StrobeSpeed", 4f, "Color Rotation", "Color change speed of the lamps (Hz)", false, false, (ValueValidator)null, (string)null); LightIntensity = Category.CreateEntry("LightIntensity", 5f, "Light Intensity", "Brightness of the rave lamps", false, false, (ValueValidator)null, (string)null); LightRange = Category.CreateEntry("LightRange", 10f, "Light Range", "Range of the lamps", false, false, (ValueValidator)null, (string)null); StrobeEnabled = Category.CreateEntry("StrobeEnabled", true, "Strobo Flash", "White flashes in addition to color cycling", false, false, (ValueValidator)null, (string)null); StrobeInterval = Category.CreateEntry("StrobeInterval", 0.5f, "Strobo Steps", "Time between flashes in seconds (0.1-0.5)", false, false, (ValueValidator)null, (string)null); StrobeDuration = Category.CreateEntry("StrobeDuration", 0.01f, "Strobo Time", "Duration of a flash in seconds (0.01-0.1)", false, false, (ValueValidator)null, (string)null); LampColorR = Category.CreateEntry("LampColorR", 255, "Lamp Color Red", "Red channel of lamp light color (0-255). Set all to 0 for rainbow mode.", false, false, (ValueValidator)null, (string)null); LampColorG = Category.CreateEntry("LampColorG", 0, "Lamp Color Green", "Green channel of lamp light color (0-255). Set all to 0 for rainbow mode.", false, false, (ValueValidator)null, (string)null); LampColorB = Category.CreateEntry("LampColorB", 255, "Lamp Color Blue", "Blue channel of lamp light color (0-255). Set all to 0 for rainbow mode.", false, false, (ValueValidator)null, (string)null); LampRotation = Category.CreateEntry("LampRotation", true, "Lamp Color Rotation", "Whether lamp colors rotate through the spectrum (true) or stay fixed (false)", false, false, (ValueValidator)null, (string)null); BundleDebugLogging = Category.CreateEntry("BundleDebugLogging", false, "Debug: Bundle Diagnostics", "Enable massive diagnostics logging for DJ bundle load/cleanup/retry flow. Keep OFF for normal gameplay.", false, false, (ValueValidator)null, (string)null); NPCCount = Category.CreateEntry("NPCCount", 8, "NPC Count (Custom)", "Number of dancing NPCs at custom locations (presets have fixed values)", false, false, (ValueValidator)null, (string)null); DanceSpeed = Category.CreateEntry("DanceSpeed", 6f, "Dance Speed (Custom)", "NPC dance speed multiplier at custom locations (1.0=slow, 3.0=normal, 6.0=fast, 10.0=very fast)", false, false, (ValueValidator)null, (string)null); DanceRadius = Category.CreateEntry("DanceRadius", 5f, "Dance Radius (Custom)", "Radius in meters where NPCs dance at custom locations (1.0-30.0)", false, false, (ValueValidator)null, (string)null); ApplySafetyClamps(); } private static void ApplySafetyClamps() { ClampSingle(MusicVolume, 0f, 2f); ClampInt(LampCount, 1, 20); ClampSingle(StrobeSpeed, 0.5f, 20f); ClampSingle(LightIntensity, 0.1f, 50f); ClampSingle(LightRange, 1f, 100f); ClampSingle(StrobeInterval, 0.05f, 5f); ClampSingle(StrobeDuration, 0.005f, 1f); ClampInt(NPCCount, 0, 30); ClampInt(LampColorR, 0, 255); ClampInt(LampColorG, 0, 255); ClampInt(LampColorB, 0, 255); ClampSingle(DanceSpeed, 0.5f, 20f); ClampSingle(DanceRadius, 1f, 30f); ClampInt(CustomRaveLocation, 0, 3); ClampInt(RaveStartTime, 100, 500); } private static void ClampSingle(MelonPreferences_Entry entry, float min, float max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } private static void ClampInt(MelonPreferences_Entry entry, int min, int max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } internal static void SetBookedDj(bool djDanBooked, bool djGirlBooked, bool djCutChemistBooked = false, bool djLudapimpBooked = false) { int num = (djDanBooked ? 1 : 0) + (djGirlBooked ? 1 : 0) + (djCutChemistBooked ? 1 : 0) + (djLudapimpBooked ? 1 : 0); if (num > 1) { RaveMod.Logger.Warning($"Invalid DJ booking state requested: {num} DJs booked. Keeping last one only."); if (djLudapimpBooked) { djDanBooked = false; djGirlBooked = false; djCutChemistBooked = false; } else if (djCutChemistBooked) { djDanBooked = false; djGirlBooked = false; djLudapimpBooked = false; } else if (djGirlBooked) { djDanBooked = false; djCutChemistBooked = false; djLudapimpBooked = false; } } DJDanBooked = djDanBooked; DJGirlBooked = djGirlBooked; DJCutChemistBooked = djCutChemistBooked; DJLudapimpBooked = djLudapimpBooked; SaveStateData(); } internal static void ClearBookedDjs() { DJDanBooked = false; DJGirlBooked = false; DJCutChemistBooked = false; DJLudapimpBooked = false; SaveStateData(); } internal static void SetActiveRaveResumeState(bool isActive, int elapsedDays, string presetName, bool djDanBooked, bool djGirlBooked, bool djCutChemistBooked = false, bool djLudapimpBooked = false) { _resumeRaveActive = isActive; _resumeRaveDay = (isActive ? elapsedDays : (-1)); _resumePresetName = (isActive ? (presetName ?? string.Empty) : string.Empty); _resumeBookedDjStateCaptured = isActive; _resumeDjDanBooked = isActive && djDanBooked; _resumeDjGirlBooked = isActive && djGirlBooked; _resumeDjCutChemistBooked = isActive && djCutChemistBooked; _resumeDjLudapimpBooked = isActive && djLudapimpBooked; int num = (_resumeDjDanBooked ? 1 : 0) + (_resumeDjGirlBooked ? 1 : 0) + (_resumeDjCutChemistBooked ? 1 : 0) + (_resumeDjLudapimpBooked ? 1 : 0); if (num > 1) { RaveMod.Logger.Warning("Invalid active rave resume DJ state requested: multiple DJs booked. Keeping last one only."); if (_resumeDjLudapimpBooked) { _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjCutChemistBooked = false; } else if (_resumeDjCutChemistBooked) { _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjLudapimpBooked = false; } else if (_resumeDjGirlBooked) { _resumeDjDanBooked = false; _resumeDjCutChemistBooked = false; _resumeDjLudapimpBooked = false; } } SaveStateData(); } internal static void ClearActiveRaveResumeState() { if (_resumeRaveActive || _resumeRaveDay >= 0 || !string.IsNullOrEmpty(_resumePresetName) || _resumeBookedDjStateCaptured || _resumeDjDanBooked || _resumeDjGirlBooked || _resumeDjCutChemistBooked || _resumeDjLudapimpBooked) { _resumeRaveActive = false; _resumeRaveDay = -1; _resumePresetName = string.Empty; _resumeBookedDjStateCaptured = false; _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjCutChemistBooked = false; _resumeDjLudapimpBooked = false; SaveStateData(); } } internal static bool TryConsumeActiveRaveResumeState(int currentDay, int currentTime, out string presetName, out bool hasBookedDjState, out bool djDanBooked, out bool djGirlBooked, out bool djCutChemistBooked, out bool djLudapimpBooked) { presetName = null; hasBookedDjState = false; djDanBooked = false; djGirlBooked = false; djCutChemistBooked = false; djLudapimpBooked = false; if (!_resumeRaveActive) { return false; } if (currentDay != _resumeRaveDay || currentTime < RaveStartTime.Value || currentTime >= 500) { ClearActiveRaveResumeState(); return false; } presetName = (string.IsNullOrWhiteSpace(_resumePresetName) ? null : _resumePresetName); hasBookedDjState = _resumeBookedDjStateCaptured; djDanBooked = _resumeDjDanBooked; djGirlBooked = _resumeDjGirlBooked; djCutChemistBooked = _resumeDjCutChemistBooked; djLudapimpBooked = _resumeDjLudapimpBooked; _resumeRaveActive = false; _resumeRaveDay = -1; _resumePresetName = string.Empty; _resumeBookedDjStateCaptured = false; _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjCutChemistBooked = false; _resumeDjLudapimpBooked = false; SaveStateData(); return true; } private static void LoadStateData() { try { DJDanBooked = false; DJGirlBooked = false; DJCutChemistBooked = false; DJLudapimpBooked = false; _customLocationsData = ""; _resumeRaveActive = false; _resumeRaveDay = -1; _resumePresetName = string.Empty; _resumeBookedDjStateCaptured = false; _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjCutChemistBooked = false; _resumeDjLudapimpBooked = false; if (!TryLoadUnifiedStateData()) { if (TryMigrateLegacyStateData()) { SaveStateData(); } else { LogRuntimeStateDebug("No state data found. Starting with defaults at '" + StateDataFile + "'."); } } } catch (IOException ex) { RaveMod.Logger.Warning("Failed to load runtime rave state: " + ex.Message); } catch (UnauthorizedAccessException ex2) { RaveMod.Logger.Warning("Failed to load runtime rave state: " + ex2.Message); } } private static bool TryLoadUnifiedStateData() { if (!File.Exists(StateDataFile)) { return false; } if (!TryReadSmallTextFile(StateDataFile, 16384L, out var content)) { return false; } Dictionary dictionary = ParseStateEntries(content, StateDataFile); if (dictionary.Count == 0) { return false; } if (!dictionary.TryGetValue("Format", out var value) || !string.Equals(value, "IllegalRaveStateV1", StringComparison.Ordinal)) { RaveMod.Logger.Warning("Unsupported rave state format in '" + StateDataFile + "'."); return false; } ApplyParsedStateEntries(dictionary, StateDataFile); LogRuntimeStateDebug($"Loaded unified rave state from '{StateDataFile}': DJDanBooked={DJDanBooked}, DJGirlBooked={DJGirlBooked}, DJCutChemistBooked={DJCutChemistBooked}, DJLudapimpBooked={DJLudapimpBooked}"); return true; } private static bool TryMigrateLegacyStateData() { bool flag = false; if (TryReadSmallTextFile(RuntimeStateFile, 16384L, out var content)) { ApplyParsedStateEntries(ParseStateEntries(content, RuntimeStateFile), RuntimeStateFile); flag = true; } if (TryReadSmallTextFile(CustomLocationsFile, 16384L, out var content2)) { _customLocationsData = content2.Trim(); flag = true; } if (flag) { LogRuntimeStateDebug($"Migrated legacy rave state from '{RuntimeStateFile}' and '{CustomLocationsFile}' into '{StateDataFile}'."); } return flag; } private static void SaveStateData() { try { string directoryName = Path.GetDirectoryName(StateDataFile); if (!string.IsNullOrWhiteSpace(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } string text = BuildStateDataContent(); byte[] bytes = Encoding.UTF8.GetBytes(text); if ((long)bytes.Length > 16384L) { RaveMod.Logger.Warning($"Refusing to save rave state because '{StateDataFile}' would exceed {16384} bytes."); return; } File.WriteAllText(StateDataFile, text, Encoding.UTF8); TryDeleteLegacyStateFile(RuntimeStateFile); TryDeleteLegacyStateFile(CustomLocationsFile); LogRuntimeStateDebug($"Saved unified rave state to '{StateDataFile}': DJDanBooked={DJDanBooked}, DJGirlBooked={DJGirlBooked}, DJCutChemistBooked={DJCutChemistBooked}, DJLudapimpBooked={DJLudapimpBooked}"); } catch (IOException ex) { RaveMod.Logger.Warning("Failed to save runtime rave state: " + ex.Message); } catch (UnauthorizedAccessException ex2) { RaveMod.Logger.Warning("Failed to save runtime rave state: " + ex2.Message); } } private static void LogRuntimeStateDebug(string message) { try { if (BundleDebugLogging != null && BundleDebugLogging.Value) { RaveMod.Logger.Msg("[RaveRuntimeState] " + message); } } catch (Exception ex) { RaveMod.Logger.Warning("Runtime state debug logging failed: " + ex.Message); } } private static bool TryReadSmallTextFile(string path, long maxBytes, out string content) { content = null; if (!File.Exists(path)) { return false; } FileInfo fileInfo = new FileInfo(path); if (fileInfo.Length > maxBytes) { RaveMod.Logger.Warning($"Ignoring state file '{path}' because it exceeds {maxBytes} bytes."); return false; } content = File.ReadAllText(path, Encoding.UTF8); return true; } private static Dictionary ParseStateEntries(string content, string sourcePath) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); if (string.IsNullOrWhiteSpace(content)) { return dictionary; } string[] array = content.Replace("\r", string.Empty).Split('\n'); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (string.IsNullOrEmpty(text) || text.StartsWith("#", StringComparison.Ordinal)) { continue; } int num = text.IndexOf('='); if (num <= 0) { RaveMod.Logger.Warning($"Ignoring invalid rave state line in '{sourcePath}': '{text}'"); } else { string text2 = text.Substring(0, num).Trim(); string value = text.Substring(num + 1).Trim(); if (!string.IsNullOrWhiteSpace(text2)) { dictionary[text2] = value; } } } return dictionary; } private static void ApplyParsedStateEntries(Dictionary entries, string sourcePath) { if (entries.TryGetValue("DJDanBooked", out var value) && bool.TryParse(value, out var result)) { DJDanBooked = result; } if (entries.TryGetValue("DJGirlBooked", out var value2) && bool.TryParse(value2, out var result2)) { DJGirlBooked = result2; } if (entries.TryGetValue("DJCutChemistBooked", out var value3) && bool.TryParse(value3, out var result3)) { DJCutChemistBooked = result3; } if (entries.TryGetValue("DJLudapimpBooked", out var value4) && bool.TryParse(value4, out var result4)) { DJLudapimpBooked = result4; } if (entries.TryGetValue("CustomLocations", out var value5)) { _customLocationsData = NormalizeCustomLocationsData(value5); } if (entries.TryGetValue("ResumeRaveActive", out var value6) && bool.TryParse(value6, out var result5)) { _resumeRaveActive = result5; } if (entries.TryGetValue("ResumeRaveDay", out var value7) && int.TryParse(value7, out var result6)) { _resumeRaveDay = result6; } if (entries.TryGetValue("ResumePresetName", out var value8)) { _resumePresetName = value8 ?? string.Empty; } if (entries.TryGetValue("ResumeBookedDjStateCaptured", out var value9) && bool.TryParse(value9, out var result7)) { _resumeBookedDjStateCaptured = result7; } if (entries.TryGetValue("ResumeDJDanBooked", out var value10) && bool.TryParse(value10, out var result8)) { _resumeDjDanBooked = result8; } if (entries.TryGetValue("ResumeDJGirlBooked", out var value11) && bool.TryParse(value11, out var result9)) { _resumeDjGirlBooked = result9; } if (entries.TryGetValue("ResumeDJCutChemistBooked", out var value12) && bool.TryParse(value12, out var result10)) { _resumeDjCutChemistBooked = result10; } if (entries.TryGetValue("ResumeDJLudapimpBooked", out var value13) && bool.TryParse(value13, out var result11)) { _resumeDjLudapimpBooked = result11; } int num = (DJDanBooked ? 1 : 0) + (DJGirlBooked ? 1 : 0) + (DJCutChemistBooked ? 1 : 0) + (DJLudapimpBooked ? 1 : 0); if (num > 1) { RaveMod.Logger.Warning($"State file '{sourcePath}' contained {num} DJs as booked. Keeping last one only."); if (DJLudapimpBooked) { DJDanBooked = false; DJGirlBooked = false; DJCutChemistBooked = false; } else if (DJCutChemistBooked) { DJDanBooked = false; DJGirlBooked = false; DJLudapimpBooked = false; } else if (DJGirlBooked) { DJDanBooked = false; DJCutChemistBooked = false; DJLudapimpBooked = false; } } int num2 = (_resumeDjDanBooked ? 1 : 0) + (_resumeDjGirlBooked ? 1 : 0) + (_resumeDjCutChemistBooked ? 1 : 0) + (_resumeDjLudapimpBooked ? 1 : 0); if (num2 > 1) { RaveMod.Logger.Warning($"State file '{sourcePath}' contained {num2} resume DJs as booked. Keeping last one only."); if (_resumeDjLudapimpBooked) { _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjCutChemistBooked = false; } else if (_resumeDjCutChemistBooked) { _resumeDjDanBooked = false; _resumeDjGirlBooked = false; _resumeDjLudapimpBooked = false; } else if (_resumeDjGirlBooked) { _resumeDjDanBooked = false; _resumeDjCutChemistBooked = false; _resumeDjLudapimpBooked = false; } } } private static string BuildStateDataContent() { string text = _customLocationsData ?? string.Empty; text = text.Replace("\r", string.Empty).Replace("\n", string.Empty); text = NormalizeCustomLocationsData(text); return string.Join(Environment.NewLine, "Format=IllegalRaveStateV1", $"{"DJDanBooked"}={DJDanBooked}", $"{"DJGirlBooked"}={DJGirlBooked}", $"{"DJCutChemistBooked"}={DJCutChemistBooked}", $"{"DJLudapimpBooked"}={DJLudapimpBooked}", "CustomLocations=" + text, $"ResumeRaveActive={_resumeRaveActive}", $"ResumeRaveDay={_resumeRaveDay}", "ResumePresetName=" + (_resumePresetName ?? string.Empty), $"ResumeBookedDjStateCaptured={_resumeBookedDjStateCaptured}", $"ResumeDJDanBooked={_resumeDjDanBooked}", $"ResumeDJGirlBooked={_resumeDjGirlBooked}", $"ResumeDJCutChemistBooked={_resumeDjCutChemistBooked}", $"ResumeDJLudapimpBooked={_resumeDjLudapimpBooked}"); } private static void TryDeleteLegacyStateFile(string path) { if (!File.Exists(path)) { return; } try { File.Delete(path); } catch (IOException ex) { LogRuntimeStateDebug("Legacy state cleanup failed for '" + path + "': " + ex.Message); } catch (UnauthorizedAccessException ex2) { LogRuntimeStateDebug("Legacy state cleanup failed for '" + path + "': " + ex2.Message); } } private static void SaveCustomLocations() { try { _customLocationsData = NormalizeCustomLocationsData(_customLocationsData); SaveStateData(); UpdateCustomSlots(); MelonPreferences.Save(); } catch (IOException ex) { MelonLogger.Warning("Could not save custom locations: " + ex.Message); } catch (UnauthorizedAccessException ex2) { MelonLogger.Warning("Could not save custom locations: " + ex2.Message); } } private static void UpdateCustomSlots() { if (_customSlots == null) { return; } string[] slotCoordinates = GetSlotCoordinates(); for (int i = 0; i < _customSlots.Length; i++) { if (_customSlots[i] != null) { _customSlots[i].Value = ((slotCoordinates[i] != null) ? "saved" : "free"); ((MelonPreferences_Entry)_customSlots[i]).Description = slotCoordinates[i] ?? ""; } } } private static string[] GetSlotCoordinates() { string[] array = new string[3]; if (string.IsNullOrWhiteSpace(_customLocationsData)) { return array; } string[] array2 = _customLocationsData.Split(';'); for (int i = 0; i < array2.Length && i < array.Length; i++) { string text = array2[i].Trim(); if (!string.IsNullOrEmpty(text)) { string[] array3 = text.Split(','); if (array3.Length == 3) { array[i] = text; } } } return array; } private static string NormalizeCustomLocationsData(string raw) { if (string.IsNullOrWhiteSpace(raw)) { return string.Empty; } string[] array = raw.Split(';'); List list = new List(3); for (int i = 0; i < array.Length; i++) { if (list.Count >= 3) { break; } string text = array[i].Trim(); if (!string.IsNullOrEmpty(text)) { string[] array2 = text.Split(','); if (array2.Length == 3) { list.Add(text); } } } return string.Join(";", list); } } public sealed class RaveDJBoothController { private enum ScaleMode { ByY, ByMaxAxis, ByWidth } private const string GO_BOOTH_NAME = "RaveDJBooth"; private const string GO_DJDAN_NAME = "RaveDJDan"; private const string GO_DJGIRL_NAME = "RaveDJGirl"; private const string GO_DJCUTCHEMIST_NAME = "RaveDJCutChemist"; private const string GO_DJLUDAPIMP_NAME = "RaveDJLudapimp"; private const string GO_STAGE_NAME = "SmallFestivalStage"; private static GameObject _boothPrefab; private static GameObject _djDanPrefab; private static GameObject _djGirlPrefab; private static GameObject _djCutChemistPrefab; private static GameObject _djLudapimpPrefab; private static GameObject _stagePrefab; private static GameObject _stageInstance; private static bool _stageCacheFailed; private static GameObject _boothInstance; private static GameObject _djDanInstance; private static GameObject _djGirlInstance; private static GameObject _djCutChemistInstance; private static GameObject _djLudapimpInstance; private static bool _boothCacheFailed; private static bool _djDanCacheFailed; private static bool _djGirlCacheFailed; private static bool _djCutChemistCacheFailed; private static bool _djLudapimpCacheFailed; private static readonly HashSet _debugOnceKeys = new HashSet(); private static Vector3 _lastNormalizedScaleFactor = Vector3.one; private const float BOOTH_TARGET_WIDTH = 1.5f; private const float BOOTH_Y_OFFSET = -0.5f; private const float DJ_Z_EXTRA = 1.2f; private const float DJ_Z_EXTRA_PIMP = 1.4f; private const float GROUND_RAYCAST_HEIGHT = 1.2f; private const float GROUND_RAYCAST_DISTANCE = 6f; private const float MIN_LOOK_DIRECTION = 0.0001f; private const float SKINNED_BOUNDS_EXPAND = 0.05f; private const float DJDAN_TARGET_HEIGHT = 1.8f; private const float DJDAN_ALIGN_Y_OFFSET = 0f; private const float DJDAN_YAW_CORRECTION = 0f; private static readonly ScaleMode DJDAN_SCALE_MODE = ScaleMode.ByMaxAxis; private const float DJGIRL_TARGET_HEIGHT = 1.9f; private const float DJGIRL_ALIGN_Y_OFFSET = -1f; private const float DJGIRL_YAW_CORRECTION = 0f; private static readonly ScaleMode DJGIRL_SCALE_MODE = ScaleMode.ByMaxAxis; private const float DJCUTCHEMIST_TARGET_HEIGHT = 1.8f; private const float DJCUTCHEMIST_ALIGN_Y_OFFSET = 0f; private const float DJCUTCHEMIST_YAW_CORRECTION = 180f; private static readonly ScaleMode DJCUTCHEMIST_SCALE_MODE = ScaleMode.ByMaxAxis; private const float DJLUDAPIMP_TARGET_HEIGHT = 1.6f; private const float DJLUDAPIMP_ALIGN_Y_OFFSET = 0f; private const float DJLUDAPIMP_YAW_CORRECTION = 0f; private static readonly ScaleMode DJLUDAPIMP_SCALE_MODE = ScaleMode.ByMaxAxis; private const float DJ_STAGE_OFFSET_X = -0.85f; private const float DJ_STAGE_OFFSET_Y = -0.6f; private const float DJ_STAGE_OFFSET_Z = 0f; private RaveDJBoothController() { } internal static void PreCacheGlbPrefabs() { try { EnsureGlbCached("booth", ref _boothPrefab, GlbAssetProvider.GetDjBooth, ref _boothCacheFailed); } catch (Exception ex) { RaveMod.Logger.Warning("PreCache booth error: " + ex.Message); } try { EnsureGlbCached("djdan", ref _djDanPrefab, GlbAssetProvider.GetDjDan, ref _djDanCacheFailed); } catch (Exception ex2) { RaveMod.Logger.Warning("PreCache djdan error: " + ex2.Message); } try { EnsureGlbCached("djgirl", ref _djGirlPrefab, GlbAssetProvider.GetDjGirl, ref _djGirlCacheFailed); } catch (Exception ex3) { RaveMod.Logger.Warning("PreCache djgirl error: " + ex3.Message); } try { EnsureGlbCached("djcutchemist", ref _djCutChemistPrefab, GlbAssetProvider.GetDjCutChemist, ref _djCutChemistCacheFailed); } catch (Exception ex4) { RaveMod.Logger.Warning("PreCache djcutchemist error: " + ex4.Message); } try { EnsureGlbCached("djludapimp", ref _djLudapimpPrefab, GlbAssetProvider.GetDjLudapimp, ref _djLudapimpCacheFailed); } catch (Exception ex5) { RaveMod.Logger.Warning("PreCache djludapimp error: " + ex5.Message); } if (RaveConfig.SmallFestivalStageEnabled.Value) { try { EnsureGlbCached("LetsGo", ref _stagePrefab, GlbAssetProvider.GetLetsGo, ref _stageCacheFailed); } catch (Exception ex6) { RaveMod.Logger.Warning("PreCache LetsGo error: " + ex6.Message); } } LogDebug($"PreCacheGlbPrefabs done: booth={(Object)(object)_boothPrefab != (Object)null}, djdan={(Object)(object)_djDanPrefab != (Object)null}, djgirl={(Object)(object)_djGirlPrefab != (Object)null}, djcutchemist={(Object)(object)_djCutChemistPrefab != (Object)null}, djludapimp={(Object)(object)_djLudapimpPrefab != (Object)null}, stage={(Object)(object)_stagePrefab != (Object)null}"); } internal static void SpawnBooth() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_05b3: Unknown result type (might be due to invalid IL or missing references) //IL_05be: Unknown result type (might be due to invalid IL or missing references) //IL_06d4: Unknown result type (might be due to invalid IL or missing references) //IL_06df: Unknown result type (might be due to invalid IL or missing references) try { DestroyInstances(); } catch (Exception ex) { RaveMod.Logger.Warning("SpawnBooth pre-cleanup error: " + ex.Message); } if (RaveLocationManager.ShouldUseStage()) { SpawnStageInsteadOfBooth(); return; } Vector3 centerPosition = RaveLocationManager.CenterPosition; float bOOTH_Z_OFFSET = RaveLocationManager.BOOTH_Z_OFFSET; LogDebug($"SpawnBooth start: djDanBooked={RaveConfig.DJDanBooked}, djGirlBooked={RaveConfig.DJGirlBooked}, djCutChemistBooked={RaveConfig.DJCutChemistBooked}, djLudapimpBooked={RaveConfig.DJLudapimpBooked}"); LogDebug($"SpawnBooth center: x={centerPosition.x:F3}, y={centerPosition.y:F3}, z={centerPosition.z:F3}, boothZOffset={bOOTH_Z_OFFSET:F3}"); try { EnsureGlbCached("booth", ref _boothPrefab, GlbAssetProvider.GetDjBooth, ref _boothCacheFailed); if ((Object)(object)_boothPrefab != (Object)null) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(centerPosition.x, centerPosition.y + -0.5f, centerPosition.z + bOOTH_Z_OFFSET); val.y = ResolveGroundY(val, val.y, "RaveDJBooth"); _boothInstance = SpawnInstance(_boothPrefab, "RaveDJBooth", val, 1.5f, ScaleMode.ByWidth, val.y + 0.18f); } if ((Object)(object)_boothInstance == (Object)null) { RaveMod.Logger.Warning("DJ Booth spawn failed."); } } catch (Exception value) { RaveMod.Logger.Error($"SpawnBooth (booth) error: {value}"); } string goName = (RaveConfig.DJLudapimpBooked ? "RaveDJLudapimp" : (RaveConfig.DJCutChemistBooked ? "RaveDJCutChemist" : (RaveConfig.DJGirlBooked ? "RaveDJGirl" : "RaveDJDan"))); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(centerPosition.x, centerPosition.y + -0.5f, centerPosition.z + bOOTH_Z_OFFSET + 1.2f); val2.y = ResolveGroundY(val2, val2.y, goName); if (RaveConfig.DJLudapimpBooked) { Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(centerPosition.x, centerPosition.y + -0.5f, centerPosition.z + bOOTH_Z_OFFSET + 1.4f); val3.y = ResolveGroundY(val3, val3.y, "RaveDJLudapimp"); try { EnsureGlbCached("djludapimp", ref _djLudapimpPrefab, GlbAssetProvider.GetDjLudapimp, ref _djLudapimpCacheFailed); if ((Object)(object)_djLudapimpPrefab != (Object)null) { _djLudapimpInstance = SpawnInstance(_djLudapimpPrefab, "RaveDJLudapimp", val3, 1.6f, DJLUDAPIMP_SCALE_MODE, val3.y + 0f, skipBottomAlign: true); AddDJCapsuleCollider(_djLudapimpInstance, "DJ Ludapimp"); FaceBooth(_djLudapimpInstance, _boothInstance, "RaveDJLudapimp"); LogDjRelativeToBooth(_djLudapimpInstance, _boothInstance, "RaveDJLudapimp"); } if ((Object)(object)_djLudapimpInstance == (Object)null) { RaveMod.Logger.Warning("DJ Ludapimp spawn failed."); } } catch (Exception value2) { RaveMod.Logger.Error($"SpawnBooth (DJ Ludapimp) error: {value2}"); } } else if (RaveConfig.DJCutChemistBooked) { try { EnsureGlbCached("djcutchemist", ref _djCutChemistPrefab, GlbAssetProvider.GetDjCutChemist, ref _djCutChemistCacheFailed); if ((Object)(object)_djCutChemistPrefab != (Object)null) { _djCutChemistInstance = SpawnInstance(_djCutChemistPrefab, "RaveDJCutChemist", val2, 1.8f, DJCUTCHEMIST_SCALE_MODE, val2.y + 0f, skipBottomAlign: true); AddDJCapsuleCollider(_djCutChemistInstance, "DJ Cut Chemist"); FaceBooth(_djCutChemistInstance, _boothInstance, "RaveDJCutChemist", 180f); LogDjRelativeToBooth(_djCutChemistInstance, _boothInstance, "RaveDJCutChemist"); } if ((Object)(object)_djCutChemistInstance == (Object)null) { RaveMod.Logger.Warning("DJ Cut Chemist spawn failed."); } } catch (Exception value3) { RaveMod.Logger.Error($"SpawnBooth (DJ Cut Chemist) error: {value3}"); } } else if (RaveConfig.DJGirlBooked) { try { EnsureGlbCached("djgirl", ref _djGirlPrefab, GlbAssetProvider.GetDjGirl, ref _djGirlCacheFailed); if ((Object)(object)_djGirlPrefab != (Object)null) { _djGirlInstance = SpawnInstance(_djGirlPrefab, "RaveDJGirl", val2, 1.9f, DJGIRL_SCALE_MODE, val2.y + -1f, skipBottomAlign: true); AddDJCapsuleCollider(_djGirlInstance, "DJ Girl"); FaceBooth(_djGirlInstance, _boothInstance, "RaveDJGirl"); LogDjRelativeToBooth(_djGirlInstance, _boothInstance, "RaveDJGirl"); } if ((Object)(object)_djGirlInstance == (Object)null) { RaveMod.Logger.Warning("DJ Girl spawn failed."); } } catch (Exception value4) { RaveMod.Logger.Error($"SpawnBooth (DJ Girl) error: {value4}"); } } else if (RaveConfig.DJDanBooked) { try { EnsureGlbCached("djdan", ref _djDanPrefab, GlbAssetProvider.GetDjDan, ref _djDanCacheFailed); if ((Object)(object)_djDanPrefab != (Object)null) { _djDanInstance = SpawnInstance(_djDanPrefab, "RaveDJDan", val2, 1.8f, DJDAN_SCALE_MODE, val2.y + 0f, skipBottomAlign: true); AddDJCapsuleCollider(_djDanInstance, "DJ Dan"); FaceBooth(_djDanInstance, _boothInstance, "RaveDJDan"); LogDjRelativeToBooth(_djDanInstance, _boothInstance, "RaveDJDan"); } if ((Object)(object)_djDanInstance == (Object)null) { RaveMod.Logger.Warning("DJ Dan spawn failed."); } } catch (Exception value5) { RaveMod.Logger.Error($"SpawnBooth (DJ Dan) error: {value5}"); } } bool flag = (Object)(object)_boothInstance != (Object)null; bool flag2 = RaveConfig.DJDanBooked || RaveConfig.DJGirlBooked || RaveConfig.DJCutChemistBooked || RaveConfig.DJLudapimpBooked; bool flag3 = !flag2 || (Object)(object)_djDanInstance != (Object)null || (Object)(object)_djGirlInstance != (Object)null || (Object)(object)_djCutChemistInstance != (Object)null || (Object)(object)_djLudapimpInstance != (Object)null; string text = ((!flag2) ? "not booked" : ((!RaveConfig.DJLudapimpBooked) ? ((!RaveConfig.DJCutChemistBooked) ? ((!RaveConfig.DJGirlBooked) ? (((Object)(object)_djDanInstance != (Object)null) ? "Dan OK" : "Dan FAIL") : (((Object)(object)_djGirlInstance != (Object)null) ? "Girl OK" : "Girl FAIL")) : (((Object)(object)_djCutChemistInstance != (Object)null) ? "CutChemist OK" : "CutChemist FAIL")) : (((Object)(object)_djLudapimpInstance != (Object)null) ? "Ludapimp OK" : "Ludapimp FAIL"))); if (!flag || !flag3) { RaveMod.Logger.Warning("DJ Booth spawn incomplete: booth=" + (((Object)(object)_boothInstance != (Object)null) ? "OK" : "FAIL") + ", dj=" + text); } else if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("DJ Booth: booth=OK, dj=" + text); } } private static void AddDJCapsuleCollider(GameObject djInstance, string label) { //IL_0019: 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)(object)djInstance == (Object)null) { return; } try { float num = djInstance.transform.localScale.x; if (num < 0.0001f) { num = 1f; } CapsuleCollider val = djInstance.AddComponent(); val.center = new Vector3(0f, 0.9f / num, 0f); val.radius = 0.3f / num; val.height = 1.8f / num; LogDebug($"{label} CapsuleCollider: rootScale={num:F4}, localRadius={val.radius:F4}, localHeight={val.height:F4}"); } catch (Exception ex) { LogDebug(label + " CapsuleCollider error (non-fatal): " + ex.Message); } } private static void EnsureGlbCached(string label, ref GameObject prefab, Func glbProvider, ref bool cacheFailed) { if ((Object)(object)prefab != (Object)null) { return; } if (cacheFailed) { LogDebug("[" + label + "] cache previously failed, skipping."); return; } byte[] array; try { array = glbProvider(); } catch (Exception value) { RaveMod.Logger.Error($"[{label}] GLB read failed: {value}"); cacheFailed = true; return; } if (array == null || array.Length < 12) { RaveMod.Logger.Error("[" + label + "] GLB data null or too short."); cacheFailed = true; return; } LogDebug($"[{label}] GLB bytes: {array.Length}"); try { DebugLog.DebugEnabled = IsBundleDebugEnabled(); GltfImporter gltfImporter = new GltfImporter().SetName(label).ImportAnimations(import: true).ImportSkins(import: true) .GenerateNormals(generate: true) .GenerateTangents(generate: true) .ReadableMeshes(readable: true); prefab = gltfImporter.Load(array); } catch (Exception value2) { RaveMod.Logger.Error($"[{label}] GltfImporter.Load failed: {value2}"); cacheFailed = true; return; } if ((Object)(object)prefab == (Object)null) { RaveMod.Logger.Error("[" + label + "] GltfImporter returned null."); cacheFailed = true; return; } prefab.SetActive(false); LogDebug($"[{label}] GLB prefab cached: '{((Object)prefab).name}'"); DiagnosePrefabStructure(prefab, label); } private static void DiagnosePrefabStructure(GameObject prefab, string label) { //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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_020d: 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) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) try { Vector3 localScale = prefab.transform.localScale; int value = 0; int value2 = 0; int value3 = 0; Vector3 val = Vector3.zero; MeshFilter[] array = Il2CppArrayBase.op_Implicit(prefab.GetComponentsInChildren(true)); Bounds bounds; if (array != null) { value = array.Length; for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && (Object)(object)array[i].sharedMesh != (Object)null) { Vector3 val2 = val; bounds = array[i].sharedMesh.bounds; val = Vector3.Max(val2, ((Bounds)(ref bounds)).size); } } } SkinnedMeshRenderer[] array2 = Il2CppArrayBase.op_Implicit(prefab.GetComponentsInChildren(true)); if (array2 != null) { value2 = array2.Length; for (int j = 0; j < array2.Length; j++) { if ((Object)(object)array2[j] != (Object)null && (Object)(object)array2[j].sharedMesh != (Object)null) { Vector3 val3 = val; bounds = array2[j].sharedMesh.bounds; val = Vector3.Max(val3, ((Bounds)(ref bounds)).size); } } } Animation[] array3 = Il2CppArrayBase.op_Implicit(prefab.GetComponentsInChildren(true)); if (array3 != null) { value3 = array3.Length; } Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(val.x * Mathf.Abs(localScale.x), val.y * Mathf.Abs(localScale.y), val.z * Mathf.Abs(localScale.z)); LogDebug($"[{label}] rootScale=({localScale.x:F1},{localScale.y:F1},{localScale.z:F1}), meshLocal=({val.x:F4},{val.y:F4},{val.z:F4}), worldSize=({val4.x:F3},{val4.y:F3},{val4.z:F3}), meshFilters={value}, skins={value2}, anims={value3}"); } catch (Exception ex) { RaveMod.Logger.Warning("[DJDiag] " + label + ": diagnosis error: " + ex.Message); } } private static GameObject SpawnInstance(GameObject prefab, string goName, Vector3 position, float targetSize, ScaleMode scaleMode, float alignBottomToY, bool skipBottomAlign = false) { //IL_0003: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0458: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0622: Unknown result type (might be due to invalid IL or missing references) //IL_0627: Unknown result type (might be due to invalid IL or missing references) //IL_062b: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_0a7e: Unknown result type (might be due to invalid IL or missing references) //IL_0aa4: Unknown result type (might be due to invalid IL or missing references) //IL_0aca: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_0678: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_0687: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06aa: Unknown result type (might be due to invalid IL or missing references) //IL_069a: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_06b4: Unknown result type (might be due to invalid IL or missing references) //IL_06d0: Unknown result type (might be due to invalid IL or missing references) //IL_06d7: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06e1: Unknown result type (might be due to invalid IL or missing references) //IL_06fd: Unknown result type (might be due to invalid IL or missing references) //IL_0704: Unknown result type (might be due to invalid IL or missing references) //IL_06f4: Unknown result type (might be due to invalid IL or missing references) //IL_0749: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_0767: Unknown result type (might be due to invalid IL or missing references) //IL_077d: Unknown result type (might be due to invalid IL or missing references) //IL_0791: Unknown result type (might be due to invalid IL or missing references) //IL_07a5: Unknown result type (might be due to invalid IL or missing references) //IL_07be: Unknown result type (might be due to invalid IL or missing references) //IL_07c0: Unknown result type (might be due to invalid IL or missing references) //IL_07c2: Unknown result type (might be due to invalid IL or missing references) //IL_07d1: Unknown result type (might be due to invalid IL or missing references) //IL_082a: Unknown result type (might be due to invalid IL or missing references) //IL_0850: Unknown result type (might be due to invalid IL or missing references) //IL_0876: Unknown result type (might be due to invalid IL or missing references) //IL_089a: Unknown result type (might be due to invalid IL or missing references) //IL_08bb: Unknown result type (might be due to invalid IL or missing references) //IL_08dc: Unknown result type (might be due to invalid IL or missing references) GameObject obj = null; _lastNormalizedScaleFactor = Vector3.one; try { obj = Object.Instantiate(prefab); if ((Object)(object)obj == (Object)null) { RaveMod.Logger.Error("[" + goName + "] Instantiate returned null."); return null; } ((Object)obj).name = goName; obj.SetActive(true); obj.transform.position = position; if (targetSize > 0f) { Vector3 val = MeasureModelSize(obj); float num; string value; switch (scaleMode) { case ScaleMode.ByMaxAxis: num = Mathf.Max(val.x, Mathf.Max(val.y, val.z)); value = "max-axis"; break; case ScaleMode.ByWidth: num = val.x; value = "width"; break; default: num = val.y; value = "height"; break; } if (num > 0.0001f) { float num2 = targetSize / num; Vector3 localScale = obj.transform.localScale; Vector3 val2 = localScale * num2; if (obj.GetComponentsInChildren(true).Length <= 0 && (val2.x < 0.05f || val2.x > 20f)) { _lastNormalizedScaleFactor = NormalizeChildScales(obj, goName); localScale = obj.transform.localScale; val = MeasureModelSize(obj); float num3 = scaleMode switch { ScaleMode.ByMaxAxis => Mathf.Max(val.x, Mathf.Max(val.y, val.z)), ScaleMode.ByWidth => val.x, _ => val.y, }; if (num3 > 0.0001f) { num2 = targetSize / num3; num = num3; } } obj.transform.localScale = localScale * num2; LogDebug($"[{goName}] measured=({val.x:F4},{val.y:F4},{val.z:F4}), ref={num:F4}({value}), autoScale={num2:F4}, rootScale=({localScale.x:F2},{localScale.y:F2},{localScale.z:F2}), finalScale=({localScale.x * num2:F4},{localScale.y * num2:F4},{localScale.z * num2:F4})"); } else { RaveMod.Logger.Warning($"[DJDiag] {goName}: model bounds too small ({num:F6}), keeping original scale ({obj.transform.localScale.x:F1},{obj.transform.localScale.y:F1},{obj.transform.localScale.z:F1})"); } } if (!skipBottomAlign) { AlignBottomToY(obj, alignBottomToY); } LogDebug($"[{goName}] spawned at ({position.x:F1},{position.y:F1},{position.z:F1}), skipAlign={skipBottomAlign}"); } catch (Exception value2) { RaveMod.Logger.Error($"[{goName}] Instantiate failed: {value2}"); DestroyObject(ref obj); return null; } try { SkinnedMeshRenderer[] array = Il2CppArrayBase.op_Implicit(obj.GetComponentsInChildren(true)); if (array != null) { Vector3 val6 = default(Vector3); Vector3 val7 = default(Vector3); foreach (SkinnedMeshRenderer val3 in array) { if ((Object)(object)val3 == (Object)null) { continue; } val3.updateWhenOffscreen = true; ((Renderer)val3).forceRenderingOff = false; ((Renderer)val3).enabled = true; ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)1; Mesh sharedMesh = val3.sharedMesh; if (!((Object)(object)sharedMesh != (Object)null)) { continue; } Bounds bounds = sharedMesh.bounds; float num4 = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)); if (num4 > 50f) { Vector3 val4 = ComputeLossyScale(((Component)val3).transform); Vector3 val5 = ComputeLossyScale(obj.transform); float num5 = ((Mathf.Abs(val5.x) > 0.001f) ? (val4.x / val5.x) : val4.x); float num6 = ((Mathf.Abs(val5.y) > 0.001f) ? (val4.y / val5.y) : val4.y); float num7 = ((Mathf.Abs(val5.z) > 0.001f) ? (val4.z / val5.z) : val4.z); if (Mathf.Abs(num5) > 5f || Mathf.Abs(num6) > 5f || Mathf.Abs(num7) > 5f) { ((Vector3)(ref val6))..ctor(((Bounds)(ref bounds)).center.x / num5, ((Bounds)(ref bounds)).center.y / num6, ((Bounds)(ref bounds)).center.z / num7); ((Vector3)(ref val7))..ctor(((Bounds)(ref bounds)).size.x / Mathf.Abs(num5), ((Bounds)(ref bounds)).size.y / Mathf.Abs(num6), ((Bounds)(ref bounds)).size.z / Mathf.Abs(num7)); sharedMesh.bounds = new Bounds(val6, val7); ((Renderer)val3).localBounds = sharedMesh.bounds; LogDebug($"[{goName}] Skinned '{((Object)val3).name}': mesh.bounds rescaled from ({((Bounds)(ref bounds)).size.x:F1},{((Bounds)(ref bounds)).size.y:F1},{((Bounds)(ref bounds)).size.z:F1}) to ({val7.x:F2},{val7.y:F2},{val7.z:F2}) by internalScale=({num5:F1},{num6:F1},{num7:F1})"); } else { LogDebug($"[{goName}] Skinned '{((Object)val3).name}': bounds large ({num4:F1}) but internalScale=({num5:F1},{num6:F1},{num7:F1}) < 5, keeping original"); } } else { LogDebug($"[{goName}] Skinned '{((Object)val3).name}': mesh.bounds=({((Bounds)(ref bounds)).size.x:F2},{((Bounds)(ref bounds)).size.y:F2},{((Bounds)(ref bounds)).size.z:F2}), OK"); } } } } catch (Exception ex) { LogDebug("[" + goName + "] SkinnedMesh fixes error (non-fatal): " + ex.Message); } try { StartImportedAnimations(obj, goName); } catch (Exception ex2) { LogDebug("[" + goName + "] Animation setup error (non-fatal): " + ex2.Message); } try { EnforceOpaqueRendering(obj, goName); } catch (Exception ex3) { LogDebug("[" + goName + "] Material fix error (non-fatal): " + ex3.Message); } try { if (goName == "RaveDJGirl" || goName == "RaveDJLudapimp") { LogRendererDiagnostics(obj, goName); ScheduleDelayedVisibilityCheck(obj, goName); } } catch (Exception ex4) { LogDebug("[" + goName + "] Renderer diagnostics error (non-fatal): " + ex4.Message); } try { MeshFilter[] array2 = Il2CppArrayBase.op_Implicit(obj.GetComponentsInChildren(true)); if (array2 != null) { foreach (MeshFilter val8 in array2) { if (!((Object)(object)val8 == (Object)null) && !((Object)(object)val8.sharedMesh == (Object)null) && !((Object)(object)((Component)val8).GetComponent() != (Object)null)) { MeshCollider val9 = ((Component)val8).gameObject.AddComponent(); val9.sharedMesh = val8.sharedMesh; } } } } catch (Exception ex5) { LogDebug("[" + goName + "] Collider setup error (non-fatal): " + ex5.Message); } return obj; } private static Vector3 NormalizeChildScales(GameObject instance, string goName) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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) Transform transform = instance.transform; Vector3 localScale = transform.localScale; NormalizeChildScalesRecursive(transform, transform, goName); Vector3 localScale2 = transform.localScale; return new Vector3((localScale.x > 0.0001f) ? (localScale2.x / localScale.x) : 1f, (localScale.y > 0.0001f) ? (localScale2.y / localScale.y) : 1f, (localScale.z > 0.0001f) ? (localScale2.z / localScale.z) : 1f); } private static void NormalizeChildScalesRecursive(Transform root, Transform current, string goName) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0069: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < current.childCount; i++) { Transform child = current.GetChild(i); Vector3 localScale = child.localScale; if (localScale.x > 5f || localScale.x < 0.2f) { Vector3 localScale2 = root.localScale; root.localScale = new Vector3(localScale2.x * localScale.x, localScale2.y * localScale.y, localScale2.z * localScale.z); child.localScale = Vector3.one; LogDebug($"[{goName}] normalized child '{((Object)child).name}' scale ({localScale.x:F4},{localScale.y:F4},{localScale.z:F4}) → root, new rootScale=({root.localScale.x:F4},{root.localScale.y:F4},{root.localScale.z:F4})"); } if (child.childCount > 0 && (Object)(object)child != (Object)(object)root) { NormalizeChildScalesRecursive(root, child, goName); } } } private static Vector3 MeasureModelSize(GameObject instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (TryGetModelMeshBasedSize(instance, out var size)) { return size; } Bounds combined; return TryGetModelWorldBounds(instance, out combined) ? ((Bounds)(ref combined)).size : Vector3.zero; } private static bool TryGetModelMeshBasedSize(GameObject instance, out Vector3 size) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0174: 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_017b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) size = Vector3.zero; bool result = false; MeshFilter[] array = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); Bounds bounds; if (array != null) { foreach (MeshFilter val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sharedMesh == (Object)null)) { bounds = val.sharedMesh.bounds; Vector3 scaledMeshSize = GetScaledMeshSize(((Bounds)(ref bounds)).size, ComputeLossyScale(((Component)val).transform)); if (!(Vector3.Dot(scaledMeshSize, scaledMeshSize) <= 1E-06f)) { size = Vector3.Max(size, scaledMeshSize); result = true; } } } } SkinnedMeshRenderer[] array2 = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); if (array2 != null) { foreach (SkinnedMeshRenderer val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.sharedMesh == (Object)null)) { bounds = val2.sharedMesh.bounds; Vector3 size2 = ((Bounds)(ref bounds)).size; Vector3 lossyScale = ComputeLossyScale(((Component)val2).transform); float num = Mathf.Max(size2.x, Mathf.Max(size2.y, size2.z)); Vector3 val3 = ((!(num > 0.5f)) ? GetScaledMeshSize(size2, lossyScale) : size2); if (!(Vector3.Dot(val3, val3) <= 1E-06f)) { size = Vector3.Max(size, val3); result = true; } } } } return result; } private static Vector3 GetScaledMeshSize(Vector3 localMeshSize, Vector3 lossyScale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_003f: Unknown result type (might be due to invalid IL or missing references) return new Vector3(localMeshSize.x * Mathf.Abs(lossyScale.x), localMeshSize.y * Mathf.Abs(lossyScale.y), localMeshSize.z * Mathf.Abs(lossyScale.z)); } private static void ApplyUniformScaleToDirectChildren(Transform root, float scale) { //IL_0045: 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) if ((Object)(object)root == (Object)null || Mathf.Abs(scale - 1f) < 0.0001f) { return; } for (int i = 0; i < root.childCount; i++) { Transform child = root.GetChild(i); if (!((Object)(object)child == (Object)null)) { child.localScale *= scale; } } } private static Vector3 ComputeLossyScale(Transform t) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_005b: 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) Vector3 localScale = t.localScale; Transform parent = t.parent; while ((Object)(object)parent != (Object)null) { Vector3 localScale2 = parent.localScale; ((Vector3)(ref localScale))..ctor(localScale.x * localScale2.x, localScale.y * localScale2.y, localScale.z * localScale2.z); parent = parent.parent; } return localScale; } private static void AlignBottomToY(GameObject instance, float targetY) { //IL_0029: 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_003f: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) float? num = TryGetMeshBasedBottomY(instance); Bounds combined; if (num.HasValue) { float num2 = targetY - num.Value; Transform transform = instance.transform; transform.position += new Vector3(0f, num2, 0f); LogDebug($"[{((Object)instance).name}] bottom align (mesh): targetY={targetY:F4}, meshBottomY={num.Value:F4}, deltaY={num2:F4}"); } else if (TryGetModelWorldBounds(instance, out combined)) { float num3 = targetY - ((Bounds)(ref combined)).min.y; Transform transform2 = instance.transform; transform2.position += new Vector3(0f, num3, 0f); LogDebug($"[{((Object)instance).name}] bottom align (world): targetY={targetY:F4}, worldMinY={((Bounds)(ref combined)).min.y:F4}, deltaY={num3:F4}"); } } private static float? TryGetMeshBasedBottomY(GameObject instance) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) float? result = null; MeshFilter[] array = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); if (array != null) { foreach (MeshFilter val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sharedMesh == (Object)null)) { float num = ComputeWorldMinY(val.sharedMesh.bounds, ((Component)val).transform); if (!result.HasValue || num < result.Value) { result = num; } } } } SkinnedMeshRenderer[] array2 = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); if (array2 != null) { foreach (SkinnedMeshRenderer val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.sharedMesh == (Object)null)) { float num2 = ComputeWorldMinY(val2.sharedMesh.bounds, ((Component)val2).transform); if (!result.HasValue || num2 < result.Value) { result = num2; } } } } return result; } private static float ComputeWorldMinY(Bounds localBounds, Transform t) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0023: 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) Vector3 val = ComputeLossyScale(t); float num = ((Bounds)(ref localBounds)).center.y - ((Bounds)(ref localBounds)).extents.y; float num2 = num * Mathf.Abs(val.y); float y = t.position.y; return y + num2; } private static void FaceBooth(GameObject djInstance, GameObject boothInstance, string goName, float yawCorrection = 0f) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_008a: 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_00c2: 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) //IL_0118: 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) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)djInstance == (Object)null || (Object)(object)boothInstance == (Object)null) { return; } Vector3 val = boothInstance.transform.position - djInstance.transform.position; val.y = 0f; if (Vector3.Dot(val, val) < 0.0001f) { LogDebugOnce(goName + "_look_small", "[" + goName + "] Booth look direction too small, keeping imported rotation."); return; } Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); if (Mathf.Abs(yawCorrection) > 0.01f) { val2 *= Quaternion.Euler(0f, yawCorrection, 0f); } djInstance.transform.rotation = val2; LogDebug($"[{goName}] facing booth: dir=({val.x:F3},{val.y:F3},{val.z:F3}), yawCorrection={yawCorrection:F0}"); } private static void LogDjRelativeToBooth(GameObject djInstance, GameObject boothInstance, string goName) { //IL_0034: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (IsBundleDebugEnabled() && !((Object)(object)djInstance == (Object)null) && !((Object)(object)boothInstance == (Object)null)) { float value = djInstance.transform.position.z - boothInstance.transform.position.z; float value2 = djInstance.transform.position.y - boothInstance.transform.position.y; LogDebug($"[{goName}] final offsets vs booth: deltaY={value2:F3}, deltaZ={value:F3}"); } } private static float ResolveGroundY(Vector3 position, float fallbackY, string goName) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_00ba: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x, fallbackY + 1.2f, position.z); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, Vector3.down, ref val2, 6f, -1, (QueryTriggerInteraction)1)) { LogDebug($"[{goName}] ground hit: y={((RaycastHit)(ref val2)).point.y:F4}, collider='{((Object)((RaycastHit)(ref val2)).collider).name}'"); return ((RaycastHit)(ref val2)).point.y; } LogDebugOnce(goName + "_ground_miss", $"[{goName}] ground raycast missed, fallbackY={fallbackY:F4}"); return fallbackY; } private static void StartImportedAnimations(GameObject instance, string goName) { Animation[] array = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); if (array == null || array.Length == 0) { if (goName != "RaveDJBooth") { RaveMod.Logger.Warning("[" + goName + "] No Animation component found — DJ will be in T-pose. GLB needs re-export with animation baked in."); } return; } bool flag = false; foreach (Animation val in array) { if ((Object)(object)val == (Object)null) { continue; } ((Behaviour)val).enabled = true; val.playAutomatically = true; val.cullingType = (AnimationCullingType)0; val.wrapMode = (WrapMode)2; AnimationClip clip = val.clip; string text = (((Object)(object)clip != (Object)null) ? ((Object)clip).name : null); int value = 0; try { value = val.GetClipCount(); } catch (Exception ex) { LogDebug("[" + goName + "] GetClipCount error (non-fatal): " + ex.Message); } if ((Object)(object)clip != (Object)null) { clip.legacy = true; clip.wrapMode = (WrapMode)2; } if ((Object)(object)clip == (Object)null || string.IsNullOrEmpty(text)) { LogDebug($"[{goName}] Animation component '{((Object)val).name}' has no playable clips."); continue; } try { AnimationState val2 = val[text]; if ((TrackedReference)(object)val2 != (TrackedReference)null) { val2.enabled = true; val2.wrapMode = (WrapMode)2; val2.speed = 1f; } } catch (Exception ex2) { LogDebug("[" + goName + "] Animation state access error (non-fatal): " + ex2.Message); } val.clip = clip; val.Stop(); bool flag2 = val.Play(text); flag |= flag2 || val.isPlaying; LogDebug($"[{goName}] animation start: component='{((Object)val).name}', clips={value}, selected='{text}', playing={flag2 || val.isPlaying}"); } if (!flag) { LogDebugOnce(goName + "_animation_not_playing", "[" + goName + "] No imported animation started."); } } private static bool TryGetModelWorldBounds(GameObject instance, out Bounds combined) { //IL_0002: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) combined = default(Bounds); bool flag = false; Renderer[] array = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); if (array != null) { foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null)) { Bounds bounds = val.bounds; if (!flag) { combined = bounds; flag = true; } else { ((Bounds)(ref combined)).Encapsulate(bounds); } } } } return flag; } private static void EnforceOpaqueRendering(GameObject root, string goName) { //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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) Renderer[] array = Il2CppArrayBase.op_Implicit(root.GetComponentsInChildren(true)); if (array == null) { return; } foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { continue; } val.forceRenderingOff = false; val.enabled = true; val.shadowCastingMode = (ShadowCastingMode)1; try { Material[] array2 = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)val.materials); if (array2 == null) { continue; } foreach (Material val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { val2.SetFloat("_Surface", 0f); val2.SetFloat("_ZWrite", 1f); val2.SetInt("_SrcBlend", 1); val2.SetInt("_DstBlend", 0); val2.SetFloat("_Cull", 0f); val2.renderQueue = 2000; val2.DisableKeyword("_ALPHAPREMULTIPLY_ON"); val2.DisableKeyword("_ALPHATEST_ON"); val2.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); if (val2.HasProperty("_BaseColor")) { Color color = val2.GetColor("_BaseColor"); color.a = 1f; val2.SetColor("_BaseColor", color); } if (val2.HasProperty("_Color")) { Color color2 = val2.GetColor("_Color"); color2.a = 1f; val2.SetColor("_Color", color2); } } } } catch (Exception ex) { LogDebug($"[{goName}] Opaque fix error on renderer '{((Object)val).name}' (non-fatal): {ex.Message}"); } } } private static void LogRendererDiagnostics(GameObject root, string goName) { //IL_007e: 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_0131: Unknown result type (might be due to invalid IL or missing references) //IL_015c: 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_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: 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_0245: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) if (!IsBundleDebugEnabled() || (Object)(object)root == (Object)null) { return; } Renderer[] array = Il2CppArrayBase.op_Implicit(root.GetComponentsInChildren(true)); if (array == null || array.Length == 0) { LogDebug("[" + goName + "] renderer diag: no Renderer components found."); return; } foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { continue; } Bounds bounds = val.bounds; LogDebug($"[{goName}] renderer diag: name='{((Object)val).name}', type={((object)val).GetType().Name}, enabled={val.enabled}, visible={val.isVisible}, pos=({((Component)val).transform.position.x:F3},{((Component)val).transform.position.y:F3},{((Component)val).transform.position.z:F3}), boundsCenter=({((Bounds)(ref bounds)).center.x:F3},{((Bounds)(ref bounds)).center.y:F3},{((Bounds)(ref bounds)).center.z:F3}), boundsSize=({((Bounds)(ref bounds)).size.x:F3},{((Bounds)(ref bounds)).size.y:F3},{((Bounds)(ref bounds)).size.z:F3})"); Material[] array2 = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)val.sharedMaterials); if (array2 == null) { continue; } for (int j = 0; j < array2.Length; j++) { Material val2 = array2[j]; if ((Object)(object)val2 == (Object)null) { LogDebug($"[{goName}] renderer diag: renderer='{((Object)val).name}' material[{j}]=null"); continue; } string value = (((Object)(object)val2.shader != (Object)null) ? ((Object)val2.shader).name : ""); float value2 = (val2.HasProperty("_Surface") ? val2.GetFloat("_Surface") : (-1f)); float value3 = (val2.HasProperty("_ZWrite") ? val2.GetFloat("_ZWrite") : (-1f)); float value4 = 1f; if (val2.HasProperty("_BaseColor")) { value4 = val2.GetColor("_BaseColor").a; } else if (val2.HasProperty("_Color")) { value4 = val2.GetColor("_Color").a; } LogDebug($"[{goName}] renderer diag: renderer='{((Object)val).name}' material[{j}]='{((Object)val2).name}', shader='{value}', surface={value2:F1}, zwrite={value3:F1}, alpha={value4:F3}, queue={val2.renderQueue}"); } } } private static void ScheduleDelayedVisibilityCheck(GameObject instance, string goName) { float checkTime = Time.time + 2f; MelonCoroutines.Start(DelayedVisibilityCheckCoroutine(instance, goName, checkTime)); } private static IEnumerator DelayedVisibilityCheckCoroutine(GameObject instance, string goName, float checkTime) { while (Time.time < checkTime) { yield return null; } if ((Object)(object)instance == (Object)null) { LogDebug("[" + goName + "] delayed check: instance destroyed before check."); } else { if (!IsBundleDebugEnabled()) { yield break; } try { SkinnedMeshRenderer[] skins = Il2CppArrayBase.op_Implicit(instance.GetComponentsInChildren(true)); if (skins == null || skins.Length == 0) { LogDebug("[" + goName + "] delayed check: no SkinnedMeshRenderer found."); yield break; } foreach (SkinnedMeshRenderer skin in skins) { if ((Object)(object)skin == (Object)null) { continue; } Bounds b = ((Renderer)skin).bounds; RaveMod.Logger.Msg($"[RaveDJDebug] [{goName}] DELAYED: renderer='{((Object)skin).name}', visible={((Renderer)skin).isVisible}, enabled={((Renderer)skin).enabled}, forceOff={((Renderer)skin).forceRenderingOff}, gameObjectActive={((Component)skin).gameObject.activeInHierarchy}, boundsCenter=({((Bounds)(ref b)).center.x:F1},{((Bounds)(ref b)).center.y:F1},{((Bounds)(ref b)).center.z:F1}), boundsSize=({((Bounds)(ref b)).size.x:F2},{((Bounds)(ref b)).size.y:F2},{((Bounds)(ref b)).size.z:F2}), layer={((Component)skin).gameObject.layer}, rootPos=({instance.transform.position.x:F1},{instance.transform.position.y:F1},{instance.transform.position.z:F1}), rootScale=({instance.transform.localScale.x:F4},{instance.transform.localScale.y:F4},{instance.transform.localScale.z:F4})"); if (skin.bones == null || ((Il2CppArrayBase)(object)skin.bones).Length <= 0) { continue; } int count = Mathf.Min(3, ((Il2CppArrayBase)(object)skin.bones).Length); for (int j = 0; j < count; j++) { Transform bone = ((Il2CppArrayBase)(object)skin.bones)[j]; if (!((Object)(object)bone == (Object)null)) { Vector3 bp = bone.position; Vector3 bs = bone.lossyScale; RaveMod.Logger.Msg($"[RaveDJDebug] [{goName}] DELAYED: bone[{j}]='{((Object)bone).name}', worldPos=({bp.x:F2},{bp.y:F2},{bp.z:F2}), lossyScale=({bs.x:F2},{bs.y:F2},{bs.z:F2})"); } } } } catch (Exception ex) { RaveMod.Logger.Warning("[DJDiag] " + goName + " delayed check error: " + ex.Message); } } } internal static void Cleanup() { LogDebug($"Cleanup(per-rave) start: booth={(Object)(object)_boothInstance != (Object)null}, djDan={(Object)(object)_djDanInstance != (Object)null}, djGirl={(Object)(object)_djGirlInstance != (Object)null}, djCutChemist={(Object)(object)_djCutChemistInstance != (Object)null}, djLudapimp={(Object)(object)_djLudapimpInstance != (Object)null}"); DestroyInstances(); LogDebug("Cleanup(per-rave) end."); } internal static void FullCleanup() { LogDebug("FullCleanup start."); DestroyInstances(); DestroyObject(ref _boothPrefab); DestroyObject(ref _djDanPrefab); DestroyObject(ref _djGirlPrefab); DestroyObject(ref _djCutChemistPrefab); DestroyObject(ref _djLudapimpPrefab); _boothCacheFailed = false; _djDanCacheFailed = false; _djGirlCacheFailed = false; _djCutChemistCacheFailed = false; _djLudapimpCacheFailed = false; _debugOnceKeys.Clear(); LogDebug("FullCleanup end."); } private static void DestroyInstances() { DestroyObject(ref _boothInstance); DestroyObject(ref _djDanInstance); DestroyObject(ref _djGirlInstance); DestroyObject(ref _djCutChemistInstance); DestroyObject(ref _djLudapimpInstance); DestroyObject(ref _stageInstance); } internal static void DestroyStaleObjects() { try { GameObject[] array = Il2CppArrayBase.op_Implicit(Object.FindObjectsOfType()); if (array == null) { return; } foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && ((Object)val).name != null && ((((Object)val).name == "RaveDJBooth" && (Object)(object)val != (Object)(object)_boothInstance) || (((Object)val).name == "RaveDJDan" && (Object)(object)val != (Object)(object)_djDanInstance) || (((Object)val).name == "RaveDJGirl" && (Object)(object)val != (Object)(object)_djGirlInstance) || (((Object)val).name == "RaveDJCutChemist" && (Object)(object)val != (Object)(object)_djCutChemistInstance) || (((Object)val).name == "RaveDJLudapimp" && (Object)(object)val != (Object)(object)_djLudapimpInstance))) { Object.DestroyImmediate((Object)(object)val); } } } catch (Exception ex) { RaveMod.Logger.Warning("DJBooth DestroyStaleObjects error: " + ex.Message); } } private static void DestroyObject(ref GameObject obj) { try { if ((Object)(object)obj != (Object)null) { LogDebug("DestroyObject: name=" + ((Object)obj).name); Object.DestroyImmediate((Object)(object)obj); } } catch { } obj = null; } private static bool IsBundleDebugEnabled() { try { return RaveConfig.BundleDebugLogging != null && RaveConfig.BundleDebugLogging.Value; } catch { return false; } } private static void LogDebug(string message) { if (IsBundleDebugEnabled()) { RaveMod.Logger.Msg("[RaveDJDebug] " + message); } } private static void LogDebugOnce(string key, string message) { if (IsBundleDebugEnabled() && !_debugOnceKeys.Contains(key)) { _debugOnceKeys.Add(key); RaveMod.Logger.Msg("[RaveDJDebug] " + message); } } private static void SpawnStageInsteadOfBooth() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) try { EnsureGlbCached("LetsGo", ref _stagePrefab, GlbAssetProvider.GetLetsGo, ref _stageCacheFailed); if ((Object)(object)_stagePrefab == (Object)null) { RaveMod.Logger.Warning("[Stage] Prefab missing."); return; } Vector3 spawnPosition = LetsGoObjectController.GetSpawnPosition(); Quaternion spawnRotation = LetsGoObjectController.GetSpawnRotation(); _stageInstance = Object.Instantiate(_stagePrefab, spawnPosition, spawnRotation); if ((Object)(object)_stageInstance != (Object)null) { ((Object)_stageInstance).name = "SmallFestivalStage"; _stageInstance.SetActive(true); LetsGoObjectController.SetupColliders(_stageInstance); LogDebug($"[Stage] Spawn at LetsGo target pos=({spawnPosition.x:F3}, {spawnPosition.y:F3}, {spawnPosition.z:F3}), rot={((Quaternion)(ref spawnRotation)).eulerAngles}"); } if ((Object)(object)_stageInstance == (Object)null) { RaveMod.Logger.Warning("[Stage] Spawn failed."); return; } SpawnDJBehindStage(spawnPosition); RaveMod.Logger.Msg("[Stage] Small Festival Stage active."); } catch (Exception value) { RaveMod.Logger.Error($"[Stage] Spawn error: {value}"); } } private static Vector3 ResolveStageDjPosition(Vector3 stagePos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_021a: 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_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023b: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) Vector3 stageAudienceForward = RaveLocationManager.GetStageAudienceForward(); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(-0.85f, -0.6f, 0f); if ((Object)(object)_stageInstance != (Object)null) { foreach (Transform componentsInChild in _stageInstance.GetComponentsInChildren(true)) { if (string.Equals(((Object)componentsInChild).name, "pultv2", StringComparison.OrdinalIgnoreCase)) { Vector3 val2 = componentsInChild.position - stageAudienceForward * 0.55f + val; LogDebug($"[Stage] pultv2 at ({componentsInChild.position.x:F3},{componentsInChild.position.y:F3},{componentsInChild.position.z:F3}); tuning=({val.x:F2},{val.y:F2},{val.z:F2}); DJ=({val2.x:F3},{val2.y:F3},{val2.z:F3})"); return val2; } } RaveMod.Logger.Warning("[Stage] pultv2 not found - using fallback offset."); } Vector3 pultWorldPosition = LetsGoObjectController.GetPultWorldPosition(); return pultWorldPosition - stageAudienceForward * 0.55f + val; } private static void SpawnDJBehindStage(Vector3 stagePos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) try { Vector3 val = ResolveStageDjPosition(stagePos); Vector3 stageAudienceForward = RaveLocationManager.GetStageAudienceForward(); Quaternion val2 = Quaternion.LookRotation(stageAudienceForward, Vector3.up); string value = (RaveConfig.DJLudapimpBooked ? "RaveDJLudapimp" : (RaveConfig.DJCutChemistBooked ? "RaveDJCutChemist" : (RaveConfig.DJGirlBooked ? "RaveDJGirl" : "RaveDJDan"))); LogDebug($"[Stage] Spawning DJ '{value}' at stage position ({val.x:F3}, {val.y:F3}, {val.z:F3}), facing audienceForward=({stageAudienceForward.x:F3},{stageAudienceForward.z:F3})"); if (RaveConfig.DJLudapimpBooked) { EnsureGlbCached("djludapimp", ref _djLudapimpPrefab, GlbAssetProvider.GetDjLudapimp, ref _djLudapimpCacheFailed); if ((Object)(object)_djLudapimpPrefab != (Object)null) { _djLudapimpInstance = SpawnInstance(_djLudapimpPrefab, "RaveDJLudapimp", val, 1.6f, DJLUDAPIMP_SCALE_MODE, val.y, skipBottomAlign: true); if ((Object)(object)_djLudapimpInstance != (Object)null) { _djLudapimpInstance.transform.rotation = val2 * Quaternion.Euler(0f, 0f, 0f); } } } else if (RaveConfig.DJCutChemistBooked) { EnsureGlbCached("djcutchemist", ref _djCutChemistPrefab, GlbAssetProvider.GetDjCutChemist, ref _djCutChemistCacheFailed); if ((Object)(object)_djCutChemistPrefab != (Object)null) { _djCutChemistInstance = SpawnInstance(_djCutChemistPrefab, "RaveDJCutChemist", val, 1.8f, DJCUTCHEMIST_SCALE_MODE, val.y, skipBottomAlign: true); if ((Object)(object)_djCutChemistInstance != (Object)null) { _djCutChemistInstance.transform.rotation = val2 * Quaternion.Euler(0f, 180f, 0f); } } } else if (RaveConfig.DJGirlBooked) { EnsureGlbCached("djgirl", ref _djGirlPrefab, GlbAssetProvider.GetDjGirl, ref _djGirlCacheFailed); if ((Object)(object)_djGirlPrefab != (Object)null) { _djGirlInstance = SpawnInstance(_djGirlPrefab, "RaveDJGirl", val, 1.9f, DJGIRL_SCALE_MODE, val.y, skipBottomAlign: true); if ((Object)(object)_djGirlInstance != (Object)null) { _djGirlInstance.transform.rotation = val2 * Quaternion.Euler(0f, 0f, 0f); } } } else { if (!RaveConfig.DJDanBooked) { return; } EnsureGlbCached("djdan", ref _djDanPrefab, GlbAssetProvider.GetDjDan, ref _djDanCacheFailed); if ((Object)(object)_djDanPrefab != (Object)null) { _djDanInstance = SpawnInstance(_djDanPrefab, "RaveDJDan", val, 1.8f, DJDAN_SCALE_MODE, val.y, skipBottomAlign: true); if ((Object)(object)_djDanInstance != (Object)null) { _djDanInstance.transform.rotation = val2 * Quaternion.Euler(0f, 0f, 0f); } } } } catch (Exception value2) { RaveMod.Logger.Error($"[Stage] DJ spawn error: {value2}"); } } } public sealed class RaveEventManager { private static bool _raveActive = false; private static bool _firstMsgSent = false; private static bool _secondMsgSent = false; private static bool _raveRanToday = false; private static int _lastCheckedDay = -1; private static bool _enteredNightPhase = false; private static bool _announcementSentThisSession = false; private static bool _djDanPitchSentThisSession = false; private static bool _triggerRolled = false; private static bool _raveWillHappenTonight = false; private static readonly Random _rng = new Random(); private const float PRESET_TRIGGER_CHANCE = 0.3f; private static TimeManager _timeManager; private static float _checkTimer = 0f; private const float CHECK_INTERVAL = 8f; private static bool _debugLoggedTime = false; private static float _debugCoordTimer = 0f; private const float DEBUG_COORD_INTERVAL = 5f; private static float _sleepCheckTimer = 0f; private const float SLEEP_CHECK_INTERVAL = 0.5f; private static bool _buttonsRegistered = false; private static float _buttonCheckTimer = 0f; private const float BUTTON_CHECK_INTERVAL = 10f; private static Action _saveLocationAction; private static Action _removeLocationAction; private static Action _djDanAction; private static Action _djGirlAction; private static Action _djCutChemistAction; private static Action _djLudapimpAction; private static Action _il2cppSaveAction; private static Action _il2cppRemoveAction; private static Action _il2cppDjDanAction; private static Action _il2cppDjGirlAction; private static Action _il2cppDjCutChemistAction; private static Action _il2cppDjLudapimpAction; private static IEnumerator _startupSteps; private static bool _raveStarting; private static readonly List _startupTimings = new List(8); private static readonly Stopwatch _startupWatch = new Stopwatch(); private static long _startupTotalMs; private static int _startupFrames; private static string _startupCurrentStep = "-"; internal static bool IsRaveActive => _raveActive; internal static bool IsRaveStarting => _raveStarting; private RaveEventManager() { } internal static void Update() { PumpStartup(); if (RaveConfig.DebugCoordinates.Value) { _debugCoordTimer += Time.deltaTime; if (_debugCoordTimer >= 5f) { _debugCoordTimer = 0f; LogPlayerPosition(); } } if (!_buttonsRegistered) { _buttonCheckTimer += Time.deltaTime; if (_buttonCheckTimer >= 10f) { _buttonCheckTimer = 0f; TryRegisterSendableButtons(); } } if (_buttonsRegistered && !_djDanPitchSentThisSession && !RaveConfig.DJDanBooked && !RaveConfig.DJGirlBooked && !RaveConfig.DJCutChemistBooked && !RaveConfig.DJLudapimpBooked) { SendIgorMessage("Yo i met some event guy who knows crazy djs from the south sector. If I couldn't access the booking system, I wouldn't be the Igor I am. Hehehe.. want me to book one of them? I'll cover it boss and lets hope that there are no bum-fights at the rave."); _djDanPitchSentThisSession = true; } if (_raveActive && (Object)(object)_timeManager != (Object)null) { _sleepCheckTimer += Time.deltaTime; if (_sleepCheckTimer >= 0.5f) { _sleepCheckTimer = 0f; try { if (_timeManager.IsSleepInProgress) { StopRave(); _raveRanToday = true; _timeManager = null; return; } } catch { } } } _checkTimer += Time.deltaTime; if (_checkTimer < 8f) { return; } _checkTimer = 0f; try { if ((Object)(object)_timeManager == (Object)null) { _timeManager = Object.FindObjectOfType(); if ((Object)(object)_timeManager == (Object)null) { return; } } int currentTime = _timeManager.CurrentTime; bool isSleepInProgress = _timeManager.IsSleepInProgress; int elapsedDays = _timeManager.ElapsedDays; if (!_debugLoggedTime && RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] CurrentTime={currentTime:D4}, SMS1={2300:D4}, SMS2={RaveConfig.SecondMessageTime:D4}, RaveStart={RaveConfig.RaveStartTime.Value:D4}, Day={elapsedDays}, RanToday={_raveRanToday}, NightPhase={_enteredNightPhase}"); _debugLoggedTime = true; } if (elapsedDays != _lastCheckedDay) { if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Neuer Tag erkannt: {_lastCheckedDay} -> {elapsedDays}"); } if (_raveActive) { StopRave(); _timeManager = null; } _lastCheckedDay = elapsedDays; _firstMsgSent = false; _secondMsgSent = false; _raveRanToday = false; _enteredNightPhase = false; _debugLoggedTime = false; _triggerRolled = false; _raveWillHappenTonight = false; _announcementSentThisSession = false; RaveLocationManager.ClearResolvedPresetName(); } if (_raveActive && currentTime >= 500) { if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Console-Zeitsprung erkannt: CurrentTime={currentTime:D4} (Tageszeit) bei aktivem Rave → StopRave"); } StopRave(); _raveRanToday = true; return; } int num = 2300; if (_raveRanToday && !_raveActive && currentTime >= 500 && currentTime < num) { _raveRanToday = false; _firstMsgSent = false; _secondMsgSent = false; _enteredNightPhase = false; _debugLoggedTime = false; _triggerRolled = false; _raveWillHappenTonight = false; _announcementSentThisSession = false; RaveLocationManager.ClearResolvedPresetName(); if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Tageszeit erkannt bei RanToday=True — Flags zurueckgesetzt (Console-Zeitaenderung?)"); } } if (!_enteredNightPhase) { if (currentTime >= num && num >= 500) { _enteredNightPhase = true; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Nachtphase aktiviert bei CurrentTime={currentTime:D4}"); } } else if (currentTime < 500) { _enteredNightPhase = true; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Nightphase active CurrentTime={currentTime:D4}"); } } } if (isSleepInProgress || (!_raveActive && TryResumePersistedRave(elapsedDays, currentTime)) || _raveRanToday || !_enteredNightPhase) { return; } if (!_triggerRolled) { _triggerRolled = true; if (RaveConfig.DJDanBooked || RaveConfig.DJGirlBooked || RaveConfig.DJCutChemistBooked || RaveConfig.DJLudapimpBooked) { _raveWillHappenTonight = true; } else if (RaveConfig.CustomRaveLocation.Value == 0) { _raveWillHappenTonight = !RaveConfig.PresetTriggerChanceEnabled.Value || _rng.NextDouble() < 0.30000001192092896; } else { _raveWillHappenTonight = true; } if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Trigger-Roll: WillHappen={_raveWillHappenTonight}, DJDanBooked={RaveConfig.DJDanBooked}, DJGirlBooked={RaveConfig.DJGirlBooked}, DJCutChemistBooked={RaveConfig.DJCutChemistBooked}, DJLudapimpBooked={RaveConfig.DJLudapimpBooked}, CustomRaveLocation={RaveConfig.CustomRaveLocation.Value}, PresetChanceEnabled={RaveConfig.PresetTriggerChanceEnabled.Value}"); } if (!_raveWillHappenTonight) { _raveRanToday = true; return; } } if (!_firstMsgSent && IsTimeReached(currentTime, num)) { if (!_announcementSentThisSession) { string text = RaveLocationManager.ResolveLocationName(); string locationDisplayName = GetLocationDisplayName(text); string value = (text.StartsWith("Custom") ? "It's at that spot you found. If you forgot where, check your gps!" : ("We're high and very lost at the " + locationDisplayName + ". Check your gps if you need directions! Some people need drugs..")); SendIgorMessage($"Yo! There's a fucking rave tonight! Project-X starts at {FormatTime(RaveConfig.RaveStartTime.Value)}, {value} Be there!"); _announcementSentThisSession = true; } _firstMsgSent = true; } int secondMessageTime = RaveConfig.SecondMessageTime; if (!_secondMsgSent && IsTimeReached(currentTime, secondMessageTime)) { string locName = RaveLocationManager.ResolveLocationName(); string locationDisplayName2 = GetLocationDisplayName(locName); SendIgorMessage("Yo the rave is sick! The tracks kickin..kurwa where are you haha come to the " + locationDisplayName2 + "!"); _secondMsgSent = true; } int value2 = RaveConfig.RaveStartTime.Value; if (!_raveActive && IsTimeReached(currentTime, value2)) { if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Rave-Trigger: CurrentTime={currentTime:D4} >= RaveStartTime={value2:D4}"); } StartRave(); } } catch (Exception ex) { RaveMod.Logger.Error("RaveEventManager.Update error: " + ex.Message); } } private static bool TryResumePersistedRave(int currentDay, int currentTime) { if (!RaveConfig.TryConsumeActiveRaveResumeState(currentDay, currentTime, out var presetName, out var hasBookedDjState, out var djDanBooked, out var djGirlBooked, out var djCutChemistBooked, out var djLudapimpBooked)) { return false; } if (hasBookedDjState) { RaveConfig.SetBookedDj(djDanBooked, djGirlBooked, djCutChemistBooked, djLudapimpBooked); } if (!string.IsNullOrWhiteSpace(presetName)) { RaveLocationManager.RestoreResolvedPresetName(presetName); } _lastCheckedDay = currentDay; _firstMsgSent = true; _secondMsgSent = true; _raveRanToday = false; _enteredNightPhase = true; _announcementSentThisSession = true; _djDanPitchSentThisSession = true; _triggerRolled = true; _raveWillHappenTonight = true; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Resuming active rave from saved state for day {currentDay} at {currentTime:D4}"); } StartRave(); return _raveActive; } private static bool IsTimeReached(int currentTime, int targetTime) { if (targetTime < 500) { return currentTime < 500 && currentTime >= targetTime; } return currentTime >= targetTime; } private static string FormatTime(int hhmm) { int value = hhmm / 100; int value2 = hhmm % 100; return $"{value:D2}:{value2:D2}"; } private static string GetLocationDisplayName(string locName) { if (!(locName == "Parkinglot")) { if (locName == "Littleforest") { return "little forest festival at the end of the casino street"; } return locName; } return "parking lot next to molley"; } private static void StartRave() { if (!_raveActive) { _raveActive = true; RaveMod.Logger.Msg("=== RAVE STARTING ==="); _startupTimings.Clear(); _startupTotalMs = 0L; _startupFrames = 0; _startupSteps = StartupSequence(); _raveStarting = true; } } private static void PumpStartup() { if (!_raveStarting) { return; } if (_startupSteps == null) { RaveMod.Logger.Warning("Startup pump without sequence — aborting rave startup."); _raveStarting = false; AbortStartup("no sequence"); return; } try { _startupFrames++; if (!_startupSteps.MoveNext()) { _raveStarting = false; _startupSteps = null; RaveMod.Logger.Msg($"[INIT] Aufbau {_startupTotalMs}ms ueber {_startupFrames} Frames: {string.Join(", ", _startupTimings)}"); RaveMod.Logger.Msg("=== RAVE ACTIVE ==="); } } catch (Exception value) { RaveMod.Logger.Error($"Error starting rave in step '{_startupCurrentStep}': {value}"); _raveStarting = false; _startupSteps = null; AbortStartup(_startupCurrentStep); } } private static void AbortStartup(string failedStep) { _raveRanToday = true; try { StopRave(); } catch (Exception ex) { RaveMod.Logger.Error("Cleanup after failed startup ('" + failedStep + "') threw: " + ex.Message); _raveActive = false; } } private static IEnumerator StartupSequence() { yield return Step("location", RaveLocationManager.Initialize); yield return Step("fog", RaveFogController.SpawnFog); yield return Step("speaker", RaveAudioController.SpawnSpeaker); yield return Step("music", RaveAudioController.StartMusic); yield return Step("npcs", RaveNPCController.GatherNPCs); yield return Step("compass", RaveCompassController.Show); bool useStage = RaveLocationManager.ShouldUseStage(); RaveMod.Logger.Msg($"[INIT] Location: {RaveLocationManager.CurrentLocationName} at ({RaveLocationManager.CenterPosition.x:F1},{RaveLocationManager.CenterPosition.y:F1},{RaveLocationManager.CenterPosition.z:F1}), StageToggle={RaveConfig.SmallFestivalStageEnabled.Value}, UseStage={useStage}"); yield return Step("djsetup", RaveDJBoothController.SpawnBooth); yield return Step("lamps", RaveLightController.SpawnLamps); } private static object Step(string name, Action action) { _startupCurrentStep = name; _startupWatch.Restart(); action(); _startupWatch.Stop(); long elapsedMilliseconds = _startupWatch.ElapsedMilliseconds; _startupTotalMs += elapsedMilliseconds; _startupTimings.Add($"{name}={elapsedMilliseconds}ms"); return null; } internal static void StopRave() { StopRave(clearBookedDjs: true, clearResumeState: true); } private static void StopRave(bool clearBookedDjs, bool clearResumeState) { if (_raveActive) { _raveStarting = false; _startupSteps = null; RaveMod.Logger.Msg("=== RAVE ENDED ==="); SafeCleanup("NPC", RaveNPCController.Cleanup); SafeCleanup("DJBooth", RaveDJBoothController.Cleanup); SafeCleanup("Compass", RaveCompassController.Cleanup); SafeCleanup("LetsGo", LetsGoObjectController.Cleanup); SafeCleanup("Audio", RaveAudioController.Cleanup); SafeCleanup("Light", RaveLightController.Cleanup); SafeCleanup("Fog", RaveFogController.Cleanup); SafeCleanup("Location", RaveLocationManager.Cleanup); string sweptNames; int num = SweepStaleRaveObjects(out sweptNames); if (num > 0) { RaveMod.Logger.Warning($"Safety sweep: {num} orphaned rave objects destroyed after cleanup: {sweptNames}"); } _raveActive = false; if (clearResumeState) { RaveConfig.ClearActiveRaveResumeState(); } if (clearBookedDjs) { RaveConfig.ClearBookedDjs(); } } } private static void PersistActiveRaveResumeState() { int num = _lastCheckedDay; try { if ((Object)(object)_timeManager == (Object)null) { _timeManager = Object.FindObjectOfType(); } if ((Object)(object)_timeManager != (Object)null) { num = _timeManager.ElapsedDays; } } catch (Exception ex) { RaveMod.Logger.Warning("PersistActiveRaveResumeState time lookup failed: " + ex.Message); } if (num < 0) { RaveConfig.ClearActiveRaveResumeState(); return; } string presetName = ((RaveConfig.CustomRaveLocation.Value == 0) ? RaveLocationManager.GetResolvedPresetName() : null); RaveConfig.SetActiveRaveResumeState(isActive: true, num, presetName, RaveConfig.DJDanBooked, RaveConfig.DJGirlBooked, RaveConfig.DJCutChemistBooked, RaveConfig.DJLudapimpBooked); } private static int SweepStaleRaveObjects(out string sweptNames) { int num = 0; List list = new List(4); sweptNames = string.Empty; try { GameObject[] array = Il2CppArrayBase.op_Implicit(Object.FindObjectsOfType()); if (array == null) { return 0; } foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && ((Object)val).name != null && (((Object)val).name.StartsWith("RaveLamp_") || ((Object)val).name.StartsWith("RaveSpeaker") || ((Object)val).name.StartsWith("RaveFog_") || ((Object)val).name == "RaveStrobeLight" || ((Object)val).name == "RaveCompassAnchor" || ((Object)val).name == "RaveCompassContent" || ((Object)val).name == "RaveDJBooth" || ((Object)val).name == "RaveDJDan" || ((Object)val).name == "RaveDJGirl" || ((Object)val).name == "RaveDJCutChemist" || ((Object)val).name == "RaveDJLudapimp" || ((Object)val).name == "SmallFestivalStage" || ((Object)val).name == "LetsGoObject")) { if (list.Count < 20) { list.Add(((Object)val).name); } Object.DestroyImmediate((Object)(object)val); num++; } } } catch (Exception ex) { RaveMod.Logger.Warning("SweepStaleRaveObjects error: " + ex.Message); } sweptNames = string.Join(", ", list); return num; } private static void SafeCleanup(string name, Action cleanup) { try { cleanup(); } catch (Exception ex) { RaveMod.Logger.Warning(name + " cleanup error: " + ex.Message); } } private static void SendIgorMessage(string messageText) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(messageText)) { return; } try { NPC nPC = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC == (Object)null) { RaveMod.Logger.Warning("Igor not found — no rave message sent."); return; } MSGConversation mSGConversation = nPC.MSGConversation; if (mSGConversation == null) { RaveMod.Logger.Warning("Conversation with Igor not found."); return; } Message val = new Message(messageText, (ESenderType)1, false, -1); mSGConversation.SendMessage(val, true, false); } catch (Exception ex) { RaveMod.Logger.Error("Error sending rave message: " + ex.Message); } } private static void TryRegisterSendableButtons() { try { NPC nPC = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC == (Object)null) { return; } if (nPC.MSGConversation == null) { try { NPCRelationData relationData = nPC.RelationData; if (relationData != null && !relationData.Unlocked) { relationData.Unlock((EUnlockType)0, false); if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Igor silently unlocked for rave SMS system"); } } return; } catch (Exception ex) { RaveMod.Logger.Warning("Failed to unlock Igor: " + ex.Message); return; } } MSGConversation mSGConversation = nPC.MSGConversation; if ((Object)(object)mSGConversation.senderInterface == (Object)null) { return; } List sendables = mSGConversation.Sendables; if (sendables == null) { return; } bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; bool flag5 = false; bool flag6 = false; for (int i = 0; i < sendables.Count; i++) { SendableMessage val = sendables[i]; if (val != null && val.Text != null) { if (val.Text == "Save Rave Location") { flag = true; } if (val.Text == "Remove Rave Location") { flag2 = true; } if (val.Text == "Book Jake Cole") { flag3 = true; } if (val.Text == "Book Zara Landry") { flag4 = true; } if (val.Text == "Book Cutter C.") { flag5 = true; } if (val.Text == "Book DJ Big Pimpin") { flag6 = true; } } } if (flag && flag2 && flag3 && flag4 && flag5 && flag6) { _buttonsRegistered = true; return; } if (!flag) { _saveLocationAction = delegate { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) try { NPC nPC2 = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC2 == (Object)null || nPC2.MSGConversation == null) { RaveMod.Logger.Warning("Save location: Igor conversation not available."); } else { MSGConversation mSGConversation2 = nPC2.MSGConversation; GameObject val8 = GameObject.Find("Player_Local"); if (!((Object)(object)val8 == (Object)null)) { Vector3 position = val8.transform.position; if (RaveLocationManager.IsNearPresetLocation(position, 15f)) { SendIgorResponse(mSGConversation2, "Yo, that's already one of our regular spots! No need to save it bro."); } else if (RaveLocationManager.GetNearbyCustomLocation(position, 10f).HasValue) { SendIgorResponse(mSGConversation2, "Yo man, are you kidding?! You already told me about this spot! I got it saved, chill."); } else { string text = (RaveLocationManager.AddCustomLocation(position) ? $"Nice find! I'll tell my people about this spot! ({position.x:F1}, {position.y:F1}, {position.z:F1})" : "I\u00b4m dope af, are you sure about the coordinates?! Try again later."); SendIgorResponse(mSGConversation2, text); } } } } catch (Exception ex4) { RaveMod.Logger.Error("Save location callback error: " + ex4.Message); } }; SendableMessage val2 = TryCreateSendableMessage(mSGConversation, "Save Rave Location", "Save location"); if (val2 == null) { return; } _il2cppSaveAction = Action.op_Implicit(_saveLocationAction); val2.onSent = _il2cppSaveAction; } if (!flag2) { _removeLocationAction = delegate { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_00a4: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) try { NPC nPC2 = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC2 == (Object)null || nPC2.MSGConversation == null) { RaveMod.Logger.Warning("Remove location: Igor conversation not available."); } else { MSGConversation mSGConversation2 = nPC2.MSGConversation; GameObject val8 = GameObject.Find("Player_Local"); if (!((Object)(object)val8 == (Object)null)) { Vector3 position = val8.transform.position; Vector3? nearbyCustomLocation = RaveLocationManager.GetNearbyCustomLocation(position, 10f); if (!nearbyCustomLocation.HasValue) { SendIgorResponse(mSGConversation2, "You're not near any rave location. Go to the spot you want to remove and try again."); } else { Vector3 value = nearbyCustomLocation.Value; string text = (RaveLocationManager.RemoveCustomLocation(value) ? $"Alright, location removed. ({value.x:F1}, {value.y:F1}, {value.z:F1}) is off the list." : "Something went wrong, try again later."); SendIgorResponse(mSGConversation2, text); } } } } catch (Exception ex4) { RaveMod.Logger.Error("Remove location callback error: " + ex4.Message); } }; SendableMessage val3 = TryCreateSendableMessage(mSGConversation, "Remove Rave Location", "Remove location"); if (val3 == null) { return; } _il2cppRemoveAction = Action.op_Implicit(_removeLocationAction); val3.onSent = _il2cppRemoveAction; } if (!flag3) { _djDanAction = delegate { try { NPC nPC2 = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC2 == (Object)null || nPC2.MSGConversation == null) { RaveMod.Logger.Warning("Book Jake Cole: Igor conversation not available."); } else { MSGConversation mSGConversation2 = nPC2.MSGConversation; if (RaveConfig.DJDanBooked) { SendIgorResponse(mSGConversation2, "Jake Cole is locked in! He'll be there tonight."); } else { RaveConfig.SetBookedDj(djDanBooked: true, djGirlBooked: false); ApplyBookedDjGuarantee(); SendIgorResponse(mSGConversation2, "Done! Jake Cole is booked. He'll be dropping beats at the next rave!"); } } } catch (Exception ex4) { RaveMod.Logger.Error("Book Jake Cole callback error: " + ex4.Message); } }; SendableMessage val4 = TryCreateSendableMessage(mSGConversation, "Book Jake Cole", "Book Jake Cole"); if (val4 == null) { return; } _il2cppDjDanAction = Action.op_Implicit(_djDanAction); val4.onSent = _il2cppDjDanAction; } if (!flag4) { _djGirlAction = delegate { try { NPC nPC2 = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC2 == (Object)null || nPC2.MSGConversation == null) { RaveMod.Logger.Warning("Book Zara Landry: Igor conversation not available."); } else { MSGConversation mSGConversation2 = nPC2.MSGConversation; if (RaveConfig.DJGirlBooked) { SendIgorResponse(mSGConversation2, "Zara Landry is already locked in! She'll be there tonight."); } else { RaveConfig.SetBookedDj(djDanBooked: false, djGirlBooked: true); ApplyBookedDjGuarantee(); SendIgorResponse(mSGConversation2, "Done! Zara Landry is booked. She'll be spinning fire at the next rave!"); } } } catch (Exception ex4) { RaveMod.Logger.Error("Book Zara Landry callback error: " + ex4.Message); } }; SendableMessage val5 = TryCreateSendableMessage(mSGConversation, "Book Zara Landry", "Book Zara Landry"); if (val5 == null) { return; } _il2cppDjGirlAction = Action.op_Implicit(_djGirlAction); val5.onSent = _il2cppDjGirlAction; } if (!flag5) { _djCutChemistAction = delegate { try { NPC nPC2 = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC2 == (Object)null || nPC2.MSGConversation == null) { RaveMod.Logger.Warning("Book Cutter C.: Igor conversation not available."); } else { MSGConversation mSGConversation2 = nPC2.MSGConversation; if (RaveConfig.DJCutChemistBooked) { SendIgorResponse(mSGConversation2, "Cutter C. is already locked in! He'll be there tonight."); } else { RaveConfig.SetBookedDj(djDanBooked: false, djGirlBooked: false, djCutChemistBooked: true); ApplyBookedDjGuarantee(); SendIgorResponse(mSGConversation2, "Done! Cutter C. is booked. He'll be cutting it up at the next rave!"); } } } catch (Exception ex4) { RaveMod.Logger.Error("Book Cutter C. callback error: " + ex4.Message); } }; SendableMessage val6 = TryCreateSendableMessage(mSGConversation, "Book Cutter C.", "Book Cutter C."); if (val6 == null) { return; } _il2cppDjCutChemistAction = Action.op_Implicit(_djCutChemistAction); val6.onSent = _il2cppDjCutChemistAction; } if (!flag6) { _djLudapimpAction = delegate { try { NPC nPC2 = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC2 == (Object)null || nPC2.MSGConversation == null) { RaveMod.Logger.Warning("Book DJ Big Pimpin: Igor conversation not available."); } else { MSGConversation mSGConversation2 = nPC2.MSGConversation; if (RaveConfig.DJLudapimpBooked) { SendIgorResponse(mSGConversation2, "DJ Big Pimpin is already locked in! He'll be there tonight."); } else { RaveConfig.SetBookedDj(djDanBooked: false, djGirlBooked: false, djCutChemistBooked: false, djLudapimpBooked: true); ApplyBookedDjGuarantee(); SendIgorResponse(mSGConversation2, "Done! DJ Big Pimpin is booked. He'll be bringing the heat at the next rave!"); } } } catch (Exception ex4) { RaveMod.Logger.Error("Book DJ Big Pimpin callback error: " + ex4.Message); } }; SendableMessage val7 = TryCreateSendableMessage(mSGConversation, "Book DJ Big Pimpin", "Book DJ Big Pimpin"); if (val7 == null) { return; } _il2cppDjLudapimpAction = Action.op_Implicit(_djLudapimpAction); val7.onSent = _il2cppDjLudapimpAction; } _buttonsRegistered = true; try { nPC.NPCData.Messaging.ConversationCanBeHidden = false; } catch (Exception ex2) { RaveMod.Logger.Warning("ConversationCanBeHidden on Igor failed: " + ex2.Message); } PatchConversationEntry(mSGConversation); } catch (Exception ex3) { RaveMod.Logger.Error("Error registering rave buttons: " + ex3.Message); } } private static void ApplyBookedDjGuarantee() { try { if (_raveActive || (!RaveConfig.DJDanBooked && !RaveConfig.DJGirlBooked && !RaveConfig.DJCutChemistBooked && !RaveConfig.DJLudapimpBooked)) { return; } if ((Object)(object)_timeManager == (Object)null) { _timeManager = Object.FindObjectOfType(); } int num = (((Object)(object)_timeManager != (Object)null) ? _timeManager.CurrentTime : (-1)); bool flag = num >= 2300 || (num >= 0 && num < 500); bool flag2 = num < 0 || num >= 2300 || num < RaveConfig.RaveStartTime.Value; if (flag && flag2) { _enteredNightPhase = true; _raveRanToday = false; _triggerRolled = true; _raveWillHappenTonight = true; if (RaveConfig.BundleDebugLogging != null && RaveConfig.BundleDebugLogging.Value) { RaveMod.Logger.Msg($"[RaveRuntimeState] Booked DJ guarantee applied for current night: time={num:D4}, DJDanBooked={RaveConfig.DJDanBooked}, DJGirlBooked={RaveConfig.DJGirlBooked}, DJCutChemistBooked={RaveConfig.DJCutChemistBooked}, DJLudapimpBooked={RaveConfig.DJLudapimpBooked}"); } } else if (RaveConfig.BundleDebugLogging != null && RaveConfig.BundleDebugLogging.Value) { RaveMod.Logger.Msg($"[RaveRuntimeState] DJ booked for upcoming night: time={num:D4}, currentNightWindow={flag}, raveStartStillAhead={flag2}"); } } catch (Exception ex) { RaveMod.Logger.Warning("ApplyBookedDjGuarantee error: " + ex.Message); } } private static void SendIgorResponse(MSGConversation conversation, string text) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (conversation == null || string.IsNullOrWhiteSpace(text)) { return; } try { Message val = new Message(text, (ESenderType)1, false, -1); conversation.SendMessage(val, true, false); } catch (Exception ex) { RaveMod.Logger.Error("Error sending Igor response: " + ex.Message); } } private static SendableMessage TryCreateSendableMessage(MSGConversation conversation, string text, string context) { if (conversation == null || (Object)(object)conversation.senderInterface == (Object)null || string.IsNullOrWhiteSpace(text)) { return null; } try { return conversation.CreateSendableMessage(text); } catch (InvalidOperationException ex) { RaveMod.Logger.Warning(context + ": could not create sendable message: " + ex.Message); } catch (ArgumentException ex2) { RaveMod.Logger.Warning(context + ": could not create sendable message: " + ex2.Message); } catch (NullReferenceException ex3) { RaveMod.Logger.Warning(context + ": could not create sendable message: " + ex3.Message); } return null; } private static void PatchConversationEntry(MSGConversation conversation) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) try { List val = new List(); val.Add((EConversationCategory)1); conversation.SetCategories(val); } catch (Exception ex) { RaveMod.Logger.Warning("SetCategories on Igor failed: " + ex.Message); } try { RectTransform entry = conversation.entry; if ((Object)(object)entry == (Object)null) { return; } Il2CppArrayBase componentsInChildren = ((Component)entry).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Count; i++) { Text val2 = componentsInChildren[i]; if ((Object)(object)val2 == (Object)null) { continue; } string text = ((val2.text != null) ? val2.text.Trim() : ""); if (text == "C" || text == "S" || text == "D") { val2.text = "S"; Image val3 = (((Object)(object)((Component)val2).transform.parent != (Object)null) ? ((Component)((Component)val2).transform.parent).GetComponent() : null); if ((Object)(object)val3 != (Object)null) { ((Graphic)val3).color = new Color(0.18f, 0.65f, 0.65f); } break; } } if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Igor conversation entry patched"); } } catch (Exception ex2) { RaveMod.Logger.Warning("Failed to patch Igor entry UI: " + ex2.Message); } } private static void LogPlayerPosition() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = GameObject.Find("Player_Local"); if (!((Object)(object)val == (Object)null)) { Vector3 position = val.transform.position; RaveMod.Logger.Msg($"[COORDS] Player position: {position.x:F2},{position.y:F2},{position.z:F2}"); } } catch { } } internal static void Reset(bool preserveActiveRaveState = false) { if (_raveActive) { if (preserveActiveRaveState) { PersistActiveRaveResumeState(); } StopRave(!preserveActiveRaveState, !preserveActiveRaveState); } else if (!preserveActiveRaveState) { RaveConfig.ClearActiveRaveResumeState(); } RaveDJBoothController.FullCleanup(); RaveFogController.ForceCleanup(); RaveCompassController.Cleanup(); _raveActive = false; _raveStarting = false; _startupSteps = null; _firstMsgSent = false; _secondMsgSent = false; _raveRanToday = false; _enteredNightPhase = false; _announcementSentThisSession = false; _triggerRolled = false; _raveWillHappenTonight = false; _lastCheckedDay = -1; _timeManager = null; _checkTimer = 0f; _sleepCheckTimer = 0f; _debugCoordTimer = 0f; _debugLoggedTime = false; _buttonsRegistered = false; _buttonCheckTimer = 0f; _saveLocationAction = null; _removeLocationAction = null; _djDanAction = null; _djGirlAction = null; _djCutChemistAction = null; _djLudapimpAction = null; _il2cppSaveAction = null; _il2cppRemoveAction = null; _il2cppDjDanAction = null; _il2cppDjGirlAction = null; _il2cppDjCutChemistAction = null; _il2cppDjLudapimpAction = null; } } public sealed class RaveFogController { private static List _fogObjects = new List(); private static List _fogRenderers = new List(); private static List _fogMaterials = new List(); private static bool _fogActive = false; private static float _pulseTimer = 0f; private static Transform _cameraTransform; private static int _updateFrameCounter = 0; private static bool _poolInitialized = false; private static List _fogAngles = new List(); private static List _fogDistances = new List(); private static List _fogOrbitSpeeds = new List(); private static List _fogHeights = new List(); private static List _fogZRotSpeeds = new List(); private const float ORBIT_SPEED_MIN = 0.01f; private const float ORBIT_SPEED_MAX = 0.04f; private const float ZROT_SPEED_MIN = 0.5f; private const float ZROT_SPEED_MAX = 2f; internal static float FogRadius = 8f; internal static float FogHeightMin = 0.2f; internal static float FogHeightMax = 0.85f; internal static float FogSizeMin = 2f; internal static float FogSizeMax = 5f; internal static float FogAlpha = 0.128f; internal static int FogCount = 94; private static Random _rng = new Random(); private static Mesh _circleMesh; private const int CIRCLE_SEGMENTS = 16; private static Texture2D _gradientTexture; private const int GRADIENT_SIZE = 64; private RaveFogController() { } internal static void SpawnFog() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) try { if (!_poolInitialized) { CleanupFogObjects(); _poolInitialized = true; } if ((Object)(object)_circleMesh == (Object)null) { _circleMesh = CreateCircleMesh(); } if ((Object)(object)_gradientTexture == (Object)null) { _gradientTexture = CreateGradientTexture(); } Vector3 centerPosition = RaveLocationManager.CenterPosition; float fogGroundY = GetFogGroundY(centerPosition); int fogCount = FogCount; int count = _fogObjects.Count; for (int i = 0; i < fogCount && i < count; i++) { if (!((Object)(object)_fogObjects[i] == (Object)null)) { float num = (float)(_rng.NextDouble() * 2.0 * 3.1415927410125732); float num2 = FogRadius * Mathf.Sqrt((float)_rng.NextDouble()) * 0.85f; float num3 = FogHeightMin + (float)(_rng.NextDouble() * (double)(FogHeightMax - FogHeightMin)); float num4 = FogSizeMin + (float)(_rng.NextDouble() * (double)(FogSizeMax - FogSizeMin)); _fogObjects[i].transform.position = new Vector3(centerPosition.x + Mathf.Cos(num) * num2, fogGroundY + num3, centerPosition.z + Mathf.Sin(num) * num2); _fogObjects[i].transform.localScale = new Vector3(num4, num4, num4); _fogObjects[i].SetActive(true); if (i < _fogAngles.Count) { _fogAngles[i] = num; _fogDistances[i] = num2; _fogHeights[i] = num3; } if (i < _fogMaterials.Count && (Object)(object)_fogMaterials[i] != (Object)null) { Color color = _fogMaterials[i].color; color.a = FogAlpha; _fogMaterials[i].color = color; } } } Vector3 position = default(Vector3); for (int j = count; j < fogCount; j++) { float num5 = (float)(_rng.NextDouble() * 2.0 * 3.1415927410125732); float num6 = FogRadius * Mathf.Sqrt((float)_rng.NextDouble()) * 0.85f; float num7 = FogHeightMin + (float)(_rng.NextDouble() * (double)(FogHeightMax - FogHeightMin)); ((Vector3)(ref position))..ctor(centerPosition.x + Mathf.Cos(num5) * num6, fogGroundY + num7, centerPosition.z + Mathf.Sin(num5) * num6); float size = FogSizeMin + (float)(_rng.NextDouble() * (double)(FogSizeMax - FogSizeMin)); float zRotation = (float)(_rng.NextDouble() * 360.0); GameObject val = CreateFogCloud(position, j, size, zRotation); if ((Object)(object)val != (Object)null) { _fogObjects.Add(val); _fogAngles.Add(num5); _fogDistances.Add(num6); _fogOrbitSpeeds.Add(0.01f + (float)(_rng.NextDouble() * 0.029999999329447746)); _fogHeights.Add(num7); _fogZRotSpeeds.Add(0.5f + (float)(_rng.NextDouble() * 1.5)); } } for (int k = fogCount; k < count; k++) { if ((Object)(object)_fogObjects[k] != (Object)null) { _fogObjects[k].SetActive(false); } } _fogActive = true; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"Fog: {_fogObjects.Count} clouds active."); } } catch (Exception ex) { RaveMod.Logger.Error("Error spawning fog: " + ex.Message); } } private static GameObject CreateFogCloud(Vector3 position, int index, float size, float zRotation) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0034: 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_00a7: 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_00ae: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject($"RaveFog_{index}"); val.transform.position = position; val.transform.localScale = new Vector3(size, size, size); MeshFilter val2 = val.AddComponent(); val2.sharedMesh = _circleMesh; MeshRenderer val3 = val.AddComponent(); Shader val4 = Shader.Find("Sprites/Default"); if ((Object)(object)val4 == (Object)null) { val4 = Shader.Find("Unlit/Transparent"); } Material val5 = (((Object)(object)val4 != (Object)null) ? new Material(val4) : new Material(Shader.Find("Standard"))); val5.renderQueue = 3000; val5.color = new Color(0.85f, 0.85f, 0.95f, FogAlpha); if ((Object)(object)_gradientTexture != (Object)null) { val5.mainTexture = (Texture)(object)_gradientTexture; } ((Renderer)val3).sharedMaterial = val5; ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val3).receiveShadows = false; _fogRenderers.Add((Renderer)(object)val3); _fogMaterials.Add(val5); return val; } catch (Exception ex) { RaveMod.Logger.Warning("CreateFogCloud error: " + ex.Message); return null; } } private static Mesh CreateCircleMesh() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0077: 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_00c1: 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) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) Mesh val = new Mesh(); ((Object)val).name = "FogCircle"; int num = 17; Vector3[] array = (Vector3[])(object)new Vector3[num]; Vector2[] array2 = (Vector2[])(object)new Vector2[num]; Color[] array3 = (Color[])(object)new Color[num]; int num2 = 48; int[] array4 = new int[num2]; array[0] = Vector3.zero; array2[0] = new Vector2(0.5f, 0.5f); array3[0] = new Color(1f, 1f, 1f, 1f); for (int i = 0; i < 16; i++) { float num3 = (float)Math.PI / 8f * (float)i; float num4 = Mathf.Cos(num3) * 0.5f; float num5 = Mathf.Sin(num3) * 0.5f; array[i + 1] = new Vector3(num4, num5, 0f); array2[i + 1] = new Vector2(0.5f + num4, 0.5f + num5); array3[i + 1] = new Color(1f, 1f, 1f, 0f); } for (int j = 0; j < 16; j++) { int num6 = j * 3; array4[num6] = 0; array4[num6 + 1] = j + 1; array4[num6 + 2] = (j + 1) % 16 + 1; } val.vertices = Il2CppStructArray.op_Implicit(array); val.uv = Il2CppStructArray.op_Implicit(array2); val.colors = Il2CppStructArray.op_Implicit(array3); val.triangles = Il2CppStructArray.op_Implicit(array4); val.RecalculateNormals(); val.RecalculateBounds(); return val; } private static Texture2D CreateGradientTexture() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) try { Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; float num = 32f; float num2 = num; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num3 = (float)j - num; float num4 = (float)i - num; float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4) / num2; float num6 = Mathf.Clamp01(1f - num5 * num5); val.SetPixel(j, i, new Color(1f, 1f, 1f, num6)); } } val.Apply(); return val; } catch (Exception ex) { RaveMod.Logger.Warning("CreateGradientTexture error: " + ex.Message); return null; } } internal static void ForceCleanup() { if (_fogActive || _fogObjects.Count > 0) { DestroyPool(); } } internal static void UpdateFog() { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) if (!_fogActive || Time.timeScale == 0f) { return; } try { if ((Object)(object)_cameraTransform == (Object)null) { Camera main = Camera.main; if ((Object)(object)main != (Object)null) { _cameraTransform = ((Component)main).transform; } } _pulseTimer += Time.deltaTime * 0.3f; _updateFrameCounter++; bool flag = _updateFrameCounter % 3 == 0; int num = Mathf.Min(FogCount, _fogObjects.Count); float deltaTime = Time.deltaTime; Vector3 centerPosition = RaveLocationManager.CenterPosition; float y = centerPosition.y; for (int i = 0; i < num; i++) { try { GameObject val = _fogObjects[i]; if (!((Object)(object)val == (Object)null) && val.activeSelf) { if (i < _fogAngles.Count) { _fogAngles[i] += _fogOrbitSpeeds[i] * deltaTime; float num2 = centerPosition.x + Mathf.Cos(_fogAngles[i]) * _fogDistances[i]; float num3 = centerPosition.z + Mathf.Sin(_fogAngles[i]) * _fogDistances[i]; val.transform.position = new Vector3(num2, y + _fogHeights[i], num3); } if ((Object)(object)_cameraTransform != (Object)null) { val.transform.LookAt(_cameraTransform); } if (i < _fogZRotSpeeds.Count) { val.transform.Rotate(0f, 0f, _fogZRotSpeeds[i] * deltaTime, (Space)1); } if (flag && i < _fogMaterials.Count && (Object)(object)_fogMaterials[i] != (Object)null) { float num4 = 0.8f + Mathf.Sin(_pulseTimer + (float)i * 0.3f) * 0.2f; Color color = _fogMaterials[i].color; color.a = FogAlpha * num4; _fogMaterials[i].color = color; } } } catch { } } } catch { } } internal static void Cleanup() { for (int i = 0; i < _fogObjects.Count; i++) { try { if ((Object)(object)_fogObjects[i] != (Object)null) { _fogObjects[i].SetActive(false); } } catch { } } _fogActive = false; _pulseTimer = 0f; _cameraTransform = null; _updateFrameCounter = 0; } private static void DestroyPool() { for (int num = _fogObjects.Count - 1; num >= 0; num--) { try { if ((Object)(object)_fogObjects[num] != (Object)null) { Object.DestroyImmediate((Object)(object)_fogObjects[num]); } } catch { } } _fogObjects.Clear(); _fogRenderers.Clear(); _fogMaterials.Clear(); _fogAngles.Clear(); _fogDistances.Clear(); _fogOrbitSpeeds.Clear(); _fogHeights.Clear(); _fogZRotSpeeds.Clear(); _fogActive = false; _pulseTimer = 0f; _cameraTransform = null; _updateFrameCounter = 0; _poolInitialized = false; } private static void CleanupFogObjects() { try { GameObject[] array = Il2CppArrayBase.op_Implicit(Object.FindObjectsOfType()); if (array == null) { return; } foreach (GameObject val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name != null && ((Object)val).name.StartsWith("RaveFog_")) { Object.DestroyImmediate((Object)(object)val); } } } catch (Exception ex) { RaveMod.Logger.Warning("CleanupFogObjects error: " + ex.Message); } } private static float GetFogGroundY(Vector3 center) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0021: 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_0164: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) try { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(center.x, center.y + 2f, center.z); RaycastHit[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)Physics.RaycastAll(val, Vector3.down, 15f)); if (array != null && array.Length != 0) { float y = center.y; for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; if ((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null || (Object)(object)((Component)((RaycastHit)(ref val2)).collider).gameObject == (Object)null) { continue; } string name = ((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name; if (name == null || (!name.StartsWith("RaveFog_") && !name.StartsWith("RaveLamp_") && !name.StartsWith("RaveSpeaker"))) { NPC componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent(); if (!((Object)(object)componentInParent != (Object)null) && ((RaycastHit)(ref val2)).point.y <= center.y + 1f && ((RaycastHit)(ref val2)).point.y < y) { y = ((RaycastHit)(ref val2)).point.y; } } } return y; } } catch { } return center.y; } } public sealed class RaveLightController { private static readonly Color[] RAVE_COLORS = (Color[])(object)new Color[8] { Color.magenta, Color.cyan, Color.yellow, Color.green, new Color(1f, 0.4f, 0f), new Color(0.5f, 0f, 1f), Color.red, Color.blue }; private static List _lampObjects = new List(); private static List _lights = new List(); private static List _headRenderers = new List(); private static float _colorTimer = 0f; private static int _currentColorIndex = 0; private static GameObject _strobeObject; private static Light _strobeLight; private static float _strobeTimer = 0f; private static bool _strobeActive = false; private RaveLightController() { } internal static void SpawnLamps() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) DestroyStaleObjects(); Vector3[] lampPositions = RaveLocationManager.LampPositions; if (lampPositions == null) { return; } for (int i = 0; i < lampPositions.Length; i++) { GameObject val = CreateLamp(lampPositions[i], i); if ((Object)(object)val != (Object)null) { _lampObjects.Add(val); } } SpawnCentralStrobe(); if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"Lamps: {_lampObjects.Count} spawned, strobe={(((Object)(object)_strobeObject != (Object)null) ? "OK" : "FAIL")}"); } } private static void SpawnCentralStrobe() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0017: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) try { Vector3 centerPosition = RaveLocationManager.CenterPosition; _strobeObject = new GameObject("RaveStrobeLight"); _strobeObject.transform.position = new Vector3(centerPosition.x, centerPosition.y + RaveLocationManager.StrobeHeightOffset, centerPosition.z); _strobeLight = _strobeObject.AddComponent(); _strobeLight.color = Color.white; _strobeLight.intensity = 0f; if (RaveLocationManager.IsUnderground) { _strobeLight.type = (LightType)0; _strobeLight.spotAngle = 140f; _strobeLight.range = RaveConfig.LightRange.Value * 1.5f; _strobeObject.transform.rotation = Quaternion.Euler(90f, 0f, 0f); } else { _strobeLight.type = (LightType)2; _strobeLight.range = RaveConfig.LightRange.Value * 3f; } } catch (Exception ex) { RaveMod.Logger.Error("Error creating strobe light: " + ex.Message); } } private static bool HasCustomColor() { return RaveConfig.LampColorR.Value != 0 || RaveConfig.LampColorG.Value != 0 || RaveConfig.LampColorB.Value != 0; } private static Color GetConfigColor() { //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_003c: Unknown result type (might be due to invalid IL or missing references) return new Color((float)RaveConfig.LampColorR.Value / 255f, (float)RaveConfig.LampColorG.Value / 255f, (float)RaveConfig.LampColorB.Value / 255f); } private static GameObject CreateLamp(Vector3 position, int index) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0035: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: 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_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject($"RaveLamp_{index}"); val.transform.position = position; GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)2); val2.transform.SetParent(val.transform); val2.transform.localPosition = new Vector3(0f, 1.5f, 0f); val2.transform.localScale = new Vector3(0.1f, 1.5f, 0.1f); Renderer component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { component.material.color = new Color(0.15f, 0.15f, 0.15f); } GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)0); val3.transform.SetParent(val.transform); val3.transform.localPosition = new Vector3(0f, 3.2f, 0f); val3.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f); Collider component2 = val2.GetComponent(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } Collider component3 = val3.GetComponent(); if ((Object)(object)component3 != (Object)null) { Object.Destroy((Object)(object)component3); } GameObject val4 = new GameObject("LightHolder"); val4.transform.SetParent(val.transform); val4.transform.localPosition = new Vector3(0f, 3.5f, 0f); Light val5 = val4.AddComponent(); val5.intensity = RaveConfig.LightIntensity.Value; val5.range = RaveConfig.LightRange.Value; if (RaveLocationManager.IsUnderground) { val5.type = (LightType)0; val5.spotAngle = 120f; Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(position.x, position.y + 3.5f, position.z); Vector3 val7 = RaveLocationManager.CenterPosition - val6; if (((Vector3)(ref val7)).sqrMagnitude > 0.01f) { val4.transform.rotation = Quaternion.LookRotation(val7); } else { val4.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); } } else if (RaveLocationManager.IsStageActive) { val5.type = (LightType)0; val5.spotAngle = 80f; val5.range = RaveConfig.LightRange.Value * 2.5f; Vector3 spawnPosition = LetsGoObjectController.GetSpawnPosition(); Vector3 stageAudienceForward = RaveLocationManager.GetStageAudienceForward(); Vector3 val8 = spawnPosition + stageAudienceForward * 6f + new Vector3(0f, -2f, 0f); Vector3 val9 = default(Vector3); ((Vector3)(ref val9))..ctor(position.x, position.y + 3.5f, position.z); Vector3 val10 = val8 - val9; if (((Vector3)(ref val10)).sqrMagnitude > 0.01f) { val4.transform.rotation = Quaternion.LookRotation(val10); } else { val4.transform.localRotation = Quaternion.Euler(45f, 0f, 0f); } } else { val5.type = (LightType)2; } Color val11; if (HasCustomColor()) { val11 = GetConfigColor(); } else { int num = index % RAVE_COLORS.Length; val11 = RAVE_COLORS[num]; } val5.color = val11; Renderer component4 = val3.GetComponent(); if ((Object)(object)component4 != (Object)null) { component4.material.color = val11; component4.material.SetColor("_EmissionColor", val11 * 2f); component4.material.EnableKeyword("_EMISSION"); _headRenderers.Add(component4); } else { _headRenderers.Add(null); } _lights.Add(val5); return val; } catch (Exception ex) { RaveMod.Logger.Error($"Error creating lamp {index}: {ex.Message}"); return null; } } internal static void UpdateLights() { //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) if (_lights.Count == 0) { return; } float deltaTime = Time.deltaTime; bool flag = false; if (RaveConfig.StrobeEnabled.Value) { _strobeTimer += deltaTime; float value = RaveConfig.StrobeInterval.Value; float value2 = RaveConfig.StrobeDuration.Value; if (_strobeActive) { if (_strobeTimer >= value2) { _strobeActive = false; _strobeTimer = 0f; } flag = true; } else if (_strobeTimer >= value) { _strobeActive = true; _strobeTimer = 0f; flag = true; } } bool flag2 = HasCustomColor(); bool value3 = RaveConfig.LampRotation.Value; if (value3) { _colorTimer += deltaTime * RaveConfig.StrobeSpeed.Value; if (_colorTimer >= 1f) { _colorTimer = 0f; _currentColorIndex = (_currentColorIndex + 1) % RAVE_COLORS.Length; } } for (int i = 0; i < _lights.Count; i++) { if (!((Object)(object)_lights[i] == (Object)null)) { Color val; if (!value3 && flag2) { val = GetConfigColor(); } else if (value3) { int num = (_currentColorIndex + i) % RAVE_COLORS.Length; int num2 = (num + 1) % RAVE_COLORS.Length; val = Color.Lerp(RAVE_COLORS[num], RAVE_COLORS[num2], _colorTimer); } else { int num3 = i % RAVE_COLORS.Length; val = RAVE_COLORS[num3]; } _lights[i].color = val; _lights[i].intensity = RaveConfig.LightIntensity.Value; if (i < _headRenderers.Count && (Object)(object)_headRenderers[i] != (Object)null) { _headRenderers[i].material.color = val; _headRenderers[i].material.SetColor("_EmissionColor", val * 2f); } } } if ((Object)(object)_strobeLight != (Object)null) { _strobeLight.intensity = (flag ? (RaveConfig.LightIntensity.Value * 5f) : 0f); } } internal static void RelocateToPositions(Vector3[] newLampPositions, Vector3 newCenter) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) try { for (int i = 0; i < _lampObjects.Count; i++) { if (!((Object)(object)_lampObjects[i] == (Object)null) && i < newLampPositions.Length) { _lampObjects[i].transform.position = newLampPositions[i]; } } if ((Object)(object)_strobeObject != (Object)null) { _strobeObject.transform.position = new Vector3(newCenter.x, newCenter.y + RaveLocationManager.StrobeHeightOffset, newCenter.z); } } catch (Exception ex) { RaveMod.Logger.Error("RelocateLamps error: " + ex.Message); } } internal static void Cleanup() { for (int num = _lampObjects.Count - 1; num >= 0; num--) { try { GameObject val = _lampObjects[num]; if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } } catch { } } _lampObjects.Clear(); _lights.Clear(); _headRenderers.Clear(); if ((Object)(object)_strobeObject != (Object)null) { Object.DestroyImmediate((Object)(object)_strobeObject); _strobeObject = null; _strobeLight = null; } _colorTimer = 0f; _currentColorIndex = 0; _strobeTimer = 0f; _strobeActive = false; } private static void DestroyStaleObjects() { try { GameObject[] array = Il2CppArrayBase.op_Implicit(Object.FindObjectsOfType()); if (array == null) { return; } int num = 0; foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null)) { if (((Object)val).name != null && ((Object)val).name.StartsWith("RaveLamp_") && !_lampObjects.Contains(val)) { Object.DestroyImmediate((Object)(object)val); num++; } if (((Object)val).name != null && ((Object)val).name == "RaveStrobeLight") { Object.DestroyImmediate((Object)(object)val); num++; } } } } catch (Exception ex) { RaveMod.Logger.Warning("Light DestroyStaleObjects error: " + ex.Message); } } } internal struct PresetSettings { internal string Name; internal Vector3 Center; internal float DanceRadius; internal float FogRadius; internal float FogAlpha; internal int FogCount; internal int NPCCount; internal float StrobeHeightOffset; internal bool IsUnderground; internal float BoothZOffset; } public sealed class RaveLocationManager { private static readonly PresetSettings PRESET_PARKINGLOT = new PresetSettings { Name = "Parkinglot", Center = new Vector3(-170.12f, -2.94f, 85.17f), DanceRadius = 4.5f, FogRadius = 15f, FogAlpha = 0.198f, FogCount = 190, NPCCount = 20, StrobeHeightOffset = 8f, IsUnderground = false, BoothZOffset = 2.8f }; private static readonly PresetSettings PRESET_UNDERGROUND = new PresetSettings { Name = "Underground", Center = new Vector3(72.53f, -5.78f, 16.99f), DanceRadius = 4f, FogRadius = 10.3f, FogAlpha = 0.128f, FogCount = 156, NPCCount = 20, StrobeHeightOffset = 3f, IsUnderground = true, BoothZOffset = 2f }; private static readonly PresetSettings PRESET_LITTLEFOREST = new PresetSettings { Name = "Littleforest", Center = new Vector3(105.86f, 0.97f, 80.92f), DanceRadius = 8f, FogRadius = 16.4f, FogAlpha = 0.12f, FogCount = 190, NPCCount = 30, StrobeHeightOffset = 8f, IsUnderground = false, BoothZOffset = 3f }; private static readonly PresetSettings[] ALL_PRESETS = new PresetSettings[3] { PRESET_PARKINGLOT, PRESET_UNDERGROUND, PRESET_LITTLEFOREST }; private static readonly Random _rng = new Random(); private static string _resolvedPresetName = null; internal const float NPC_HEIGHT_OFFSET = -0.99f; internal const float FOG_HEIGHT_MIN = 0.2f; internal const float FOG_HEIGHT_MAX = 0.85f; internal static float NPC_DANCE_RADIUS = PRESET_PARKINGLOT.DanceRadius; internal static int CurrentNPCCount = PRESET_PARKINGLOT.NPCCount; internal static float CurrentDanceSpeed = 6f; internal static float StrobeHeightOffset = 8f; internal static bool IsUnderground = false; private const float LAMP_RADIUS = 6f; internal static float BOOTH_Z_OFFSET = 3f; internal static bool IsStageActive = false; private const float STAGE_NPC_FRONT_BUFFER = 3.25f; private const float STAGE_NPC_MIN_FRONT_OFFSET = 0.55f; internal static Vector3 CenterPosition = PRESET_PARKINGLOT.Center; internal static string CurrentLocationName = "Parkinglot"; internal static Vector3 MusicPosition; internal static Vector3[] LampPositions; internal static Vector3[] DancePositions; private RaveLocationManager() { } internal static void Initialize() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) IsStageActive = false; PresetSettings? presetSettings = null; if (RaveConfig.CustomRaveLocation.Value == 0) { if (!RaveConfig.SmallFestivalStageEnabled.Value) { presetSettings = ((_resolvedPresetName == null) ? new PresetSettings?(ALL_PRESETS[_rng.Next(ALL_PRESETS.Length)]) : new PresetSettings?(GetPresetByName(_resolvedPresetName))); } else { presetSettings = PRESET_PARKINGLOT; _resolvedPresetName = PRESET_PARKINGLOT.Name; } } if (presetSettings.HasValue) { PresetSettings value = presetSettings.Value; _resolvedPresetName = value.Name; CenterPosition = value.Center; CurrentLocationName = value.Name; ApplyPresetSettings(value); CurrentDanceSpeed = 5f; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Location: " + CurrentLocationName); } } else { int value2 = RaveConfig.CustomRaveLocation.Value; Vector3[] array = ParseCustomLocations(); bool flag = false; if (value2 >= 1 && value2 <= 3 && array != null && array.Length >= value2) { CenterPosition = array[value2 - 1]; CurrentLocationName = $"Custom{value2}"; CurrentNPCCount = RaveConfig.NPCCount.Value; NPC_DANCE_RADIUS = RaveConfig.DanceRadius.Value; CurrentDanceSpeed = RaveConfig.DanceSpeed.Value; StrobeHeightOffset = 8f; IsUnderground = false; BOOTH_Z_OFFSET = 3f; RaveFogController.FogRadius = 10f; RaveFogController.FogHeightMin = 0.2f; RaveFogController.FogHeightMax = 0.85f; RaveFogController.FogAlpha = 0.13f; RaveFogController.FogCount = 120; flag = true; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Location: " + CurrentLocationName); } } if (!flag) { RaveMod.Logger.Warning($"No preset active and custom slot {value2} invalid \ufffd fallback to Parkinglot."); CenterPosition = PRESET_PARKINGLOT.Center; CurrentLocationName = PRESET_PARKINGLOT.Name; ApplyPresetSettings(PRESET_PARKINGLOT); CurrentDanceSpeed = 5f; } } IsStageActive = ShouldUseStage(); MusicPosition = CenterPosition + new Vector3(0f, 0.2f, -2f); CalculateLampPositions(); CalculateNPCPositions(); } internal static string ResolveLocationName() { if (RaveConfig.CustomRaveLocation.Value == 0) { if (RaveConfig.SmallFestivalStageEnabled.Value) { _resolvedPresetName = PRESET_PARKINGLOT.Name; return _resolvedPresetName; } if (_resolvedPresetName == null) { _resolvedPresetName = ALL_PRESETS[_rng.Next(ALL_PRESETS.Length)].Name; } return _resolvedPresetName; } int value = RaveConfig.CustomRaveLocation.Value; if (value >= 1 && value <= 3) { return $"Custom{value}"; } return PRESET_PARKINGLOT.Name; } internal static string GetResolvedPresetName() { return _resolvedPresetName; } internal static void ClearResolvedPresetName() { _resolvedPresetName = null; } internal static void RestoreResolvedPresetName(string presetName) { _resolvedPresetName = (string.IsNullOrWhiteSpace(presetName) ? null : GetPresetByName(presetName).Name); } internal static void ApplyPresetSettings(PresetSettings preset) { NPC_DANCE_RADIUS = preset.DanceRadius; CurrentNPCCount = preset.NPCCount; StrobeHeightOffset = preset.StrobeHeightOffset; IsUnderground = preset.IsUnderground; BOOTH_Z_OFFSET = preset.BoothZOffset; RaveFogController.FogRadius = preset.FogRadius; RaveFogController.FogHeightMin = 0.2f; RaveFogController.FogHeightMax = 0.85f; RaveFogController.FogAlpha = preset.FogAlpha; RaveFogController.FogCount = preset.FogCount; } internal static PresetSettings GetPresetByName(string name) { for (int i = 0; i < ALL_PRESETS.Length; i++) { if (string.Equals(ALL_PRESETS[i].Name, name, StringComparison.OrdinalIgnoreCase)) { return ALL_PRESETS[i]; } } return PRESET_PARKINGLOT; } internal static bool ShouldUseStage() { try { return RaveConfig.SmallFestivalStageEnabled.Value && CurrentLocationName.Equals(PRESET_PARKINGLOT.Name, StringComparison.OrdinalIgnoreCase); } catch { return false; } } internal static Vector3 GetStageAudienceForward() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) Vector3 spawnPosition = LetsGoObjectController.GetSpawnPosition(); Vector3 val = CenterPosition - spawnPosition; val.y = 0f; if (Vector3.Dot(val, val) <= 0.0001f) { val = LetsGoObjectController.GetSpawnRotation() * Vector3.forward; val.y = 0f; } float num = Vector3.Dot(val, val); if (num <= 0.0001f) { return Vector3.forward; } return val / Mathf.Sqrt(num); } private static void CalculateLampPositions() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) int value = RaveConfig.LampCount.Value; LampPositions = (Vector3[])(object)new Vector3[value]; for (int i = 0; i < value; i++) { float num = (float)Math.PI * 2f / (float)value * (float)i; float num2 = CenterPosition.x + Mathf.Cos(num) * 6f; float num3 = CenterPosition.z + Mathf.Sin(num) * 6f; LampPositions[i] = new Vector3(num2, CenterPosition.y, num3); } } private static void CalculateNPCPositions() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) int currentNPCCount = CurrentNPCCount; Random random = new Random(); DancePositions = (Vector3[])(object)new Vector3[currentNPCCount]; if (IsStageActive = ShouldUseStage()) { int num = (CurrentNPCCount = Mathf.RoundToInt((float)currentNPCCount * 1.5f)); DancePositions = (Vector3[])(object)new Vector3[num]; Vector3 spawnPosition = LetsGoObjectController.GetSpawnPosition(); Vector3 stageAudienceForward = GetStageAudienceForward(); Vector3 val = Vector3.Cross(Vector3.up, stageAudienceForward); Vector3 normalized = ((Vector3)(ref val)).normalized; for (int i = 0; i < num; i++) { float num2 = (float)(random.NextDouble() * 2.0 - 1.0) * 3.8f; float num3 = 2.5f + (float)random.NextDouble() * 11f; Vector3 val2 = spawnPosition + stageAudienceForward * num3 + normalized * num2; DancePositions[i] = new Vector3(val2.x, CenterPosition.y + -0.99f, val2.z); } return; } float num4 = CenterPosition.z + BOOTH_Z_OFFSET; for (int j = 0; j < currentNPCCount; j++) { float num5 = 0f; float num6 = 0f; bool flag = false; for (int k = 0; k < 20; k++) { float num7 = (float)(random.NextDouble() * 2.0 * 3.1415927410125732); float num8 = NPC_DANCE_RADIUS * Mathf.Sqrt((float)random.NextDouble()) * 0.9f; num5 = CenterPosition.x + Mathf.Cos(num7) * num8; num6 = CenterPosition.z + Mathf.Sin(num7) * num8; if (!(Mathf.Abs(num5 - CenterPosition.x) < 0.8f) || !(Mathf.Abs(num6 - num4) < 0.8f)) { flag = true; break; } } if (!flag) { float num9 = (float)Math.PI + (float)(random.NextDouble() * 3.1415927410125732); num5 = CenterPosition.x + Mathf.Cos(num9) * NPC_DANCE_RADIUS * 0.85f; num6 = CenterPosition.z + Mathf.Sin(num9) * NPC_DANCE_RADIUS * 0.85f; } DancePositions[j] = new Vector3(num5, CenterPosition.y + -0.99f, num6); } } private static Vector3[] ParseCustomLocations() { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) string customLocationsValue = RaveConfig.CustomLocationsValue; if (string.IsNullOrWhiteSpace(customLocationsValue)) { return null; } try { string[] array = customLocationsValue.Split(';'); List list = new List(); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (!string.IsNullOrEmpty(text2)) { string[] array3 = text2.Split(','); float result; float result2; float result3; if (array3.Length != 3) { RaveMod.Logger.Warning("Invalid location format: '" + text2 + "' (expected: X,Y,Z)"); } else if (float.TryParse(array3[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result) && float.TryParse(array3[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result2) && float.TryParse(array3[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result3)) { list.Add(new Vector3(result, result2, result3)); } else { RaveMod.Logger.Warning("Could not parse location: '" + text2 + "'"); } } } if (list.Count > 0) { return list.ToArray(); } } catch (Exception ex) { RaveMod.Logger.Error("Error parsing custom locations: " + ex.Message); } return null; } internal static bool IsNearPresetLocation(Vector3 position, float radius) { //IL_0006: 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) for (int i = 0; i < ALL_PRESETS.Length; i++) { if (Vector3.Distance(position, ALL_PRESETS[i].Center) <= radius) { return true; } } return false; } internal static Vector3? GetNearbyCustomLocation(Vector3 position, float radius) { //IL_0028: 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_0030: 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_0049: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = ParseCustomLocations(); if (array == null) { return null; } Vector3[] array2 = array; foreach (Vector3 val in array2) { float num = Vector3.Distance(position, val); if (num <= radius) { return val; } } return null; } internal static bool AddCustomLocation(Vector3 position) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) try { Vector3[] array = ParseCustomLocations(); if (array != null && array.Length >= 10) { RaveMod.Logger.Warning("Max 10 custom locations reached."); return false; } string text = RaveConfig.CustomLocationsValue ?? ""; string text2 = string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2}", position.x, position.y, position.z); string customLocationsValue = (string.IsNullOrWhiteSpace(text) ? text2 : (text + ";" + text2)); RaveConfig.CustomLocationsValue = customLocationsValue; return true; } catch (Exception ex) { RaveMod.Logger.Error("Error adding custom location: " + ex.Message); return false; } } internal static bool RemoveCustomLocation(Vector3 location) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) try { string customLocationsValue = RaveConfig.CustomLocationsValue; if (string.IsNullOrWhiteSpace(customLocationsValue)) { return false; } string[] array = customLocationsValue.Split(';'); List list = new List(); string[] array2 = array; Vector3 val = default(Vector3); foreach (string text in array2) { string text2 = text.Trim(); if (string.IsNullOrEmpty(text2)) { continue; } string[] array3 = text2.Split(','); if (array3.Length == 3 && float.TryParse(array3[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array3[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array3[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { ((Vector3)(ref val))..ctor(result, result2, result3); if (Vector3.Distance(val, location) > 0.5f) { list.Add(text2); } } } RaveConfig.CustomLocationsValue = string.Join(";", list); return true; } catch (Exception ex) { RaveMod.Logger.Error("Error removing custom location: " + ex.Message); return false; } } internal static void RecalculateLampPositions() { CalculateLampPositions(); } internal static void RecalculateNPCPositions() { CalculateNPCPositions(); } internal static Vector3 GetDanceFocusPosition() { //IL_0037: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) if (ShouldUseStage()) { return LetsGoObjectController.GetPultWorldPosition(); } return new Vector3(CenterPosition.x, CenterPosition.y, CenterPosition.z + BOOTH_Z_OFFSET); } internal static void Cleanup() { LampPositions = null; DancePositions = null; _resolvedPresetName = null; IsStageActive = false; } internal static bool IsParkinglotActive() { try { return CurrentLocationName.Equals("Parkinglot", StringComparison.OrdinalIgnoreCase); } catch { return false; } } } public class RaveMod : MelonMod { private bool _sceneReady = false; internal static Instance Logger; public override void OnInitializeMelon() { Logger = ((MelonBase)this).LoggerInstance; RaveConfig.Initialize(); ((MelonBase)this).LoggerInstance.Msg("Illegal Rave v" + ((MelonBase)this).Info.Version + " initialized."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Main") { CleanupStaleRaveObjects(); RaveDJBoothController.PreCacheGlbPrefabs(); RaveAudioController.PreloadAudio(); _sceneReady = true; ((MelonBase)this).LoggerInstance.Msg("Main scene loaded."); return; } if (_sceneReady) { try { RaveEventManager.Reset(preserveActiveRaveState: true); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("Reset error during scene change: " + ex.Message); } } _sceneReady = false; } public override void OnDeinitializeMelon() { try { if (_sceneReady) { RaveEventManager.Reset(preserveActiveRaveState: true); } } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("Cleanup on mod disable: " + ex.Message); } _sceneReady = false; } public override void OnUpdate() { if (_sceneReady) { RaveEventManager.Update(); if (RaveEventManager.IsRaveActive && !RaveEventManager.IsRaveStarting) { RaveLightController.UpdateLights(); RaveAudioController.UpdateAudio(); RaveNPCController.UpdateNPCs(); RaveFogController.UpdateFog(); } } } private void CleanupStaleRaveObjects() { try { Il2CppArrayBase val = Object.FindObjectsOfType(); if (val == null) { return; } int num = 0; for (int i = 0; i < val.Length; i++) { GameObject val2 = val[i]; if (!((Object)(object)val2 == (Object)null) && ((Object)val2).name != null && (((Object)val2).name.StartsWith("RaveLamp_") || ((Object)val2).name.StartsWith("RaveSpeaker") || ((Object)val2).name.StartsWith("RaveFog_") || ((Object)val2).name == "RaveStrobeLight" || ((Object)val2).name == "RaveCompassAnchor" || ((Object)val2).name == "RaveCompassContent" || ((Object)val2).name == "RaveDJBooth" || ((Object)val2).name == "RaveDJDan" || ((Object)val2).name == "RaveDJGirl")) { Object.DestroyImmediate((Object)(object)val2); num++; } } if (num > 0 && RaveConfig.DebugCoordinates.Value) { ((MelonBase)this).LoggerInstance.Msg($"[DEBUG] {num} stale rave objects removed."); } } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("CleanupStaleRaveObjects error: " + ex.Message); } } } internal enum DanceBehavior { CrouchLoop, ArmsUpSpin, EmotionShuffle, SideSprintInPlace, SprintStrafeHandsUp } internal class NpcRaveState { internal Vector3 BasePosition; internal float PhaseOffset; internal float SpeedMultiplier; internal float AnimTimer; internal float NextAnimTime; internal DanceBehavior Behavior; internal bool IsCrouched; internal float BehaviorChangeTimer; internal float NextBehaviorChangeTime; internal float SpinAngle; internal float EmotionShuffleTimer; internal float NextEmotionShuffleTime; internal bool HasHandsUp; } public sealed class RaveNPCController { private static List _dancingNPCs; private static Dictionary _npcStates; private static Dictionary _npcScheduleManagers; private static Dictionary _npcAnimators; private static Dictionary _npcAnimations; private static Dictionary _npcDisabledIndicators; private static Dictionary _npcDisabledColliders; private static List _blockedCustomers; private static float _globalTimer; private static Random _rng; private static NPC _showcaseNPC; private static int _showcaseEmotionIndex; private static float _showcaseTimer; private static float _showcaseNPCTimer; private const float SHOWCASE_EMOTION_DURATION = 0.8f; private const float SHOWCASE_NPC_CHANGE_MIN = 15f; private const float SHOWCASE_NPC_CHANGE_MAX = 25f; private static float _nextShowcaseNPCChange; private const string EMOTION_LABEL = "RaveMod"; private static readonly (DanceBehavior behavior, int weight)[] DANCE_BEHAVIOR_WEIGHTS; private static readonly int TOTAL_BEHAVIOR_WEIGHT; private static readonly string[] GESTURE_TRIGGERS; private const float DANCE_SPEED_MIN = 0.6f; private const float DANCE_SPEED_MAX = 1.4f; private const float IDLE_SWAY_RADIUS = 0.3f; private const float LEASH_RADIUS = 10f; private const float ANIM_INTERVAL_MIN = 4f; private const float ANIM_INTERVAL_MAX = 10f; private const float BEHAVIOR_CHANGE_MIN = 8f; private const float BEHAVIOR_CHANGE_MAX = 10f; private const float CROUCH_LOOP_MIN = 0.4f; private const float CROUCH_LOOP_MAX = 0.6f; private const float SPIN_SPEED_MIN = 260f; private const float SPIN_SPEED_MAX = 300f; private const float EMOTION_SHUFFLE_MIN = 0.5f; private const float EMOTION_SHUFFLE_MAX = 1f; private const float SPRINT_HANDSUP_EXPR_MIN = 0.8f; private const float SPRINT_HANDSUP_EXPR_MAX = 1.5f; private static readonly string[] EMOTION_NAMES; private static readonly string[] DRUG_EMOTIONS; private static readonly string[] ALL_EMOTIONS; private RaveNPCController() { } private static void DetachFromNavMesh(NPCMovement movement) { if (!((Object)(object)movement == (Object)null)) { movement.PauseMovement(); movement.SetAgentEnabled(false); movement.ResumeMovement(); } } static RaveNPCController() { _dancingNPCs = new List(); _npcStates = new Dictionary(); _npcScheduleManagers = new Dictionary(); _npcAnimators = new Dictionary(); _npcAnimations = new Dictionary(); _npcDisabledIndicators = new Dictionary(); _npcDisabledColliders = new Dictionary(); _blockedCustomers = new List(); _globalTimer = 0f; _rng = new Random(); _showcaseNPC = null; _showcaseEmotionIndex = 0; _showcaseTimer = 0f; _showcaseNPCTimer = 0f; _nextShowcaseNPCChange = 0f; DANCE_BEHAVIOR_WEIGHTS = new(DanceBehavior, int)[5] { (DanceBehavior.CrouchLoop, 30), (DanceBehavior.ArmsUpSpin, 6), (DanceBehavior.EmotionShuffle, 30), (DanceBehavior.SideSprintInPlace, 30), (DanceBehavior.SprintStrafeHandsUp, 25) }; GESTURE_TRIGGERS = new string[4] { "ThumbsUp", "Nod", "ConversationGesture1", "Eat" }; EMOTION_NAMES = new string[8] { "Happy", "Cheery", "Surprised", "Angry", "Shroom", "Cocaine", "Zombie", "Meth" }; DRUG_EMOTIONS = new string[4] { "Shroom", "Cocaine", "Zombie", "Meth" }; ALL_EMOTIONS = new string[11] { "Happy", "Cheery", "Surprised", "Angry", "Concerned", "Annoyed", "Scared", "Shroom", "Cocaine", "Zombie", "Meth" }; int num = 0; for (int i = 0; i < DANCE_BEHAVIOR_WEIGHTS.Length; i++) { num += DANCE_BEHAVIOR_WEIGHTS[i].weight; } TOTAL_BEHAVIOR_WEIGHT = num; } internal static void GatherNPCs() { //IL_07f5: Unknown result type (might be due to invalid IL or missing references) //IL_0820: Unknown result type (might be due to invalid IL or missing references) //IL_084b: Unknown result type (might be due to invalid IL or missing references) //IL_0720: Unknown result type (might be due to invalid IL or missing references) //IL_0725: Unknown result type (might be due to invalid IL or missing references) //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) //IL_0576: Unknown result type (might be due to invalid IL or missing references) //IL_0578: Unknown result type (might be due to invalid IL or missing references) //IL_055b: Unknown result type (might be due to invalid IL or missing references) //IL_0560: Unknown result type (might be due to invalid IL or missing references) try { List nPCRegistry = NPCManager.NPCRegistry; if (nPCRegistry == null || nPCRegistry.Count == 0) { RaveMod.Logger.Warning("No NPCs found in registry."); return; } int count = nPCRegistry.Count; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"NPCRegistry: {count} NPCs found."); } int currentNPCCount = RaveLocationManager.CurrentNPCCount; List list = new List(); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; NPC val = TryGetIgorForRave(); if ((Object)(object)val != (Object)null) { list.Add(val); if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("Igor Romanovich is attending the rave."); } } for (int i = 0; i < nPCRegistry.Count && list.Count < currentNPCCount; i++) { NPC val2 = nPCRegistry[i]; if ((Object)(object)val2 == (Object)null) { num++; } else { if ((Object)(object)val != (Object)null && (Object)(object)val2 == (Object)(object)val) { continue; } try { Dealer val3 = ((Il2CppObjectBase)val2).TryCast(); if ((Object)(object)val3 != (Object)null) { num2++; continue; } } catch (Exception ex) { num6++; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Warning($"[DIAG] TryCast exception for NPC #{i}: {ex.GetType().Name}: {ex.Message}"); } } try { PoliceOfficer val4 = ((Il2CppObjectBase)val2).TryCast(); if ((Object)(object)val4 != (Object)null) { num3++; continue; } } catch (Exception ex2) { num7++; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Warning($"[DIAG] TryCast exception for NPC #{i}: {ex2.GetType().Name}: {ex2.Message}"); } } try { Supplier val5 = ((Il2CppObjectBase)val2).TryCast(); if ((Object)(object)val5 != (Object)null) { num4++; continue; } } catch (Exception ex3) { num8++; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Warning($"[DIAG] TryCast exception for NPC #{i}: {ex3.GetType().Name}: {ex3.Message}"); } } if (IsNPCBusyWithDeal(val2)) { num5++; } else { list.Add(val2); } } } if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"NPC filter: {count} total, {list.Count} available, needed {currentNPCCount} (null={num}, dealer={num2}, police={num3}, supplier={num4}, busy={num5}, dealerEx={num6}, policeEx={num7}, supplierEx={num8})"); } if (list.Count == 0) { RaveMod.Logger.Warning("No available NPCs found for the rave."); return; } Vector3[] dancePositions = RaveLocationManager.DancePositions; int num9 = 0; for (int j = 0; j < list.Count; j++) { NPC val6 = list[j]; Vector3 val7 = RaveLocationManager.CenterPosition; if (dancePositions != null && j < dancePositions.Length) { val7 = dancePositions[j]; } WarpNPCToPosition(val6, val7); NpcRaveState npcRaveState = new NpcRaveState(); npcRaveState.BasePosition = val7; npcRaveState.PhaseOffset = (float)(_rng.NextDouble() * 2.0 * Math.PI); npcRaveState.SpeedMultiplier = RandRange(0.6f, 1.4f); npcRaveState.Behavior = PickWeightedBehavior(); npcRaveState.NextAnimTime = RandRange(4f, 10f); npcRaveState.NextBehaviorChangeTime = RandRange(8f, 10f); _npcStates[val6] = npcRaveState; _dancingNPCs.Add(val6); num9++; } if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"Warped {num9} NPCs to rave at ({RaveLocationManager.CenterPosition.x:F1},{RaveLocationManager.CenterPosition.y:F1},{RaveLocationManager.CenterPosition.z:F1})"); for (int k = 0; k < _dancingNPCs.Count; k++) { NPC val8 = _dancingNPCs[k]; if ((Object)(object)val8 == (Object)null) { continue; } try { float value = Vector3.Distance(((Component)val8).transform.position, RaveLocationManager.CenterPosition); string value2 = "?"; try { value2 = val8.FirstName; } catch { } bool value3 = (Object)(object)((Component)val8).gameObject != (Object)null && ((Component)val8).gameObject.activeInHierarchy; RaveMod.Logger.Msg($"[WARP] '{value2}' dist={value:F1}m visible={val8.isVisible} goActive={value3} pos=({((Component)val8).transform.position.x:F1},{((Component)val8).transform.position.y:F1},{((Component)val8).transform.position.z:F1})"); } catch (Exception ex4) { RaveMod.Logger.Warning($"[WARP] Verify failed for NPC #{k}: {ex4.GetType().Name}: {ex4.Message}"); } } } foreach (NPC dancingNPC in _dancingNPCs) { try { CacheNPCAnimator(dancingNPC); } catch { } try { SetRaveEmotion(dancingNPC); } catch { } } BlockCustomerDeals(); } catch (Exception ex5) { RaveMod.Logger.Error("Error gathering NPCs: " + ex5.Message); } } private static void WarpNPCToPosition(NPC npc, Vector3 position) { //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04c4: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) try { string text = "?"; try { text = npc.FirstName; } catch { } if ((Object)(object)npc.Movement == (Object)null) { RaveMod.Logger.Warning("NPC '" + text + "' has no Movement, warp skipped."); return; } DetachFromNavMesh(npc.Movement); try { List list = new List(); LineRenderer[] array = Il2CppArrayBase.op_Implicit(((Component)npc).GetComponentsInChildren(true)); if (array != null) { for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && ((Renderer)array[i]).enabled) { ((Renderer)array[i]).enabled = false; } } } Projector[] array2 = Il2CppArrayBase.op_Implicit(((Component)npc).GetComponentsInChildren(true)); if (array2 != null) { for (int j = 0; j < array2.Length; j++) { if ((Object)(object)array2[j] != (Object)null && ((Behaviour)array2[j]).enabled) { ((Behaviour)array2[j]).enabled = false; } } } try { NPCAwareness componentInChildren = ((Component)npc).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && ((Behaviour)componentInChildren).enabled) { ((Behaviour)componentInChildren).enabled = false; list.Add((Behaviour)(object)componentInChildren); } } catch { } try { VisionCone componentInChildren2 = ((Component)npc).GetComponentInChildren(true); if ((Object)(object)componentInChildren2 != (Object)null && ((Behaviour)componentInChildren2).enabled) { ((Behaviour)componentInChildren2).enabled = false; list.Add((Behaviour)(object)componentInChildren2); } } catch { } try { Il2CppArrayBase componentsInChildren = ((Component)npc).GetComponentsInChildren(true); if (componentsInChildren != null) { for (int k = 0; k < componentsInChildren.Length; k++) { if ((Object)(object)componentsInChildren[k] != (Object)null && ((Behaviour)componentsInChildren[k]).enabled) { ((Behaviour)componentsInChildren[k]).enabled = false; list.Add((Behaviour)(object)componentsInChildren[k]); } } } } catch { } if (list.Count > 0) { _npcDisabledIndicators[npc] = list.ToArray(); } if (RaveConfig.DebugCoordinates.Value && !_npcDisabledIndicators.ContainsKey(npc)) { Component[] array3 = Il2CppArrayBase.op_Implicit(((Component)npc).GetComponentsInChildren(true)); if (array3 != null) { HashSet hashSet = new HashSet(); for (int l = 0; l < array3.Length; l++) { if ((Object)(object)array3[l] != (Object)null) { try { hashSet.Add(((object)array3[l]).GetType().Name); } catch { } } } RaveMod.Logger.Msg("[DEBUG] NPC '" + text + "' components: " + string.Join(", ", hashSet)); } } } catch { } try { NPCScheduleManager componentInChildren3 = ((Component)npc).gameObject.GetComponentInChildren(true); if ((Object)(object)componentInChildren3 != (Object)null) { componentInChildren3.DisableSchedule(); _npcScheduleManagers[npc] = componentInChildren3; } } catch { } try { NPCBehaviour behaviour = npc.Behaviour; if ((Object)(object)behaviour != (Object)null) { ((Behaviour)behaviour).enabled = false; } } catch { } Vector3 position2 = ((Component)npc).transform.position; ((Component)npc).transform.position = position; try { NPCActions actions = npc.Actions; if ((Object)(object)actions != (Object)null) { actions.SetCanUseUmbrella(false); } } catch { } try { npc.UnequipAll(); } catch { } try { npc.SetVisible(true, false); } catch { } if (RaveConfig.DebugCoordinates.Value) { Vector3 position3 = ((Component)npc).transform.position; RaveMod.Logger.Msg($"[DEBUG] NPC '{text}' gewarpt: ({position2.x:F1},{position2.y:F1},{position2.z:F1}) -> ({position3.x:F1},{position3.y:F1},{position3.z:F1}), Visible={npc.isVisible}"); } } catch (Exception ex) { RaveMod.Logger.Error("Error warping NPC: " + ex.Message); } } internal static void UpdateNPCs() { //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: 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_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_059a: Unknown result type (might be due to invalid IL or missing references) float deltaTime = Time.deltaTime; _globalTimer += deltaTime; TryLazyCacheAnimators(); Vector3 val = default(Vector3); foreach (NPC dancingNPC in _dancingNPCs) { if ((Object)(object)dancingNPC == (Object)null) { continue; } try { GameObject gameObject = ((Component)dancingNPC).gameObject; if ((Object)(object)gameObject == (Object)null || !_npcStates.TryGetValue(dancingNPC, out var value)) { continue; } float num = _globalTimer * value.SpeedMultiplier * RaveLocationManager.CurrentDanceSpeed + value.PhaseOffset; float num2 = Mathf.Sin(num) * 0.3f * 1.5f; float num3 = Mathf.Cos(num * 0.7f) * 0.3f; ((Vector3)(ref val))..ctor(value.BasePosition.x + num2, value.BasePosition.y, value.BasePosition.z + num3); gameObject.transform.position = Vector3.Lerp(gameObject.transform.position, val, deltaTime * 2f); float num4 = Mathf.Abs(gameObject.transform.position.y - value.BasePosition.y); if (num4 > 1f) { gameObject.transform.position = val; try { if ((Object)(object)dancingNPC.Movement != (Object)null) { DetachFromNavMesh(dancingNPC.Movement); } } catch { } try { NPCBehaviour behaviour = dancingNPC.Behaviour; if ((Object)(object)behaviour != (Object)null) { ((Behaviour)behaviour).enabled = false; } } catch { } } if (value.Behavior != DanceBehavior.ArmsUpSpin) { Vector3 danceFocusPosition = RaveLocationManager.GetDanceFocusPosition(); Vector3 val2 = danceFocusPosition - gameObject.transform.position; val2.y = 0f; if (Vector3.Dot(val2, val2) > 0.01f) { Quaternion val3 = Quaternion.LookRotation(val2); gameObject.transform.rotation = Quaternion.Slerp(gameObject.transform.rotation, val3, deltaTime * 2f); } } ApplyDanceBehavior(dancingNPC, value, num, deltaTime); value.BehaviorChangeTimer += deltaTime; if (value.BehaviorChangeTimer >= value.NextBehaviorChangeTime) { value.BehaviorChangeTimer = 0f; value.NextBehaviorChangeTime = RandRange(8f, 10f); if (value.Behavior == DanceBehavior.CrouchLoop && value.IsCrouched) { value.IsCrouched = false; TrySetCrouched(dancingNPC, crouched: false); } if ((value.Behavior == DanceBehavior.ArmsUpSpin || value.Behavior == DanceBehavior.SprintStrafeHandsUp) && value.HasHandsUp) { value.HasHandsUp = false; TrySetHandsUp(dancingNPC, handsUp: false); SetRaveEmotion(dancingNPC); } if (value.Behavior == DanceBehavior.EmotionShuffle || value.Behavior == DanceBehavior.SprintStrafeHandsUp) { value.EmotionShuffleTimer = 0f; SetRaveEmotion(dancingNPC); } value.Behavior = PickWeightedBehavior(); value.SpeedMultiplier = RandRange(0.6f, 1.4f); value.PhaseOffset = (float)(_rng.NextDouble() * 2.0 * Math.PI); value.AnimTimer = 0f; value.NextAnimTime = RandRange(4f, 10f); value.SpinAngle = 0f; if (value.Behavior == DanceBehavior.CrouchLoop || value.Behavior == DanceBehavior.SideSprintInPlace) { if (_rng.NextDouble() < 0.4) { TrySetEmotionOverride(dancingNPC, DRUG_EMOTIONS[_rng.Next(DRUG_EMOTIONS.Length)]); } else { SetRaveEmotion(dancingNPC); } } } if (value.Behavior != DanceBehavior.CrouchLoop && value.Behavior != DanceBehavior.ArmsUpSpin && value.Behavior != DanceBehavior.SprintStrafeHandsUp) { value.AnimTimer += deltaTime; if (value.AnimTimer >= value.NextAnimTime) { value.AnimTimer = 0f; value.NextAnimTime = RandRange(4f, 10f); string triggerName = GESTURE_TRIGGERS[_rng.Next(GESTURE_TRIGGERS.Length)]; TrySetAnimationTrigger(dancingNPC, triggerName); } } if (!dancingNPC.isVisible) { dancingNPC.SetVisible(true, false); } } catch { } } UpdateExpressionShowcase(deltaTime); foreach (KeyValuePair npcState in _npcStates) { try { NPC key = npcState.Key; NpcRaveState value2 = npcState.Value; if (!((Object)(object)key == (Object)null) && !((Object)(object)((Component)key).gameObject == (Object)null)) { float num5 = Vector3.Distance(((Component)key).transform.position, value2.BasePosition); float num6 = Mathf.Abs(((Component)key).transform.position.y - value2.BasePosition.y); if (num5 > 10f || num6 > 1.5f) { ((Component)key).transform.position = value2.BasePosition; } } } catch { } } } private static void TrySetMovementAnimation(NPC npc, float direction, float strafe) { try { if (!_npcAnimators.TryGetValue(npc, out var value)) { return; } if ((Object)(object)value == (Object)null || ((Il2CppObjectBase)value).WasCollected) { _npcAnimators.Remove(npc); return; } value.SetFloat("Direction", direction); value.SetFloat("Strafe", strafe); value.SetBool("isGrounded", true); value.SetFloat("TimeAirborne", 0f); value.SetBool("Sitting", false); value.SetBool("Smoking", false); value.SetBool("SkateIdle", false); value.SetBool("Drinking", false); value.SetBool("IsClimbing", false); try { NPCActions actions = npc.Actions; if ((Object)(object)actions != (Object)null) { actions.SetCanUseUmbrella(false); } } catch { } if (_npcStates.TryGetValue(npc, out var value2)) { if (value2.Behavior != DanceBehavior.ArmsUpSpin && value2.Behavior != DanceBehavior.SprintStrafeHandsUp) { value.SetBool("HandsUp", false); } } else { value.SetBool("HandsUp", false); } if (_npcAnimations.TryGetValue(npc, out var value3) && (Object)(object)value3 != (Object)null && !((Il2CppObjectBase)value3).WasCollected && ((Behaviour)value3).enabled) { ((Behaviour)value3).enabled = false; } } catch { } } private static void TrySetAnimationTrigger(NPC npc, string triggerName) { try { npc.SetAnimationTrigger(triggerName); } catch { } } private static void ApplyDanceBehavior(NPC npc, NpcRaveState state, float t, float dt) { //IL_016b: Unknown result type (might be due to invalid IL or missing references) switch (state.Behavior) { case DanceBehavior.CrouchLoop: { state.AnimTimer += dt; if (state.AnimTimer >= state.NextAnimTime) { state.AnimTimer = 0f; state.NextAnimTime = RandRange(0.4f, 0.6f); state.IsCrouched = !state.IsCrouched; TrySetCrouched(npc, state.IsCrouched); } float direction2 = Mathf.Abs(Mathf.Sin(t * 1.5f)) * 0.3f + 0.05f; TrySetMovementAnimation(npc, direction2, 0f); break; } case DanceBehavior.ArmsUpSpin: { if (!state.HasHandsUp) { TrySetHandsUp(npc, handsUp: true); state.HasHandsUp = true; TrySetEmotionOverride(npc, "Surprised"); } float num = RandRange(260f, 300f) * state.SpeedMultiplier; state.SpinAngle += num * dt; if (state.SpinAngle >= 360f) { state.SpinAngle -= 360f; } try { GameObject gameObject = ((Component)npc).gameObject; if ((Object)(object)gameObject != (Object)null) { gameObject.transform.rotation = Quaternion.Euler(0f, state.SpinAngle, 0f); } } catch { } TrySetMovementAnimation(npc, 0.2f, 0f); break; } case DanceBehavior.EmotionShuffle: { state.EmotionShuffleTimer += dt; if (state.EmotionShuffleTimer >= state.NextEmotionShuffleTime) { state.EmotionShuffleTimer = 0f; state.NextEmotionShuffleTime = RandRange(0.5f, 1f); string emotionName2 = EMOTION_NAMES[_rng.Next(EMOTION_NAMES.Length)]; TrySetEmotionOverride(npc, emotionName2); } float direction3 = Mathf.Abs(Mathf.Sin(t * 1.2f)) * 0.25f + 0.05f; float strafe2 = Mathf.Sin(t * 1.8f + state.PhaseOffset) * 0.3f; TrySetMovementAnimation(npc, direction3, strafe2); break; } case DanceBehavior.SideSprintInPlace: { float strafe3 = Mathf.Sin(t * 3f) * 0.9f; TrySetMovementAnimation(npc, 0f, strafe3); break; } case DanceBehavior.SprintStrafeHandsUp: { if (!state.HasHandsUp) { TrySetHandsUp(npc, handsUp: true); state.HasHandsUp = true; } float direction = 0.8f + Mathf.Abs(Mathf.Sin(t * 1f)) * 0.2f; float strafe = Mathf.Sin(t * 2.5f + state.PhaseOffset) * 0.7f; TrySetMovementAnimation(npc, direction, strafe); state.EmotionShuffleTimer += dt; if (state.EmotionShuffleTimer >= state.NextEmotionShuffleTime) { state.EmotionShuffleTimer = 0f; state.NextEmotionShuffleTime = RandRange(0.8f, 1.5f); string emotionName = EMOTION_NAMES[_rng.Next(EMOTION_NAMES.Length)]; TrySetEmotionOverride(npc, emotionName); } break; } } } private static void UpdateExpressionShowcase(float dt) { if (_dancingNPCs.Count < 2) { return; } if ((Object)(object)_showcaseNPC != (Object)null && ((Il2CppObjectBase)_showcaseNPC).WasCollected) { _showcaseNPC = null; } _showcaseNPCTimer += dt; if ((Object)(object)_showcaseNPC == (Object)null) { if (_showcaseNPCTimer >= _nextShowcaseNPCChange) { PickNewShowcaseNPC(); } } else if (_showcaseNPCTimer >= _nextShowcaseNPCChange) { PickNewShowcaseNPC(); } if ((Object)(object)_showcaseNPC == (Object)null) { return; } _showcaseTimer += dt; if (_showcaseTimer >= 0.8f) { _showcaseTimer = 0f; _showcaseEmotionIndex++; if (_showcaseEmotionIndex >= ALL_EMOTIONS.Length) { _showcaseEmotionIndex = 0; } TrySetEmotionOverride(_showcaseNPC, ALL_EMOTIONS[_showcaseEmotionIndex]); } } private static void PickNewShowcaseNPC() { if ((Object)(object)_showcaseNPC != (Object)null) { SetRaveEmotion(_showcaseNPC); } NPC showcaseNPC = null; for (int i = 0; i < 10; i++) { if (_dancingNPCs.Count <= 0) { break; } NPC val = _dancingNPCs[_rng.Next(_dancingNPCs.Count)]; if ((Object)(object)val != (Object)null && !((Il2CppObjectBase)val).WasCollected && (Object)(object)val != (Object)(object)_showcaseNPC) { showcaseNPC = val; break; } } _showcaseNPC = showcaseNPC; _showcaseEmotionIndex = 0; _showcaseTimer = 0f; _showcaseNPCTimer = 0f; _nextShowcaseNPCChange = RandRange(15f, 25f); if ((Object)(object)_showcaseNPC != (Object)null) { TrySetEmotionOverride(_showcaseNPC, ALL_EMOTIONS[0]); } } private static void TrySetCrouched(NPC npc, bool crouched) { try { if (_npcAnimators.TryGetValue(npc, out var value) && (Object)(object)value != (Object)null) { value.SetBool("isCrouched", crouched); } } catch { } } private static void TrySetHandsUp(NPC npc, bool handsUp) { try { if (_npcAnimators.TryGetValue(npc, out var value) && (Object)(object)value != (Object)null) { value.SetBool("HandsUp", handsUp); } } catch { } } private static void TrySetEmotionOverride(NPC npc, string emotionName) { try { Avatar avatar = npc.Avatar; if (!((Object)(object)avatar == (Object)null)) { AvatarEmotionManager emotionManager = avatar.EmotionManager; if (!((Object)(object)emotionManager == (Object)null)) { emotionManager.AddEmotionOverride(emotionName, "RaveMod", 0f, 10); } } } catch { } } private static void CacheNPCAnimator(NPC npc) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) try { Animator componentInChildren = ((Component)npc).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { _npcAnimators[npc] = componentInChildren; ForceGroundState(componentInChildren); if (RaveConfig.DebugCoordinates.Value) { int parameterCount = componentInChildren.parameterCount; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < parameterCount; i++) { AnimatorControllerParameter parameter = componentInChildren.GetParameter(i); if (parameter != null) { stringBuilder.Append(parameter.name); stringBuilder.Append("("); stringBuilder.Append(((object)parameter.type/*cast due to .constrained prefix*/).ToString()); stringBuilder.Append(") "); } } string value = "?"; try { value = npc.FirstName; } catch { } RaveMod.Logger.Msg($"[DEBUG] Animator-Parameter fuer '{value}': {stringBuilder}"); } } NPCAnimation componentInChildren2 = ((Component)npc).GetComponentInChildren(); if (!((Object)(object)componentInChildren2 != (Object)null)) { return; } ((Behaviour)componentInChildren2).enabled = false; _npcAnimations[npc] = componentInChildren2; if (RaveConfig.DebugCoordinates.Value) { string text = "?"; try { text = npc.FirstName; } catch { } RaveMod.Logger.Msg("[DEBUG] NPCAnimation deaktiviert fuer '" + text + "'"); } } catch { } } private static void ForceGroundState(Animator animator) { try { animator.SetBool("isGrounded", true); animator.SetFloat("TimeAirborne", 0f); animator.SetFloat("Direction", 0f); animator.SetFloat("Strafe", 0f); animator.SetBool("isCrouched", false); animator.SetBool("Sitting", false); animator.SetBool("Smoking", false); animator.SetBool("HandsUp", false); animator.SetBool("SkateIdle", false); animator.SetBool("Drinking", false); animator.SetBool("IsClimbing", false); } catch { } } private static void SetRaveEmotion(NPC npc) { try { Avatar avatar = npc.Avatar; if (!((Object)(object)avatar == (Object)null)) { AvatarEmotionManager emotionManager = avatar.EmotionManager; if (!((Object)(object)emotionManager == (Object)null)) { double num = _rng.NextDouble(); string text = ((num < 0.7) ? DefaultEmotions.Happy : ((!(num < 0.9)) ? DefaultEmotions.Surprised : DefaultEmotions.Cheery)); emotionManager.AddEmotionOverride(text, "RaveMod", 0f, 10); } } } catch { } } private static void ClearRaveEmotions() { foreach (NPC dancingNPC in _dancingNPCs) { try { if ((Object)(object)dancingNPC == (Object)null) { continue; } Avatar avatar = dancingNPC.Avatar; if (!((Object)(object)avatar == (Object)null)) { AvatarEmotionManager emotionManager = avatar.EmotionManager; if ((Object)(object)emotionManager != (Object)null) { emotionManager.RemoveEmotionOverride("RaveMod"); } } } catch { } } } private static float RandRange(float min, float max) { return (float)(_rng.NextDouble() * (double)(max - min) + (double)min); } private static DanceBehavior PickWeightedBehavior() { int num = _rng.Next(TOTAL_BEHAVIOR_WEIGHT); int num2 = 0; for (int i = 0; i < DANCE_BEHAVIOR_WEIGHTS.Length; i++) { num2 += DANCE_BEHAVIOR_WEIGHTS[i].weight; if (num < num2) { return DANCE_BEHAVIOR_WEIGHTS[i].behavior; } } return DanceBehavior.CrouchLoop; } internal static float GetGroundY(Vector3 position) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0021: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: 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_024a: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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_019d: Unknown result type (might be due to invalid IL or missing references) try { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x, position.y + 5f, position.z); RaycastHit[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)Physics.RaycastAll(val, Vector3.down, 30f)); if (array != null && array.Length != 0) { float y = RaveLocationManager.CenterPosition.y; float num = float.MaxValue; bool flag = false; RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val2 = array2[i]; try { if ((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null || (Object)(object)((Component)((RaycastHit)(ref val2)).collider).gameObject == (Object)null) { continue; } string name = ((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name; if (name != null && (name.StartsWith("RaveFog_") || name.StartsWith("RaveLamp_") || name == "RaveStrobeLight" || name.StartsWith("RaveSpeaker"))) { continue; } NPC componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent(); if (!((Object)(object)componentInParent != (Object)null) && ((RaycastHit)(ref val2)).point.y <= y + 1f && ((RaycastHit)(ref val2)).point.y < num) { num = ((RaycastHit)(ref val2)).point.y; flag = true; if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Bowl-Raycast hit: y={((RaycastHit)(ref val2)).point.y:F2} (name={name})"); } } } catch { } } if (flag) { return num; } } GameObject val3 = GameObject.Find("Player_Local"); if ((Object)(object)val3 != (Object)null) { Vector3 position2 = val3.transform.position; Vector3 val4 = position2 - RaveLocationManager.CenterPosition; float num2 = Vector3.Dot(val4, val4); float num3 = RaveConfig.EventRadius.Value * RaveConfig.EventRadius.Value; if (num2 <= num3) { if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Spieler im Radius \ufffd verwende Spieler-Y={position2.y:F2}"); } return position2.y; } if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg($"[DEBUG] Spieler NICHT im Radius (dist={Mathf.Sqrt(num2):F1}m) \ufffd verwende Preset-Y"); } } } catch { } return RaveLocationManager.CenterPosition.y; } private static void TryLazyCacheAnimators() { //IL_0100: Unknown result type (might be due to invalid IL or missing references) foreach (NPC dancingNPC in _dancingNPCs) { if ((Object)(object)dancingNPC == (Object)null) { continue; } try { if (!_npcAnimators.TryGetValue(dancingNPC, out var value)) { goto IL_006f; } if ((Object)(object)value != (Object)null && !((Il2CppObjectBase)value).WasCollected) { continue; } _npcAnimators.Remove(dancingNPC); goto IL_006f; IL_006f: Animator componentInChildren = ((Component)dancingNPC).GetComponentInChildren(); if (!((Object)(object)componentInChildren != (Object)null)) { continue; } _npcAnimators[dancingNPC] = componentInChildren; ForceGroundState(componentInChildren); if (!_npcAnimations.ContainsKey(dancingNPC)) { NPCAnimation componentInChildren2 = ((Component)dancingNPC).GetComponentInChildren(); if ((Object)(object)componentInChildren2 != (Object)null) { ((Behaviour)componentInChildren2).enabled = false; _npcAnimations[dancingNPC] = componentInChildren2; } } if (_npcStates.TryGetValue(dancingNPC, out var value2)) { ((Component)dancingNPC).transform.position = value2.BasePosition; } try { if ((Object)(object)dancingNPC.Movement != (Object)null) { DetachFromNavMesh(dancingNPC.Movement); } } catch { } try { NPCBehaviour behaviour = dancingNPC.Behaviour; if ((Object)(object)behaviour != (Object)null) { ((Behaviour)behaviour).enabled = false; } } catch { } try { dancingNPC.SetVisible(true, false); } catch { } } catch { } } } private static NPC TryGetIgorForRave() { try { NPC nPC = NPCManager.GetNPC("igor_romanovich"); if ((Object)(object)nPC == (Object)null && RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Msg("[DEBUG] Igor Romanovich nicht in Registry gefunden."); } return nPC; } catch (Exception ex) { if (RaveConfig.DebugCoordinates.Value) { RaveMod.Logger.Error("TryGetIgorForRave error: " + ex.Message); } return null; } } private static bool IsNPCBusyWithDeal(NPC npc) { try { List unlockedCustomers = Customer.UnlockedCustomers; if (unlockedCustomers == null) { return false; } for (int i = 0; i < unlockedCustomers.Count; i++) { Customer val = unlockedCustomers[i]; if ((Object)(object)val == (Object)null) { continue; } try { NPC nPC = val.NPC; if ((Object)(object)nPC == (Object)null || (Object)(object)nPC != (Object)(object)npc || (!((Object)(object)val.CurrentContract != (Object)null) && !val.IsAwaitingDelivery)) { continue; } if (RaveConfig.DebugCoordinates.Value) { string text = "?"; try { text = npc.FirstName; } catch { } RaveMod.Logger.Msg("[DEBUG] NPC '" + text + "' has active deal \ufffd skipping for rave."); } return true; } catch { } } } catch { } return false; } private static void BlockCustomerDeals() { try { List unlockedCustomers = Customer.UnlockedCustomers; if (unlockedCustomers == null) { return; } for (int i = 0; i < unlockedCustomers.Count; i++) { Customer val = unlockedCustomers[i]; if ((Object)(object)val == (Object)null) { continue; } try { NPC nPC = val.NPC; if ((Object)(object)nPC == (Object)null || !_dancingNPCs.Contains(nPC) || !((Behaviour)val).enabled) { continue; } ((Behaviour)val).enabled = false; _blockedCustomers.Add(val); if (RaveConfig.DebugCoordinates.Value) { string text = "?"; try { text = nPC.FirstName; } catch { } RaveMod.Logger.Msg("[DEBUG] Customer '" + text + "' blocked from deals during rave."); } } catch { } } } catch { } } private static void UnblockCustomerDeals() { foreach (Customer blockedCustomer in _blockedCustomers) { try { if ((Object)(object)blockedCustomer != (Object)null && !((Il2CppObjectBase)blockedCustomer).WasCollected) { ((Behaviour)blockedCustomer).enabled = true; } } catch { } } _blockedCustomers.Clear(); } internal static void Cleanup() { ClearRaveEmotions(); UnblockCustomerDeals(); foreach (NPC dancingNPC in _dancingNPCs) { try { if ((Object)(object)dancingNPC == (Object)null) { continue; } TrySetCrouched(dancingNPC, crouched: false); TrySetHandsUp(dancingNPC, handsUp: false); try { NPCActions actions = dancingNPC.Actions; if ((Object)(object)actions != (Object)null) { actions.SetCanUseUmbrella(true); } } catch { } try { NPCBehaviour behaviour = dancingNPC.Behaviour; if ((Object)(object)behaviour != (Object)null) { ((Behaviour)behaviour).enabled = true; } } catch { } try { if (_npcScheduleManagers.TryGetValue(dancingNPC, out var value) && (Object)(object)value != (Object)null) { value.EnableSchedule(); } } catch { } try { if ((Object)(object)dancingNPC.Movement != (Object)null) { dancingNPC.Movement.SetAgentEnabled(true); dancingNPC.Movement.ResumeMovement(); } } catch { } try { if (_npcDisabledIndicators.TryGetValue(dancingNPC, out var value2) && value2 != null) { for (int i = 0; i < value2.Length; i++) { if ((Object)(object)value2[i] != (Object)null) { value2[i].enabled = true; } } } } catch { } try { if (!_npcDisabledColliders.TryGetValue(dancingNPC, out var value3) || value3 == null) { continue; } for (int j = 0; j < value3.Length; j++) { if ((Object)(object)value3[j] != (Object)null) { value3[j].enabled = true; } } } catch { } } catch { } } foreach (KeyValuePair npcAnimation in _npcAnimations) { try { if ((Object)(object)npcAnimation.Value != (Object)null) { ((Behaviour)npcAnimation.Value).enabled = true; } } catch { } } _dancingNPCs.Clear(); _npcStates.Clear(); _npcScheduleManagers.Clear(); _npcAnimators.Clear(); _npcAnimations.Clear(); _npcDisabledIndicators.Clear(); _npcDisabledColliders.Clear(); _globalTimer = 0f; _showcaseNPC = null; _showcaseEmotionIndex = 0; _showcaseTimer = 0f; _showcaseNPCTimer = 0f; _nextShowcaseNPCChange = 0f; } internal static void RewarpNPCs() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0073: 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_0094: Unknown result type (might be due to invalid IL or missing references) try { Vector3[] dancePositions = RaveLocationManager.DancePositions; if (dancePositions == null) { return; } int num = 0; foreach (NPC dancingNPC in _dancingNPCs) { if ((Object)(object)dancingNPC == (Object)null || (Object)(object)((Component)dancingNPC).gameObject == (Object)null) { num++; continue; } Vector3 val = ((num < dancePositions.Length) ? dancePositions[num] : RaveLocationManager.CenterPosition); ((Component)dancingNPC).transform.position = val; if (_npcStates.TryGetValue(dancingNPC, out var value)) { value.BasePosition = val; } num++; } } catch (Exception ex) { RaveMod.Logger.Error("Error re-warping NPCs: " + ex.Message); } } } public sealed class RavePlaylistManager { private static readonly string RAVE_FOLDER = Path.Combine(MelonEnvironment.UserDataDirectory, "Rave"); private static List _tracks = new List(); private static int[] _shuffledIndices; private static int _currentIndex = 0; private static Random _rng = new Random(); internal static int TrackCount => _tracks.Count; internal static IReadOnlyList AllTrackPaths => _tracks; private RavePlaylistManager() { } internal static void Initialize() { _tracks.Clear(); _shuffledIndices = null; _currentIndex = 0; try { if (!Directory.Exists(RAVE_FOLDER)) { Directory.CreateDirectory(RAVE_FOLDER); RaveMod.Logger.Msg("Rave folder created: " + Path.GetFullPath(RAVE_FOLDER)); } try { string[] files = Directory.GetFiles(RAVE_FOLDER, "*.wav"); foreach (string item in files) { _tracks.Add(item); } } catch (Exception ex) { RaveMod.Logger.Warning("Error scanning WAV files: " + ex.Message); } try { string[] files2 = Directory.GetFiles(RAVE_FOLDER, "*.mp3"); foreach (string item2 in files2) { _tracks.Add(item2); } } catch (Exception ex2) { RaveMod.Logger.Warning("Error scanning MP3 files: " + ex2.Message); } if (_tracks.Count == 0) { RaveMod.Logger.Warning("No WAV/MP3 files in: " + Path.GetFullPath(RAVE_FOLDER)); return; } ShufflePlaylist(); RaveMod.Logger.Msg($"Playlist: {_tracks.Count} tracks found and shuffled."); } catch (Exception ex3) { RaveMod.Logger.Error("Playlist error: " + ex3.Message); } } private static void ShufflePlaylist() { _shuffledIndices = new int[_tracks.Count]; for (int i = 0; i < _tracks.Count; i++) { _shuffledIndices[i] = i; } for (int num = _shuffledIndices.Length - 1; num >= 1; num--) { int num2 = _rng.Next(num + 1); int num3 = _shuffledIndices[num]; _shuffledIndices[num] = _shuffledIndices[num2]; _shuffledIndices[num2] = num3; } _currentIndex = 0; } internal static string GetNextTrack() { if (_tracks.Count == 0 || _shuffledIndices == null) { return null; } if (_currentIndex >= _shuffledIndices.Length) { ShufflePlaylist(); } int index = _shuffledIndices[_currentIndex]; _currentIndex++; string text = _tracks[index]; if (File.Exists(text)) { return text; } RaveMod.Logger.Warning("Track not found: " + Path.GetFileNameWithoutExtension(text)); return null; } internal static string PeekNextTrack() { if (_tracks.Count == 0 || _shuffledIndices == null) { return null; } int num = _currentIndex; if (num >= _shuffledIndices.Length) { num = 0; } string text = _tracks[_shuffledIndices[num]]; return File.Exists(text) ? text : null; } internal static string GetCurrentTrackName() { if (_tracks.Count == 0 || _shuffledIndices == null) { return null; } int num = _currentIndex - 1; if (num < 0 || num >= _shuffledIndices.Length) { return null; } return Path.GetFileNameWithoutExtension(_tracks[_shuffledIndices[num]]); } internal static void Cleanup() { } } namespace NLayer { 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 enum MpegChannelMode { Stereo, JointStereo, DualChannel, Mono } 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; } object seekLock = _seekLock; 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; object seekLock = _seekLock; 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 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; } case 8: buffer.SetValue((byte)Math.Round(127.5f * _readBuf[_readBufOfs / 4 + i] + 127.5f), index / 4 + i); 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(); } } } public enum MpegLayer { Unknown, LayerI, LayerII, LayerIII } public enum MpegVersion { Unknown = 0, Version1 = 10, Version2 = 20, Version25 = 25 } public enum StereoMode { Both, LeftOnly, RightOnly, DownmixToMono } } 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!"); } byte[] buf = _buf; 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) { return _reader.Read(Offset + offset, buffer, index, count); } 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; } protected int ReadByte(int offset) { if (_savedBuffer == null) { return _reader.ReadByte(Offset + offset); } if (offset < 0) { throw new ArgumentOutOfRangeException(); } if (offset >= _savedBuffer.Length) { return -1; } return _savedBuffer[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 b = DecodeSymbol(br, table); int num = b >> 4; int num2 = b & 0xF; int num3 = LIN_BITS[table]; if (num3 > 0 && num == 15) { num += br.GetBits(num3); } if (num != 0 && br.Get1Bit() != 0) { x = 0f - _floatLookup[num]; } else { x = _floatLookup[num]; } if (num3 > 0 && num2 == 15) { num2 += br.GetBits(num3); } if (num2 != 0 && br.Get1Bit() != 0) { y = 0f - _floatLookup[num2]; } else { y = _floatLookup[num2]; } } internal static void Decode(BitReservoir br, int table, out float x, out float y, out float v, out float w) { byte b = DecodeSymbol(br, table); v = (w = (x = (y = 0f))); if ((b & 8) != 0) { if (br.Get1Bit() == 1) { v = 0f - _floatLookup[1]; } else { v = _floatLookup[1]; } } if ((b & 4) != 0) { if (br.Get1Bit() == 1) { w = 0f - _floatLookup[1]; } else { w = _floatLookup[1]; } } if ((b & 2) != 0) { if (br.Get1Bit() == 1) { x = 0f - _floatLookup[1]; } else { x = _floatLookup[1]; } } if ((b & 1) != 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 list = new List(); List list2 = new List(); List list3 = new List(); 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) { if (tree[num, i] < 250) { bit = i; return num; } int result = FindPreviousNode(tree, num, out bit); if (bit != i) { throw new InvalidOperationException(); } return result; } } } } throw new InvalidOperationException(); } private static HuffmanListNode BuildLinkedList(List values, List lengthList, List codeList, out int maxBits) { HuffmanListNode[] array = new HuffmanListNode[lengthList.Count]; maxBits = lengthList.Max(); for (int i = 0; i < array.Length; i++) { int num = maxBits - lengthList[i]; array[i] = new HuffmanListNode { Value = values[i], Length = lengthList[i], Bits = codeList[i] << num, Mask = (1 << lengthList[i]) - 1 << num }; } Array.Sort(array, (HuffmanListNode huffmanListNode, HuffmanListNode huffmanListNode2) => huffmanListNode.Length - huffmanListNode2.Length); for (int num2 = 1; num2 < array.Length && array[num2].Length < 99999; num2++) { array[num2 - 1].Next = array[num2]; } 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) { return null; } if ((syncMark & 0xFF) == 43) { return new ID3Frame { _version = 1 }; } return new ID3Frame { _version = 0 }; } private ID3Frame() { } protected override int Validate() { switch (_version) { case 0: return 128; case 1: return 355; 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; } } return -1; } internal override void Parse() { switch (_version) { case 0: ParseV1(3); break; case 1: ParseV1Enh(); break; case 2: ParseV2(); 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 _synBuf = new List(2); private List _bufOffset = new List(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 j = 0; j < 15; j++) { _out[2 * j + k] = eo32[j]; _out[2 * j + 1 + k] = oo32[j] + oo32[j + 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 l = 0; l < 16; l++) { u_vec[num + l + 32] = 0f - cur_synbuf[k + 16 - l]; u_vec[num + l + 48] = 0f - cur_synbuf[k + l]; } 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) { return _rateLookupTable[4]; } 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]; } 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.JointStereo: _channels = 2; _jsbound = frame.ChannelModeExtension * 4 + 4; break; case MpegChannelMode.Mono: _channels = 1; _jsbound = 32; 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 = (float)Math.PI; private static float[][] _swin; private static float[] icos72_table; private List _prevBlock; private List _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 j = 0; j < 18; j++) { _swin[1][j] = (float)Math.Sin(0.0872664675116539 * ((double)j + 0.5)); } for (int k = 18; k < 24; k++) { _swin[1][k] = 1f; } for (int l = 24; l < 30; l++) { _swin[1][l] = (float)Math.Sin(0.2617993950843811 * ((double)l + 0.5 - 18.0)); } for (int m = 30; m < 36; m++) { _swin[1][m] = 0f; } for (int n = 0; n < 6; n++) { _swin[3][n] = 0f; } for (int num = 6; num < 12; num++) { _swin[3][num] = (float)Math.Sin(0.2617993950843811 * ((double)num + 0.5 - 6.0)); } for (int num2 = 12; num2 < 18; num2++) { _swin[3][num2] = 1f; } for (int num3 = 18; num3 < 36; num3++) { _swin[3][num3] = (float)Math.Sin(0.0872664675116539 * ((double)num3 + 0.5)); } for (int num4 = 0; num4 < 12; num4++) { _swin[2][num4] = (float)Math.Sin(0.2617993950843811 * ((double)num4 + 0.5)); } for (int num5 = 12; num5 < 36; num5++) { _swin[2][num5] = 0f; } } internal HybridMDCT() { _prevBlock = new List(); _nextBlock = new List(); } 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 j = 5; j < 9; j++) { outvec[j] = array[8 - j] - array2[8 - j]; } } private void ShortImpl(float[] fsIn, int sbStart, float[] nextblck) { float[] array = _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(_imdctTemp, 6, _imdctResult); for (int k = 0; k < 6; k++) { fsIn[num2 + k + 12] += _imdctResult[k]; } Array.Copy(_imdctResult, 6, nextblck, num2, 6); ShortIMDCT(_imdctTemp, 12, _imdctResult); for (int l = 0; l < 6; l++) { nextblck[num2 + l] += _imdctResult[l]; } Array.Copy(_imdctResult, 6, nextblck, num2 + 6, 6); Array.Clear(nextblck, num2 + 12, 6); num++; num2 += 18; } } private static void ShortIMDCT(float[] invec, int inIdx, float[] outvec) { float[] array = new float[6]; float[] array2 = new float[6]; float[] array3 = new float[3]; float[] array4 = new float[3]; int num = inIdx; for (int i = 1; i < 6; i++) { array[i] = invec[num]; array[i] += invec[++num]; } float num2 = array[4] / 2f + invec[inIdx]; float num3 = array[2] * 0.8660254f; array3[0] = num2 + num3; array3[1] = invec[inIdx] - array[4]; array3[2] = num2 - num3; float num4 = array[3] + array[5]; num2 = num4 / 2f + array[1]; num3 = (array[1] + array[3]) * 0.8660254f; array4[0] = num2 + num3; array4[1] = array[1] - num4; array4[2] = num2 - num3; array4[0] *= 0.5176381f; array4[1] *= 0.70710677f; array4[2] *= 1.9318516f; array2[0] = (array3[0] + array4[0]) * 0.5043145f; array2[1] = (array3[1] + array4[1]) * 0.5411961f; array2[2] = (array3[2] + array4[2]) * 0.6302362f; array2[3] = (array3[2] - array4[2]) * 0.82133985f; array2[4] = (array3[1] - array4[1]) * 1.306563f; array2[5] = (array3[0] - array4[0]) * 3.830649f; outvec[0] = array2[3] * _swin[2][0]; outvec[1] = array2[4] * _swin[2][1]; outvec[2] = array2[5] * _swin[2][2]; outvec[3] = (0f - array2[5]) * _swin[2][3]; outvec[4] = (0f - array2[4]) * _swin[2][4]; outvec[5] = (0f - array2[3]) * _swin[2][5]; outvec[6] = (0f - array2[2]) * _swin[2][6]; outvec[7] = (0f - array2[1]) * _swin[2][7]; outvec[8] = (0f - array2[0]) * _swin[2][8]; outvec[9] = (0f - array2[0]) * _swin[2][9]; outvec[10] = (0f - array2[1]) * _swin[2][10]; outvec[11] = (0f - array2[2]) * _swin[2][11]; } } private const int SSLIMIT = 18; private HybridMDCT _hybrid = new HybridMDCT(); private BitReservoir _bitRes = new BitReservoir(); private int _channels; private int _privBits; private int _mainDataBegin; private int[][] _scfsi = new int[2][] { new int[4], new int[4] }; private int[][] _part23Length = new int[2][] { new int[2], new int[2] }; private int[][] _bigValues = new int[2][] { new int[2], new int[2] }; private float[][] _globalGain = new float[2][] { new float[2], new float[2] }; private int[][] _scalefacCompress = new int[2][] { new int[2], new int[2] }; private bool[][] _blockSplitFlag = new bool[2][] { new bool[2], new bool[2] }; private bool[][] _mixedBlockFlag = new bool[2][] { new bool[2], new bool[2] }; private int[][] _blockType = new int[2][] { new int[2], new int[2] }; private int[][][] _tableSelect; private float[][][] _subblockGain; private int[][] _regionAddress1 = new int[2][] { new int[2], new int[2] }; private int[][] _regionAddress2 = new int[2][] { new int[2], new int[2] }; private int[][] _preflag = new int[2][] { new int[2], new int[2] }; private float[][] _scalefacScale = new float[2][] { new float[2], new float[2] }; private int[][] _count1TableSelect = new int[2][] { new int[2], new int[2] }; private static float[] GAIN_TAB; private int[] _sfBandIndexL; private int[] _sfBandIndexS; private byte[] _cbLookupL = new byte[576]; private byte[] _cbLookupS = new byte[576]; private byte[] _cbwLookupS = new byte[576]; private int _cbLookupSR; private static readonly int[][] _sfBandIndexLTable; private static readonly int[][] _sfBandIndexSTable; private int[][][] _scalefac = new int[2][][] { new int[4][] { new int[13], new int[13], new int[13], new int[23] }, new int[4][] { new int[13], new int[13], new int[13], new int[23] } }; private static readonly int[][] _slen; private static readonly int[][][] _sfbBlockCntTab; private float[][] _samples = new float[2][] { new float[579], new float[579] }; private static readonly int[] PRETAB; private static readonly float[] POW2_TAB; private static readonly float[][] _isRatio; private static readonly float[][][] _lsfRatio; private float[] _reorderBuf = new float[576]; private static readonly float[] _scs; private static readonly float[] _sca; private float[] _polyPhase = new float[32]; internal static bool GetCRC(MpegFrame frame, ref uint crc) { int num = frame.GetSideDataSize(); while (--num >= 0) { MpegFrame.UpdateCRC(frame.ReadBits(8), 8, ref crc); } return true; } internal LayerIIIDecoder() { _tableSelect = new int[2][][] { new int[2][] { new int[3], new int[3] }, new int[2][] { new int[3], new int[3] } }; _subblockGain = new float[2][][] { new float[2][] { new float[3], new float[3] }, new float[2][] { new float[3], new float[3] } }; } internal override int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1) { ReadSideInfo(frame); if (!_bitRes.AddBits(frame, _mainDataBegin)) { return 0; } PrepTables(frame); float[][] array = new float[2][]; int num = 0; int num2 = _channels - 1; if (_channels == 1 || base.StereoMode == StereoMode.LeftOnly || base.StereoMode == StereoMode.DownmixToMono) { 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 = ((frame.Version != MpegVersion.Version1) ? 1 : 2); int num4 = 0; for (int i = 0; i < num3; i++) { for (int j = 0; j < _channels; j++) { int sfBits = ((frame.Version != MpegVersion.Version1) ? ReadLsfScalefactors(i, j, frame.ChannelModeExtension) : ReadScalefactors(i, j)); ReadSamples(sfBits, i, j); } Stereo(frame.ChannelMode, frame.ChannelModeExtension, i, frame.Version != MpegVersion.Version1); for (int k = num; k <= num2; k++) { float[] array2 = _samples[k]; int num5 = _blockType[i][k]; bool flag = _blockSplitFlag[i][k]; bool flag2 = _mixedBlockFlag[i][k]; if (flag && num5 == 2) { if (flag2) { Reorder(array2, mixedBlock: true); AntiAlias(array2, mixedBlock: true); } else { Reorder(array2, mixedBlock: false); } } else { AntiAlias(array2, mixedBlock: false); } _hybrid.Apply(array2, k, num5, flag && flag2); FrequencyInversion(array2); InversePolyphase(array2, k, num4, array[k]); } num4 += 576; } return num4; } internal override void ResetForSeek() { base.ResetForSeek(); _hybrid.Reset(); _bitRes.Reset(); } private void ReadSideInfo(IMpegFrame frame) { if (frame.Version == MpegVersion.Version1) { _mainDataBegin = frame.ReadBits(9); if (frame.ChannelMode == MpegChannelMode.Mono) { _privBits = frame.ReadBits(5); _channels = 1; } else { _privBits = frame.ReadBits(3); _channels = 2; } for (int i = 0; i < _channels; i++) { _scfsi[i][0] = frame.ReadBits(1); _scfsi[i][1] = frame.ReadBits(1); _scfsi[i][2] = frame.ReadBits(1); _scfsi[i][3] = frame.ReadBits(1); } for (int j = 0; j < 2; j++) { for (int k = 0; k < _channels; k++) { _part23Length[j][k] = frame.ReadBits(12); _bigValues[j][k] = frame.ReadBits(9); _globalGain[j][k] = GAIN_TAB[frame.ReadBits(8)]; _scalefacCompress[j][k] = frame.ReadBits(4); _blockSplitFlag[j][k] = frame.ReadBits(1) == 1; if (_blockSplitFlag[j][k]) { _blockType[j][k] = frame.ReadBits(2); _mixedBlockFlag[j][k] = frame.ReadBits(1) == 1; _tableSelect[j][k][0] = frame.ReadBits(5); _tableSelect[j][k][1] = frame.ReadBits(5); _tableSelect[j][k][2] = 0; if (_blockType[j][k] == 2 && !_mixedBlockFlag[j][k]) { _regionAddress1[j][k] = 8; } else { _regionAddress1[j][k] = 7; } _regionAddress2[j][k] = 20 - _regionAddress1[j][k]; _subblockGain[j][k][0] = (float)frame.ReadBits(3) * -2f; _subblockGain[j][k][1] = (float)frame.ReadBits(3) * -2f; _subblockGain[j][k][2] = (float)frame.ReadBits(3) * -2f; } else { _tableSelect[j][k][0] = frame.ReadBits(5); _tableSelect[j][k][1] = frame.ReadBits(5); _tableSelect[j][k][2] = frame.ReadBits(5); _regionAddress1[j][k] = frame.ReadBits(4); _regionAddress2[j][k] = frame.ReadBits(3); _blockType[j][k] = 0; _subblockGain[j][k][0] = 0f; _subblockGain[j][k][1] = 0f; _subblockGain[j][k][2] = 0f; } _preflag[j][k] = frame.ReadBits(1); _scalefacScale[j][k] = 0.5f * (1f + (float)frame.ReadBits(1)); _count1TableSelect[j][k] = frame.ReadBits(1); } } return; } _mainDataBegin = frame.ReadBits(8); if (frame.ChannelMode == MpegChannelMode.Mono) { _privBits = frame.ReadBits(1); _channels = 1; } else { _privBits = frame.ReadBits(2); _channels = 2; } int num = 0; for (int l = 0; l < _channels; l++) { _part23Length[num][l] = frame.ReadBits(12); _bigValues[num][l] = frame.ReadBits(9); _globalGain[num][l] = GAIN_TAB[frame.ReadBits(8)]; _scalefacCompress[num][l] = frame.ReadBits(9); _blockSplitFlag[num][l] = frame.ReadBits(1) == 1; if (_blockSplitFlag[num][l]) { _blockType[num][l] = frame.ReadBits(2); _mixedBlockFlag[num][l] = frame.ReadBits(1) == 1; _tableSelect[num][l][0] = frame.ReadBits(5); _tableSelect[num][l][1] = frame.ReadBits(5); _tableSelect[num][l][2] = 0; if (_blockType[num][l] == 2 && !_mixedBlockFlag[num][l]) { _regionAddress1[num][l] = 8; } else { _regionAddress1[num][l] = 7; } _regionAddress2[num][l] = 20 - _regionAddress1[num][l]; _subblockGain[num][l][0] = (float)frame.ReadBits(3) * -2f; _subblockGain[num][l][1] = (float)frame.ReadBits(3) * -2f; _subblockGain[num][l][2] = (float)frame.ReadBits(3) * -2f; } else { _tableSelect[num][l][0] = frame.ReadBits(5); _tableSelect[num][l][1] = frame.ReadBits(5); _tableSelect[num][l][2] = frame.ReadBits(5); _regionAddress1[num][l] = frame.ReadBits(4); _regionAddress2[num][l] = frame.ReadBits(3); _blockType[num][l] = 0; _subblockGain[num][l][0] = 0f; _subblockGain[num][l][1] = 0f; _subblockGain[num][l][2] = 0f; } _scalefacScale[num][l] = 0.5f * (1f + (float)frame.ReadBits(1)); _count1TableSelect[num][l] = frame.ReadBits(1); } } private void PrepTables(IMpegFrame frame) { if (_cbLookupSR == frame.SampleRate) { return; } switch (frame.SampleRate) { case 11025: _sfBandIndexL = _sfBandIndexLTable[6]; _sfBandIndexS = _sfBandIndexSTable[6]; break; case 8000: _sfBandIndexL = _sfBandIndexLTable[8]; _sfBandIndexS = _sfBandIndexSTable[8]; break; case 16000: _sfBandIndexL = _sfBandIndexLTable[5]; _sfBandIndexS = _sfBandIndexSTable[5]; break; case 12000: _sfBandIndexL = _sfBandIndexLTable[7]; _sfBandIndexS = _sfBandIndexSTable[7]; break; case 24000: _sfBandIndexL = _sfBandIndexLTable[4]; _sfBandIndexS = _sfBandIndexSTable[4]; break; case 22050: _sfBandIndexL = _sfBandIndexLTable[3]; _sfBandIndexS = _sfBandIndexSTable[3]; break; case 48000: _sfBandIndexL = _sfBandIndexLTable[1]; _sfBandIndexS = _sfBandIndexSTable[1]; break; case 44100: _sfBandIndexL = _sfBandIndexLTable[0]; _sfBandIndexS = _sfBandIndexSTable[0]; break; case 32000: _sfBandIndexL = _sfBandIndexLTable[2]; _sfBandIndexS = _sfBandIndexSTable[2]; break; } int num = 0; int num2 = 0; int num3 = _sfBandIndexL[1]; int num4 = _sfBandIndexS[1] * 3; for (int i = 0; i < 576; i++) { if (i == num3) { num++; num3 = _sfBandIndexL[num + 1]; } if (i == num4) { num2++; num4 = _sfBandIndexS[num2 + 1] * 3; } _cbLookupL[i] = (byte)num; _cbLookupS[i] = (byte)num2; } int num5 = 0; for (num2 = 0; num2 < 12; num2++) { int num6 = _sfBandIndexS[num2 + 1] - _sfBandIndexS[num2]; for (int j = 0; j < 3; j++) { int num7 = 0; while (num7 < num6) { _cbwLookupS[num5] = (byte)j; num7++; num5++; } } } _cbLookupSR = frame.SampleRate; } private int ReadScalefactors(int gr, int ch) { int num = _slen[0][_scalefacCompress[gr][ch]]; int num2 = _slen[1][_scalefacCompress[gr][ch]]; int i = 0; int num3; if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2) { if (num > 0) { num3 = num * 18; if (_mixedBlockFlag[gr][ch]) { for (; i < 8; i++) { _scalefac[ch][3][i] = _bitRes.GetBits(num); } i = 3; num3 -= num; } for (; i < 6; i++) { _scalefac[ch][0][i] = _bitRes.GetBits(num); _scalefac[ch][1][i] = _bitRes.GetBits(num); _scalefac[ch][2][i] = _bitRes.GetBits(num); } } else { Array.Clear(_scalefac[ch][3], 0, 8); Array.Clear(_scalefac[ch][0], 0, 6); Array.Clear(_scalefac[ch][1], 0, 6); Array.Clear(_scalefac[ch][2], 0, 6); num3 = 0; } if (num2 > 0) { num3 += num2 * 18; for (i = 6; i < 12; i++) { _scalefac[ch][0][i] = _bitRes.GetBits(num2); _scalefac[ch][1][i] = _bitRes.GetBits(num2); _scalefac[ch][2][i] = _bitRes.GetBits(num2); } } else { Array.Clear(_scalefac[ch][0], 6, 6); Array.Clear(_scalefac[ch][1], 6, 6); Array.Clear(_scalefac[ch][2], 6, 6); } } else { num3 = 0; if (gr == 0 || _scfsi[ch][0] == 0) { if (num > 0) { num3 += num * 6; _scalefac[ch][3][0] = _bitRes.GetBits(num); _scalefac[ch][3][1] = _bitRes.GetBits(num); _scalefac[ch][3][2] = _bitRes.GetBits(num); _scalefac[ch][3][3] = _bitRes.GetBits(num); _scalefac[ch][3][4] = _bitRes.GetBits(num); _scalefac[ch][3][5] = _bitRes.GetBits(num); } else { Array.Clear(_scalefac[ch][3], 0, 6); } } if (gr == 0 || _scfsi[ch][1] == 0) { if (num > 0) { num3 += num * 5; _scalefac[ch][3][6] = _bitRes.GetBits(num); _scalefac[ch][3][7] = _bitRes.GetBits(num); _scalefac[ch][3][8] = _bitRes.GetBits(num); _scalefac[ch][3][9] = _bitRes.GetBits(num); _scalefac[ch][3][10] = _bitRes.GetBits(num); } else { Array.Clear(_scalefac[ch][3], 6, 5); } } if (gr == 0 || _scfsi[ch][2] == 0) { if (num2 > 0) { num3 += num2 * 5; _scalefac[ch][3][11] = _bitRes.GetBits(num2); _scalefac[ch][3][12] = _bitRes.GetBits(num2); _scalefac[ch][3][13] = _bitRes.GetBits(num2); _scalefac[ch][3][14] = _bitRes.GetBits(num2); _scalefac[ch][3][15] = _bitRes.GetBits(num2); } else { Array.Clear(_scalefac[ch][3], 11, 5); } } if (gr == 0 || _scfsi[ch][3] == 0) { if (num2 > 0) { num3 += num2 * 5; _scalefac[ch][3][16] = _bitRes.GetBits(num2); _scalefac[ch][3][17] = _bitRes.GetBits(num2); _scalefac[ch][3][18] = _bitRes.GetBits(num2); _scalefac[ch][3][19] = _bitRes.GetBits(num2); _scalefac[ch][3][20] = _bitRes.GetBits(num2); } else { Array.Clear(_scalefac[ch][3], 16, 5); } } } return num3; } private int ReadLsfScalefactors(int gr, int ch, int chanModeExt) { int num = _scalefacCompress[gr][ch]; int num2 = ((_blockType[gr][ch] == 2) ? ((!_mixedBlockFlag[gr][ch]) ? 1 : 2) : 0); int[] array = new int[4]; int num4; if ((chanModeExt & 1) == 1 && ch == 1) { int num3 = num >> 1; if (num3 < 180) { array[0] = num3 / 36; array[1] = num3 % 36 / 6; array[2] = num3 % 6; array[3] = 0; _preflag[gr][ch] = 0; num4 = 3; } else if (num3 < 244) { array[0] = (num3 - 180) % 64 >> 4; array[1] = (num3 - 180) % 16 >> 2; array[2] = (num3 - 180) % 4; array[3] = 0; _preflag[gr][ch] = 0; num4 = 4; } else if (num3 < 255) { array[0] = (num3 - 244) / 3; array[1] = (num3 - 244) % 3; array[2] = 0; array[3] = 0; _preflag[gr][ch] = 0; num4 = 5; } else { num4 = 0; } } else if (num < 400) { array[0] = (num >> 4) / 5; array[1] = (num >> 4) % 5; array[2] = (num & 0xF) >> 2; array[3] = num & 3; _preflag[gr][ch] = 0; num4 = 0; } else if (num < 500) { array[0] = (num - 400 >> 2) / 5; array[1] = (num - 400 >> 2) % 5; array[2] = (num - 400) & 3; array[3] = 0; _preflag[gr][ch] = 0; num4 = 1; } else if (num < 512) { array[0] = (num - 500) / 3; array[1] = (num - 500) % 3; array[2] = 0; array[3] = 0; _preflag[gr][ch] = 1; num4 = 2; } else { num4 = 0; } int[] array2 = new int[54]; int num5 = 0; int[] array3 = _sfbBlockCntTab[num4][num2]; for (int i = 0; i < 4; i++) { if (array[i] != 0) { int num6 = 0; while (num6 < array3[i]) { array2[num5] = _bitRes.GetBits(array[i]); num6++; num5++; } } else { num5 += array3[i]; } } num5 = 0; int j = 0; if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2) { if (_mixedBlockFlag[gr][ch]) { for (; j < 8; j++) { _scalefac[ch][3][j] = array2[num5++]; } j = 3; } for (; j < 12; j++) { for (int k = 0; k < 3; k++) { _scalefac[ch][k][j] = array2[num5++]; } } _scalefac[ch][0][12] = 0; _scalefac[ch][1][12] = 0; _scalefac[ch][2][12] = 0; } else { for (; j < 21; j++) { _scalefac[ch][3][j] = array2[num5++]; } _scalefac[ch][3][22] = 0; } return array[0] * array3[0] + array[1] * array3[1] + array[2] * array3[2] + array[3] * array3[3]; } private void ReadSamples(int sfBits, int gr, int ch) { int num; int num2; if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2) { num = 36; num2 = 576; } else { num = _sfBandIndexL[_regionAddress1[gr][ch] + 1]; num2 = _sfBandIndexL[Math.Min(_regionAddress1[gr][ch] + _regionAddress2[gr][ch] + 2, 22)]; } long num3 = _bitRes.BitsRead - sfBits + _part23Length[gr][ch]; int num4 = 0; int table = _tableSelect[gr][ch][0]; int num5 = _bigValues[gr][ch] * 2; while (num4 < num5 && num4 < num) { Huffman.Decode(_bitRes, table, out var x, out var y); _samples[ch][num4] = Dequantize(num4, x, gr, ch); num4++; _samples[ch][num4] = Dequantize(num4, y, gr, ch); num4++; } table = _tableSelect[gr][ch][1]; while (num4 < num5 && num4 < num2) { Huffman.Decode(_bitRes, table, out var x2, out var y2); _samples[ch][num4] = Dequantize(num4, x2, gr, ch); num4++; _samples[ch][num4] = Dequantize(num4, y2, gr, ch); num4++; } table = _tableSelect[gr][ch][2]; while (num4 < num5) { Huffman.Decode(_bitRes, table, out var x3, out var y3); _samples[ch][num4] = Dequantize(num4, x3, gr, ch); num4++; _samples[ch][num4] = Dequantize(num4, y3, gr, ch); num4++; } table = _count1TableSelect[gr][ch] + 32; while (num3 > _bitRes.BitsRead && num4 < 573) { Huffman.Decode(_bitRes, table, out var x4, out var y4, out var v, out var w); _samples[ch][num4] = Dequantize(num4, v, gr, ch); num4++; _samples[ch][num4] = Dequantize(num4, w, gr, ch); num4++; _samples[ch][num4] = Dequantize(num4, x4, gr, ch); num4++; _samples[ch][num4] = Dequantize(num4, y4, gr, ch); num4++; } if (_bitRes.BitsRead > num3) { _bitRes.RewindBits((int)(_bitRes.BitsRead - num3)); num4 -= 4; if (num4 < 0) { num4 = 0; } } if (_bitRes.BitsRead < num3) { _bitRes.SkipBits((int)(num3 - _bitRes.BitsRead)); } if (num4 < 576) { Array.Clear(_samples[ch], num4, 579 - num4); } } private float Dequantize(int idx, float val, int gr, int ch) { if (val == 0f) { return 0f; } int num; if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2 && (!_mixedBlockFlag[gr][ch] || idx >= _sfBandIndexL[8])) { num = _cbLookupS[idx]; int num2 = _cbwLookupS[idx]; return val * _globalGain[gr][ch] * POW2_TAB[(int)(-2f * (_subblockGain[gr][ch][num2] - _scalefacScale[gr][ch] * (float)_scalefac[ch][num2][num]))]; } num = _cbLookupL[idx]; return val * _globalGain[gr][ch] * POW2_TAB[(int)(2f * _scalefacScale[gr][ch] * (float)(_scalefac[ch][3][num] + _preflag[gr][ch] * PRETAB[num]))]; } private void Stereo(MpegChannelMode channelMode, int chanModeExt, int gr, bool lsf) { if (channelMode != MpegChannelMode.JointStereo || chanModeExt == 0) { if (_channels != 1) { ApplyFullStereo(0, 576); } return; } bool flag = (chanModeExt & 2) == 2; if ((chanModeExt & 1) == 1) { int num = -1; for (int num2 = 543; num2 >= 0; num2--) { if (_samples[1][num2] != 0f) { num = num2; break; } } int num3 = -1; int num4 = -1; if (_blockSplitFlag[gr][0] && _blockType[gr][0] == 2) { if (_mixedBlockFlag[gr][0]) { if (num < _sfBandIndexL[8]) { num3 = 8; } num4 = 3; } else { num4 = 0; } } else { num3 = 21; } int i = 0; if (num > -1) { i = _cbLookupL[num] + 1; } if (i > 0 && num4 == -1) { if (flag) { ApplyMidSide(0, _sfBandIndexL[i]); } else { ApplyFullStereo(0, _sfBandIndexL[i]); } } for (; i < num3; i++) { int i2 = _sfBandIndexL[i]; int sb = _sfBandIndexL[i + 1] - _sfBandIndexL[i]; int num5 = _scalefac[1][3][i]; if (num5 == 7) { if (flag) { ApplyMidSide(i2, sb); } else { ApplyFullStereo(i2, sb); } } else if (lsf) { ApplyLsfIStereo(i2, sb, num5, _scalefacCompress[gr][0]); } else { ApplyIStereo(i2, sb, num5); } } if (num4 > -1) { int[] array = new int[3] { -1, -1, -1 }; int num6; if (num > -1) { i = _cbLookupS[num]; num6 = _cbwLookupS[num]; array[num6] = i; } else { i = 12; num6 = 3; } num6 = (num6 - 1) % 3; while (i >= num4 && num6 >= 0) { if (array[num6] != -1) { if (array[0] != -1 && array[1] != -1 && array[2] != -1) { break; } } else { int num7 = _sfBandIndexS[i + 1] - _sfBandIndexS[i]; int num8 = _sfBandIndexS[i] * 3 + num7 * (num6 + 1); while (--num7 >= -1) { if (_samples[1][--num8] != 0f) { array[num6] = i; break; } } if (num6 == 0) { i--; } } num6 = (num6 - 1) % 3; } for (i = num4; i < 12; i++) { int num9 = _sfBandIndexS[i + 1] - _sfBandIndexS[i]; int num10 = _sfBandIndexS[i] * 3; for (num6 = 0; num6 < 3; num6++) { if (i > array[num6]) { int num11 = _scalefac[1][num6][i]; if (num11 == 7) { if (flag) { ApplyMidSide(num10, num9); } else { ApplyFullStereo(num10, num9); } } else if (lsf) { ApplyLsfIStereo(num10, num9, num11, _scalefacCompress[gr][0]); } else { ApplyIStereo(num10, num9, num11); } } else if (flag) { ApplyMidSide(num10, num9); } else { ApplyFullStereo(num10, num9); } num10 += num9; } } int num12 = _sfBandIndexS[13] - _sfBandIndexS[12]; for (num6 = 0; num6 < 3; num6++) { int num13 = _scalefac[1][num6][11]; if (num13 == 7) { if (flag) { ApplyMidSide(_sfBandIndexS[11] * 3 + num12 * num6, num12); } else { ApplyFullStereo(_sfBandIndexS[11] * 3 + num12 * num6, num12); } } else if (lsf) { ApplyLsfIStereo(_sfBandIndexS[11] * 3 + num12 * num6, num12, num13, _scalefacCompress[gr][0]); } else { ApplyIStereo(_sfBandIndexS[11] * 3 + num12 * num6, num12, num13); } } return; } int num14 = _scalefac[1][3][20]; if (num14 == 7) { if (flag) { ApplyMidSide(_sfBandIndexL[21], 576 - _sfBandIndexL[21]); } else { ApplyFullStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21]); } } else if (lsf) { ApplyLsfIStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21], num14, _scalefacCompress[gr][0]); } else { ApplyIStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21], num14); } } else if (flag) { ApplyMidSide(0, 576); } else { ApplyFullStereo(0, 576); } } private void ApplyIStereo(int i, int sb, int isPos) { if (base.StereoMode == StereoMode.DownmixToMono) { while (sb > 0) { _samples[0][i] /= 2f; sb--; i++; } return; } float num = _isRatio[0][isPos]; float num2 = _isRatio[1][isPos]; while (sb > 0) { _samples[1][i] = _samples[0][i] * num2; _samples[0][i] *= num; sb--; i++; } } private void ApplyLsfIStereo(int i, int sb, int isPos, int scalefacCompress) { float num = _lsfRatio[scalefacCompress % 1][isPos][0]; float num2 = _lsfRatio[scalefacCompress % 1][isPos][1]; if (base.StereoMode == StereoMode.DownmixToMono) { float num3 = 1f / (num + num2); while (sb > 0) { _samples[0][i] *= num3; sb--; i++; } } else { while (sb > 0) { _samples[1][i] = _samples[0][i] * num2; _samples[0][i] *= num; sb--; i++; } } } private void ApplyMidSide(int i, int sb) { if (base.StereoMode == StereoMode.DownmixToMono) { while (sb > 0) { _samples[0][i] *= 0.70710677f; sb--; i++; } return; } while (sb > 0) { float num = _samples[0][i]; float num2 = _samples[1][i]; _samples[0][i] = (num + num2) * 0.70710677f; _samples[1][i] = (num - num2) * 0.70710677f; sb--; i++; } } private void ApplyFullStereo(int i, int sb) { if (base.StereoMode == StereoMode.DownmixToMono) { while (sb > 0) { _samples[0][i] = (_samples[0][i] + _samples[1][i]) / 2f; sb--; i++; } } } private void Reorder(float[] buf, bool mixedBlock) { int i = 0; if (mixedBlock) { Array.Copy(buf, 0, _reorderBuf, 0, 36); i = 3; } for (; i < 13; i++) { int num = _sfBandIndexS[i]; int num2 = _sfBandIndexS[i + 1] - num; for (int j = 0; j < 3; j++) { for (int k = 0; k < num2; k++) { int num3 = num * 3 + j * num2 + k; int num4 = num * 3 + j + k * 3; _reorderBuf[num4] = buf[num3]; } } } Array.Copy(_reorderBuf, buf, 576); } private void AntiAlias(float[] buf, bool mixedBlock) { int num = (mixedBlock ? 1 : 31); int num2 = 0; int num3 = 0; while (num2 < num) { int num4 = 0; int num5 = num3 + 18 - 1; int num6 = num3 + 18; while (num4 < 8) { float num7 = buf[num5]; float num8 = buf[num6]; buf[num5] = num7 * _scs[num4] - num8 * _sca[num4]; buf[num6] = num8 * _scs[num4] + num7 * _sca[num4]; num4++; num5--; num6++; } num2++; num3 += 18; } } private void FrequencyInversion(float[] buf) { for (int i = 1; i < 18; i += 2) { for (int j = 1; j < 32; j += 2) { buf[j * 18 + i] = 0f - buf[j * 18 + i]; } } } private void InversePolyphase(float[] buf, int ch, int ofs, float[] outBuf) { int num = 0; while (num < 18) { for (int i = 0; i < 32; i++) { _polyPhase[i] = buf[i * 18 + num]; } InversePolyPhase(ch, _polyPhase); Array.Copy(_polyPhase, 0, outBuf, ofs, 32); num++; ofs += 32; } } static LayerIIIDecoder() { GAIN_TAB = new float[256] { 1.5700924E-16f, 1.8671652E-16f, 2.220446E-16f, 2.6405702E-16f, 3.1401849E-16f, 3.7343303E-16f, 4.440892E-16f, 5.2811403E-16f, 6.2803697E-16f, 7.4686606E-16f, 8.881784E-16f, 1.0562281E-15f, 1.2560739E-15f, 1.4937321E-15f, 1.7763568E-15f, 2.1124561E-15f, 2.5121479E-15f, 2.9874642E-15f, 3.5527137E-15f, 4.2249122E-15f, 5.0242958E-15f, 5.9749285E-15f, 7.1054274E-15f, 8.4498245E-15f, 1.00485916E-14f, 1.1949857E-14f, 1.4210855E-14f, 1.6899649E-14f, 2.0097183E-14f, 2.3899714E-14f, 2.842171E-14f, 3.3799298E-14f, 4.0194366E-14f, 4.7799428E-14f, 5.684342E-14f, 6.7598596E-14f, 8.038873E-14f, 9.5598856E-14f, 1.1368684E-13f, 1.3519719E-13f, 1.6077747E-13f, 1.9119771E-13f, 2.2737368E-13f, 2.7039438E-13f, 3.2155493E-13f, 3.8239542E-13f, 4.5474735E-13f, 5.4078877E-13f, 6.4310986E-13f, 7.6479085E-13f, 9.094947E-13f, 1.0815775E-12f, 1.2862197E-12f, 1.5295817E-12f, 1.8189894E-12f, 2.163155E-12f, 2.5724394E-12f, 3.0591634E-12f, 3.637979E-12f, 4.32631E-12f, 5.144879E-12f, 6.1183268E-12f, 7.275958E-12f, 8.65262E-12f, 1.0289758E-11f, 1.22366535E-11f, 1.4551915E-11f, 1.730524E-11f, 2.0579516E-11f, 2.4473307E-11f, 2.910383E-11f, 3.461048E-11f, 4.115903E-11f, 4.8946614E-11f, 5.820766E-11f, 6.922096E-11f, 8.231806E-11f, 9.789323E-11f, 1.1641532E-10f, 1.3844192E-10f, 1.6463612E-10f, 1.9578646E-10f, 2.3283064E-10f, 2.7688385E-10f, 3.2927225E-10f, 3.915729E-10f, 4.656613E-10f, 5.537677E-10f, 6.585445E-10f, 7.831458E-10f, 9.313226E-10f, 1.1075354E-09f, 1.317089E-09f, 1.5662917E-09f, 1.8626451E-09f, 2.2150708E-09f, 2.634178E-09f, 3.1325833E-09f, 3.7252903E-09f, 4.4301416E-09f, 5.268356E-09f, 6.2651666E-09f, 7.450581E-09f, 8.860283E-09f, 1.0536712E-08f, 1.2530333E-08f, 1.4901161E-08f, 1.7720566E-08f, 2.1073424E-08f, 2.5060666E-08f, 2.9802322E-08f, 3.5441133E-08f, 4.2146848E-08f, 5.0121333E-08f, 5.9604645E-08f, 7.0882265E-08f, 8.4293696E-08f, 1.00242666E-07f, 1.1920929E-07f, 1.4176453E-07f, 1.6858739E-07f, 2.0048533E-07f, 2.3841858E-07f, 2.8352906E-07f, 3.3717478E-07f, 4.0097066E-07f, 4.7683716E-07f, 5.670581E-07f, 6.7434956E-07f, 8.019413E-07f, 9.536743E-07f, 1.1341162E-06f, 1.3486991E-06f, 1.6038827E-06f, 1.9073486E-06f, 2.2682325E-06f, 2.6973983E-06f, 3.2077653E-06f, 3.8146973E-06f, 4.536465E-06f, 5.3947965E-06f, 6.4155306E-06f, 7.6293945E-06f, 9.07293E-06f, 1.0789593E-05f, 1.2831061E-05f, 1.5258789E-05f, 1.814586E-05f, 2.1579186E-05f, 2.5662122E-05f, 3.0517578E-05f, 3.629172E-05f, 4.3158372E-05f, 5.1324245E-05f, 6.1035156E-05f, 7.258344E-05f, 8.6316744E-05f, 0.00010264849f, 0.00012207031f, 0.00014516688f, 0.00017263349f, 0.00020529698f, 0.00024414062f, 0.00029033376f, 0.00034526698f, 0.00041059396f, 0.00048828125f, 0.0005806675f, 0.00069053395f, 0.0008211879f, 0.0009765625f, 0.001161335f, 0.0013810679f, 0.0016423758f, 0.001953125f, 0.00232267f, 0.0027621358f, 0.0032847517f, 0.00390625f, 0.00464534f, 0.0055242716f, 0.0065695033f, 1f / 128f, 0.00929068f, 0.011048543f, 0.013139007f, 1f / 64f, 0.01858136f, 0.022097087f, 0.026278013f, 1f / 32f, 0.03716272f, 0.044194173f, 0.052556027f, 0.0625f, 0.07432544f, 0.088388346f, 0.10511205f, 0.125f, 0.14865088f, 0.17677669f, 0.2102241f, 0.25f, 0.29730177f, 0.35355338f, 0.4204482f, 0.5f, 0.59460354f, 0.70710677f, 0.8408964f, 1f, 1.1892071f, 1.4142135f, 1.6817929f, 2f, 2.3784142f, 2.828427f, 3.3635857f, 4f, 4.7568283f, 5.656854f, 6.7271714f, 8f, 9.513657f, 11.313708f, 13.454343f, 16f, 19.027313f, 22.627417f, 26.908686f, 32f, 38.054626f, 45.254833f, 53.81737f, 64f, 76.10925f, 90.50967f, 107.63474f, 128f, 152.2185f, 181.01933f, 215.26949f, 256f, 304.437f, 362.03867f, 430.53897f, 512f, 608.874f, 724.07733f, 861.07794f, 1024f, 1217.748f, 1448.1547f, 1722.1559f, 2048f, 2435.496f }; _sfBandIndexLTable = new int[9][] { new int[23] { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 }, new int[23] { 0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 }, new int[23] { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 }, new int[23] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, new int[23] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 330, 394, 464, 540, 576 }, new int[23] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, new int[23] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, new int[23] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, new int[23] { 0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 } }; _sfBandIndexSTable = new int[9][] { new int[14] { 0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192 }, new int[14] { 0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192 }, new int[14] { 0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192 }, new int[14] { 0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192 }, new int[14] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192 }, new int[14] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 }, new int[14] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 }, new int[14] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 }, new int[14] { 0, 8, 16, 24, 36, 52, 72, 96, 124, 160, 162, 164, 166, 192 } }; _slen = new int[2][] { new int[16] { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }, new int[16] { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 } }; int[][][] array = new int[6][][] { new int[3][] { new int[4] { 6, 5, 5, 5 }, new int[4] { 9, 9, 9, 9 }, new int[4] { 6, 9, 9, 9 } }, new int[3][] { new int[4] { 6, 5, 7, 3 }, new int[4] { 9, 9, 12, 6 }, new int[4] { 6, 9, 12, 6 } }, null, null, null, null }; int num = 2; int[][] array2 = new int[3][]; int num2 = 0; array2[num2] = new int[4] { 11, 10, 0, 0 }; int num3 = 1; array2[num3] = new int[4] { 18, 18, 0, 0 }; int num4 = 2; array2[num4] = new int[4] { 15, 18, 0, 0 }; array[num] = array2; array[3] = new int[3][] { new int[4] { 7, 7, 7, 0 }, new int[4] { 12, 12, 12, 0 }, new int[4] { 6, 15, 12, 0 } }; array[4] = new int[3][] { new int[4] { 6, 6, 6, 3 }, new int[4] { 12, 9, 9, 6 }, new int[4] { 6, 12, 9, 6 } }; array[5] = new int[3][] { new int[4] { 8, 8, 5, 0 }, new int[4] { 15, 12, 9, 0 }, new int[4] { 6, 18, 9, 0 } }; _sfbBlockCntTab = array; PRETAB = new int[22] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 }; POW2_TAB = new float[64] { 1f, 0.70710677f, 0.5f, 0.35355338f, 0.25f, 0.17677669f, 0.125f, 0.088388346f, 0.0625f, 0.044194173f, 1f / 32f, 0.022097087f, 1f / 64f, 0.011048543f, 1f / 128f, 0.0055242716f, 0.00390625f, 0.0027621358f, 0.001953125f, 0.0013810679f, 0.0009765625f, 0.00069053395f, 0.00048828125f, 0.00034526698f, 0.00024414062f, 0.00017263349f, 0.00012207031f, 8.6316744E-05f, 6.1035156E-05f, 4.3158372E-05f, 3.0517578E-05f, 2.1579186E-05f, 1.5258789E-05f, 1.0789593E-05f, 7.6293945E-06f, 5.3947965E-06f, 3.8146973E-06f, 2.6973983E-06f, 1.9073486E-06f, 1.3486991E-06f, 9.536743E-07f, 6.7434956E-07f, 4.7683716E-07f, 3.3717478E-07f, 2.3841858E-07f, 1.6858739E-07f, 1.1920929E-07f, 8.4293696E-08f, 5.9604645E-08f, 4.2146848E-08f, 2.9802322E-08f, 2.1073424E-08f, 1.4901161E-08f, 1.0536712E-08f, 7.450581E-09f, 5.268356E-09f, 3.7252903E-09f, 2.634178E-09f, 1.8626451E-09f, 1.317089E-09f, 9.313226E-10f, 6.585445E-10f, 4.656613E-10f, 3.2927225E-10f }; _isRatio = new float[2][] { new float[7] { 0f, 0.21132487f, 0.36602542f, 0.5f, 0.6339746f, 0.7886751f, 1f }, new float[7] { 1f, 0.7886751f, 0.6339746f, 0.5f, 0.36602542f, 0.21132487f, 0f } }; _lsfRatio = new float[2][][] { new float[2][] { new float[32] { 1f, 0.8408964f, 1f, 0.70710677f, 1f, 0.59460354f, 1f, 0.5f, 1f, 0.4204482f, 1f, 0.35355338f, 1f, 0.29730177f, 1f, 0.25f, 1f, 0.2102241f, 1f, 0.17677669f, 1f, 0.14865088f, 1f, 0.125f, 1f, 0.10511205f, 1f, 0.088388346f, 1f, 0.07432544f, 1f, 0.0625f }, new float[32] { 1f, 1f, 0.8408964f, 1f, 0.70710677f, 1f, 0.59460354f, 1f, 0.5f, 1f, 0.4204482f, 1f, 0.35355338f, 1f, 0.29730177f, 1f, 0.25f, 1f, 0.2102241f, 1f, 0.17677669f, 1f, 0.14865088f, 1f, 0.125f, 1f, 0.10511205f, 1f, 0.088388346f, 1f, 0.07432544f, 1f } }, new float[2][] { new float[32] { 1f, 0.70710677f, 1f, 0.5f, 1f, 0.35355338f, 1f, 0.25f, 1f, 0.17677669f, 1f, 0.125f, 1f, 0.088388346f, 1f, 0.0625f, 1f, 0.044194173f, 1f, 1f / 32f, 1f, 0.022097087f, 1f, 1f / 64f, 1f, 0.011048543f, 1f, 1f / 128f, 1f, 0.0055242716f, 1f, 0.00390625f }, new float[32] { 1f, 1f, 0.70710677f, 1f, 0.5f, 1f, 0.35355338f, 1f, 0.25f, 1f, 0.17677669f, 1f, 0.125f, 1f, 0.088388346f, 1f, 0.0625f, 1f, 0.044194173f, 1f, 1f / 32f, 1f, 0.022097087f, 1f, 1f / 64f, 1f, 0.011048543f, 1f, 1f / 128f, 1f, 0.0055242716f, 1f } } }; _scs = new float[8] { 0.8574929f, 0.881742f, 0.94962865f, 0.9833146f, 0.9955178f, 0.9991606f, 0.9998992f, 0.99999315f }; _sca = new float[8] { -0.51449573f, -0.47173196f, -0.31337744f, -0.1819132f, -0.09457419f, -0.040965583f, -0.014198569f, -0.0036999746f }; } } internal class MpegFrame : FrameBase, IMpegFrame { private static readonly int[][][] _bitRateTable = new int[2][][] { new int[3][] { new int[15] { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, new int[15] { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, new int[15] { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } }, new int[3][] { new int[15] { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 }, new int[15] { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }, new int[15] { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } } }; internal MpegFrame Next; internal int Number; private int _syncBits; private int _readOffset; private int _bitsRead; private ulong _bitBucket; private long _offset; private bool _isMuted; public int FrameLength => base.Length; public MpegVersion Version => ((_syncBits >> 19) & 3) switch { 0 => MpegVersion.Version25, 2 => MpegVersion.Version2, 3 => MpegVersion.Version1, _ => MpegVersion.Unknown, }; public MpegLayer Layer => (MpegLayer)((4 - ((_syncBits >> 17) & 3)) % 4); public bool HasCrc => (_syncBits & 0x10000) == 0; public int BitRate { get { if (BitRateIndex > 0) { return _bitRateTable[(int)Version / 10 - 1][(int)(Layer - 1)][BitRateIndex] * 1000; } return (FrameLength * 8 * SampleRate / SampleCount + 499 + 500) / 1000 * 1000; } } public int BitRateIndex => (_syncBits >> 12) & 0xF; public int SampleRate { get { int num = SampleRateIndex switch { 0 => 44100, 1 => 48000, 2 => 32000, _ => 0, }; if (Version > MpegVersion.Version1) { num = ((Version != MpegVersion.Version25) ? (num / 2) : (num / 4)); } return num; } } public int SampleRateIndex => (_syncBits >> 10) & 3; private int Padding => (_syncBits >> 9) & 1; public MpegChannelMode ChannelMode => (MpegChannelMode)((_syncBits >> 6) & 3); public int ChannelModeExtension => (_syncBits >> 4) & 3; internal int Channels { get { if (ChannelMode != MpegChannelMode.Mono) { return 2; } return 1; } } public bool IsCopyrighted => (_syncBits & 8) == 8; internal bool IsOriginal => (_syncBits & 4) == 4; internal int EmphasisMode => _syncBits & 3; public bool IsCorrupted => _isMuted; public int SampleCount { get { if (Layer == MpegLayer.LayerI) { return 384; } if (Layer == MpegLayer.LayerIII && Version > MpegVersion.Version1) { return 576; } return 1152; } } internal long SampleOffset { get { return _offset; } set { _offset = value; } } internal static MpegFrame TrySync(uint syncMark) { if ((syncMark & 0xFFE00000u) == 4292870144u && (syncMark & 0x180000) != 524288 && (syncMark & 0x60000) != 0 && (syncMark & 0xF000) != 61440 && (syncMark & 0xC00) != 3072) { switch ((syncMark >> 4) & 0xF) { case 0u: case 4u: case 5u: case 6u: case 7u: case 8u: case 12u: return new MpegFrame { _syncBits = (int)syncMark }; } } return null; } private MpegFrame() { } protected override int Validate() { if (Layer == MpegLayer.LayerII) { int bitRate = BitRate; if (bitRate <= 80000) { if (bitRate <= 48000) { if (bitRate == 32000 || bitRate == 48000) { goto IL_0082; } } else if (bitRate == 56000 || bitRate == 80000) { goto IL_0082; } } else if (bitRate <= 256000) { if (bitRate == 224000 || bitRate == 256000) { goto IL_00f4; } } else if (bitRate == 320000 || bitRate == 384000) { goto IL_00f4; } } goto IL_010e; IL_010e: int result = ((BitRateIndex <= 0) ? (_readOffset + GetSideDataSize() + Padding) : ((Layer != MpegLayer.LayerI) ? (144 * BitRate / SampleRate + Padding) : ((12 * BitRate / SampleRate + Padding) * 4))); if (HasCrc) { _readOffset = 4 + (HasCrc ? 2 : 0); if (!ValidateCRC()) { _isMuted = true; return 6; } } Reset(); return result; IL_0082: if (ChannelMode != MpegChannelMode.Mono) { return -1; } goto IL_010e; IL_00f4: if (ChannelMode == MpegChannelMode.Mono) { return -1; } goto IL_010e; } internal int GetSideDataSize() { switch (Layer) { case MpegLayer.LayerI: if (ChannelMode == MpegChannelMode.Mono) { return 16; } if (ChannelMode == MpegChannelMode.Stereo || ChannelMode == MpegChannelMode.DualChannel) { return 32; } switch (ChannelModeExtension) { case 0: return 18; case 1: return 20; case 2: return 22; case 3: return 24; } break; case MpegLayer.LayerII: return 0; case MpegLayer.LayerIII: if (ChannelMode == MpegChannelMode.Mono && Version >= MpegVersion.Version2) { return 9; } if (ChannelMode != MpegChannelMode.Mono && Version < MpegVersion.Version2) { return 32; } return 17; } return 0; } private bool ValidateCRC() { uint crc = 65535u; UpdateCRC(_syncBits, 16, ref crc); bool flag = false; switch (Layer) { case MpegLayer.LayerI: flag = LayerIDecoder.GetCRC(this, ref crc); break; case MpegLayer.LayerII: flag = LayerIIDecoder.GetCRC(this, ref crc); break; case MpegLayer.LayerIII: flag = LayerIIIDecoder.GetCRC(this, ref crc); break; } return !flag || ((ReadByte(4) << 8) | ReadByte(5)) == crc; } internal static void UpdateCRC(int data, int length, ref uint crc) { uint num = (uint)(1 << length); while ((num >>= 1) != 0) { int num2 = (int)(crc & 0x8000); crc <<= 1; if ((num2 == 0) ^ ((data & num) == 0)) { crc ^= 32773u; } } crc &= 65535u; } internal VBRInfo ParseVBR() { byte[] array = new byte[4]; int num = ((Version == MpegVersion.Version1 && ChannelMode != MpegChannelMode.Mono) ? 36 : ((Version <= MpegVersion.Version1 || ChannelMode != MpegChannelMode.Mono) ? 21 : 13)); if (Read(num, array) != 4) { return null; } if ((array[0] == 88 && array[1] == 105 && array[2] == 110 && array[3] == 103) || (array[0] == 73 && array[1] == 110 && array[2] == 102 && array[3] == 111)) { return ParseXing(num + 4); } if (Read(36, array) != 4) { return null; } if (array[0] == 86 && array[1] == 66 && array[2] == 82 && array[3] == 73) { return ParseVBRI(); } return null; } private VBRInfo ParseXing(int offset) { VBRInfo vBRInfo = new VBRInfo(); vBRInfo.Channels = Channels; vBRInfo.SampleRate = SampleRate; vBRInfo.SampleCount = SampleCount; byte[] array = new byte[100]; if (Read(offset, array, 0, 4) != 4) { return null; } offset += 4; int num = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]; if ((num & 1) != 0) { if (Read(offset, array, 0, 4) != 4) { return null; } offset += 4; vBRInfo.VBRFrames = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]; } if ((num & 2) != 0) { if (Read(offset, array, 0, 4) != 4) { return null; } offset += 4; vBRInfo.VBRBytes = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]; } if ((num & 4) != 0) { if (Read(offset, array) != 100) { return null; } offset += 100; } if ((num & 8) != 0) { if (Read(offset, array, 0, 4) != 4) { return null; } offset += 4; vBRInfo.VBRQuality = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]; } return vBRInfo; } private VBRInfo ParseVBRI() { VBRInfo vBRInfo = new VBRInfo(); vBRInfo.Channels = Channels; vBRInfo.SampleRate = SampleRate; vBRInfo.SampleCount = SampleCount; byte[] array = new byte[26]; if (Read(36, array) != 26) { return null; } byte b = array[4]; byte b2 = array[5]; vBRInfo.VBRDelay = (array[6] << 8) | array[7]; vBRInfo.VBRQuality = (array[8] << 8) | array[9]; vBRInfo.VBRBytes = (array[10] << 24) | (array[11] << 16) | (array[12] << 8) | array[13]; vBRInfo.VBRFrames = (array[14] << 24) | (array[15] << 16) | (array[16] << 8) | array[17]; int num = (array[18] << 8) | array[19]; byte b3 = array[20]; byte b4 = array[21]; int num2 = (array[22] << 8) | array[23]; byte b5 = array[24]; byte b6 = array[25]; int num3 = num * num2; byte[] buffer = new byte[num3]; if (Read(62, buffer) != num3) { return null; } return vBRInfo; } public void Reset() { _readOffset = 4 + (HasCrc ? 2 : 0); _bitBucket = 0uL; _bitsRead = 0; } public int ReadBits(int bitCount) { if (bitCount < 1 || bitCount > 32) { throw new ArgumentOutOfRangeException("bitCount"); } if (_isMuted) { return 0; } while (_bitsRead < bitCount) { int num = ReadByte(_readOffset); if (num == -1) { throw new EndOfStreamException(); } _readOffset++; _bitBucket <<= 8; _bitBucket |= (byte)(num & 0xFF); _bitsRead += 8; } int result = (int)((long)(_bitBucket >> _bitsRead - bitCount) & ((1L << bitCount) - 1)); _bitsRead -= bitCount; return result; } } internal class MpegStreamReader { private class ReadBuffer { public byte[] Data; public long BaseOffset; public int End; public int DiscardCount; private object _localLock = new object(); public ReadBuffer(int initialSize) { initialSize = 2 << (int)Math.Log(initialSize, 2.0); Data = new byte[initialSize]; } public int Read(MpegStreamReader reader, long offset, byte[] buffer, int index, int count) { object localLock = _localLock; lock (localLock) { int srcOffset = EnsureFilled(reader, offset, ref count); Buffer.BlockCopy(Data, srcOffset, buffer, index, count); } return count; } public int ReadByte(MpegStreamReader reader, long offset) { object localLock = _localLock; lock (localLock) { int count = 1; int num = EnsureFilled(reader, offset, ref count); if (count == 1) { return Data[num]; } } return -1; } private int EnsureFilled(MpegStreamReader reader, long offset, ref int count) { int num = (int)(offset - BaseOffset); int num2 = num + count; if (num < 0 || num2 > End) { int num3 = 0; int num4 = 0; int num5 = 0; long num6 = 0L; if (num < 0) { if (!reader._source.CanSeek) { throw new InvalidOperationException("Cannot seek backwards on a forward-only stream!"); } if (End > 0 && (num + Data.Length > 0 || (Data.Length * 2 <= 16384 && num + Data.Length * 2 > 0))) { num2 = End; } num6 = offset; if (num2 < 0) { Truncate(); BaseOffset = offset; num = 0; num2 = count; num4 = count; } else { num5 = -num2; num4 = -num; } } else if (num2 < Data.Length) { num4 = num2 - End; num3 = End; num6 = BaseOffset + num3; } else if (num2 - DiscardCount < Data.Length) { num5 = DiscardCount; num3 = End; num4 = num2 - num3; num6 = BaseOffset + num3; } else if (Data.Length * 2 <= 16384) { num5 = DiscardCount; num3 = End; num4 = num2 - End; num6 = BaseOffset + num3; } else { Truncate(); BaseOffset = offset; num6 = offset; num = 0; num2 = count; num4 = count; } if (num2 - num5 > Data.Length || num3 + num4 - num5 > Data.Length) { int num7; for (num7 = Data.Length * 2; num7 < num2 - num5; num7 *= 2) { } byte[] array = new byte[num7]; if (num5 < 0) { Buffer.BlockCopy(Data, 0, array, -num5, End + num5); DiscardCount = 0; } else { Buffer.BlockCopy(Data, num5, array, 0, End - num5); DiscardCount -= num5; } Data = array; } else if (num5 != 0) { if (num5 > 0) { Buffer.BlockCopy(Data, num5, Data, 0, End - num5); DiscardCount -= num5; } else { int num8 = 0; int num9 = Data.Length - 1; int num10 = Data.Length - 1 - num5; while (num8 < num5) { Data[num10] = Data[num9]; num8++; num9--; num10--; } DiscardCount = 0; } } BaseOffset += num5; num3 -= num5; num -= num5; num2 -= num5; End -= num5; object readLock = reader._readLock; lock (readLock) { if (num4 > 0 && reader._source.Position != num6 && num6 < reader._eofOffset) { if (reader._canSeek) { try { reader._source.Position = num6; } catch (EndOfStreamException) { reader._eofOffset = reader._source.Length; num4 = 0; } } else { long num11 = num6 - reader._source.Position; while (--num11 >= 0) { if (reader._source.ReadByte() == -1) { reader._eofOffset = reader._source.Position; num4 = 0; break; } } } } while (num4 > 0 && num6 < reader._eofOffset) { int num12 = reader._source.Read(Data, num3, num4); if (num12 == 0) { break; } num3 += num12; num6 += num12; num4 -= num12; } if (num3 > End) { End = num3; } if (End < num2) { count = Math.Max(0, End - num); } else if (End < Data.Length) { int num13 = reader._source.Read(Data, End, Data.Length - End); End += num13; } } } return num; } public void DiscardThrough(long offset) { object localLock = _localLock; lock (localLock) { int val = (int)(offset - BaseOffset); DiscardCount = Math.Max(val, DiscardCount); if (DiscardCount >= Data.Length) { CommitDiscard(); } } } private void Truncate() { End = 0; DiscardCount = 0; } private void CommitDiscard() { if (DiscardCount >= Data.Length || DiscardCount >= End) { BaseOffset += DiscardCount; End = 0; } else { Buffer.BlockCopy(Data, DiscardCount, Data, 0, End - DiscardCount); BaseOffset += DiscardCount; End -= DiscardCount; } DiscardCount = 0; } } private ID3Frame _id3Frame; private ID3Frame _id3v1Frame; private RiffHeaderFrame _riffHeaderFrame; private VBRInfo _vbrInfo; private MpegFrame _first; private MpegFrame _current; private MpegFrame _last; private MpegFrame _lastFree; private long _readOffset; private long _eofOffset; private Stream _source; private bool _canSeek; private bool _endFound; private bool _mixedFrameSize; private object _readLock = new object(); private object _frameLock = new object(); private ReadBuffer _readBuf = new ReadBuffer(2048); internal bool CanSeek => _canSeek; internal long SampleCount { get { if (_vbrInfo != null) { return _vbrInfo.VBRStreamSampleCount; } if (!_canSeek) { return -1L; } ReadToEnd(); return _last.SampleCount + _last.SampleOffset; } } internal int SampleRate { get { if (_vbrInfo != null) { return _vbrInfo.SampleRate; } return _first.SampleRate; } } internal int Channels { get { if (_vbrInfo != null) { return _vbrInfo.Channels; } return _first.Channels; } } internal int FirstFrameSampleCount { get { if (_first == null) { return 0; } return _first.SampleCount; } } internal MpegStreamReader(Stream source) { _source = source; _canSeek = source.CanSeek; _readOffset = 0L; _eofOffset = long.MaxValue; FrameBase frameBase = FindNextFrame(); while (frameBase != null && !(frameBase is MpegFrame)) { frameBase = FindNextFrame(); } if (frameBase == null) { throw new InvalidDataException("Not a valid MPEG file!"); } frameBase = FindNextFrame(); if (frameBase == null || !(frameBase is MpegFrame)) { throw new InvalidDataException("Not a valid MPEG file!"); } _current = _first; } private FrameBase FindNextFrame() { if (_endFound) { return null; } MpegFrame lastFree = _lastFree; long num = _readOffset; object frameLock = _frameLock; FrameBase result; lock (frameLock) { byte[] array = new byte[4]; try { if (Read(_readOffset, array, 0, 4) == 4) { do { uint syncMark = (uint)((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]); num = _readOffset; if (_id3Frame == null) { ID3Frame iD3Frame = ID3Frame.TrySync(syncMark); if (iD3Frame != null && iD3Frame.Validate(_readOffset, this)) { if (!_canSeek) { iD3Frame.SaveBuffer(); } _readOffset += iD3Frame.Length; DiscardThrough(_readOffset, minimalRead: true); return _id3Frame = iD3Frame; } } if (_first == null && _riffHeaderFrame == null) { RiffHeaderFrame riffHeaderFrame = RiffHeaderFrame.TrySync(syncMark); if (riffHeaderFrame != null && riffHeaderFrame.Validate(_readOffset, this)) { _readOffset += riffHeaderFrame.Length; DiscardThrough(_readOffset, minimalRead: true); return _riffHeaderFrame = riffHeaderFrame; } } MpegFrame mpegFrame = MpegFrame.TrySync(syncMark); if (mpegFrame == null || !mpegFrame.Validate(_readOffset, this) || (lastFree != null && (mpegFrame.Layer != lastFree.Layer || mpegFrame.Version != lastFree.Version || mpegFrame.SampleRate != lastFree.SampleRate || mpegFrame.BitRateIndex > 0))) { if (_last != null) { ID3Frame iD3Frame2 = ID3Frame.TrySync(syncMark); if (iD3Frame2 != null && iD3Frame2.Validate(_readOffset, this)) { if (!_canSeek) { iD3Frame2.SaveBuffer(); } if (iD3Frame2.Version == 1) { _id3v1Frame = iD3Frame2; } else { _id3Frame.Merge(iD3Frame2); } _readOffset += iD3Frame2.Length; DiscardThrough(_readOffset, minimalRead: true); return iD3Frame2; } } _readOffset++; if (_first == null || !_canSeek) { DiscardThrough(_readOffset, minimalRead: true); } Buffer.BlockCopy(array, 1, array, 0, 3); continue; } if (!_canSeek) { mpegFrame.SaveBuffer(); DiscardThrough(_readOffset + mpegFrame.FrameLength, minimalRead: true); } _readOffset += mpegFrame.FrameLength; if (_first == null) { if (_vbrInfo == null && (_vbrInfo = mpegFrame.ParseVBR()) != null) { return FindNextFrame(); } mpegFrame.Number = 0; _first = (_last = mpegFrame); } else { if (mpegFrame.SampleCount != _first.SampleCount) { _mixedFrameSize = true; } mpegFrame.SampleOffset = _last.SampleCount + _last.SampleOffset; mpegFrame.Number = _last.Number + 1; _last = (_last.Next = mpegFrame); } if (mpegFrame.BitRateIndex == 0) { _lastFree = mpegFrame; } return mpegFrame; } while (Read(_readOffset + 3, array, 3, 1) == 1); } num += 4; _endFound = true; result = null; } finally { if (lastFree != null) { lastFree.Length = (int)(num - lastFree.Offset); if (!_canSeek) { throw new InvalidOperationException("Free frames cannot be read properly from forward-only streams!"); } if (_lastFree == lastFree) { _lastFree = null; } } } } return result; } internal int Read(long offset, byte[] buffer, int index, int count) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (index < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("index"); } return _readBuf.Read(this, offset, buffer, index, count); } internal int ReadByte(long offset) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } return _readBuf.ReadByte(this, offset); } internal void DiscardThrough(long offset, bool minimalRead) { _readBuf.DiscardThrough(offset); } internal void ReadToEnd() { try { int num = 40000; if (_id3Frame != null) { num += _id3Frame.Length; } while (!_endFound) { FindNextFrame(); while (!_canSeek && FrameBase.TotalAllocation >= num) { Task.Delay(500).Wait(); } } } catch (ObjectDisposedException) { } } internal long SeekTo(long sampleNumber) { if (!_canSeek) { throw new InvalidOperationException("Cannot seek!"); } int num = (int)(sampleNumber / _first.SampleCount); MpegFrame mpegFrame = _first; if (_current != null && _current.Number <= num && _current.SampleOffset <= sampleNumber) { mpegFrame = _current; num -= mpegFrame.Number; } while (!_mixedFrameSize && --num >= 0 && mpegFrame != null) { if (mpegFrame == _last && !_endFound) { do { FindNextFrame(); } while (mpegFrame == _last && !_endFound); } if (_mixedFrameSize) { break; } mpegFrame = mpegFrame.Next; } while (mpegFrame != null && mpegFrame.SampleOffset + mpegFrame.SampleCount < sampleNumber) { if (mpegFrame == _last && !_endFound) { do { FindNextFrame(); } while (mpegFrame == _last && !_endFound); } mpegFrame = mpegFrame.Next; } if (mpegFrame == null) { return -1L; } return (_current = mpegFrame).SampleOffset; } internal MpegFrame NextFrame() { MpegFrame current = _current; if (current != null) { if (_canSeek) { current.SaveBuffer(); DiscardThrough(current.Offset + current.FrameLength, minimalRead: false); } if (current == _last && !_endFound) { do { FindNextFrame(); } while (current == _last && !_endFound); } _current = current.Next; if (!_canSeek) { object frameLock = _frameLock; lock (frameLock) { MpegFrame first = _first; _first = first.Next; first.Next = null; } } } return current; } internal MpegFrame GetCurrentFrame() { return _current; } } internal class RiffHeaderFrame : FrameBase { internal static RiffHeaderFrame TrySync(uint syncMark) { if (syncMark == 1380533830) { return new RiffHeaderFrame(); } return null; } private RiffHeaderFrame() { } protected override int Validate() { byte[] array = new byte[4]; if (Read(8, array) != 4) { return -1; } if (array[0] != 87 || array[1] != 65 || array[2] != 86 || array[3] != 69) { return -1; } if (Read(12, array) != 4) { return -1; } if (array[0] != 102 || array[1] != 109 || array[2] != 116 || array[3] != 32) { return -1; } int num = 16; while (Read(num, array) == 4) { num += 4 + BitConverter.ToInt32(array, 0); if (Read(num, array) != 4) { return -1; } num += 4; if (array[0] == 100 && array[1] == 97 && array[2] == 116 && array[3] == 97) { return num + 4; } } return -1; } } internal class VBRInfo { internal int SampleCount { get; set; } internal int SampleRate { get; set; } internal int Channels { get; set; } internal int VBRFrames { get; set; } internal int VBRBytes { get; set; } internal int VBRQuality { get; set; } internal int VBRDelay { get; set; } internal long VBRStreamSampleCount => VBRFrames * SampleCount; internal int VBRAverageBitrate => (int)((double)VBRBytes / ((double)VBRStreamSampleCount / (double)SampleRate) * 8.0); internal VBRInfo() { } } } namespace IllegalRave.Gltf { internal static class DebugLog { internal static bool DebugEnabled { get; set; } internal static void Info(string message) { if (DebugEnabled) { RaveMod.Logger.Msg("[GLTF] " + message); } } internal static void Warning(string message) { if (DebugEnabled) { RaveMod.Logger.Warning("[GLTF] " + message); } } internal static void Error(string message) { RaveMod.Logger.Error("[GLTF] " + message); } internal static void Exception(Exception ex) { RaveMod.Logger.Error($"[GLTF] {ex.GetType().Name}: {ex.Message}\n{ex.StackTrace}"); } internal static void InfoFormat(string format, params object[] args) { if (DebugEnabled) { Info(string.Format(format, args)); } } internal static void WarningFormat(string format, params object[] args) { if (DebugEnabled) { Warning(string.Format(format, args)); } } internal static void ErrorFormat(string format, params object[] args) { Error(string.Format(format, args)); } } public sealed class GltfImporter { private const uint GLB_MAGIC = 1179937895u; private const uint CHUNK_TYPE_JSON = 1313821514u; private const uint CHUNK_TYPE_BIN = 5130562u; private readonly GltfImportOptions _options; private string _basePath; public GltfImporter() { _options = new GltfImportOptions(); } public GltfImporter(GltfImportOptions options) { _options = options ?? new GltfImportOptions(); } public GltfImporter SetName(string name) { _options.RootName = name; return this; } public GltfImporter SetShader(Shader shader) { _options.Shader = shader; return this; } public GltfImporter SetScale(float scale) { _options.ScaleFactor = scale; return this; } public GltfImporter ImportAnimations(bool import) { _options.ImportAnimations = import; return this; } public GltfImporter ImportSkins(bool import) { _options.ImportSkins = import; return this; } public GltfImporter ImportBlendShapes(bool import) { _options.ImportBlendShapes = import; return this; } public GltfImporter ImportCameras(bool import) { _options.ImportCameras = import; return this; } public GltfImporter ReadableMeshes(bool readable) { _options.ReadableMeshes = readable; return this; } public GltfImporter GenerateNormals(bool generate) { _options.GenerateMissingNormals = generate; return this; } public GltfImporter GenerateTangents(bool generate) { _options.GenerateMissingTangents = generate; return this; } public GltfImporter SetEmissionIntensity(float intensity) { _options.EmissionIntensity = intensity; return this; } public GameObject Load(byte[] data) { if (data == null || data.Length < 4) { DebugLog.Error("Invalid GLTF data: null or too short"); return null; } uint num = BitConverter.ToUInt32(data, 0); if (num == 1179937895) { return LoadGlb(data); } string json = Encoding.UTF8.GetString(data); return LoadGltfJson(json, null); } public GameObject LoadGlb(byte[] glbBytes) { if (glbBytes == null || glbBytes.Length < 12) { DebugLog.Error("Invalid GLB data: too short"); return null; } if (!ParseGlbChunks(glbBytes, out var root, out var binaryChunk)) { return null; } if (root == null) { DebugLog.Error("Failed to parse GLB root"); return null; } GltfBufferResolver resolver = new GltfBufferResolver(null, binaryChunk); return ImportModel(root, resolver); } public GameObject LoadFromFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { DebugLog.Error("Invalid file path: null or empty"); return null; } try { if (!File.Exists(filePath)) { DebugLog.Error("File not found: " + filePath); return null; } byte[] data = File.ReadAllBytes(filePath); _basePath = Path.GetDirectoryName(filePath); if (_options.RootName == "GltfModel") { _options.RootName = Path.GetFileNameWithoutExtension(filePath); } return Load(data); } catch (IOException ex) { DebugLog.Error("Failed to load file '" + filePath + "': " + ex.Message); return null; } catch (UnauthorizedAccessException ex2) { DebugLog.Error("Failed to load file '" + filePath + "': " + ex2.Message); return null; } catch (ArgumentException ex3) { DebugLog.Error("Failed to load file '" + filePath + "': " + ex3.Message); return null; } } public GameObject LoadGltfJson(string json, string basePath) { //IL_002c: Expected O, but got Unknown GameObject result; if (string.IsNullOrEmpty(json)) { DebugLog.Error("Invalid GLTF JSON: null or empty"); result = null; } else { GltfRoot gltfRoot; try { gltfRoot = JsonConvert.DeserializeObject(json); } catch (JsonException ex) { JsonException ex2 = ex; DebugLog.Error("Failed to parse GLTF JSON: " + ((Exception)(object)ex2).Message); return null; } if (gltfRoot == null) { DebugLog.Error("Deserialized GLTF root is null"); result = null; } else { string basePath2 = basePath ?? _basePath; GltfBufferResolver resolver = new GltfBufferResolver(basePath2); result = ImportModel(gltfRoot, resolver); } } return result; } private bool ParseGlbChunks(byte[] glbBytes, out GltfRoot root, out byte[] binaryChunk) { //IL_01ce: Expected O, but got Unknown root = null; binaryChunk = null; bool result; using (MemoryStream memoryStream = new MemoryStream(glbBytes)) { using BinaryReader binaryReader = new BinaryReader(memoryStream); uint num = binaryReader.ReadUInt32(); if (num != 1179937895) { DebugLog.Error($"Invalid GLB magic: 0x{num:X8}"); result = false; } else { uint num2 = binaryReader.ReadUInt32(); if (num2 != 2) { DebugLog.Warning($"GLB version is {num2}, expected 2. Loading may fail."); } uint num3 = binaryReader.ReadUInt32(); if (num3 != glbBytes.Length) { DebugLog.Warning($"GLB length mismatch: header says {num3}, actual {glbBytes.Length}"); } while (memoryStream.Position < memoryStream.Length && memoryStream.Position + 8 <= memoryStream.Length) { uint num4 = binaryReader.ReadUInt32(); uint num5 = binaryReader.ReadUInt32(); if (memoryStream.Position + num4 > memoryStream.Length) { DebugLog.Error("GLB chunk extends beyond file"); return false; } byte[] array = binaryReader.ReadBytes((int)num4); switch (num5) { case 1313821514u: { string text = Encoding.UTF8.GetString(array); try { root = JsonConvert.DeserializeObject(text); } catch (JsonException ex) { JsonException ex2 = ex; DebugLog.Error("Failed to parse GLB JSON chunk: " + ((Exception)(object)ex2).Message); return false; } break; } case 5130562u: binaryChunk = array; break; } } if (root == null) { DebugLog.Error("GLB file missing JSON chunk"); result = false; } else { result = true; } } } return result; } private GameObject ImportModel(GltfRoot root, GltfBufferResolver resolver) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_008f: 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) if (!resolver.ResolveBuffers(root)) { DebugLog.Error("Failed to resolve GLTF buffers"); return null; } GltfLoadContext gltfLoadContext = new GltfLoadContext(root, resolver, _options); List list = ProcessTextures(gltfLoadContext); List list2 = GltfMaterialProcessor.ProcessMaterials(gltfLoadContext); List list3 = ProcessMeshes(gltfLoadContext); GameObject val = new GameObject(_options.RootName); if (Math.Abs(_options.ScaleFactor - 1f) > 0.0001f) { val.transform.localScale = Vector3.one * _options.ScaleFactor; } ProcessNodes(gltfLoadContext, val, list3, list2); if (_options.ImportAnimations) { List list4 = GltfAnimationProcessor.ProcessAnimations(gltfLoadContext); if (list4.Count > 0) { Animation val2 = val.AddComponent(); foreach (AnimationClip item in list4) { val2.AddClip(item, ((Object)item).name); } if (list4.Count > 0) { val2.clip = list4[0]; } } } DebugLog.Info($"Imported GLTF model '{_options.RootName}': {list3.Count} meshes, {list2.Count} materials, {list.Count} textures, {gltfLoadContext.Animations.Count} animations"); return val; } private List ProcessTextures(GltfLoadContext context) { GltfRoot root = context.Root; List list = new List(); if (root.textures == null) { return list; } foreach (GltfTexture texture in root.textures) { Texture2D val = null; if (texture.source.HasValue && root.images != null && texture.source.Value < root.images.Count) { GltfImage gltfImage = root.images[texture.source.Value]; val = LoadImage(context, gltfImage); if ((Object)(object)val != (Object)null) { Object val2 = (Object)(object)val; string name; if ((name = texture.name) == null && (name = gltfImage.name) == null) { name = $"texture_{list.Count}"; } val2.name = name; if (texture.sampler.HasValue && root.samplers != null && texture.sampler.Value < root.samplers.Count) { ApplySampler(val, root.samplers[texture.sampler.Value]); } } } list.Add(val); if ((Object)(object)val != (Object)null) { context.RegisterTexture(val); } } return list; } private Texture2D LoadImage(GltfLoadContext context, GltfImage image) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown byte[] array = null; if (image.bufferView.HasValue) { array = context.BufferResolver.GetBufferViewData(context.Root, image.bufferView.Value); } else if (!string.IsNullOrEmpty(image.uri) && image.uri.StartsWith("data:", StringComparison.OrdinalIgnoreCase)) { int num = image.uri.IndexOf(','); if (num > 0 && image.uri.Substring(0, num).Contains(";base64")) { try { array = Convert.FromBase64String(image.uri.Substring(num + 1)); } catch (FormatException) { DebugLog.Warning("Failed to decode base64 image data"); } } } if (array == null || array.Length == 0) { return null; } Texture2D val = new Texture2D(2, 2); if (ImageConversion.LoadImage(val, Il2CppStructArray.op_Implicit(array))) { return val; } Object.Destroy((Object)(object)val); return null; } private void ApplySampler(Texture2D tex, GltfSampler sampler) { //IL_001f: 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_0092: Unknown result type (might be due to invalid IL or missing references) if (sampler.wrapS.HasValue) { ((Texture)tex).wrapModeU = GetWrapMode(sampler.wrapS.Value); } if (sampler.wrapT.HasValue) { ((Texture)tex).wrapModeV = GetWrapMode(sampler.wrapT.Value); } if (sampler.minFilter.HasValue || sampler.magFilter.HasValue) { ((Texture)tex).filterMode = GetFilterMode(sampler.minFilter.GetValueOrDefault(), sampler.magFilter.GetValueOrDefault()); } } private static TextureWrapMode GetWrapMode(int mode) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0038: 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) bool flag = false; TextureWrapMode result = (TextureWrapMode)(mode switch { 33648 => 2, 33071 => 1, 10497 => 0, _ => 0, }); bool flag2 = false; return result; } private static FilterMode GetFilterMode(int min, int mag) { //IL_001c: 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_0036: 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_0040: 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) if (min == 9728 || mag == 9728) { return (FilterMode)0; } if (min >= 9984) { return (FilterMode)2; } return (FilterMode)1; } private List ProcessMeshes(GltfLoadContext context) { GltfRoot root = context.Root; byte[] array = root.buffers?[0]?.Data; byte[] binaryBuffer = array; List list = GltfMeshProcessor.ProcessMeshes(root, binaryBuffer); foreach (GltfMeshResult item in list) { if ((Object)(object)item?.mesh != (Object)null) { context.RegisterMesh(item.mesh); } } return list; } private void ProcessNodes(GltfLoadContext context, GameObject root, List meshResults, List materials) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown GltfRoot root2 = context.Root; if (root2.nodes == null) { return; } Dictionary dictionary = new Dictionary(); for (int i = 0; i < root2.nodes.Count; i++) { GltfNode gltfNode = root2.nodes[i]; string text; if ((text = gltfNode.name) == null) { text = $"node_{i}"; } GameObject val = new GameObject(text); dictionary[i] = val.transform; context.RegisterNodeTransform(i, val.transform); ApplyNodeTransform(val.transform, gltfNode); } for (int j = 0; j < root2.nodes.Count; j++) { GltfNode gltfNode2 = root2.nodes[j]; Transform val2 = dictionary[j]; if (gltfNode2.children == null) { continue; } foreach (int child in gltfNode2.children) { if (dictionary.TryGetValue(child, out var value) && (Object)(object)value != (Object)null) { value.SetParent(val2, false); } } } foreach (Transform value2 in dictionary.Values) { if ((Object)(object)value2.parent == (Object)null) { value2.SetParent(root.transform, false); } } for (int k = 0; k < root2.nodes.Count; k++) { GltfNode gltfNode3 = root2.nodes[k]; Transform val3 = dictionary[k]; if (gltfNode3.mesh.HasValue && gltfNode3.mesh.Value < meshResults.Count) { AttachMesh(((Component)val3).gameObject, gltfNode3, meshResults[gltfNode3.mesh.Value], materials, context); } if (_options.ImportCameras && gltfNode3.camera.HasValue && root2.cameras != null && gltfNode3.camera.Value < root2.cameras.Count) { AttachCamera(((Component)val3).gameObject, root2.cameras[gltfNode3.camera.Value]); } } } private void ApplyNodeTransform(Transform transform, GltfNode node) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_0089: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) if (node.matrix != null && node.matrix.Length == 16) { Matrix4x4 val = default(Matrix4x4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { ((Matrix4x4)(ref val))[j, i] = node.matrix[i * 4 + j]; } } Vector3 val2 = Vector4.op_Implicit(((Matrix4x4)(ref val)).GetColumn(3)); Quaternion rotation = ((Matrix4x4)(ref val)).rotation; Vector3 lossyScale = ((Matrix4x4)(ref val)).lossyScale; transform.localPosition = new Vector3(0f - val2.x, val2.y, val2.z); transform.localRotation = new Quaternion(rotation.x, 0f - rotation.y, 0f - rotation.z, rotation.w); transform.localScale = lossyScale; } else { if (node.translation != null && node.translation.Length >= 3) { transform.localPosition = new Vector3(0f - node.translation[0], node.translation[1], node.translation[2]); } if (node.rotation != null && node.rotation.Length >= 4) { transform.localRotation = new Quaternion(node.rotation[0], 0f - node.rotation[1], 0f - node.rotation[2], node.rotation[3]); } if (node.scale != null && node.scale.Length >= 3) { transform.localScale = new Vector3(node.scale[0], node.scale[1], node.scale[2]); } } } private void AttachMesh(GameObject go, GltfNode node, GltfMeshResult meshResult, List materials, GltfLoadContext context) { if (!((Object)(object)meshResult?.mesh == (Object)null)) { Material[] array = CreateMaterialArray(meshResult, materials, context); if (TryCreateSkin(go.transform, node, context, out var bones, out var rootBone, out var bindPoses)) { Mesh val = Object.Instantiate(meshResult.mesh); ((Object)val).name = ((Object)meshResult.mesh).name + "_skinned"; val.bindposes = Il2CppStructArray.op_Implicit(bindPoses); val.RecalculateBounds(); SkinnedMeshRenderer val2 = go.AddComponent(); val2.sharedMesh = val; val2.bones = Il2CppReferenceArray.op_Implicit(bones); val2.rootBone = rootBone ?? bones[0]; ((Renderer)val2).materials = Il2CppReferenceArray.op_Implicit(array); DebugLog.Info("Attached skinned mesh to node '" + ((Object)go).name + "' with " + bones.Length + " bones"); } else { MeshFilter val3 = go.AddComponent(); val3.mesh = meshResult.mesh; MeshRenderer val4 = go.AddComponent(); ((Renderer)val4).materials = Il2CppReferenceArray.op_Implicit(array); } } } private Material[] CreateMaterialArray(GltfMeshResult meshResult, List materials, GltfLoadContext context) { Material[] array = (Material[])(object)new Material[meshResult.mesh.subMeshCount]; Material val = null; for (int i = 0; i < meshResult.mesh.subMeshCount; i++) { int num = ((i < meshResult.materialIndices.Length) ? meshResult.materialIndices[i] : (-1)); if (num >= 0 && num < materials.Count) { array[i] = materials[num]; continue; } if ((Object)(object)val == (Object)null) { val = GltfMaterialProcessor.CreateDefaultMaterial(context); } array[i] = val; } return array; } private bool TryCreateSkin(Transform meshTransform, GltfNode node, GltfLoadContext context, out Transform[] bones, out Transform rootBone, out Matrix4x4[] bindPoses) { bones = null; rootBone = null; bindPoses = null; if (!_options.ImportSkins || node == null || !node.skin.HasValue) { return false; } GltfRoot root = context.Root; int value = node.skin.Value; if (root.skins == null || value < 0 || value >= root.skins.Count) { DebugLog.Warning("Skin index out of range for node '" + ((Object)meshTransform).name + "'"); return false; } GltfSkin gltfSkin = root.skins[value]; if (gltfSkin == null || gltfSkin.joints == null || gltfSkin.joints.Count == 0) { DebugLog.Warning("Skin has no joints for node '" + ((Object)meshTransform).name + "'"); return false; } bones = (Transform[])(object)new Transform[gltfSkin.joints.Count]; for (int i = 0; i < gltfSkin.joints.Count; i++) { Transform nodeTransform = context.GetNodeTransform(gltfSkin.joints[i]); if ((Object)(object)nodeTransform == (Object)null) { DebugLog.Warning("Missing joint transform for skinned node '" + ((Object)meshTransform).name + "'"); bones = null; return false; } bones[i] = nodeTransform; } if (gltfSkin.skeleton.HasValue) { rootBone = context.GetNodeTransform(gltfSkin.skeleton.Value); } if ((Object)(object)rootBone == (Object)null && bones.Length != 0) { rootBone = bones[0]; } bindPoses = ReadInverseBindMatrices(context, gltfSkin, bones.Length); if (bindPoses == null || bindPoses.Length != bones.Length) { bindPoses = CreateFallbackBindPoses(meshTransform, bones); DebugLog.Warning("Using fallback bind poses for node '" + ((Object)meshTransform).name + "'"); } return true; } private Matrix4x4[] ReadInverseBindMatrices(GltfLoadContext context, GltfSkin skin, int expectedCount) { //IL_00ed: 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_00f7: Unknown result type (might be due to invalid IL or missing references) if (!skin.inverseBindMatrices.HasValue) { return null; } int value = skin.inverseBindMatrices.Value; GltfAccessor accessor = context.GetAccessor(value); byte[] accessorData = context.GetAccessorData(value); if (accessor == null || accessorData == null) { return null; } int num = (accessor.bufferView.HasValue ? context.GetBufferView(accessor.bufferView.Value) : null)?.byteStride ?? 64; int num2 = Math.Min(expectedCount, accessor.count); Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[num2]; for (int i = 0; i < num2; i++) { int num3 = accessor.byteOffset + i * num; if (num3 + 64 > accessorData.Length) { return null; } array[i] = ConvertCoordinateSpace(ReadMatrix4x4(accessorData, num3)); } return array; } private Matrix4x4[] CreateFallbackBindPoses(Transform meshTransform, Transform[] bones) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[bones.Length]; for (int i = 0; i < bones.Length; i++) { array[i] = bones[i].worldToLocalMatrix * meshTransform.localToWorldMatrix; } return array; } private Matrix4x4 ReadMatrix4x4(byte[] data, int offset) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 result = default(Matrix4x4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { ((Matrix4x4)(ref result))[j, i] = BitConverter.ToSingle(data, offset + (i * 4 + j) * 4); } } return result; } private static Matrix4x4 ConvertCoordinateSpace(Matrix4x4 matrix) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 val = Matrix4x4.Scale(new Vector3(-1f, 1f, 1f)); return val * matrix * val; } private void AttachCamera(GameObject go, GltfCamera gltfCamera) { Camera val = go.AddComponent(); if (gltfCamera.type == "perspective" && gltfCamera.perspective != null) { val.orthographic = false; val.fieldOfView = gltfCamera.perspective.yfov * 57.29578f; val.nearClipPlane = gltfCamera.perspective.znear; if (gltfCamera.perspective.zfar.HasValue) { val.farClipPlane = gltfCamera.perspective.zfar.Value; } if (gltfCamera.perspective.aspectRatio.HasValue) { val.aspect = gltfCamera.perspective.aspectRatio.Value; } } else if (gltfCamera.type == "orthographic" && gltfCamera.orthographic != null) { val.orthographic = true; val.orthographicSize = gltfCamera.orthographic.ymag; val.nearClipPlane = gltfCamera.orthographic.znear; val.farClipPlane = gltfCamera.orthographic.zfar; } } } public static class GltfLoader { public static GameObject Load(byte[] data, Shader shader = null) { GltfImporter gltfImporter = new GltfImporter(); if ((Object)(object)shader != (Object)null) { gltfImporter.SetShader(shader); } return gltfImporter.Load(data); } public static GameObject LoadGlb(byte[] glbBytes, Shader shader = null) { GltfImporter gltfImporter = new GltfImporter(); if ((Object)(object)shader != (Object)null) { gltfImporter.SetShader(shader); } return gltfImporter.LoadGlb(glbBytes); } public static GameObject LoadFromFile(string filePath, Shader shader = null) { GltfImporter gltfImporter = new GltfImporter(); if ((Object)(object)shader != (Object)null) { gltfImporter.SetShader(shader); } return gltfImporter.LoadFromFile(filePath); } public static GameObject LoadFromJson(string json, string basePath, Shader shader = null) { GltfImporter gltfImporter = new GltfImporter(); if ((Object)(object)shader != (Object)null) { gltfImporter.SetShader(shader); } return gltfImporter.LoadGltfJson(json, basePath); } } internal static class Il2CppListExtensions { internal static List ToIl2CppList(this List managed) { List val = new List(managed.Count); for (int i = 0; i < managed.Count; i++) { val.Add(managed[i]); } return val; } } } namespace IllegalRave.Gltf.Processing { internal static class GltfAnimationProcessor { public static List ProcessAnimations(GltfLoadContext context) { List list = new List(); GltfRoot root = context.Root; if (root.animations == null || !context.Options.ImportAnimations) { return list; } for (int i = 0; i < root.animations.Count; i++) { GltfAnimation gltfAnim = root.animations[i]; AnimationClip val = CreateAnimationClip(context, gltfAnim, i); if ((Object)(object)val != (Object)null) { list.Add(val); context.RegisterAnimation(val); } } return list; } private static AnimationClip CreateAnimationClip(GltfLoadContext context, GltfAnimation gltfAnim, int index) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (gltfAnim.channels == null || gltfAnim.samplers == null) { return null; } AnimationClip val = new AnimationClip(); Object val2 = (Object)(object)val; string name; if ((name = gltfAnim.name) == null) { name = $"animation_{index}"; } val2.name = name; val.legacy = true; foreach (GltfAnimationChannel channel in gltfAnim.channels) { GltfAnimationChannelTarget target = channel.target; if (target == null || !target.node.HasValue || channel.target.path == null) { continue; } int sampler = channel.sampler; if (sampler < 0 || sampler >= gltfAnim.samplers.Count) { continue; } GltfAnimationSampler gltfAnimationSampler = gltfAnim.samplers[sampler]; int value = channel.target.node.Value; string path = channel.target.path; string nodePath = GetNodePath(context, value); if (string.IsNullOrEmpty(nodePath)) { continue; } float[] array = ReadFloatArray(context, gltfAnimationSampler.input); if (array != null && array.Length != 0) { switch (path) { case "weights": ApplyMorphTargetAnimation(context, val, gltfAnimationSampler, array, nodePath, value); break; case "scale": ApplyScaleAnimation(context, val, gltfAnimationSampler, array, nodePath); break; case "rotation": ApplyRotationAnimation(context, val, gltfAnimationSampler, array, nodePath); break; case "translation": ApplyTranslationAnimation(context, val, gltfAnimationSampler, array, nodePath); break; } } } val.EnsureQuaternionContinuity(); return val; } private static void ApplyTranslationAnimation(GltfLoadContext context, AnimationClip clip, GltfAnimationSampler sampler, float[] times, string nodePath) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_007b: 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) Vector3[] array = ReadVector3Array(context, sampler.output); if (array == null || array.Length == 0) { return; } bool flag = sampler.interpolation == "CUBICSPLINE"; int num = times.Length; AnimationCurve val = new AnimationCurve(); AnimationCurve val2 = new AnimationCurve(); AnimationCurve val3 = new AnimationCurve(); for (int i = 0; i < num; i++) { float num2 = times[i]; Vector3 val4; if (flag) { int num3 = i * 3 + 1; val4 = ((num3 < array.Length) ? array[num3] : Vector3.zero); } else { int num4 = Math.Min(i, array.Length - 1); val4 = array[num4]; } val.AddKey(num2, 0f - val4.x); val2.AddKey(num2, val4.y); val3.AddKey(num2, val4.z); } clip.SetCurve(nodePath, Il2CppType.Of(), "localPosition.x", val); clip.SetCurve(nodePath, Il2CppType.Of(), "localPosition.y", val2); clip.SetCurve(nodePath, Il2CppType.Of(), "localPosition.z", val3); } private static void ApplyRotationAnimation(GltfLoadContext context, AnimationClip clip, GltfAnimationSampler sampler, float[] times, string nodePath) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) Vector4[] array = ReadVector4Array(context, sampler.output); if (array == null || array.Length == 0) { return; } bool flag = sampler.interpolation == "CUBICSPLINE"; int num = times.Length; AnimationCurve val = new AnimationCurve(); AnimationCurve val2 = new AnimationCurve(); AnimationCurve val3 = new AnimationCurve(); AnimationCurve val4 = new AnimationCurve(); for (int i = 0; i < num; i++) { float num2 = times[i]; Vector4 val5; if (flag) { int num3 = i * 3 + 1; val5 = ((num3 < array.Length) ? array[num3] : Vector4.zero); } else { int num4 = Math.Min(i, array.Length - 1); val5 = array[num4]; } val.AddKey(num2, val5.x); val2.AddKey(num2, 0f - val5.y); val3.AddKey(num2, 0f - val5.z); val4.AddKey(num2, val5.w); } clip.SetCurve(nodePath, Il2CppType.Of(), "localRotation.x", val); clip.SetCurve(nodePath, Il2CppType.Of(), "localRotation.y", val2); clip.SetCurve(nodePath, Il2CppType.Of(), "localRotation.z", val3); clip.SetCurve(nodePath, Il2CppType.Of(), "localRotation.w", val4); } private static void ApplyScaleAnimation(GltfLoadContext context, AnimationClip clip, GltfAnimationSampler sampler, float[] times, string nodePath) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) Vector3[] array = ReadVector3Array(context, sampler.output); if (array == null || array.Length == 0) { return; } bool flag = sampler.interpolation == "CUBICSPLINE"; int num = times.Length; AnimationCurve val = new AnimationCurve(); AnimationCurve val2 = new AnimationCurve(); AnimationCurve val3 = new AnimationCurve(); for (int i = 0; i < num; i++) { float num2 = times[i]; Vector3 val4; if (flag) { int num3 = i * 3 + 1; val4 = ((num3 < array.Length) ? array[num3] : Vector3.one); } else { int num4 = Math.Min(i, array.Length - 1); val4 = array[num4]; } val.AddKey(num2, val4.x); val2.AddKey(num2, val4.y); val3.AddKey(num2, val4.z); } clip.SetCurve(nodePath, Il2CppType.Of(), "localScale.x", val); clip.SetCurve(nodePath, Il2CppType.Of(), "localScale.y", val2); clip.SetCurve(nodePath, Il2CppType.Of(), "localScale.z", val3); } private static void ApplyMorphTargetAnimation(GltfLoadContext context, AnimationClip clip, GltfAnimationSampler sampler, float[] times, string nodePath, int nodeIndex) { //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown if (!context.Options.ImportBlendShapes) { return; } float[] array = ReadFloatArray(context, sampler.output); if (array == null || array.Length == 0) { return; } GltfRoot root = context.Root; if (root.nodes == null || nodeIndex < 0 || nodeIndex >= root.nodes.Count) { return; } GltfNode gltfNode = root.nodes[nodeIndex]; if (!gltfNode.mesh.HasValue || root.meshes == null || gltfNode.mesh.Value >= root.meshes.Count) { return; } GltfMesh gltfMesh = root.meshes[gltfNode.mesh.Value]; int num = 0; if (gltfMesh.primitives != null && gltfMesh.primitives.Count > 0 && gltfMesh.primitives[0].targets != null) { num = gltfMesh.primitives[0].targets.Count; } if (num == 0) { return; } bool flag = sampler.interpolation == "CUBICSPLINE"; int num2 = times.Length; int num3 = (flag ? (num * 3) : num); AnimationCurve[] array2 = (AnimationCurve[])(object)new AnimationCurve[num]; for (int i = 0; i < num; i++) { array2[i] = new AnimationCurve(); } for (int j = 0; j < num2; j++) { float num4 = times[j]; for (int k = 0; k < num; k++) { int num5 = ((!flag) ? (j * num + k) : (j * num3 + num + k)); float num6 = ((num5 < array.Length) ? (array[num5] * 100f) : 0f); array2[k].AddKey(num4, num6); } } for (int l = 0; l < num; l++) { string text = $"blendShape.{l}"; clip.SetCurve(nodePath, Il2CppType.Of(), text, array2[l]); } } private static string GetNodePath(GltfLoadContext context, int nodeIndex) { Transform nodeTransform = context.GetNodeTransform(nodeIndex); if ((Object)(object)nodeTransform == (Object)null) { return null; } List list = new List(); Transform val = nodeTransform; while ((Object)(object)val != (Object)null && (Object)(object)val.parent != (Object)null) { list.Insert(0, ((Object)val).name); val = val.parent; if (((Object)val).name == context.Options.RootName) { break; } } return string.Join("/", list); } private static float[] ReadFloatArray(GltfLoadContext context, int accessorIndex) { GltfAccessor accessor = context.GetAccessor(accessorIndex); if (accessor == null) { return null; } byte[] accessorData = context.GetAccessorData(accessorIndex); if (accessorData == null) { return null; } int num = context.GetBufferView(accessor.bufferView.GetValueOrDefault())?.byteStride ?? 4; int count = accessor.count; float[] array = new float[count]; for (int i = 0; i < count; i++) { int num2 = accessor.byteOffset + i * num; if (num2 + 4 <= accessorData.Length) { array[i] = BitConverter.ToSingle(accessorData, num2); } } return array; } private static Vector3[] ReadVector3Array(GltfLoadContext context, int accessorIndex) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) GltfAccessor accessor = context.GetAccessor(accessorIndex); if (accessor == null) { return null; } byte[] accessorData = context.GetAccessorData(accessorIndex); if (accessorData == null) { return null; } int num = context.GetBufferView(accessor.bufferView.GetValueOrDefault())?.byteStride ?? 12; int count = accessor.count; Vector3[] array = (Vector3[])(object)new Vector3[count]; for (int i = 0; i < count; i++) { int num2 = accessor.byteOffset + i * num; if (num2 + 12 <= accessorData.Length) { float num3 = BitConverter.ToSingle(accessorData, num2); float num4 = BitConverter.ToSingle(accessorData, num2 + 4); float num5 = BitConverter.ToSingle(accessorData, num2 + 8); array[i] = new Vector3(num3, num4, num5); } } return array; } private static Vector4[] ReadVector4Array(GltfLoadContext context, int accessorIndex) { //IL_00f3: 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) GltfAccessor accessor = context.GetAccessor(accessorIndex); if (accessor == null) { return null; } byte[] accessorData = context.GetAccessorData(accessorIndex); if (accessorData == null) { return null; } int num = context.GetBufferView(accessor.bufferView.GetValueOrDefault())?.byteStride ?? 16; int count = accessor.count; Vector4[] array = (Vector4[])(object)new Vector4[count]; for (int i = 0; i < count; i++) { int num2 = accessor.byteOffset + i * num; if (num2 + 16 <= accessorData.Length) { float num3 = BitConverter.ToSingle(accessorData, num2); float num4 = BitConverter.ToSingle(accessorData, num2 + 4); float num5 = BitConverter.ToSingle(accessorData, num2 + 8); float num6 = BitConverter.ToSingle(accessorData, num2 + 12); array[i] = new Vector4(num3, num4, num5, num6); } } return array; } } internal sealed class GltfBufferResolver { private readonly string _basePath; private readonly byte[] _glbBinaryChunk; public GltfBufferResolver(byte[] glbBinaryChunk) { _glbBinaryChunk = glbBinaryChunk; _basePath = null; } public GltfBufferResolver(string basePath) { _basePath = basePath; _glbBinaryChunk = null; } public GltfBufferResolver(string basePath, byte[] glbBinaryChunk) { _basePath = basePath; _glbBinaryChunk = glbBinaryChunk; } public bool ResolveBuffers(GltfRoot gltf) { bool result; if (gltf.buffers == null || gltf.buffers.Count == 0) { result = true; } else { for (int i = 0; i < gltf.buffers.Count; i++) { GltfBuffer gltfBuffer = gltf.buffers[i]; if (gltfBuffer.Data == null) { byte[] array = ResolveBuffer(gltfBuffer, i); if (array == null) { DebugLog.Error($"Failed to resolve buffer {i}"); return false; } gltfBuffer.Data = array; } } result = true; } return result; } public byte[] ResolveBuffer(GltfBuffer buffer, int bufferIndex) { if (string.IsNullOrEmpty(buffer.uri)) { if (bufferIndex == 0 && _glbBinaryChunk != null) { return _glbBinaryChunk; } DebugLog.Error($"Buffer {bufferIndex} has no URI and no GLB binary chunk available"); return null; } if (IsDataUri(buffer.uri)) { return DecodeDataUri(buffer.uri); } return LoadExternalFile(buffer.uri); } public byte[] GetBufferViewData(GltfRoot gltf, int bufferViewIndex) { if (gltf.bufferViews == null || bufferViewIndex < 0 || bufferViewIndex >= gltf.bufferViews.Count) { return null; } GltfBufferView gltfBufferView = gltf.bufferViews[bufferViewIndex]; if (gltf.buffers == null || gltfBufferView.buffer < 0 || gltfBufferView.buffer >= gltf.buffers.Count) { return null; } GltfBuffer gltfBuffer = gltf.buffers[gltfBufferView.buffer]; if (gltfBuffer.Data == null) { DebugLog.Error($"Buffer {gltfBufferView.buffer} not resolved"); return null; } int byteOffset = gltfBufferView.byteOffset; int byteLength = gltfBufferView.byteLength; if (byteOffset + byteLength > gltfBuffer.Data.Length) { DebugLog.Error($"Buffer view {bufferViewIndex} exceeds buffer bounds"); return null; } byte[] array = new byte[byteLength]; Array.Copy(gltfBuffer.Data, byteOffset, array, 0, byteLength); return array; } private static bool IsDataUri(string uri) { return uri?.StartsWith("data:", StringComparison.OrdinalIgnoreCase) ?? false; } private static byte[] DecodeDataUri(string uri) { int num = uri.IndexOf(','); if (num < 0) { DebugLog.Error("Invalid data URI: missing comma separator"); return null; } string text = uri.Substring(0, num); string text2 = uri.Substring(num + 1); bool flag = text.Contains(";base64"); try { if (flag) { return Convert.FromBase64String(text2); } string s = Uri.UnescapeDataString(text2); return Encoding.UTF8.GetBytes(s); } catch (Exception ex) { DebugLog.Error("Failed to decode data URI: " + ex.Message); return null; } } private byte[] LoadExternalFile(string uri) { if (string.IsNullOrEmpty(_basePath)) { DebugLog.Error("Cannot load external file '" + uri + "': no base path specified"); return null; } try { string path = Uri.UnescapeDataString(uri); string path2 = Path.Combine(_basePath, path); path2 = Path.GetFullPath(path2); string fullPath = Path.GetFullPath(_basePath); if (!path2.StartsWith(fullPath, StringComparison.OrdinalIgnoreCase)) { DebugLog.Error("Security: external file '" + uri + "' resolves outside base directory"); return null; } if (!File.Exists(path2)) { DebugLog.Error("External file not found: " + path2); return null; } return File.ReadAllBytes(path2); } catch (Exception ex) { DebugLog.Error("Failed to load external file '" + uri + "': " + ex.Message); return null; } } } internal static class GltfMaterialProcessor { private static class UrpProperty { public const string BaseMap = "_BaseMap"; public const string BumpMap = "_BumpMap"; public const string MetallicGlossMap = "_MetallicGlossMap"; public const string OcclusionMap = "_OcclusionMap"; public const string EmissionMap = "_EmissionMap"; public const string BaseColor = "_BaseColor"; public const string EmissionColor = "_EmissionColor"; public const string Metallic = "_Metallic"; public const string Smoothness = "_Smoothness"; public const string BumpScale = "_BumpScale"; public const string OcclusionStrength = "_OcclusionStrength"; public const string Surface = "_Surface"; public const string Blend = "_Blend"; public const string AlphaClip = "_AlphaClip"; public const string Cutoff = "_Cutoff"; public const string Cull = "_Cull"; public const string SrcBlend = "_SrcBlend"; public const string DstBlend = "_DstBlend"; public const string ZWrite = "_ZWrite"; } private static class UrpShaderName { public const string Lit = "Universal Render Pipeline/Lit"; public const string SimpleLit = "Universal Render Pipeline/Simple Lit"; public const string Unlit = "Universal Render Pipeline/Unlit"; } public static List ProcessMaterials(GltfLoadContext context) { List list = new List(); GltfRoot root = context.Root; if (root.materials == null) { return list; } Shader shader = GetShader(context); if ((Object)(object)shader == (Object)null) { DebugLog.Error("Failed to find URP Lit shader for materials"); return list; } for (int i = 0; i < root.materials.Count; i++) { GltfMaterial gltfMat = root.materials[i]; Material val = CreateMaterial(context, gltfMat, shader, i); list.Add(val); context.RegisterMaterial(val); } return list; } public static Material CreateDefaultMaterial(GltfLoadContext context) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) Shader shader = GetShader(context); if ((Object)(object)shader == (Object)null) { DebugLog.Error("Failed to find URP shader for default material"); return null; } Material val = new Material(shader); ((Object)val).name = "DefaultGltfMaterial"; SetBaseColor(val, new Color(0.8f, 0.8f, 0.8f, 1f)); SetMetallicSmoothness(val, 0f, 0.5f); context.RegisterMaterial(val); return val; } private static Shader GetShader(GltfLoadContext context) { if ((Object)(object)context.Options.Shader != (Object)null) { return context.Options.Shader; } Shader val = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val != (Object)null) { return val; } val = Shader.Find("Universal Render Pipeline/Simple Lit"); if ((Object)(object)val != (Object)null) { DebugLog.Warning("URP Lit shader not found, using Simple Lit"); return val; } val = Shader.Find("Standard"); if ((Object)(object)val != (Object)null) { DebugLog.Warning("URP shaders not found, falling back to Standard (may not render correctly)"); } return val; } private static Material CreateMaterial(GltfLoadContext context, GltfMaterial gltfMat, Shader shader, int index) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) Material val = new Material(shader); Object val2 = (Object)(object)val; string name; if ((name = gltfMat.name) == null) { name = $"material_{index}"; } val2.name = name; if (gltfMat.pbrMetallicRoughness != null) { ApplyPbrMetallicRoughness(context, val, gltfMat.pbrMetallicRoughness); } else { SetBaseColor(val, Color.white); SetMetallicSmoothness(val, 0f, 0.5f); } if (gltfMat.normalTexture != null) { ApplyNormalTexture(context, val, gltfMat.normalTexture); } if (gltfMat.occlusionTexture != null) { ApplyOcclusionTexture(context, val, gltfMat.occlusionTexture); } if (gltfMat.emissiveTexture != null || gltfMat.emissiveFactor != null) { ApplyEmission(context, val, gltfMat); } ApplyAlphaMode(val, gltfMat); if (gltfMat.doubleSided == true) { val.SetFloat("_Cull", 0f); } return val; } private static void ApplyPbrMetallicRoughness(GltfLoadContext context, Material mat, GltfPbrMetallicRoughness pbr) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Color white = Color.white; if (pbr.baseColorFactor != null && pbr.baseColorFactor.Length >= 4) { ((Color)(ref white))..ctor(pbr.baseColorFactor[0], pbr.baseColorFactor[1], pbr.baseColorFactor[2], pbr.baseColorFactor[3]); } SetBaseColor(mat, white); if (pbr.baseColorTexture != null) { Texture2D texture = GetTexture(context, pbr.baseColorTexture.index); if ((Object)(object)texture != (Object)null) { mat.SetTexture("_BaseMap", (Texture)(object)texture); } } float metallic = pbr.metallicFactor ?? 1f; float num = pbr.roughnessFactor ?? 1f; float smoothness = 1f - num; SetMetallicSmoothness(mat, metallic, smoothness); if (pbr.metallicRoughnessTexture != null) { Texture2D texture2 = GetTexture(context, pbr.metallicRoughnessTexture.index); if ((Object)(object)texture2 != (Object)null) { DebugLog.Warning("MetallicRoughnessTexture requires channel remapping for URP. Material '" + ((Object)mat).name + "' may not render correctly."); mat.SetTexture("_MetallicGlossMap", (Texture)(object)texture2); } } } private static void SetBaseColor(Material mat, Color color) { //IL_0019: 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) if (mat.HasProperty("_BaseColor")) { mat.SetColor("_BaseColor", color); } else if (mat.HasProperty("_Color")) { mat.SetColor("_Color", color); } } private static void SetMetallicSmoothness(Material mat, float metallic, float smoothness) { if (mat.HasProperty("_Metallic")) { mat.SetFloat("_Metallic", metallic); } else if (mat.HasProperty("_Metallic")) { mat.SetFloat("_Metallic", metallic); } if (mat.HasProperty("_Smoothness")) { mat.SetFloat("_Smoothness", smoothness); } else if (mat.HasProperty("_Glossiness")) { mat.SetFloat("_Glossiness", smoothness); } } private static void ApplyNormalTexture(GltfLoadContext context, Material mat, GltfNormalTextureInfo normalInfo) { Texture2D texture = GetTexture(context, normalInfo.index); if ((Object)(object)texture != (Object)null) { mat.SetTexture("_BumpMap", (Texture)(object)texture); mat.EnableKeyword("_NORMALMAP"); if (normalInfo.scale.HasValue) { mat.SetFloat("_BumpScale", normalInfo.scale.Value); } } } private static void ApplyOcclusionTexture(GltfLoadContext context, Material mat, GltfOcclusionTextureInfo occlusionInfo) { Texture2D texture = GetTexture(context, occlusionInfo.index); if ((Object)(object)texture != (Object)null) { mat.SetTexture("_OcclusionMap", (Texture)(object)texture); mat.EnableKeyword("_OCCLUSIONMAP"); if (occlusionInfo.strength.HasValue) { mat.SetFloat("_OcclusionStrength", occlusionInfo.strength.Value); } } } private static void ApplyEmission(GltfLoadContext context, Material mat, GltfMaterial gltfMat) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) Color val = Color.black; float num = context.Options.EmissionIntensity; if (gltfMat.extensions != null && gltfMat.extensions.ContainsKey("KHR_materials_emissive_strength")) { try { object obj = gltfMat.extensions["KHR_materials_emissive_strength"]; if (obj is Dictionary dictionary && dictionary.ContainsKey("emissiveStrength")) { object obj2 = dictionary["emissiveStrength"]; float num2 = 1f; bool flag; if (obj2 is float) { num2 = (float)obj2; flag = true; } else { flag = false; } if (flag) { num *= num2; } else { obj2 = dictionary["emissiveStrength"]; double num3 = 1.0; bool flag2; if (obj2 is double) { num3 = (double)obj2; flag2 = true; } else { flag2 = false; } if (flag2) { num *= (float)num3; } } } } catch { } } if (gltfMat.emissiveFactor != null && gltfMat.emissiveFactor.Length >= 3) { ((Color)(ref val))..ctor(gltfMat.emissiveFactor[0] * num, gltfMat.emissiveFactor[1] * num, gltfMat.emissiveFactor[2] * num, 1f); } if (gltfMat.emissiveTexture != null) { Texture2D texture = GetTexture(context, gltfMat.emissiveTexture.index); if ((Object)(object)texture != (Object)null) { mat.SetTexture("_EmissionMap", (Texture)(object)texture); mat.EnableKeyword("_EMISSION"); if (gltfMat.emissiveFactor == null) { val = Color.white * num; } } } if (val != Color.black) { mat.SetColor("_EmissionColor", val); mat.EnableKeyword("_EMISSION"); mat.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)2; } } private static void ApplyAlphaMode(Material mat, GltfMaterial gltfMat) { switch (gltfMat.alphaMode ?? "OPAQUE") { default: SetUrpOpaqueMode(mat); break; case "BLEND": SetUrpTransparentMode(mat); break; case "MASK": SetUrpCutoutMode(mat, gltfMat.alphaCutoff ?? 0.5f); break; case "OPAQUE": SetUrpOpaqueMode(mat); break; } } private static void SetUrpOpaqueMode(Material mat) { mat.SetFloat("_Surface", 0f); mat.SetFloat("_AlphaClip", 0f); mat.SetFloat("_SrcBlend", 1f); mat.SetFloat("_DstBlend", 0f); mat.SetFloat("_ZWrite", 1f); mat.DisableKeyword("_ALPHATEST_ON"); mat.DisableKeyword("_ALPHABLEND_ON"); mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); mat.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.renderQueue = 2000; } private static void SetUrpCutoutMode(Material mat, float cutoff) { mat.SetFloat("_Surface", 0f); mat.SetFloat("_AlphaClip", 1f); mat.SetFloat("_Cutoff", cutoff); mat.SetFloat("_SrcBlend", 1f); mat.SetFloat("_DstBlend", 0f); mat.SetFloat("_ZWrite", 1f); mat.EnableKeyword("_ALPHATEST_ON"); mat.DisableKeyword("_ALPHABLEND_ON"); mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); mat.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.renderQueue = 2450; } private static void SetUrpTransparentMode(Material mat) { mat.SetFloat("_Surface", 1f); mat.SetFloat("_Blend", 0f); mat.SetFloat("_AlphaClip", 0f); mat.SetFloat("_SrcBlend", 5f); mat.SetFloat("_DstBlend", 10f); mat.SetFloat("_ZWrite", 0f); mat.DisableKeyword("_ALPHATEST_ON"); mat.EnableKeyword("_ALPHABLEND_ON"); mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.renderQueue = 3000; } private static Texture2D GetTexture(GltfLoadContext context, int textureIndex) { IReadOnlyList textures = context.Textures; if (textures == null || textureIndex < 0 || textureIndex >= textures.Count) { return null; } return textures[textureIndex]; } } internal static class GltfMeshProcessor { public static List ProcessMeshes(GltfRoot gltf, byte[] binaryBuffer) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown List list = new List(); if (gltf.meshes == null) { return list; } foreach (GltfMesh mesh in gltf.meshes) { Mesh val = new Mesh(); ((Object)val).name = mesh.name ?? "gltf_mesh"; val.indexFormat = (IndexFormat)1; List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); List list6 = new List(); List list7 = new List(); List list8 = new List(); int num = 0; if (mesh.primitives != null) { foreach (GltfPrimitive primitive in mesh.primitives) { if (primitive.attributes == null) { continue; } int num2 = 0; if (primitive.attributes.TryGetValue("POSITION", out var value)) { Vector3[] array = ReadVector3Array(gltf, binaryBuffer, value, convertCoordinate: true); num2 = array.Length; list2.AddRange(array); } if (primitive.attributes.TryGetValue("NORMAL", out var value2)) { list3.AddRange(ReadVector3Array(gltf, binaryBuffer, value2, convertCoordinate: true)); } if (primitive.attributes.TryGetValue("TEXCOORD_0", out var value3)) { Vector2[] array2 = ReadVector2Array(gltf, binaryBuffer, value3, flipY: false); FlipUVs(array2); list4.AddRange(array2); } if (primitive.attributes.TryGetValue("TANGENT", out var value4)) { list5.AddRange(ReadVector4Array(gltf, binaryBuffer, value4, convertCoordinate: true)); } int value5 = 0; if (primitive.attributes.TryGetValue("JOINTS_0", out var value6) && primitive.attributes.TryGetValue("WEIGHTS_0", out value5)) { list6.AddRange(ReadBoneWeights(gltf, binaryBuffer, value6, value5)); } if (primitive.indices.HasValue) { int[] array3 = ReadIntArray(gltf, binaryBuffer, primitive.indices.Value); FlipTriangles(array3); if (num > 0) { for (int i = 0; i < array3.Length; i++) { array3[i] += num; } } list7.Add(array3); } else { int[] array4 = new int[num2]; for (int j = 0; j < num2; j++) { array4[j] = num + j; } FlipTriangles(array4); list7.Add(array4); DebugLog.Info("Non-indexed primitive in mesh '" + ((Object)val).name + "': generated " + num2 + " sequential indices."); } list8.Add(primitive.material ?? (-1)); num += num2; } } val.SetVertices(list2.ToIl2CppList()); if (list3.Count > 0) { val.SetNormals(list3.ToIl2CppList()); } if (list4.Count > 0) { val.SetUVs(0, list4.ToIl2CppList()); } if (list5.Count > 0) { val.SetTangents(list5.ToIl2CppList()); } if (list6.Count > 0) { val.boneWeights = Il2CppStructArray.op_Implicit(list6.ToArray()); } val.subMeshCount = list7.Count; for (int k = 0; k < list7.Count; k++) { val.SetTriangles(Il2CppStructArray.op_Implicit(list7[k]), k); } if (list5.Count == 0 && list3.Count > 0 && list4.Count > 0) { val.RecalculateTangents(); } val.RecalculateBounds(); list.Add(new GltfMeshResult { mesh = val, materialIndices = list8.ToArray() }); } return list; } private static void FlipUVs(Vector2[] uvs) { for (int i = 0; i < uvs.Length; i++) { uvs[i].y = 1f - uvs[i].y; } } private static void FlipTriangles(int[] indices) { for (int i = 0; i < indices.Length; i += 3) { int num = indices[i]; indices[i] = indices[i + 2]; indices[i + 2] = num; } } private static Vector3[] ReadVector3Array(GltfRoot gltf, byte[] buffer, int accessorIndex, bool convertCoordinate) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (!TryGetAccessorReadContext(gltf, buffer, accessorIndex, 12, 12, out var _, out var count, out var offset, out var stride)) { return (Vector3[])(object)new Vector3[0]; } Vector3[] array = (Vector3[])(object)new Vector3[count]; for (int i = 0; i < count; i++) { int num = offset + i * stride; float value = 0f; float value2 = 0f; float value3 = 0f; if (!TryReadSingle(buffer, num, out value) || !TryReadSingle(buffer, num + 4, out value2) || !TryReadSingle(buffer, num + 8, out value3)) { DebugLog.Warning("Aborted Vector3 accessor read because buffer bounds were exceeded"); return (Vector3[])(object)new Vector3[0]; } if (convertCoordinate) { array[i] = new Vector3(0f - value, value2, value3); } else { array[i] = new Vector3(value, value2, value3); } } return array; } private static Vector2[] ReadVector2Array(GltfRoot gltf, byte[] buffer, int accessorIndex, bool flipY) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!TryGetAccessorReadContext(gltf, buffer, accessorIndex, 8, 8, out var _, out var count, out var offset, out var stride)) { return (Vector2[])(object)new Vector2[0]; } Vector2[] array = (Vector2[])(object)new Vector2[count]; for (int i = 0; i < count; i++) { int num = offset + i * stride; float value = 0f; float value2 = 0f; if (!TryReadSingle(buffer, num, out value) || !TryReadSingle(buffer, num + 4, out value2)) { DebugLog.Warning("Aborted Vector2 accessor read because buffer bounds were exceeded"); return (Vector2[])(object)new Vector2[0]; } array[i] = new Vector2(value, value2); } return array; } private static Vector4[] ReadVector4Array(GltfRoot gltf, byte[] buffer, int accessorIndex, bool convertCoordinate) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) if (!TryGetAccessorReadContext(gltf, buffer, accessorIndex, 16, 16, out var _, out var count, out var offset, out var stride)) { return (Vector4[])(object)new Vector4[0]; } Vector4[] array = (Vector4[])(object)new Vector4[count]; for (int i = 0; i < count; i++) { int num = offset + i * stride; float value = 0f; float value2 = 0f; float value3 = 0f; float value4 = 0f; if (!TryReadSingle(buffer, num, out value) || !TryReadSingle(buffer, num + 4, out value2) || !TryReadSingle(buffer, num + 8, out value3) || !TryReadSingle(buffer, num + 12, out value4)) { DebugLog.Warning("Aborted Vector4 accessor read because buffer bounds were exceeded"); return (Vector4[])(object)new Vector4[0]; } if (convertCoordinate) { array[i] = new Vector4(0f - value, value2, value3, value4); } else { array[i] = new Vector4(value, value2, value3, value4); } } return array; } private static int[] ReadIntArray(GltfRoot gltf, byte[] buffer, int accessorIndex) { if (gltf.accessors == null || accessorIndex < 0 || accessorIndex >= gltf.accessors.Count) { return new int[0]; } GltfAccessor accessor = gltf.accessors[accessorIndex]; int componentSize = GetComponentSize(accessor.componentType); if (accessor.componentType != 5121 && accessor.componentType != 5123 && accessor.componentType != 5125) { DebugLog.Warning("Unsupported component type for indices: " + accessor.componentType); return new int[0]; } if (!TryGetAccessorReadContext(gltf, buffer, accessorIndex, componentSize, componentSize, out accessor, out var count, out var offset, out var stride)) { return new int[0]; } int[] array = new int[count]; for (int i = 0; i < count; i++) { int num = offset + i * stride; switch (accessor.componentType) { case 5121: array[i] = buffer[num]; break; case 5123: { if (!TryReadUInt16(buffer, num, out var value2)) { DebugLog.Warning("Aborted index accessor read because buffer bounds were exceeded"); return new int[0]; } array[i] = value2; break; } case 5125: { if (!TryReadUInt32(buffer, num, out var value)) { DebugLog.Warning("Aborted index accessor read because buffer bounds were exceeded"); return new int[0]; } array[i] = (int)value; break; } } } return array; } private static BoneWeight[] ReadBoneWeights(GltfRoot gltf, byte[] buffer, int jointsIndex, int weightsIndex) { //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) if (gltf.accessors == null || gltf.bufferViews == null || buffer == null || jointsIndex < 0 || weightsIndex < 0 || jointsIndex >= gltf.accessors.Count || weightsIndex >= gltf.accessors.Count) { return (BoneWeight[])(object)new BoneWeight[0]; } GltfAccessor accessor = gltf.accessors[jointsIndex]; GltfAccessor accessor2 = gltf.accessors[weightsIndex]; if (accessor.componentType != 5121 && accessor.componentType != 5123) { DebugLog.Warning("Unsupported component type for joints: " + accessor.componentType); return (BoneWeight[])(object)new BoneWeight[0]; } int count = 0; int offset = 0; int stride = 0; if (!TryGetAccessorReadContext(gltf, buffer, jointsIndex, (accessor.componentType == 5123) ? 8 : 4, (accessor.componentType == 5123) ? 8 : 4, out accessor, out var count2, out var offset2, out var stride2) || !TryGetAccessorReadContext(gltf, buffer, weightsIndex, GetBoneWeightStride(accessor2.componentType), GetBoneWeightStride(accessor2.componentType), out accessor2, out count, out offset, out stride)) { return (BoneWeight[])(object)new BoneWeight[0]; } int num = Math.Min(count2, count); if (count2 != count) { DebugLog.Warning("Joint and weight accessor counts differ. Truncating to the smaller count."); } BoneWeight[] array = (BoneWeight[])(object)new BoneWeight[num]; for (int i = 0; i < num; i++) { BoneWeight boneWeight = default(BoneWeight); int num2 = offset2 + i * stride2; if (accessor.componentType == 5123) { ushort value = 0; ushort value2 = 0; ushort value3 = 0; ushort value4 = 0; if (!TryReadUInt16(buffer, num2, out value) || !TryReadUInt16(buffer, num2 + 2, out value2) || !TryReadUInt16(buffer, num2 + 4, out value3) || !TryReadUInt16(buffer, num2 + 6, out value4)) { DebugLog.Warning("Aborted bone joint accessor read because buffer bounds were exceeded"); return (BoneWeight[])(object)new BoneWeight[0]; } ((BoneWeight)(ref boneWeight)).boneIndex0 = value; ((BoneWeight)(ref boneWeight)).boneIndex1 = value2; ((BoneWeight)(ref boneWeight)).boneIndex2 = value3; ((BoneWeight)(ref boneWeight)).boneIndex3 = value4; } else { if (!HasBufferRange(buffer, num2, 4)) { DebugLog.Warning("Aborted bone joint accessor read because buffer bounds were exceeded"); return (BoneWeight[])(object)new BoneWeight[0]; } ((BoneWeight)(ref boneWeight)).boneIndex0 = buffer[num2]; ((BoneWeight)(ref boneWeight)).boneIndex1 = buffer[num2 + 1]; ((BoneWeight)(ref boneWeight)).boneIndex2 = buffer[num2 + 2]; ((BoneWeight)(ref boneWeight)).boneIndex3 = buffer[num2 + 3]; } int offset3 = offset + i * stride; float weight = 0f; float weight2 = 0f; float weight3 = 0f; float weight4 = 0f; if (!ReadBoneWeightValues(buffer, accessor2, offset3, out weight, out weight2, out weight3, out weight4)) { DebugLog.Warning("Aborted bone weight accessor read because buffer bounds were exceeded"); return (BoneWeight[])(object)new BoneWeight[0]; } ((BoneWeight)(ref boneWeight)).weight0 = weight; ((BoneWeight)(ref boneWeight)).weight1 = weight2; ((BoneWeight)(ref boneWeight)).weight2 = weight3; ((BoneWeight)(ref boneWeight)).weight3 = weight4; NormalizeBoneWeights(ref boneWeight); array[i] = boneWeight; } return array; } private static int GetComponentSize(int componentType) { return componentType switch { 5120 => 1, 5121 => 1, 5122 => 2, 5123 => 2, 5125 => 4, 5126 => 4, _ => 1, }; } private static int GetBoneWeightStride(int componentType) { return componentType switch { 5121 => 4, 5123 => 8, 5126 => 16, _ => 16, }; } private static bool ReadBoneWeightValues(byte[] buffer, GltfAccessor accessor, int offset, out float weight0, out float weight1, out float weight2, out float weight3) { weight0 = 0f; weight1 = 0f; weight2 = 0f; weight3 = 0f; switch (accessor.componentType) { case 5121: if (!HasBufferRange(buffer, offset, 4)) { return false; } weight0 = ReadNormalizedByteWeight(buffer, offset, accessor.normalized == true); weight1 = ReadNormalizedByteWeight(buffer, offset + 1, accessor.normalized == true); weight2 = ReadNormalizedByteWeight(buffer, offset + 2, accessor.normalized == true); weight3 = ReadNormalizedByteWeight(buffer, offset + 3, accessor.normalized == true); return true; case 5123: if (!HasBufferRange(buffer, offset, 8)) { return false; } weight0 = ReadNormalizedUShortWeight(buffer, offset, accessor.normalized == true); weight1 = ReadNormalizedUShortWeight(buffer, offset + 2, accessor.normalized == true); weight2 = ReadNormalizedUShortWeight(buffer, offset + 4, accessor.normalized == true); weight3 = ReadNormalizedUShortWeight(buffer, offset + 6, accessor.normalized == true); return true; case 5126: if (!TryReadSingle(buffer, offset, out weight0) || !TryReadSingle(buffer, offset + 4, out weight1) || !TryReadSingle(buffer, offset + 8, out weight2) || !TryReadSingle(buffer, offset + 12, out weight3)) { return false; } return true; default: DebugLog.Warning("Unsupported component type for bone weights: " + accessor.componentType); return false; } } private static float ReadNormalizedByteWeight(byte[] buffer, int offset, bool normalized) { float num = (int)buffer[offset]; return normalized ? (num / 255f) : num; } private static float ReadNormalizedUShortWeight(byte[] buffer, int offset, bool normalized) { float num = (int)BitConverter.ToUInt16(buffer, offset); return normalized ? (num / 65535f) : num; } private static bool TryGetAccessorReadContext(GltfRoot gltf, byte[] buffer, int accessorIndex, int defaultStride, int minimumElementSize, out GltfAccessor accessor, out int count, out int offset, out int stride) { accessor = null; count = 0; offset = 0; stride = 0; if (gltf.accessors == null || gltf.bufferViews == null || buffer == null || accessorIndex < 0 || accessorIndex >= gltf.accessors.Count) { return false; } accessor = gltf.accessors[accessorIndex]; if (accessor == null || !accessor.bufferView.HasValue || accessor.bufferView.Value < 0 || accessor.bufferView.Value >= gltf.bufferViews.Count) { DebugLog.Warning("Accessor " + accessorIndex + " references an invalid bufferView"); return false; } GltfBufferView gltfBufferView = gltf.bufferViews[accessor.bufferView.Value]; count = accessor.count; stride = gltfBufferView.byteStride ?? defaultStride; if (count < 0 || stride < minimumElementSize) { DebugLog.Warning("Accessor " + accessorIndex + " has an invalid count or stride"); return false; } offset = gltfBufferView.byteOffset + accessor.byteOffset; long num = minimumElementSize + (long)Math.Max(0, count - 1) * (long)stride; if (num > int.MaxValue || (count > 0 && !HasBufferRange(buffer, offset, (int)num))) { DebugLog.Warning("Accessor " + accessorIndex + " exceeds buffer bounds"); return false; } return true; } private static bool HasBufferRange(byte[] buffer, int offset, int length) { return buffer != null && offset >= 0 && length >= 0 && (long)offset + (long)length <= buffer.Length; } private static bool TryReadSingle(byte[] buffer, int offset, out float value) { value = 0f; if (!HasBufferRange(buffer, offset, 4)) { return false; } value = BitConverter.ToSingle(buffer, offset); return true; } private static bool TryReadUInt16(byte[] buffer, int offset, out ushort value) { value = 0; if (!HasBufferRange(buffer, offset, 2)) { return false; } value = BitConverter.ToUInt16(buffer, offset); return true; } private static bool TryReadUInt32(byte[] buffer, int offset, out uint value) { value = 0u; if (!HasBufferRange(buffer, offset, 4)) { return false; } value = BitConverter.ToUInt32(buffer, offset); return true; } private static void NormalizeBoneWeights(ref BoneWeight boneWeight) { float num = ((BoneWeight)(ref boneWeight)).weight0 + ((BoneWeight)(ref boneWeight)).weight1 + ((BoneWeight)(ref boneWeight)).weight2 + ((BoneWeight)(ref boneWeight)).weight3; if (num > 0.0001f) { float num2 = 1f / num; ((BoneWeight)(ref boneWeight)).weight0 = ((BoneWeight)(ref boneWeight)).weight0 * num2; ((BoneWeight)(ref boneWeight)).weight1 = ((BoneWeight)(ref boneWeight)).weight1 * num2; ((BoneWeight)(ref boneWeight)).weight2 = ((BoneWeight)(ref boneWeight)).weight2 * num2; ((BoneWeight)(ref boneWeight)).weight3 = ((BoneWeight)(ref boneWeight)).weight3 * num2; } } } internal class GltfMeshResult { public Mesh mesh = null; public int[] materialIndices = null; } internal static class GltfNodeProcessor { public static List ProcessNodes(GltfRoot gltf, GameObject root, List meshes, List textures, Shader shader) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016f: 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_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Expected O, but got Unknown //IL_0432: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Dictionary dictionary = new Dictionary(); if (gltf.nodes == null) { return list; } for (int i = 0; i < gltf.nodes.Count; i++) { GltfNode gltfNode = gltf.nodes[i]; string text; if ((text = gltfNode.name) == null) { text = $"node_{i}"; } GameObject val = new GameObject(text); dictionary[i] = val.transform; list.Add(val.transform); if (gltfNode.matrix != null && gltfNode.matrix.Length == 16) { Matrix4x4 val2 = default(Matrix4x4); for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) { ((Matrix4x4)(ref val2))[k, j] = gltfNode.matrix[j * 4 + k]; } } Vector3 val3 = Vector4.op_Implicit(((Matrix4x4)(ref val2)).GetColumn(3)); Quaternion rotation = ((Matrix4x4)(ref val2)).rotation; Vector3 lossyScale = ((Matrix4x4)(ref val2)).lossyScale; val.transform.localPosition = new Vector3(0f - val3.x, val3.y, val3.z); val.transform.localRotation = new Quaternion(rotation.x, 0f - rotation.y, 0f - rotation.z, rotation.w); val.transform.localScale = lossyScale; } else { if (gltfNode.translation != null) { val.transform.localPosition = new Vector3(0f - gltfNode.translation[0], gltfNode.translation[1], gltfNode.translation[2]); } if (gltfNode.rotation != null) { val.transform.localRotation = new Quaternion(gltfNode.rotation[0], 0f - gltfNode.rotation[1], 0f - gltfNode.rotation[2], gltfNode.rotation[3]); } if (gltfNode.scale != null) { val.transform.localScale = new Vector3(gltfNode.scale[0], gltfNode.scale[1], gltfNode.scale[2]); } } if (!gltfNode.mesh.HasValue || gltfNode.mesh.Value >= meshes.Count) { continue; } GltfMeshResult gltfMeshResult = meshes[gltfNode.mesh.Value]; MeshFilter val4 = val.AddComponent(); val4.mesh = gltfMeshResult.mesh; MeshRenderer val5 = val.AddComponent(); Material[] array = (Material[])(object)new Material[gltfMeshResult.mesh.subMeshCount]; Shader val6 = shader ?? Shader.Find("Standard"); for (int l = 0; l < gltfMeshResult.mesh.subMeshCount; l++) { Material val7 = new Material(val6); int num = ((l < gltfMeshResult.materialIndices.Length) ? gltfMeshResult.materialIndices[l] : (-1)); if (num >= 0 && gltf.materials != null && num < gltf.materials.Count) { GltfMaterial gltfMaterial = gltf.materials[num]; Object val8 = (Object)(object)val7; string name; if ((name = gltfMaterial.name) == null) { name = $"material_{num}"; } val8.name = name; if (gltfMaterial.pbrMetallicRoughness != null) { GltfPbrMetallicRoughness pbrMetallicRoughness = gltfMaterial.pbrMetallicRoughness; if (pbrMetallicRoughness.baseColorFactor != null && pbrMetallicRoughness.baseColorFactor.Length == 4) { val7.color = new Color(pbrMetallicRoughness.baseColorFactor[0], pbrMetallicRoughness.baseColorFactor[1], pbrMetallicRoughness.baseColorFactor[2], pbrMetallicRoughness.baseColorFactor[3]); } if (pbrMetallicRoughness.baseColorTexture != null && textures != null) { int index = pbrMetallicRoughness.baseColorTexture.index; if (index >= 0 && index < textures.Count) { val7.mainTexture = (Texture)(object)textures[index]; } } if (((Object)val6).name == "Standard") { if (pbrMetallicRoughness.metallicFactor.HasValue) { val7.SetFloat("_Metallic", pbrMetallicRoughness.metallicFactor.Value); } if (pbrMetallicRoughness.roughnessFactor.HasValue) { val7.SetFloat("_Glossiness", 1f - pbrMetallicRoughness.roughnessFactor.Value); } } } } else { ((Object)val7).name = "DefaultMaterial"; } array[l] = val7; } ((Renderer)val5).materials = Il2CppReferenceArray.op_Implicit(array); if (((Object)val).name.StartsWith("COL_")) { MeshCollider val9 = val.AddComponent(); val9.sharedMesh = gltfMeshResult.mesh; ((Renderer)val5).enabled = false; } } for (int m = 0; m < gltf.nodes.Count; m++) { GltfNode gltfNode2 = gltf.nodes[m]; Transform val10 = dictionary[m]; if (gltfNode2.children == null) { continue; } foreach (int child in gltfNode2.children) { if (dictionary.TryGetValue(child, out var value) && (Object)(object)value != (Object)null) { value.SetParent(val10, false); } } } foreach (Transform item in list) { if ((Object)(object)item.parent == (Object)null) { item.SetParent(root.transform, false); } } return list; } } internal static class GltfTextureProcessor { public static List ProcessTextures(GltfRoot gltf, byte[] binaryBuffer) { List list = new List(); if (gltf.textures == null) { return list; } foreach (GltfTexture texture in gltf.textures) { if (texture.source.HasValue && gltf.images != null && texture.source.Value < gltf.images.Count) { GltfImage gltfImage = gltf.images[texture.source.Value]; Texture2D val = LoadImage(gltf, gltfImage, binaryBuffer); if ((Object)(object)val != (Object)null) { Object val2 = (Object)(object)val; string name; if ((name = texture.name) == null && (name = gltfImage.name) == null) { name = $"texture_{list.Count}"; } val2.name = name; if (texture.sampler.HasValue && gltf.samplers != null && texture.sampler.Value < gltf.samplers.Count) { ApplySampler(val, gltf.samplers[texture.sampler.Value]); } list.Add(val); } else { list.Add(null); DebugLog.Warning($"Failed to load texture index {list.Count - 1}"); } } else { list.Add(null); } } return list; } private static Texture2D LoadImage(GltfRoot gltf, GltfImage image, byte[] binaryBuffer) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown if (image.bufferView.HasValue && gltf.bufferViews != null && image.bufferView.Value < gltf.bufferViews.Count) { GltfBufferView gltfBufferView = gltf.bufferViews[image.bufferView.Value]; if (gltfBufferView.buffer == 0 && binaryBuffer != null) { int byteOffset = gltfBufferView.byteOffset; int byteLength = gltfBufferView.byteLength; if (byteOffset + byteLength <= binaryBuffer.Length) { byte[] array = new byte[byteLength]; Array.Copy(binaryBuffer, byteOffset, array, 0, byteLength); Texture2D val = new Texture2D(2, 2); if (ImageConversion.LoadImage(val, Il2CppStructArray.op_Implicit(array))) { return val; } } } } return null; } private static void ApplySampler(Texture2D tex, GltfSampler sampler) { //IL_001f: 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_0092: Unknown result type (might be due to invalid IL or missing references) if (sampler.wrapS.HasValue) { ((Texture)tex).wrapModeU = GetWrapMode(sampler.wrapS.Value); } if (sampler.wrapT.HasValue) { ((Texture)tex).wrapModeV = GetWrapMode(sampler.wrapT.Value); } if (sampler.minFilter.HasValue || sampler.magFilter.HasValue) { ((Texture)tex).filterMode = GetFilterMode(sampler.minFilter.GetValueOrDefault(), sampler.magFilter.GetValueOrDefault()); } } private static TextureWrapMode GetWrapMode(int mode) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) return (TextureWrapMode)(mode switch { 33648 => 2, 33071 => 1, 10497 => 0, _ => 0, }); } private static FilterMode GetFilterMode(int min, int mag) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (min == 9728 || mag == 9728) { return (FilterMode)0; } return (FilterMode)1; } } } namespace IllegalRave.Gltf.Data { [Serializable] internal sealed class GltfAccessor { public int? bufferView; public int byteOffset; public int componentType; public int count; public string type; public bool? normalized; public float[] min; public float[] max; public GltfAccessorSparse sparse; public string name; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfAccessorSparse { public int count; public GltfAccessorSparseIndices indices; public GltfAccessorSparseValues values; } [Serializable] internal sealed class GltfAccessorSparseIndices { public int bufferView; public int byteOffset; public int componentType; } [Serializable] internal sealed class GltfAccessorSparseValues { public int bufferView; public int byteOffset; } internal static class GltfAccessorType { public const string Scalar = "SCALAR"; public const string Vec2 = "VEC2"; public const string Vec3 = "VEC3"; public const string Vec4 = "VEC4"; public const string Mat2 = "MAT2"; public const string Mat3 = "MAT3"; public const string Mat4 = "MAT4"; public static int GetComponentCount(string type) { return type switch { "SCALAR" => 1, "VEC2" => 2, "VEC3" => 3, "VEC4" => 4, "MAT2" => 4, "MAT3" => 9, "MAT4" => 16, _ => 1, }; } } internal static class GltfAlphaMode { public const string Opaque = "OPAQUE"; public const string Mask = "MASK"; public const string Blend = "BLEND"; } [Serializable] internal sealed class GltfAnimation { public string name; public List channels; public List samplers; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfAnimationChannel { public int sampler; public GltfAnimationChannelTarget target; } [Serializable] internal sealed class GltfAnimationChannelTarget { public int? node; public string path; } internal static class GltfAnimationPath { public const string Translation = "translation"; public const string Rotation = "rotation"; public const string Scale = "scale"; public const string Weights = "weights"; } [Serializable] internal sealed class GltfAnimationSampler { public int input; public string interpolation; public int output; } [Serializable] internal sealed class GltfAsset { public string version; public string minVersion; public string generator; public string copyright; } [Serializable] internal sealed class GltfBuffer { public int byteLength; public string uri; public string name; [NonSerialized] public byte[] Data; } [Serializable] internal sealed class GltfBufferView { public int buffer; public int byteOffset; public int byteLength; public int? byteStride; public int? target; public string name; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfCamera { public string name; public string type; public GltfCameraPerspective perspective; public GltfCameraOrthographic orthographic; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfCameraOrthographic { public float xmag; public float ymag; public float znear; public float zfar; } [Serializable] internal sealed class GltfCameraPerspective { public float? aspectRatio; public float yfov; public float znear; public float? zfar; } internal static class GltfComponentType { public const int Byte = 5120; public const int UnsignedByte = 5121; public const int Short = 5122; public const int UnsignedShort = 5123; public const int UnsignedInt = 5125; public const int Float = 5126; public static int GetSize(int componentType) { bool flag = false; int result = componentType switch { 5120 => 1, 5121 => 1, 5122 => 2, 5123 => 2, 5125 => 4, 5126 => 4, _ => 1, }; bool flag2 = false; return result; } } [Serializable] internal sealed class GltfImage { public string uri; public string mimeType; public int? bufferView; public string name; public Dictionary extensions; public object extras; } public sealed class GltfImportOptions { public Shader Shader { get; set; } public bool ImportAnimations { get; set; } = true; public bool ImportSkins { get; set; } = true; public bool ImportBlendShapes { get; set; } = true; public bool ImportCameras { get; set; } = false; public bool GenerateMissingNormals { get; set; } = true; public bool GenerateMissingTangents { get; set; } = true; public bool ReadableMeshes { get; set; } = false; public float ScaleFactor { get; set; } = 1f; public string RootName { get; set; } = "GltfModel"; public float EmissionIntensity { get; set; } = 1f; } internal static class GltfInterpolation { public const string Linear = "LINEAR"; public const string Step = "STEP"; public const string CubicSpline = "CUBICSPLINE"; } internal sealed class GltfLoadContext { private readonly GltfRoot _root; private readonly GltfBufferResolver _bufferResolver; private readonly GltfImportOptions _options; private List _meshes; private List _materials; private List _textures; private List _animations; private Dictionary _nodeTransforms; public GltfRoot Root => _root; public GltfBufferResolver BufferResolver => _bufferResolver; public GltfImportOptions Options => _options; public IReadOnlyList Meshes => _meshes; public IReadOnlyList Materials => _materials; public IReadOnlyList Textures => _textures; public IReadOnlyList Animations => _animations; public IReadOnlyDictionary NodeTransforms => _nodeTransforms; public GltfLoadContext(GltfRoot root, GltfBufferResolver bufferResolver, GltfImportOptions options = null) { _root = root; _bufferResolver = bufferResolver; _options = options ?? new GltfImportOptions(); _meshes = new List(); _materials = new List(); _textures = new List(); _animations = new List(); _nodeTransforms = new Dictionary(); } public void RegisterMesh(Mesh mesh) { if (!((Object)(object)mesh == (Object)null)) { _meshes.Add(mesh); } } public void RegisterMaterial(Material material) { if (!((Object)(object)material == (Object)null)) { _materials.Add(material); } } public void RegisterTexture(Texture2D texture) { if ((Object)(object)texture == (Object)null) { _textures.Add(null); } else { _textures.Add(texture); } } public void RegisterAnimation(AnimationClip clip) { if (!((Object)(object)clip == (Object)null)) { _animations.Add(clip); } } public void RegisterNodeTransform(int nodeIndex, Transform transform) { _nodeTransforms[nodeIndex] = transform; } public Transform GetNodeTransform(int nodeIndex) { Transform value; return _nodeTransforms.TryGetValue(nodeIndex, out value) ? value : null; } public byte[] GetAccessorData(int accessorIndex) { if (_root.accessors == null || accessorIndex < 0 || accessorIndex >= _root.accessors.Count) { return null; } GltfAccessor gltfAccessor = _root.accessors[accessorIndex]; if (gltfAccessor.type == null) { return null; } if (!gltfAccessor.bufferView.HasValue) { int size = GltfComponentType.GetSize(gltfAccessor.componentType); int componentCount = GltfAccessorType.GetComponentCount(gltfAccessor.type); return new byte[gltfAccessor.count * size * componentCount]; } return _bufferResolver.GetBufferViewData(_root, gltfAccessor.bufferView.Value); } public GltfAccessor GetAccessor(int accessorIndex) { if (_root.accessors == null || accessorIndex < 0 || accessorIndex >= _root.accessors.Count) { return null; } return _root.accessors[accessorIndex]; } public GltfBufferView GetBufferView(int bufferViewIndex) { if (_root.bufferViews == null || bufferViewIndex < 0 || bufferViewIndex >= _root.bufferViews.Count) { return null; } return _root.bufferViews[bufferViewIndex]; } } [Serializable] internal sealed class GltfMaterial { public string name; public GltfPbrMetallicRoughness pbrMetallicRoughness; public GltfNormalTextureInfo normalTexture; public GltfOcclusionTextureInfo occlusionTexture; public GltfTextureInfo emissiveTexture; public float[] emissiveFactor; public string alphaMode; public float? alphaCutoff; public bool? doubleSided; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfMesh { public string name; public List primitives; public float[] weights; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfNode { public string name; public int? mesh; public int? skin; public int? camera; public float[] weights; public List children; public float[] matrix; public float[] translation; public float[] rotation; public float[] scale; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfNormalTextureInfo { public int index; public int? texCoord; public float? scale; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfOcclusionTextureInfo { public int index; public int? texCoord; public float? strength; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfPbrMetallicRoughness { public float[] baseColorFactor; public GltfTextureInfo baseColorTexture; public float? metallicFactor; public float? roughnessFactor; public GltfTextureInfo metallicRoughnessTexture; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfPrimitive { public Dictionary attributes; public int? indices; public int? material; public int mode = 4; public List> targets; public Dictionary extensions; public object extras; } internal static class GltfPrimitiveMode { public const int Points = 0; public const int Lines = 1; public const int LineLoop = 2; public const int LineStrip = 3; public const int Triangles = 4; public const int TriangleStrip = 5; public const int TriangleFan = 6; } [Serializable] internal sealed class GltfRoot { public GltfAsset asset; public List scenes; public List nodes; public List meshes; public List buffers; public List bufferViews; public List accessors; public List textures; public List images; public List samplers; public List materials; public List skins; public List animations; public List cameras; public int scene; public List extensionsUsed; public List extensionsRequired; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfSampler { public int? magFilter; public int? minFilter; public int? wrapS; public int? wrapT; public string name; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfScene { public string name; public List nodes; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfSkin { public string name; public int? inverseBindMatrices; public int? skeleton; public List joints; public Dictionary extensions; public object extras; } [Serializable] internal sealed class GltfTexture { public int? sampler; public int? source; public string name; public Dictionary extensions; public object extras; } internal static class GltfTextureFilter { public const int Nearest = 9728; public const int Linear = 9729; public const int NearestMipmapNearest = 9984; public const int LinearMipmapNearest = 9985; public const int NearestMipmapLinear = 9986; public const int LinearMipmapLinear = 9987; } [Serializable] internal sealed class GltfTextureInfo { public int index; public int? texCoord; public Dictionary extensions; public object extras; } internal static class GltfTextureWrap { public const int ClampToEdge = 33071; public const int MirroredRepeat = 33648; public const int Repeat = 10497; } }