catastropy averted?
This commit is contained in:
@@ -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>
|
||||
+53
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -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")]
|
||||
Reference in New Issue
Block a user