catastropy averted?

This commit is contained in:
2026-04-30 11:18:02 +03:00
parent 3e19aac2c2
commit 585abc7132
149 changed files with 25785 additions and 14 deletions
@@ -0,0 +1,203 @@
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<GetSpecialModeByScenePrototype> _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<AddDisableRestartIdPrototype>(BGMAddressResolver.AddRestartId);
_getSpecialModeForSceneHook = DalamudApi.Hooks.HookFromAddress<GetSpecialModeByScenePrototype>((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;
}
}
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>OmicronMountMusicFixer</AssemblyName>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<TargetFramework>net10.0</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<LangVersion>14.0</LangVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup />
<ItemGroup />
<ItemGroup>
<Reference Include="Dalamud" />
<Reference Include="FFXIVClientStructs" />
<Reference Include="Lumina" />
<Reference Include="Lumina.Excel" />
<Reference Include="Dalamud.Bindings.ImGui" />
</ItemGroup>
</Project>
@@ -0,0 +1,53 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace OmicronMountMusicFixer.dll.Resourcer;
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
internal static class ResourceHelper
{
private static Assembly assembly;
static ResourceHelper()
{
assembly = typeof(ResourceHelper).GetTypeInfo().Assembly;
}
public static Stream AsStream(string P_0)
{
return assembly.GetManifestResourceStream(P_0);
}
public static StreamReader AsStreamReader(string P_0)
{
Stream manifestResourceStream = assembly.GetManifestResourceStream(P_0);
if (manifestResourceStream == null)
{
return null;
}
return new StreamReader(manifestResourceStream);
}
public static string AsString(string P_0)
{
StreamReader streamReader = null;
Stream stream = null;
try
{
stream = assembly.GetManifestResourceStream(P_0);
if (stream == null)
{
throw new Exception("Could not find a resource named '" + P_0 + "'.");
}
streamReader = new StreamReader(stream);
return streamReader.ReadToEnd();
}
finally
{
streamReader?.Dispose();
stream?.Dispose();
}
}
}
@@ -0,0 +1,44 @@
using System;
using System.Runtime.InteropServices;
using FFXIVClientStructs.FFXIV.Client.System.Framework;
namespace OmicronMountMusicFixer;
public static class BGMAddressResolver
{
private static nint _baseAddress;
private static nint _musicManager;
public static nint AddRestartId { get; private set; }
public static nint GetSpecialMode { get; private set; }
public static nint BGMSceneManager => Marshal.ReadIntPtr(_baseAddress);
public static nint BGMSceneList
{
get
{
nint num = Marshal.ReadIntPtr(_baseAddress);
if (num != IntPtr.Zero)
{
return Marshal.ReadIntPtr(num + 192);
}
return IntPtr.Zero;
}
}
public static bool StreamingEnabled => Marshal.ReadByte(_musicManager + 50) == 1;
public unsafe static void Init()
{
_baseAddress = DalamudApi.SigScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 85 C0 74 51 83 78 08 0B", 0);
AddRestartId = DalamudApi.SigScanner.ScanText("E8 ?? ?? ?? ?? 88 9E ?? ?? ?? ?? 84 DB");
GetSpecialMode = DalamudApi.SigScanner.ScanText("40 57 48 83 EC 20 48 83 79 ?? ?? 48 8B F9 0F 84 ?? ?? ?? ?? 0F B6 51 4D");
DalamudApi.PluginLog.Debug($"[BGMAddressResolver] init: base address at {((IntPtr)_baseAddress).ToInt64():X}", Array.Empty<object>());
int num = Marshal.ReadInt32((nint)DalamudApi.SigScanner.ScanText("48 8B 8F ?? ?? ?? ?? 85 C0 0F 95 C2 E8 ?? ?? ?? ?? 48 8B 9F") + 3);
_musicManager = Marshal.ReadIntPtr(new IntPtr(Framework.Instance()) + num);
DalamudApi.PluginLog.Debug($"[BGMAddressResolver] MusicManager found at {((IntPtr)_musicManager).ToInt64():X}", Array.Empty<object>());
}
}
@@ -0,0 +1,99 @@
using System;
using System.Runtime.CompilerServices;
using Dalamud.Plugin.Services;
namespace OmicronMountMusicFixer;
internal static class BGMManager
{
public delegate void SongChanged(int oldSong, int currentSong, int oldSecondSong, int oldCurrentSong, bool oldPlayedByOrch, bool playedByOrchestrion);
[CompilerGenerated]
private static class _003C_003EO
{
public static OnUpdateDelegate _003C0_003E__Update;
}
private static readonly BGMController _bgmController;
private static bool _isPlayingReplacement;
private static string _ddPlaylist;
public static int CurrentSongId => _bgmController.CurrentSongId;
public static int PlayingSongId => _bgmController.PlayingSongId;
public static int CurrentAudibleSong => _bgmController.CurrentAudibleSong;
public static int PlayingScene => _bgmController.PlayingScene;
public static event SongChanged OnSongChanged;
static BGMManager()
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
_bgmController = new BGMController();
BGMController bgmController = _bgmController;
bgmController.OnSongChanged = (BGMController.SongChangedHandler)Delegate.Combine(bgmController.OnSongChanged, new BGMController.SongChangedHandler(HandleSongChanged));
DalamudApi.Framework.Update += new OnUpdateDelegate(Update);
}
public static void Dispose()
{
//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_0020: Expected O, but got Unknown
IFramework framework = DalamudApi.Framework;
object obj = _003C_003EO._003C0_003E__Update;
if (obj == null)
{
OnUpdateDelegate val = Update;
_003C_003EO._003C0_003E__Update = val;
obj = (object)val;
}
framework.Update -= (OnUpdateDelegate)obj;
Stop();
_bgmController.Dispose();
}
public static void Update(IFramework ignored)
{
_bgmController.Update();
}
private static void HandleSongChanged(int oldSong, int newSong, int oldSecondSong, int newSecondSong)
{
InvokeSongChanged(oldSong, newSong, oldSecondSong, newSecondSong, oldPlayedByOrch: false, playedByOrch: false);
}
public static void Play(int songId, bool isReplacement = false)
{
bool oldPlayedByOrch = PlayingSongId != 0;
int currentAudibleSong = CurrentAudibleSong;
int secondSongId = _bgmController.SecondSongId;
DalamudApi.PluginLog.Debug($"[Play] Playing {songId}", Array.Empty<object>());
InvokeSongChanged(currentAudibleSong, songId, secondSongId, currentAudibleSong, oldPlayedByOrch, playedByOrch: true);
_bgmController.SetSong((ushort)songId);
_isPlayingReplacement = isReplacement;
}
public static void Stop()
{
_ddPlaylist = null;
if (PlayingSongId != 0)
{
DalamudApi.PluginLog.Debug($"[Stop] Stopping playing {_bgmController.PlayingSongId}...", Array.Empty<object>());
int secondSongId = _bgmController.SecondSongId;
InvokeSongChanged(PlayingSongId, CurrentSongId, secondSongId, secondSongId, oldPlayedByOrch: true, playedByOrch: false);
_bgmController.SetSong(0);
}
}
private static void InvokeSongChanged(int oldSongId, int newSongId, int oldSecondSongId, int newSecondSongId, bool oldPlayedByOrch, bool playedByOrch)
{
DalamudApi.PluginLog.Debug($"[InvokeSongChanged] Invoking SongChanged event with {oldSongId} -> {newSongId}, {oldSecondSongId} -> {newSecondSongId} | {oldPlayedByOrch} {playedByOrch}", Array.Empty<object>());
BGMManager.OnSongChanged?.Invoke(oldSongId, newSongId, oldSecondSongId, newSecondSongId, oldPlayedByOrch, playedByOrch);
}
}
@@ -0,0 +1,46 @@
using System.Runtime.InteropServices;
namespace OmicronMountMusicFixer;
[StructLayout(LayoutKind.Explicit)]
internal struct BGMPlayer
{
[FieldOffset(0)]
public float MaxStandbyTime;
[FieldOffset(4)]
public uint State;
[FieldOffset(8)]
public ushort BgmId;
[FieldOffset(16)]
public uint BgmScene;
[FieldOffset(32)]
public uint SpecialMode;
[FieldOffset(37)]
public bool IsStandby;
[FieldOffset(40)]
public uint FadeOutTime;
[FieldOffset(44)]
public uint ResumeFadeInTime;
[FieldOffset(48)]
public uint FadeInStartTime;
[FieldOffset(52)]
public uint FadeInTime;
[FieldOffset(56)]
public uint ElapsedTime;
[FieldOffset(64)]
public float StandbyTime;
[FieldOffset(77)]
public byte SpecialModeType;
}
@@ -0,0 +1,52 @@
namespace OmicronMountMusicFixer;
public struct BGMScene
{
public int SceneIndex;
public SceneFlags Flags;
private int Padding1;
public ushort BgmReference;
public ushort BgmId;
public ushort PreviousBgmId;
public byte TimerEnable;
private byte Padding2;
public float Timer;
private unsafe fixed byte DisableRestartList[24];
private byte Unknown1;
private uint Unknown2;
private uint Unknown3;
private uint Unknown4;
private uint Unknown5;
private uint Unknown6;
private ulong Unknown7;
private uint Unknown8;
private byte Unknown9;
private byte Unknown10;
private byte Unknown11;
private byte Unknown12;
private float Unknown13;
private uint Unknown14;
}
@@ -0,0 +1,28 @@
using System;
using Dalamud.Configuration;
using Dalamud.Plugin;
namespace OmicronMountMusicFixer;
[Serializable]
public class Configuration : IPluginConfiguration
{
[NonSerialized]
private IDalamudPluginInterface? pluginInterface;
public int Version { get; set; }
public bool Enabled { get; set; } = true;
public int RightClickDelay { get; set; } = 250;
public void Initialize(IDalamudPluginInterface pluginInterface)
{
this.pluginInterface = pluginInterface;
}
public void Save()
{
pluginInterface.SavePluginConfig((IPluginConfiguration)(object)this);
}
}
@@ -0,0 +1,53 @@
using System;
using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
namespace OmicronMountMusicFixer;
public class DalamudApi
{
[PluginService]
public static IChatGui ChatGui { get; private set; }
[PluginService]
public static IClientState ClientState { get; private set; }
[PluginService]
public static ICommandManager CommandManager { get; private set; }
[PluginService]
public static IDalamudPluginInterface PluginInterface { get; private set; }
[PluginService]
public static IDataManager DataManager { get; private set; }
[PluginService]
public static IDtrBar DtrBar { get; private set; }
[PluginService]
public static IFramework Framework { get; private set; }
[PluginService]
public static IGameGui GameGui { get; private set; }
[PluginService]
public static IKeyState KeyState { get; private set; }
[PluginService]
public static ISigScanner SigScanner { get; private set; }
[PluginService]
public static IGameInteropProvider Hooks { get; private set; }
[PluginService]
public static IPluginLog PluginLog { get; private set; }
[PluginService]
public static IAddonLifecycle AddonLifecycle { get; private set; }
public static void Initialize(IDalamudPluginInterface pluginInterface)
{
pluginInterface.Create<DalamudApi>(Array.Empty<object>());
}
}
@@ -0,0 +1,16 @@
namespace OmicronMountMusicFixer;
public struct DisableRestart
{
public ushort DisableRestartId;
public bool IsTimedOut;
public byte Padding1;
public float ResetWaitTime;
public float ElapsedTime;
public bool TimerEnabled;
}
@@ -0,0 +1,319 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.NativeWrapper;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Hooking;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI;
namespace OmicronMountMusicFixer;
public class Plugin : IDalamudPlugin, IDisposable
{
private static class Signatures
{
internal const string GetSpecialMode = "48 89 5C 24 ?? 57 48 83 EC 20 8B 41 10 33 DB";
}
private unsafe delegate int GetSpecialMode(void* unused, byte specialModeType);
private unsafe delegate void* AgentShow(void* a1);
private Hook<GetSpecialMode> getSpecialModeHook;
private bool isPlayingReplacement;
private const int ResourceDataPointerOffset = 176;
private const int MusicManagerStreamingOffset = 50;
private const string commandName = "/omm";
private HttpClient httpCl;
public int currentSpecialMode;
public bool currentCastHandled;
public bool modEnabled;
public long enabledTimestamp;
private bool swapNextSong;
private List<Payload> songEchoPayload;
private readonly Dictionary<long, int> mountIDToSongIDMap = new Dictionary<long, int>();
private bool wasMounted;
private uint lastMountId;
private Hook<GetSpecialMode>? GetResourceSyncHook { get; set; }
public string Name => "Omicron mount fixer";
private IDalamudPluginInterface PluginInterface { get; init; }
private ICommandManager CommandManager { get; init; }
private Configuration Configuration { get; init; }
private PluginUI PluginUi { get; init; }
public long rcStartTime { get; private set; }
private Hook<AgentShow> DutyFinderHook { get; set; }
public unsafe AtkUnitBase* dutyFinderAtkUnitBase { get; private set; }
public string DataPath { get; }
private nint NoSoundPtr { get; }
private nint InfoPtr { get; }
public bool WasStreamingEnabled { get; private set; }
public bool Streaming { get; private set; }
private ConcurrentDictionary<nint, string> Scds { get; } = new ConcurrentDictionary<nint, string>();
internal ConcurrentQueue<string> Recent { get; } = new ConcurrentQueue<string>();
public uint lastSpellBeingCast { get; private set; }
public long lastSpellCast { get; private set; }
public Plugin(IDalamudPluginInterface pluginInterface, ICommandManager commandManager)
{
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Expected O, but got Unknown
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
DalamudApi.Initialize(pluginInterface);
PluginInterface = pluginInterface;
CommandManager = commandManager;
pluginInterface.Create<Service>(Array.Empty<object>());
Configuration = (PluginInterface.GetPluginConfig() as Configuration) ?? new Configuration();
Configuration.Initialize(PluginInterface);
PluginUi = new PluginUI(Configuration, DataPath);
PluginInterface.UiBuilder.Draw += DrawUI;
PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
httpCl = new HttpClient();
BGMAddressResolver.Init();
BGMManager.OnSongChanged += HandleSongChanged;
Service.Framework.Update += new OnUpdateDelegate(Framework_Update);
Service.ClientState.Logout += new LogoutDelegate(ClientState_Logout);
mountIDToSongIDMap.Add(298L, 929);
mountIDToSongIDMap.Add(287L, 906);
mountIDToSongIDMap.Add(343L, 20047);
mountIDToSongIDMap.Add(331L, 501);
mountIDToSongIDMap.Add(235L, 796);
}
private void ClientState_Logout(int type, int code)
{
BGMManager.Play(0);
}
private void ClientState_Login()
{
}
private void HandleSongChanged(int oldSong, int newSong, int oldSecondSong, int newSecondSong, bool nocare, bool playedByPlugin)
{
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
DalamudApi.PluginLog.Debug($"HandleSongChanged called: {oldSong} -> {newSong}, playedByPlugin: {playedByPlugin}", Array.Empty<object>());
if (DalamudApi.ClientState.IsPvP)
{
DalamudApi.PluginLog.Debug("In PvP, ignoring song change", Array.Empty<object>());
return;
}
if (playedByPlugin)
{
DalamudApi.PluginLog.Debug("Song changed by plugin, ignoring", Array.Empty<object>());
return;
}
if (Service.ObjectTable.LocalPlayer == null)
{
DalamudApi.PluginLog.Debug("No mount.", Array.Empty<object>());
return;
}
uint num = (((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.HasValue ? ((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.Value.RowId : 0u);
DalamudApi.PluginLog.Debug("Mount ID: " + num, Array.Empty<object>());
byte value = (byte)Marshal.ReadIntPtr((nint)((IGameObject)Service.ObjectTable.LocalPlayer).Address + 9044);
DalamudApi.PluginLog.Debug($"MountID: {num:X} eventState: {value:X}. Addresses: {(nint)((IGameObject)Service.ObjectTable.LocalPlayer).Address + 1736:X} and {(nint)((IGameObject)Service.ObjectTable.LocalPlayer).Address + 8844:X}", Array.Empty<object>());
if (((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.HasValue)
{
DalamudApi.PluginLog.Debug("We are mounted, lets check if there is a replacement for our song. Current mount: " + num, Array.Empty<object>());
if (mountIDToSongIDMap.ContainsKey(num))
{
DalamudApi.PluginLog.Debug("We do indeed have a replacement for this song. Lets play it then.", Array.Empty<object>());
PlaySong(mountIDToSongIDMap[num]);
}
}
else if (!((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.HasValue)
{
DalamudApi.PluginLog.Debug("We have dismounted. Lets stop music?", Array.Empty<object>());
StopSong();
}
}
public void StopSong()
{
DalamudApi.PluginLog.Debug($"StopSong called - Playing: {BGMManager.PlayingSongId}, Current: {BGMManager.CurrentSongId}", Array.Empty<object>());
IPluginLog pluginLog = DalamudApi.PluginLog;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(26, 1);
defaultInterpolatedStringHandler.AppendLiteral("LocalPlayer CastActionId: ");
IPlayerCharacter localPlayer = Service.ObjectTable.LocalPlayer;
defaultInterpolatedStringHandler.AppendFormatted((localPlayer != null) ? new uint?(((IBattleChara)localPlayer).CastActionId) : ((uint?)null));
pluginLog.Debug(defaultInterpolatedStringHandler.ToStringAndClear(), Array.Empty<object>());
IPlayerCharacter localPlayer2 = Service.ObjectTable.LocalPlayer;
if (localPlayer2 != null && ((IBattleChara)localPlayer2).CastActionId == 298)
{
DalamudApi.PluginLog.Debug($"Song ID {BGMManager.CurrentSongId} has a replacement of {929}...", Array.Empty<object>());
if (929 != BGMManager.PlayingSongId)
{
PlaySong(929, isReplacement: true);
return;
}
DalamudApi.PluginLog.Debug($"But that's the song we're playing [{BGMManager.PlayingSongId}], so let's stop", Array.Empty<object>());
}
IPlayerCharacter localPlayer3 = Service.ObjectTable.LocalPlayer;
if (localPlayer3 != null && ((IBattleChara)localPlayer3).CastActionId == 287)
{
DalamudApi.PluginLog.Debug($"Song ID {BGMManager.CurrentSongId} has a replacement of {906}...", Array.Empty<object>());
if (906 != BGMManager.PlayingSongId)
{
PlaySong(906, isReplacement: true);
return;
}
DalamudApi.PluginLog.Debug($"But that's the song we're playing [{BGMManager.PlayingSongId}], so let's stop", Array.Empty<object>());
}
DalamudApi.PluginLog.Debug("Calling BGMManager.Play(0) to stop music", Array.Empty<object>());
BGMManager.Play(0);
}
public void PlaySong(int songId, bool isReplacement = false)
{
DalamudApi.PluginLog.Debug($"Playing {songId}", Array.Empty<object>());
isPlayingReplacement = isReplacement;
BGMManager.Play(songId);
}
private unsafe void installSpecialModeHook()
{
string text = "48 89 5C 24 ?? 57 48 83 EC 20 8B 41 10 33 DB";
nint num = DalamudApi.SigScanner.ScanText(text);
DalamudApi.PluginLog.Debug("MCA: " + (IntPtr)num, Array.Empty<object>());
getSpecialModeHook = DalamudApi.Hooks.HookFromAddress<GetSpecialMode>((IntPtr)num, (GetSpecialMode)SpecialModeDetour, (HookBackend)0);
getSpecialModeHook?.Enable();
}
private unsafe int SpecialModeDetour(void* unused, byte specialModeType)
{
currentSpecialMode = specialModeType;
return getSpecialModeHook.Original(unused, specialModeType);
}
private bool IsLoadingScreen()
{
//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_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
AtkUnitBasePtr addonByName = Service.GameGui.GetAddonByName("_LocationTitle", 1);
AtkUnitBasePtr addonByName2 = Service.GameGui.GetAddonByName("FadeMiddle", 1);
if (((AtkUnitBasePtr)(ref addonByName)).IsNull || !((AtkUnitBase)(nint)addonByName.Address).IsVisible)
{
if (!((AtkUnitBasePtr)(ref addonByName2)).IsNull)
{
return ((AtkUnitBase)(nint)addonByName2.Address).IsVisible;
}
return false;
}
return true;
}
private void Framework_Update(IFramework framework)
{
//IL_008f: 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)
if (Configuration.Enabled && Service.ClientState.IsLoggedIn)
{
CheckForCastBar();
}
if (IsLoadingScreen())
{
return;
}
if (Service.ClientState.IsLoggedIn && Service.ObjectTable.LocalPlayer != null)
{
bool hasValue = ((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.HasValue;
uint num = ((hasValue && ((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.HasValue) ? ((ICharacter)Service.ObjectTable.LocalPlayer).CurrentMount.Value.RowId : 0u);
if (wasMounted && !hasValue)
{
DalamudApi.PluginLog.Debug($"Dismounted detected! Was on mount {lastMountId}, now dismounted", Array.Empty<object>());
if (mountIDToSongIDMap.ContainsKey(lastMountId))
{
DalamudApi.PluginLog.Debug("Had replacement music, stopping it now", Array.Empty<object>());
StopSong();
}
}
wasMounted = hasValue;
lastMountId = num;
}
BGMManager.Update(null);
songEchoPayload = null;
}
private void CheckForCastBar()
{
if (!IsLoadingScreen() && Service.ClientState != null && Service.ClientState.IsLoggedIn && !Service.ClientState.IsPvP && ((IBattleChara)Service.ObjectTable.LocalPlayer).IsCasting)
{
lastSpellBeingCast = ((IBattleChara)Service.ObjectTable.LocalPlayer).CastActionId;
lastSpellCast = long.Parse(Convert.ToString((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds));
}
}
public void Dispose()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Expected O, but got Unknown
PluginUi.Dispose();
CommandManager.RemoveHandler("/omm");
Service.Framework.Update -= new OnUpdateDelegate(Framework_Update);
Service.ClientState.Login -= ClientState_Login;
Service.ClientState.Logout -= new LogoutDelegate(ClientState_Logout);
BGMManager.Play(0);
BGMManager.Dispose();
}
private void OnCommand(string command, string args)
{
PluginUi.Visible = true;
}
private void DrawUI()
{
PluginUi.Draw();
}
private void DrawConfigUI()
{
PluginUi.SettingsVisible = true;
}
}
@@ -0,0 +1,102 @@
using System;
using System.Numerics;
using Dalamud.Bindings.ImGui;
namespace OmicronMountMusicFixer;
internal class PluginUI : IDisposable
{
private Configuration configuration;
private bool settingsVisible;
private bool visible;
public string DataPath { get; }
public bool SettingsVisible
{
get
{
return settingsVisible;
}
set
{
settingsVisible = value;
}
}
public bool Visible
{
get
{
return visible;
}
set
{
visible = value;
}
}
public PluginUI(Configuration configuration, string DataPath)
{
this.configuration = configuration;
this.DataPath = DataPath;
}
public void DrawMainWindow()
{
//IL_0046: 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)
if (Visible)
{
ImGui.SetNextWindowSize(new Vector2(700f, 330f), (ImGuiCond)4);
ImGui.SetNextWindowSizeConstraints(new Vector2(700f, 330f), new Vector2(float.MaxValue, float.MaxValue));
if (ImGui.Begin(ImU8String.op_Implicit("Dickheads be gone from mine chat"), ref visible, (ImGuiWindowFlags)24))
{
ImGui.Text(ImU8String.op_Implicit("Anti-fags :D"));
}
ImGui.End();
}
}
public void Dispose()
{
}
public void Draw()
{
DrawMainWindow();
DrawSettingsWindow();
}
public void DrawSettingsWindow()
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
if (!SettingsVisible)
{
return;
}
ImGui.SetNextWindowSize(new Vector2(450f, 100f), (ImGuiCond)1);
if (ImGui.Begin(ImU8String.op_Implicit("World Map Enhancer Settings"), ref settingsVisible, (ImGuiWindowFlags)58))
{
bool enabled = configuration.Enabled;
if (ImGui.Checkbox(ImU8String.op_Implicit("Enable zooming out with right click"), ref enabled))
{
configuration.Enabled = enabled;
configuration.Save();
}
int rightClickDelay = configuration.RightClickDelay;
if (ImGui.InputInt(ImU8String.op_Implicit("Right click release delay"), ref rightClickDelay, 25, 100, default(ImU8String), (ImGuiInputTextFlags)0))
{
configuration.RightClickDelay = rightClickDelay;
configuration.Save();
}
}
ImGui.End();
}
}
@@ -0,0 +1,15 @@
using System;
namespace OmicronMountMusicFixer;
[Flags]
public enum SceneFlags : byte
{
None = 0,
Unknown = 1,
Resume = 2,
EnablePassEnd = 4,
ForceAutoReset = 8,
EnableDisableRestart = 0x10,
IgnoreBattle = 0x20
}
@@ -0,0 +1,31 @@
using Dalamud.IoC;
using Dalamud.Plugin.Services;
namespace OmicronMountMusicFixer;
public class Service
{
[PluginService]
public static IClientState ClientState { get; private set; }
[PluginService]
public static IFramework Framework { get; private set; }
[PluginService]
public static IGameGui GameGui { get; private set; }
[PluginService]
public static ISigScanner SigScanner { get; private set; }
[PluginService]
public static IChatGui Chat { get; private set; }
[PluginService]
public static IDataManager DataManager { get; private set; }
[PluginService]
public static IGameInteropProvider Hooks { get; private set; }
[PluginService]
public static IObjectTable ObjectTable { get; private set; }
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
namespace OmicronMountMusicFixer;
public struct Song
{
public int Id;
public Dictionary<string, SongStrings> Strings;
public bool DisableRestart;
public byte SpecialMode;
public string FilePath;
public bool FileExists;
public TimeSpan Duration;
public string Name => Strings.GetValueOrDefault(Util.Lang(), Strings["en"]).Name;
public string AlternateName => Strings.GetValueOrDefault(Util.Lang(), Strings["en"]).AlternateName;
public string SpecialModeName => Strings.GetValueOrDefault(Util.Lang(), Strings["en"]).SpecialModeName;
public string Locations => Strings.GetValueOrDefault(Util.Lang(), Strings["en"]).Locations;
public string AdditionalInfo => Strings.GetValueOrDefault(Util.Lang(), Strings["en"]).AdditionalInfo;
public Song(Dictionary<string, SongStrings> strings)
{
Id = 0;
DisableRestart = false;
SpecialMode = 0;
FilePath = null;
FileExists = false;
Duration = default(TimeSpan);
Strings = strings;
}
public Song()
{
Id = 0;
DisableRestart = false;
SpecialMode = 0;
FilePath = null;
FileExists = false;
Duration = default(TimeSpan);
Strings = new Dictionary<string, SongStrings>();
}
}
@@ -0,0 +1,213 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using Dalamud.Plugin.Services;
using Lumina.Data;
using Lumina.Excel.Sheets;
using Lumina.Text.ReadOnly;
namespace OmicronMountMusicFixer;
public class SongList
{
private const string SheetPath = "https://docs.google.com/spreadsheets/d/1s-xJjxqp6pwS7oewNy1aOQnr3gaJbewvIBbyYchZ6No/gviz/tq?tqx=out:csv&sheet={0}";
private const string SheetFileName = "xiv_bgm_{0}.csv";
private readonly Dictionary<int, Song> _songs;
private readonly HttpClient _client = new HttpClient();
private static SongList _instance;
public static SongList Instance => _instance ?? (_instance = new SongList());
private SongList()
{
_songs = new Dictionary<int, Song>();
try
{
DalamudApi.PluginLog.Information("[SongList] Checking for updated bgm sheets", Array.Empty<object>());
LoadMetadataSheet(GetRemoteSheet("metadata"));
LoadLangSheet(GetRemoteSheet("en"), "en");
LoadLangSheet(GetRemoteSheet("ja"), "ja");
LoadLangSheet(GetRemoteSheet("de"), "de");
LoadLangSheet(GetRemoteSheet("fr"), "fr");
LoadLangSheet(GetRemoteSheet("zh"), "zh");
}
catch (Exception ex)
{
DalamudApi.PluginLog.Error(ex, "[SongList] Orchestrion failed to update bgm sheet; using previous version", Array.Empty<object>());
LoadMetadataSheet(GetLocalSheet("metadata"));
LoadLangSheet(GetLocalSheet("en"), "en");
LoadLangSheet(GetLocalSheet("ja"), "ja");
LoadLangSheet(GetLocalSheet("de"), "de");
LoadLangSheet(GetLocalSheet("fr"), "fr");
LoadLangSheet(GetLocalSheet("zh"), "zh");
}
}
private void DebugLogSongs()
{
DalamudApi.PluginLog.Debug("Songs:", Array.Empty<object>());
foreach (KeyValuePair<int, Song> song in _songs)
{
DalamudApi.PluginLog.Debug($"{song.Key}: {song.Value.Id} {song.Value.Strings} {song.Value.FilePath}", Array.Empty<object>());
}
}
private string GetRemoteSheet(string code)
{
return _client.GetStringAsync($"https://docs.google.com/spreadsheets/d/1s-xJjxqp6pwS7oewNy1aOQnr3gaJbewvIBbyYchZ6No/gviz/tq?tqx=out:csv&sheet={code}").Result;
}
private string GetLocalSheet(string code)
{
return File.ReadAllText(Path.Combine(DalamudApi.PluginInterface.AssemblyLocation.DirectoryName, $"xiv_bgm_{code}.csv"));
}
private void SaveLocalSheet(string text, string code)
{
File.WriteAllText(Path.Combine(DalamudApi.PluginInterface.AssemblyLocation.DirectoryName, $"xiv_bgm_{code}.csv"), text);
}
private void LoadMetadataSheet(string sheetText)
{
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
_songs.Clear();
Dictionary<uint, BGM> dictionary = ((IEnumerable<BGM>)DalamudApi.DataManager.Excel.GetSheet<BGM>((Language?)null, (string)null)).ToDictionary((BGM k) => ((BGM)(ref k)).RowId, (BGM v) => v);
string[] array = sheetText.Split('\n');
for (int num = 1; num < array.Length; num++)
{
string[] array2 = array[num].Split(new string[1] { "\"," }, StringSplitOptions.None);
int num2 = int.Parse(array2[0].Substring(1));
string text = array2[1].Substring(1, array2[1].Length - 2).Replace("\"\"", "\"");
double result;
bool num3 = double.TryParse(text, out result);
TimeSpan duration = (num3 ? TimeSpan.FromSeconds(result) : TimeSpan.Zero);
if (!num3)
{
DalamudApi.PluginLog.Debug($"failed parse {num2}: {text}", Array.Empty<object>());
}
if (dictionary.TryGetValue((uint)num2, out var value))
{
DalamudApi.PluginLog.Debug($"{num2}", Array.Empty<object>());
DalamudApi.PluginLog.Debug($"{((BGM)(ref value)).File}", Array.Empty<object>());
IPluginLog pluginLog = DalamudApi.PluginLog;
ReadOnlySeString file = ((BGM)(ref value)).File;
pluginLog.Debug(((ReadOnlySeString)(ref file)).ExtractText() ?? "", Array.Empty<object>());
Song song = new Song();
song.Id = num2;
file = ((BGM)(ref value)).File;
song.FilePath = ((ReadOnlySeString)(ref file)).ExtractText();
song.SpecialMode = ((BGM)(ref value)).SpecialMode;
song.DisableRestart = ((BGM)(ref value)).DisableRestart;
IDataManager dataManager = DalamudApi.DataManager;
file = ((BGM)(ref value)).File;
song.FileExists = dataManager.FileExists(((ReadOnlySeString)(ref file)).ExtractText());
song.Duration = duration;
Song value2 = song;
_songs[num2] = value2;
}
}
SaveLocalSheet(sheetText, "metadata");
}
private void LoadLangSheet(string sheetText, string code)
{
string[] array = sheetText.Split('\n');
for (int i = 1; i < array.Length; i++)
{
string[] array2 = array[i].Split(new string[1] { "\"," }, StringSplitOptions.None);
int key = int.Parse(array2[0].Substring(1));
string text = array2[1].Substring(1);
string alternateName = array2[2].Substring(1);
string specialModeName = array2[3].Substring(1);
string locations = array2[4].Substring(1);
string additionalInfo = array2[5].Substring(1, array2[5].Length - 2).Replace("\"\"", "\"");
if (_songs.TryGetValue(key, out var value))
{
if ((code == "en" && string.IsNullOrEmpty(text)) || text == "Null BGM" || text == "test")
{
_songs.Remove(key);
}
value.Strings[code] = new SongStrings
{
Name = text,
AlternateName = alternateName,
SpecialModeName = specialModeName,
Locations = locations,
AdditionalInfo = additionalInfo
};
}
}
SaveLocalSheet(sheetText, code);
}
public bool IsDisableRestart(int id)
{
if (_songs.TryGetValue(id, out var value))
{
return value.DisableRestart;
}
return false;
}
public Dictionary<int, Song> GetSongs()
{
return _songs;
}
public Song GetSong(int id)
{
if (!_songs.TryGetValue(id, out var value))
{
return default(Song);
}
return value;
}
public bool TryGetSong(int id, out Song song)
{
return _songs.TryGetValue(id, out song);
}
public string GetSongTitle(int id)
{
if (!_songs.TryGetValue(id, out var value))
{
return "";
}
return value.Name;
}
public bool SongExists(int id)
{
return _songs.ContainsKey(id);
}
public bool TryGetSongByName(string name, out int songId)
{
songId = 0;
foreach (Song value in _songs.Values)
{
foreach (string availableTitleLanguage in Util.AvailableTitleLanguages)
{
if (string.Equals(value.Strings[availableTitleLanguage].Name, name, StringComparison.InvariantCultureIgnoreCase) || string.Equals(value.Strings[availableTitleLanguage].AlternateName, name, StringComparison.InvariantCultureIgnoreCase))
{
songId = value.Id;
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,14 @@
namespace OmicronMountMusicFixer;
public struct SongStrings
{
public string Name;
public string AlternateName;
public string SpecialModeName;
public string Locations;
public string AdditionalInfo;
}
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Numerics;
using System.Text;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Plugin.Services;
namespace OmicronMountMusicFixer;
internal static class Util
{
public static List<string> AvailableTitleLanguages => new List<string> { "en" };
internal static bool TryScanText(this ISigScanner scanner, string sig, out nint result)
{
result = IntPtr.Zero;
try
{
result = scanner.ScanText(sig);
return true;
}
catch (KeyNotFoundException)
{
return false;
}
}
public static string Lang()
{
return "en";
}
private unsafe static byte[] ReadTerminatedBytes(byte* ptr)
{
if (ptr == null)
{
return new byte[0];
}
List<byte> list = new List<byte>();
while (*ptr != 0)
{
list.Add(*ptr);
ptr++;
}
return list.ToArray();
}
internal unsafe static string ReadTerminatedString(byte* ptr)
{
return Encoding.UTF8.GetString(ReadTerminatedBytes(ptr));
}
internal static bool ContainsIgnoreCase(this string haystack, string needle)
{
return CultureInfo.InvariantCulture.CompareInfo.IndexOf(haystack, needle, CompareOptions.IgnoreCase) >= 0;
}
internal static bool IconButton(FontAwesomeIcon icon, string id)
{
//IL_0000: 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_0034: Unknown result type (might be due to invalid IL or missing references)
ImGui.PushFont(UiBuilder.IconFont);
ImU8String val = default(ImU8String);
((ImU8String)(ref val))._002Ector(2, 2);
((ImU8String)(ref val)).AppendFormatted<string>(FontAwesomeExtensions.ToIconString(icon));
((ImU8String)(ref val)).AppendLiteral("##");
((ImU8String)(ref val)).AppendFormatted<string>(id);
bool result = ImGui.Button(val, default(Vector2));
ImGui.PopFont();
return result;
}
}
@@ -0,0 +1,6 @@
internal class OmicronMountMusicFixer_ProcessedByFody
{
internal const string FodyVersion = "6.6.4.0";
internal const string Resourcer = "1.8.0.0";
}
@@ -0,0 +1,16 @@
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyCompany("aRkker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Music")]
[assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: AssemblyInformationalVersion("1.0.0+8c181f19a2ba71e0bee0e08ad8a42953b3276520")]
[assembly: AssemblyProduct("OmicronMountMusicFixer")]
[assembly: AssemblyTitle("OmicronMountMusicFixer")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/aRkker/ffxiv-dalamud-wme.git")]
[assembly: AssemblyVersion("1.0.7.0")]