using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Dalamud.Hooking; using Dalamud.Plugin.Services; using OmicronMountMusicFixer; public class BGMController { public delegate void SongChangedHandler(int oldSong, int currentSong, int oldSecondSong, int secondSong); private unsafe delegate DisableRestart* AddDisableRestartIdPrototype(BGMScene* scene, ushort songId); private unsafe delegate int GetSpecialModeByScenePrototype(BGMPlayer* bgmPlayer); private const SceneFlags SceneZeroFlags = SceneFlags.Resume; private const int SceneCount = 12; private const int PlayersCount = 2; public SongChangedHandler OnSongChanged; private readonly AddDisableRestartIdPrototype _addDisableRestartId; private readonly Hook _getSpecialModeForSceneHook; public int OldSongId { get; private set; } public int OldScene { get; private set; } public int CurrentSongId { get; private set; } public int CurrentScene { get; private set; } public int SecondSongId { get; private set; } public int SecondScene { get; private set; } public int OldSecondSongId { get; private set; } public int OldSecondScene { get; private set; } public int PlayingSongId { get; private set; } public int PlayingScene { get; private set; } public int CurrentAudibleSong { get { if (PlayingSongId != 0) { return PlayingSongId; } return CurrentSongId; } } public unsafe BGMController() { _addDisableRestartId = Marshal.GetDelegateForFunctionPointer(BGMAddressResolver.AddRestartId); _getSpecialModeForSceneHook = DalamudApi.Hooks.HookFromAddress((IntPtr)BGMAddressResolver.GetSpecialMode, (GetSpecialModeByScenePrototype)GetSpecialModeBySceneDetour, (HookBackend)0); _getSpecialModeForSceneHook.Enable(); } public void Dispose() { _getSpecialModeForSceneHook?.Disable(); _getSpecialModeForSceneHook?.Dispose(); } public void SetSpecialModeHandling(bool value) { if (value) { _getSpecialModeForSceneHook.Enable(); } else { _getSpecialModeForSceneHook.Disable(); } } public unsafe void Update() { ushort num = 0; ushort num2 = 0; int currentScene = 0; int secondScene = 0; if (BGMAddressResolver.BGMSceneList != IntPtr.Zero) { BGMScene* ptr = (BGMScene*)((IntPtr)BGMAddressResolver.BGMSceneList).ToPointer(); for (int i = 0; i < 12; i++) { if (PlayingSongId != 0 && i == PlayingScene) { if (ptr[PlayingScene].BgmId != PlayingSongId) { SetSong((ushort)PlayingSongId, PlayingScene); } } else if (ptr[i].BgmReference != 0 && ptr[i].BgmId != 0 && ptr[i].BgmId != 9999) { if (num != 0) { num2 = ptr[i].BgmId; secondScene = i; break; } num = ptr[i].BgmId; currentScene = i; } } } int oldSong = 0; int currentSong = 0; int oldSecondSong = 0; int secondSong = 0; bool flag = false; bool flag2 = false; if (CurrentSongId != num) { OldSongId = CurrentSongId; OldScene = CurrentScene; CurrentSongId = num; CurrentScene = currentScene; flag = true; oldSong = OldSongId; currentSong = CurrentSongId; } if (SecondSongId != num2) { OldSecondSongId = SecondSongId; OldSecondScene = SecondScene; SecondSongId = num2; SecondScene = secondScene; flag2 = true; oldSecondSong = OldSecondSongId; secondSong = SecondSongId; } if (flag || flag2) { OnSongChanged?.Invoke(oldSong, currentSong, oldSecondSong, secondSong); } } public unsafe void SetSong(ushort songId, int priority = 0) { if ((priority < 0 || priority >= 12) ? true : false) { throw new IndexOutOfRangeException(); } if ((songId != 0 && SongList.Instance.TryGetSong(songId, out var song) && !song.FileExists) || BGMAddressResolver.BGMSceneList == IntPtr.Zero) { return; } BGMScene* bgms = (BGMScene*)((IntPtr)BGMAddressResolver.BGMSceneList).ToPointer(); bgms[priority].BgmReference = songId; bgms[priority].BgmId = songId; bgms[priority].PreviousBgmId = songId; if (songId == 0 && priority == 0) { bgms[priority].Flags = SceneFlags.Resume; } bgms[priority].Timer = 0f; bgms[priority].TimerEnable = 0; PlayingSongId = songId; PlayingScene = priority; if (SongList.Instance.IsDisableRestart(songId)) { bgms[priority].Flags = SceneFlags.EnableDisableRestart; _addDisableRestartId(bgms + priority, songId); bgms[priority].Flags = SceneFlags.ForceAutoReset; Task.Delay(500).ContinueWith(delegate { bgms[priority].Flags = SceneFlags.ForceAutoReset | SceneFlags.EnableDisableRestart; }); } } private unsafe int GetSpecialModeBySceneDetour(BGMPlayer* player) { if (player->BgmScene != PlayingScene || player->BgmId != PlayingSongId) { return _getSpecialModeForSceneHook.Original(player); } if (!SongList.Instance.TryGetSong(player->BgmId, out var song)) { return _getSpecialModeForSceneHook.Original(player); } uint bgmScene = 10u; if (song.SpecialMode == 2) { bgmScene = 6u; } uint bgmScene2 = player->BgmScene; player->BgmScene = bgmScene; int result = _getSpecialModeForSceneHook.Original(player); player->BgmScene = bgmScene2; return result; } }