Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Smug Dance Fix v1.0.1
SmugDanceFix.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EmotesAPI; using HarmonyLib; using Microsoft.CodeAnalysis; using RoR2; using RoR2.ConVar; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SmugDanceFix { internal static class MusicPlayer { private struct WaveFormat { public short wFormatTag; public short nChannels; public int nSamplesPerSec; public int nAvgBytesPerSec; public short nBlockAlign; public short wBitsPerSample; public short cbSize; } private struct WaveHeader { public IntPtr lpData; public int dwBufferLength; public int dwBytesRecorded; public IntPtr dwUser; public int dwFlags; public int dwLoops; public IntPtr lpNext; public IntPtr reserved; } private class Channel { public int start; public int value; public int index; public short Next(byte[] data, int frame) { int num = data[start + (frame >> 1)]; int num2 = (((frame & 1) == 0) ? (num >> 4) : (num & 0xF)); int num3 = Steps[index]; index = Math.Min(88, Math.Max(0, index + IndexStep[num2])); int num4 = num3 >> 3; if ((num2 & 4) != 0) { num4 += num3; } if ((num2 & 2) != 0) { num4 += num3 >> 1; } if ((num2 & 1) != 0) { num4 += num3 >> 2; } value = (((num2 & 8) != 0) ? (value - num4) : (value + num4)); value = Math.Max(-32768, Math.Min(32767, value)); return (short)value; } } private const int BufferFrames = 2205; private const int BufferCount = 8; private const int WAVE_MAPPER = -1; private const int CALLBACK_EVENT = 327680; private const int WHDR_DONE = 1; private static readonly int headerSize = Marshal.SizeOf(typeof(WaveHeader)); private static readonly int flagsOffset = (int)Marshal.OffsetOf(typeof(WaveHeader), "dwFlags"); private static readonly short[] Steps = new short[89] { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; private static readonly sbyte[] IndexStep = new sbyte[16] { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; public static volatile bool Wanted; public static volatile bool Paused; public static volatile float TargetLeft; public static volatile float TargetRight; public static volatile float FadeInSeconds = 2f; public static volatile float FadeOutSeconds = 1.5f; internal static long FramesWritten; internal static volatile bool DeviceOpen; private static byte[] data; private static int rate; private static int frames; private static Channel left; private static Channel right; private static Thread thread; private static volatile bool quit; [DllImport("winmm.dll")] private static extern int waveOutOpen(out IntPtr handle, int deviceId, ref WaveFormat format, IntPtr callback, IntPtr instance, int flags); [DllImport("winmm.dll")] private static extern int waveOutPrepareHeader(IntPtr handle, IntPtr header, int size); [DllImport("winmm.dll")] private static extern int waveOutWrite(IntPtr handle, IntPtr header, int size); [DllImport("winmm.dll")] private static extern int waveOutUnprepareHeader(IntPtr handle, IntPtr header, int size); [DllImport("winmm.dll")] private static extern int waveOutPause(IntPtr handle); [DllImport("winmm.dll")] private static extern int waveOutRestart(IntPtr handle); [DllImport("winmm.dll")] private static extern int waveOutReset(IntPtr handle); [DllImport("winmm.dll")] private static extern int waveOutClose(IntPtr handle); public static bool Load(byte[] sdm) { if (sdm == null || sdm.Length < 14 || sdm[0] != 83 || sdm[1] != 68 || sdm[2] != 77 || sdm[3] != 65) { return false; } rate = BitConverter.ToInt32(sdm, 4); int num = BitConverter.ToInt16(sdm, 8); frames = BitConverter.ToInt32(sdm, 10); int num2 = (frames + 1) / 2; if (num < 1 || sdm.Length < 14 + num * num2) { return false; } data = sdm; left = new Channel { start = 14 }; right = new Channel { start = ((num > 1) ? (14 + num2) : 14) }; return true; } public static void Start() { if (data != null && thread == null) { quit = false; thread = new Thread(Run) { IsBackground = true, Name = "SmugDanceFix" }; thread.Start(); } } public static void Stop() { quit = true; thread?.Join(500); thread = null; } private static void Run() { AutoResetEvent autoResetEvent = new AutoResetEvent(initialState: false); IntPtr[] array = new IntPtr[8]; IntPtr[] array2 = new IntPtr[8]; bool[] array3 = new bool[8]; byte[] array4 = new byte[8820]; for (int i = 0; i < 8; i++) { array[i] = Marshal.AllocHGlobal(headerSize); array2[i] = Marshal.AllocHGlobal(array4.Length); } IntPtr handle = IntPtr.Zero; bool flag = false; int num = 0; float num2 = 0f; float num3 = 0f; float num4 = 0f; try { while (!quit) { autoResetEvent.WaitOne(20); bool wanted = Wanted; if (handle == IntPtr.Zero) { if (!wanted) { continue; } WaveFormat format = new WaveFormat { wFormatTag = 1, nChannels = 2, nSamplesPerSec = rate, wBitsPerSample = 16, nBlockAlign = 4, nAvgBytesPerSec = rate * 4 }; if (waveOutOpen(out handle, -1, ref format, autoResetEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, 327680) != 0) { handle = IntPtr.Zero; Thread.Sleep(1000); continue; } for (int j = 0; j < 8; j++) { Marshal.StructureToPtr(new WaveHeader { lpData = array2[j], dwBufferLength = array4.Length }, array[j], fDeleteOld: false); waveOutPrepareHeader(handle, array[j], headerSize); array3[j] = false; } num = 0; left.value = (left.index = (right.value = (right.index = 0))); num2 = (num3 = (num4 = 0f)); flag = false; DeviceOpen = true; } if (Paused != flag) { flag = Paused; if (flag) { waveOutPause(handle); } else { waveOutRestart(handle); } } bool flag2 = false; for (int k = 0; k < 8; k++) { if (array3[k] && (Marshal.ReadInt32(array[k], flagsOffset) & 1) == 0) { flag2 = true; continue; } array3[k] = false; if (!wanted && num2 <= 0f) { continue; } float num5 = 2205f / (float)rate; num2 = (wanted ? Math.Min(1f, num2 + num5 / Math.Max(0.01f, FadeInSeconds)) : Math.Max(0f, num2 - num5 / Math.Max(0.01f, FadeOutSeconds))); float num6 = num2 * num2; float num7 = TargetLeft * num6; float num8 = TargetRight * num6; for (int l = 0; l < 2205; l++) { float num9 = ((float)l + 1f) / 2205f; float num10 = num3 + (num7 - num3) * num9; float num11 = num4 + (num8 - num4) * num9; int val = (int)((float)left.Next(data, num) * num10); int val2 = (int)((float)right.Next(data, num) * num11); if (++num >= frames) { num = 0; left.value = (left.index = (right.value = (right.index = 0))); } val = Math.Max(-32768, Math.Min(32767, val)); val2 = Math.Max(-32768, Math.Min(32767, val2)); array4[l * 4] = (byte)val; array4[l * 4 + 1] = (byte)(val >> 8); array4[l * 4 + 2] = (byte)val2; array4[l * 4 + 3] = (byte)(val2 >> 8); } num3 = num7; num4 = num8; Marshal.Copy(array4, 0, array2[k], array4.Length); waveOutWrite(handle, array[k], headerSize); flag2 = (array3[k] = true); FramesWritten += 2205L; } if (!wanted && num2 <= 0f && !flag2) { Close(ref handle, array); } } } catch (Exception ex) { SmugDanceFixPlugin.Log.LogWarning((object)("Music stream stopped: " + ex)); } finally { Close(ref handle, array); for (int m = 0; m < 8; m++) { Marshal.FreeHGlobal(array[m]); Marshal.FreeHGlobal(array2[m]); } autoResetEvent.Close(); } } private static void Close(ref IntPtr handle, IntPtr[] headers) { if (!(handle == IntPtr.Zero)) { waveOutReset(handle); foreach (IntPtr header in headers) { waveOutUnprepareHeader(handle, header, headerSize); } waveOutClose(handle); handle = IntPtr.Zero; DeviceOpen = false; } } } [BepInPlugin("com.chaz.smugdancefix", "SmugDanceFix", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SmugDanceFixPlugin : BaseUnityPlugin { public const string GUID = "com.chaz.smugdancefix"; public const string Version = "1.0.1"; private const string SmugDanceGUID = "com.themysticsword.smugdanceemote"; private const string EmoteName = "Smug Dance"; private const float SongBPM = 128f; private const float DanceBPM = 103f; internal static ManualLogSource Log; private static ConfigEntry<bool> allowMovement; private static ConfigEntry<bool> syncDance; private static ConfigEntry<bool> dimGameMusic; private static ConfigEntry<bool> removeScreenFilter; private static ConfigEntry<float> volume; private static ConfigEntry<float> fullVolumeRange; private static ConfigEntry<float> hearingRange; private static FieldInfo animClipsField; private static FieldInfo allMappersField; private static FieldInfo clipNameField; private static FieldInfo emoteAnimatorField; private static FieldInfo stopOnMoveField; private static FieldInfo dimField; private static FieldInfo allClipNamesField; private static FieldInfo blacklistField; private static FieldInfo emotesVolumeField; private void Awake() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; allowMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Emote", "AllowMovement", true, "Keep dancing while walking, sprinting and jumping (attacking still stops the emote)."); syncDance = ((BaseUnityPlugin)this).Config.Bind<bool>("Emote", "SyncDanceToMusic", true, "Dance at Peace and Tranquility's tempo (128 BPM) instead of the stage music's."); removeScreenFilter = ((BaseUnityPlugin)this).Config.Bind<bool>("Emote", "RemoveScreenFilter", true, "Turn off the screen distortion SmugDanceEmote fades in while you dance (its optional Retro filters still work)."); dimGameMusic = ((BaseUnityPlugin)this).Config.Bind<bool>("Emote", "DimGameMusic", true, "Lower the game's music near someone doing the Smug Dance (CustomEmotesAPI's dimming, like BadAssEmotes' music emotes)."); volume = ((BaseUnityPlugin)this).Config.Bind<float>("Music", "Volume", 1f, new ConfigDescription("Music volume. Also scaled by the game's Master and SFX volume and CustomEmotesAPI's Emotes Volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); fullVolumeRange = ((BaseUnityPlugin)this).Config.Bind<float>("Music", "FullVolumeRange", 10f, "Other players' Smug Dance music is at full volume within this many metres..."); hearingRange = ((BaseUnityPlugin)this).Config.Bind<float>("Music", "HearingRange", 60f, "...and fades out completely at this distance."); ConfigEntry<float> fadeIn = ((BaseUnityPlugin)this).Config.Bind<float>("Music", "FadeInSeconds", 2f, "How long the music takes to fade in."); ConfigEntry<float> fadeOut = ((BaseUnityPlugin)this).Config.Bind<float>("Music", "FadeOutSeconds", 1.5f, "How long the music takes to fade out after the dance stops."); MusicPlayer.FadeInSeconds = fadeIn.Value; fadeIn.SettingChanged += delegate { MusicPlayer.FadeInSeconds = fadeIn.Value; }; MusicPlayer.FadeOutSeconds = fadeOut.Value; fadeOut.SettingChanged += delegate { MusicPlayer.FadeOutSeconds = fadeOut.Value; }; Assembly assembly = typeof(CustomEmotesAPI).Assembly; animClipsField = AccessTools.Field(typeof(BoneMapper), "animClips"); allMappersField = AccessTools.Field(typeof(BoneMapper), "allMappers"); clipNameField = AccessTools.Field(typeof(BoneMapper), "currentClipName"); emoteAnimatorField = AccessTools.Field(typeof(BoneMapper), "a2"); stopOnMoveField = AccessTools.Field(typeof(CustomAnimationClip), "stopOnMove"); dimField = AccessTools.Field(typeof(CustomAnimationClip), "dimAudioWhenClose"); allClipNamesField = AccessTools.Field(typeof(CustomEmotesAPI), "allClipNames"); blacklistField = AccessTools.Field(typeof(CustomEmotesAPI), "blacklistedClips"); emotesVolumeField = AccessTools.Field(assembly.GetType("EmotesAPI.Settings"), "EmotesVolume"); using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("peace_and_tranquility.sdm")) { using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); if (MusicPlayer.Load(memoryStream.ToArray())) { MusicPlayer.Start(); } else { Log.LogError((object)"Couldn't read the embedded music."); } } PatchSmugDanceEmote(); ApplyEmoteSettings(); allowMovement.SettingChanged += delegate { ApplyEmoteSettings(); }; dimGameMusic.SettingChanged += delegate { ApplyEmoteSettings(); }; RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(ApplyEmoteSettings)); } private void OnDestroy() { MusicPlayer.Stop(); } private void PatchSmugDanceEmote() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown Harmony val = new Harmony("com.chaz.smugdancefix"); Type type = AccessTools.TypeByName("SmugDanceEmote.SmugDanceEmotePlugin+SmugDanceEmoteHelper"); Type type2 = AccessTools.TypeByName("SmugDanceEmote.SmugDanceEmotePlugin+SmugDanceEmoteController"); Type type3 = AccessTools.TypeByName("SmugDanceEmote.SmugDanceEmotePlugin+SmugDanceEmotePostProcessing"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "ShouldCancelEmote", (Type[])null, (Type[])null) : null); MethodInfo methodInfo2 = ((type2 != null) ? AccessTools.Method(type2, "Update", (Type[])null, (Type[])null) : null); MethodInfo methodInfo3 = ((type3 != null) ? AccessTools.Method(type3, "OnRenderImage", (Type[])null, (Type[])null) : null); if (methodInfo != null) { val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(SmugDanceFixPlugin), "ShouldCancelPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogWarning((object)"SmugDanceEmote's cancel check wasn't found; moving may still stop the dance."); } if (methodInfo2 != null) { val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(SmugDanceFixPlugin), "ControllerUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogWarning((object)"SmugDanceEmote's dance controller wasn't found; the dance won't follow the song's tempo."); } if (methodInfo3 != null) { val.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(SmugDanceFixPlugin), "RenderImagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogWarning((object)"SmugDanceEmote's screen effect wasn't found; it can't be turned off."); } } private static void RenderImagePrefix(ref float ___intensity) { if (removeScreenFilter.Value) { ___intensity = 0f; } } private static bool ShouldCancelPrefix(ref bool __result) { if (!allowMovement.Value) { return true; } __result = false; return false; } private static void ControllerUpdatePostfix(bool ___playing, BoneMapper ___mapper) { if (syncDance.Value && ___playing && Object.op_Implicit((Object)(object)___mapper)) { ___mapper.SetAnimationSpeed(1.2427185f); } } private static void ApplyEmoteSettings() { try { IDictionary dictionary = (IDictionary)animClipsField.GetValue(null); if (dictionary == null || !dictionary.Contains("Smug Dance")) { Log.LogWarning((object)"CustomEmotesAPI has no \"Smug Dance\" emote; is SmugDanceEmote installed?"); return; } object obj = dictionary["Smug Dance"]; stopOnMoveField.SetValue(obj, !allowMovement.Value); dimField.SetValue(obj, dimGameMusic.Value); List<string> list = (List<string>)allClipNamesField.GetValue(null); List<int> list2 = blacklistField.GetValue(null) as List<int>; int num = list?.IndexOf("Smug Dance") ?? (-1); Log.LogInfo((object)(string.Format("\"{0}\": stopOnMove={1}, dimAudioWhenClose={2}, ", "Smug Dance", !allowMovement.Value, dimGameMusic.Value) + string.Format("in emote list / random pool: {0} ({1} of {2})", (num >= 0 && (list2 == null || !list2.Contains(num))) ? "yes" : "NO", num, list?.Count))); } catch (Exception ex) { Log.LogError((object)("Couldn't adjust the Smug Dance emote: " + ex)); } } private void Update() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) List<BoneMapper> list = allMappersField.GetValue(null) as List<BoneMapper>; Camera main = Camera.main; LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null); Vector3 val2 = (Object.op_Implicit((Object)(object)val) ? val.corePosition : (Object.op_Implicit((Object)(object)main) ? ((Component)main).transform.position : Vector3.zero)); float num = -1f; float num2 = 0f; if (list != null) { foreach (BoneMapper item in list) { if (!Object.op_Implicit((Object)(object)item) || (string)clipNameField.GetValue(item) != "Smug Dance") { continue; } object? value = emoteAnimatorField.GetValue(item); Animator val3 = (Animator)((value is Animator) ? value : null); if (!Object.op_Implicit((Object)(object)val3) || !((Behaviour)val3).enabled) { continue; } Vector3 position = ((Component)item).transform.position; float num3 = Vector3.Distance(val2, position); float num4 = Mathf.Max(0f, fullVolumeRange.Value); float num5 = Mathf.Max(num4 + 0.01f, hearingRange.Value); float num6 = ((num3 <= num4) ? 1f : Mathf.Clamp01(1f - (num3 - num4) / (num5 - num4))); if (!(num6 <= num)) { num = num6; float num7; if (!Object.op_Implicit((Object)(object)main) || !(num3 > 1f)) { num7 = 0f; } else { Vector3 val4 = position - ((Component)main).transform.position; num7 = Vector3.Dot(((Vector3)(ref val4)).normalized, ((Component)main).transform.right) * 0.35f; } num2 = num7; } } } MusicPlayer.Paused = PauseManager.isPaused; MusicPlayer.Wanted = num >= 0f; if (!(num < 0f)) { float num8 = num * Mathf.Max(0f, volume.Value) * GameVolume("volume_master") * GameVolume("volume_sfx") * EmotesVolume(); MusicPlayer.TargetLeft = num8 * Mathf.Min(1f, 1f - num2); MusicPlayer.TargetRight = num8 * Mathf.Min(1f, 1f + num2); } } private static float EmotesVolume() { try { return (emotesVolumeField?.GetValue(null) is ConfigEntry<float> val) ? Mathf.Clamp01(val.Value / 100f) : 1f; } catch { return 1f; } } private static float GameVolume(string name) { try { BaseConVar val = (Object.op_Implicit((Object)(object)Console.instance) ? Console.instance.FindConVar(name) : null); if (val != null && float.TryParse(val.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return Mathf.Clamp01(result / 100f); } } catch { } return 1f; } } }