Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of IllegalRave v1.0.10
IllegalRave.IL2CPP.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; 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<GameObject>(_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<Vector3>(((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<Transform>(true)) { if (!((Object)componentsInChild).name.StartsWith("COL_", StringComparison.OrdinalIgnoreCase)) { continue; } MeshFilter component = ((Component)componentsInChild).GetComponent<MeshFilter>(); 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<MeshCollider>() ?? ((Component)componentsInChild).gameObject.AddComponent<MeshCollider>(); val.sharedMesh = component.sharedMesh; val.convex = false; MeshRenderer component2 = ((Component)componentsInChild).GetComponent<MeshRenderer>(); 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<GameObject> _stageAudioObjects = new List<GameObject>(); 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<string, AudioClip> _clipCache = new Dictionary<string, AudioClip>(); private static LinkedList<string> _cacheOrder = new LinkedList<string>(); private static Dictionary<AudioSource, float> _mutedSources = new Dictionary<AudioSource, float>(); 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<PendingClip> _pendingClips = new Queue<PendingClip>(); 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>(); _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<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = val5.GetComponent<Renderer>(); 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<Transform>(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<AudioSource>(); 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<AudioSource>(); 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<AudioSource>(); 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<AudioSource>(); 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<AudioSource>(); 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<AudioSource>(); 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<AudioSource>(); 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<float>.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<float>.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<float>.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<AudioSource>.op_Implicit(Object.FindObjectsOfType<AudioSource>()); if (array == null) { _cachedVanillaSources = null; return; } HashSet<AudioSource> hashSet = new HashSet<AudioSource>(); foreach (GameObject stageAudioObject in _stageAudioObjects) { if (!((Object)(object)stageAudioObject == (Object)null)) { AudioSource component = stageAudioObject.GetComponent<AudioSource>(); if ((Object)(object)component != (Object)null) { hashSet.Add(component); } } } List<AudioSource> list = new List<AudioSource>(); 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<AudioSource, float> 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<GameObject>.op_Implicit(Object.FindObjectsOfType<GameObject>()); 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<byte>.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<CompassManager>.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<RectTransform>(); val.sizeDelta = instance.ElementContentSize * 2.5f; Image val2 = _contentGO.AddComponent<Image>(); 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<CompassManager>.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<T> { 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<bool> SmallFestivalStageEnabled; internal static MelonPreferences_Entry<int> RaveStartTime; internal const bool EndOnSleep = true; internal const int FirstMessageTime = 2300; internal static readonly FixedEntry<float> EventRadius = new FixedEntry<float>(60f); internal static readonly FixedEntry<bool> DebugCoordinates = new FixedEntry<bool>(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<int> CustomRaveLocation; internal static MelonPreferences_Entry<bool> PresetTriggerChanceEnabled; private static MelonPreferences_Entry<string>[] _customSlots; internal static MelonPreferences_Entry<float> MusicVolume; internal static MelonPreferences_Entry<int> LampCount; internal static MelonPreferences_Entry<float> StrobeSpeed; internal static MelonPreferences_Entry<float> LightIntensity; internal static MelonPreferences_Entry<float> LightRange; internal static MelonPreferences_Entry<bool> StrobeEnabled; internal static MelonPreferences_Entry<float> StrobeInterval; internal static MelonPreferences_Entry<float> StrobeDuration; internal static MelonPreferences_Entry<int> LampColorR; internal static MelonPreferences_Entry<int> LampColorG; internal static MelonPreferences_Entry<int> LampColorB; internal static MelonPreferences_Entry<bool> LampRotation; internal static bool DJDanBooked; internal static bool DJGirlBooked; internal static bool DJCutChemistBooked; internal static bool DJLudapimpBooked; internal static MelonPreferences_Entry<bool> BundleDebugLogging; internal static MelonPreferences_Entry<int> NPCCount; internal static MelonPreferences_Entry<float> DanceSpeed; internal static MelonPreferences_Entry<float> 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<bool>("SmallFestivalStageEnabled", true, "Enable Small Rave Stage (Parkinglot only - trigger 100%)", (string)null, false, false, (ValueValidator)null, (string)null); RaveStartTime = Category.CreateEntry<int>("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<int>("CustomRaveLocation", 0, "Custom Rave", "Custom location slot (1-3). 0=use a random preset location.", false, false, (ValueValidator)null, (string)null); PresetTriggerChanceEnabled = Category.CreateEntry<bool>("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<string>[3]; string[] slotCoordinates = GetSlotCoordinates(); for (int i = 0; i < _customSlots.Length; i++) { string text = ((slotCoordinates[i] != null) ? "saved" : "free"); _customSlots[i] = Category.CreateEntry<string>($"Custom{i + 1}", text, $"Custom{i + 1}", slotCoordinates[i] ?? "", false, false, (ValueValidator)null, (string)null); _customSlots[i].Value = text; } MusicVolume = Category.CreateEntry<float>("MusicVolume", 0.7f, "Music Volume", "Rave music volume (0.0 - 1.5)", false, false, (ValueValidator)null, (string)null); LampCount = Category.CreateEntry<int>("LampCount", 6, "Lamp Count", "Number of standing lamps placed around the rave", false, false, (ValueValidator)null, (string)null); StrobeSpeed = Category.CreateEntry<float>("StrobeSpeed", 4f, "Color Rotation", "Color change speed of the lamps (Hz)", false, false, (ValueValidator)null, (string)null); LightIntensity = Category.CreateEntry<float>("LightIntensity", 5f, "Light Intensity", "Brightness of the rave lamps", false, false, (ValueValidator)null, (string)null); LightRange = Category.CreateEntry<float>("LightRange", 10f, "Light Range", "Range of the lamps", false, false, (ValueValidator)null, (string)null); StrobeEnabled = Category.CreateEntry<bool>("StrobeEnabled", true, "Strobo Flash", "White flashes in addition to color cycling", false, false, (ValueValidator)null, (string)null); StrobeInterval = Category.CreateEntry<float>("StrobeInterval", 0.5f, "Strobo Steps", "Time between flashes in seconds (0.1-0.5)", false, false, (ValueValidator)null, (string)null); StrobeDuration = Category.CreateEntry<float>("StrobeDuration", 0.01f, "Strobo Time", "Duration of a flash in seconds (0.01-0.1)", false, false, (ValueValidator)null, (string)null); LampColorR = Category.CreateEntry<int>("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<int>("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<int>("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<bool>("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<bool>("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<int>("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<float>("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<float>("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<float> 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<int> 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<string, string> 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<string, string> ParseStateEntries(string content, string sourcePath) { Dictionary<string, string> dictionary = new Dictionary<string, string>(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<string, string> 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<string> list = new List<string>(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<string> _debugOnceKeys = new HashSet<string>(); 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<CapsuleCollider>(); 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<byte[]> 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<MeshFilter>.op_Implicit(prefab.GetComponentsInChildren<MeshFilter>(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<SkinnedMeshRenderer>.op_Implicit(prefab.GetComponentsInChildren<SkinnedMeshRenderer>(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<Animation>.op_Implicit(prefab.GetComponentsInChildren<Animation>(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