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 LoopingSoundFix v1.1.1
plugins/LoopingSoundFix/LoopingSoundFix.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Toolbot; using HarmonyLib; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using On.EntityStates.Toolbot; using R2API.Utils; using RiskOfOptions; using RiskOfOptions.Options; using RoR2; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: NetworkCompatibility(/*Could not decode attribute arguments.*/)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LoopingSoundFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+312a7c65684b0fada7a8e68aa38c996208444391")] [assembly: AssemblyProduct("LoopingSoundFix")] [assembly: AssemblyTitle("LoopingSoundFix")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LoopingSoundFix { internal static class EnsureSoundEventsStopOnDestroy { private delegate AKRESULT orig_AkSoundEngine_UnregisterGameObj(GameObject gameObject); private delegate AKRESULT orig_AkSoundEngine_UnregisterGameObjInternal(GameObject in_GameObj); private delegate AKRESULT orig_AkSoundEngine_UnregisterAllGameObj(); private static readonly List<IDetour> _hooks = new List<IDetour>(); private static uint[] _sharedPlayingIdsBuffer = new uint[16]; public static void ApplyPatches() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown if (_hooks.Count > 0) { Log.Error("Patches already applied", "X:\\Git\\RoR2\\AudioLoopFix\\LoopingSoundFix\\EnsureSoundEventsStopOnDestroy.cs", "ApplyPatches", 18); return; } MethodInfo methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => AkSoundEngine.UnregisterGameObj((GameObject)null))); if (methodInfo != null) { _hooks.Add((IDetour)new Hook((MethodBase)methodInfo, (Delegate)new Func<orig_AkSoundEngine_UnregisterGameObj, GameObject, AKRESULT>(AkSoundEngine_UnregisterGameObj))); } else { Log.Error("Failed to find method: AkSoundEngine.UnregisterGameObj", "X:\\Git\\RoR2\\AudioLoopFix\\LoopingSoundFix\\EnsureSoundEventsStopOnDestroy.cs", "ApplyPatches", 29); } MethodInfo methodInfo2 = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => AkSoundEngine.UnregisterGameObjInternal((GameObject)null))); if (methodInfo2 != null) { _hooks.Add((IDetour)new Hook((MethodBase)methodInfo2, (Delegate)new Func<orig_AkSoundEngine_UnregisterGameObjInternal, GameObject, AKRESULT>(AkSoundEngine_UnregisterGameObjInternal))); } else { Log.Error("Failed to find method: AkSoundEngine.UnregisterGameObjInternal", "X:\\Git\\RoR2\\AudioLoopFix\\LoopingSoundFix\\EnsureSoundEventsStopOnDestroy.cs", "ApplyPatches", 40); } MethodInfo methodInfo3 = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => AkSoundEngine.UnregisterAllGameObj())); if (methodInfo3 != null) { _hooks.Add((IDetour)new Hook((MethodBase)methodInfo3, (Delegate)new Func<orig_AkSoundEngine_UnregisterAllGameObj, AKRESULT>(AkSoundEngine_UnregisterAllGameObj))); } else { Log.Error("Failed to find method: AkSoundEngine.UnregisterAllGameObj", "X:\\Git\\RoR2\\AudioLoopFix\\LoopingSoundFix\\EnsureSoundEventsStopOnDestroy.cs", "ApplyPatches", 50); } } public static void UndoPatches() { foreach (IDetour hook in _hooks) { if (hook != null) { hook.Undo(); ((IDisposable)hook).Dispose(); } } _hooks.Clear(); } private static void stopAllSoundEvents(GameObject gameObject) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)gameObject)) { return; } uint num; while (true) { num = (uint)_sharedPlayingIdsBuffer.Length; if ((int)AkSoundEngine.GetPlayingIDsFromGameObject(gameObject, ref num, _sharedPlayingIdsBuffer) != 1) { return; } if (num < _sharedPlayingIdsBuffer.Length) { break; } Array.Resize(ref _sharedPlayingIdsBuffer, _sharedPlayingIdsBuffer.Length * 2); } if (num == 0) { return; } for (int i = 0; i < num; i++) { uint num2 = _sharedPlayingIdsBuffer[i]; switch (Main.SoundCancelMode) { case SoundCancelMode.Immediate: AkSoundEngine.StopPlayingID(num2); break; case SoundCancelMode.NextLoop: AkSoundEngine.ExecuteActionOnPlayingID((AkActionOnEventType)3, num2); break; default: Log.Warning($"Stop mode not implemented: {Main.SoundCancelMode}", "X:\\Git\\RoR2\\AudioLoopFix\\LoopingSoundFix\\EnsureSoundEventsStopOnDestroy.cs", "stopAllSoundEvents", 112); break; } } } private static AKRESULT AkSoundEngine_UnregisterGameObj(orig_AkSoundEngine_UnregisterGameObj orig, GameObject gameObject) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) AKRESULT result; try { stopAllSoundEvents(gameObject); } finally { result = orig(gameObject); } return result; } private static AKRESULT AkSoundEngine_UnregisterGameObjInternal(orig_AkSoundEngine_UnregisterGameObjInternal orig, GameObject in_GameObj) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) AKRESULT result; try { stopAllSoundEvents(in_GameObj); } finally { result = orig(in_GameObj); } return result; } private static AKRESULT AkSoundEngine_UnregisterAllGameObj(orig_AkSoundEngine_UnregisterAllGameObj orig) { //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_0008: Invalid comparison between Unknown and I4 AKRESULT val = orig(); if ((int)val == 1) { AkSoundEngine.StopAll(); } return val; } } internal static class Log { internal static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } private static string getLogPrefix(string callerPath, string callerMemberName, int callerLineNumber) { int num = callerPath.LastIndexOf("LoopingSoundFix\\"); if (num >= 0) { callerPath = callerPath.Substring(num + "LoopingSoundFix\\".Length); } return $"{callerPath}:{callerLineNumber} ({callerMemberName}) "; } internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogError((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Error_NoCallerPrefix(object data) { _logSource.LogError(data); } internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogFatal((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Fatal_NoCallerPrefix(object data) { _logSource.LogFatal(data); } internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogInfo((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Info_NoCallerPrefix(object data) { _logSource.LogInfo(data); } internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogMessage((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Message_NoCallerPrefix(object data) { _logSource.LogMessage(data); } internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogWarning((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Warning_NoCallerPrefix(object data) { _logSource.LogWarning(data); } } [BepInPlugin("Gorakh.LoopingSoundFix", "LoopingSoundFix", "1.1.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Main : BaseUnityPlugin { public const string PluginGUID = "Gorakh.LoopingSoundFix"; public const string PluginAuthor = "Gorakh"; public const string PluginName = "LoopingSoundFix"; public const string PluginVersion = "1.1.1"; internal static ConfigEntry<SoundCancelMode> SoundCancelModeConfig; internal static Main Instance { get; private set; } public static SoundCancelMode SoundCancelMode => SoundCancelModeConfig.Value; private void Awake() { Stopwatch stopwatch = Stopwatch.StartNew(); Log.Init(((BaseUnityPlugin)this).Logger); Instance = SingletonHelper.Assign<Main>(Instance, this); SoundCancelModeConfig = ((BaseUnityPlugin)this).Config.Bind<SoundCancelMode>("General", "Sound Stop Mode", SoundCancelMode.NextLoop, "Determines how the mod handles an active sound when its audio source is removed.\r\n\r\nImmediate: The sound is cut off immediately. This guarantees that all sounds stop, but can cause certain sounds to not play fully.\r\n\r\nNextLoop: Stops the sound after it finishes playing the current loop, if the sound is non-looping, it plays to completion"); if (RiskOfOptionsCompat.IsActive) { RiskOfOptionsCompat.Init(); } EnsureSoundEventsStopOnDestroy.ApplyPatches(); MultPowerModeFix.Apply(); stopwatch.Stop(); Log.Info_NoCallerPrefix($"Initialized in {stopwatch.Elapsed.TotalSeconds:F2} seconds"); } private void OnDestroy() { EnsureSoundEventsStopOnDestroy.UndoPatches(); MultPowerModeFix.Undo(); Instance = SingletonHelper.Unassign<Main>(Instance, this); } } internal static class MultPowerModeFix { [CompilerGenerated] private static class <>O { public static hook_OnExit <0>__ToolbotDualWieldBase_OnExit; } public static void Apply() { //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_001b: Expected O, but got Unknown object obj = <>O.<0>__ToolbotDualWieldBase_OnExit; if (obj == null) { hook_OnExit val = ToolbotDualWieldBase_OnExit; <>O.<0>__ToolbotDualWieldBase_OnExit = val; obj = (object)val; } ToolbotDualWieldBase.OnExit += (hook_OnExit)obj; } public static void Undo() { //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_001b: Expected O, but got Unknown object obj = <>O.<0>__ToolbotDualWieldBase_OnExit; if (obj == null) { hook_OnExit val = ToolbotDualWieldBase_OnExit; <>O.<0>__ToolbotDualWieldBase_OnExit = val; obj = (object)val; } ToolbotDualWieldBase.OnExit -= (hook_OnExit)obj; } private static void ToolbotDualWieldBase_OnExit(orig_OnExit orig, ToolbotDualWieldBase self) { orig.Invoke(self); if (self is ToolbotDualWieldStart) { Util.PlaySound(ToolbotDualWield.stopLoopSoundString, ((EntityState)self).gameObject); } } } internal static class RiskOfOptionsCompat { public static bool IsActive => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); public static void Init() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)Main.SoundCancelModeConfig)); } } public enum SoundCancelMode { Immediate, NextLoop } }