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,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>AntiDickheadChatmodule</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="Dalamud.Bindings.ImGui" />
</ItemGroup>
</Project>
@@ -0,0 +1,28 @@
using System;
using Dalamud.Configuration;
using Dalamud.Plugin;
namespace AntiDickheadChatmodule;
[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,181 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Dalamud.Game.Command;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Hooking;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI;
namespace AntiDickheadChatmodule;
public sealed class Plugin : IDalamudPlugin, IDisposable
{
private unsafe delegate void* AgentShow(void* a1);
private const string commandName = "/adh";
public string Name => "Anti-Dickhead chatmodule";
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; } = string.Empty;
public Plugin(IDalamudPluginInterface pluginInterface, ICommandManager commandManager)
{
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Expected O, but got Unknown
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Expected O, but got Unknown
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Expected O, but got Unknown
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);
CommandManager.AddHandler("/adh", new CommandInfo(new HandlerDelegate(OnCommand))
{
HelpMessage = "Show the tracker UI"
});
PluginInterface.UiBuilder.Draw += DrawUI;
PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
Service.Chat.ChatMessage += new OnMessageDelegate(Chat_ChatMessage1);
}
private void Chat_ChatMessage1(XivChatType type, int timestamp, ref SeString sender, ref SeString message, ref bool isHandled)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
if (!new List<XivChatType>
{
(XivChatType)15,
(XivChatType)37,
(XivChatType)101,
(XivChatType)102,
(XivChatType)103,
(XivChatType)104,
(XivChatType)105,
(XivChatType)106,
(XivChatType)107,
(XivChatType)14,
(XivChatType)11,
(XivChatType)10,
(XivChatType)30,
(XivChatType)24,
(XivChatType)13,
(XivChatType)27
}.Contains(type))
{
return;
}
try
{
bool flag = false;
foreach (Payload payload in message.Payloads)
{
TextPayload val = (TextPayload)(object)((payload is TextPayload) ? payload : null);
if (val == null)
{
continue;
}
if (flag)
{
flag = false;
continue;
}
string text = val.Text;
Service.PluginLog.Debug(text ?? string.Empty, Array.Empty<object>());
if (string.IsNullOrEmpty(text) || text.Contains('\ue0bb'))
{
Service.PluginLog.Debug("Skipping, because empty or symbol", Array.Empty<object>());
flag = true;
continue;
}
string text2 = text;
if (text2.Contains(".") || char.IsUpper(text2[0]))
{
string[] array = text2.Split(" ");
for (int i = 0; i < array.Length; i++)
{
if (array[i].Length > 1 && char.IsUpper(array[i][0]) && !char.IsUpper(array[i][1]) && array[i][1] != '\'')
{
array[i] = array[i].ToLower();
}
if (!array[i].EndsWith("."))
{
continue;
}
if (i + 1 < array.Length)
{
string pattern = "((?::|;|=)(?:-)?(?:\\)|D|P))";
if (Regex.Match(array[i + 1], pattern, RegexOptions.IgnoreCase).Success)
{
array[i] = array[i].Substring(0, array[i].Length - 1);
}
}
else
{
array[i] = array[i].Substring(0, array[i].Length - 1);
}
}
string text3 = "";
string[] array2 = array;
foreach (string text4 in array2)
{
text3 = text3 + text4 + " ";
}
text2 = text3;
}
if (!text.Equals(text2))
{
val.Text = text2;
}
}
}
catch
{
Service.PluginLog.Debug($"Failed to process message: {message}.", Array.Empty<object>());
}
}
public void Dispose()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
PluginUi.Dispose();
CommandManager.RemoveHandler("/adh");
Service.Chat.ChatMessage -= new OnMessageDelegate(Chat_ChatMessage1);
}
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 AntiDickheadChatmodule;
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,19 @@
using Dalamud.IoC;
using Dalamud.Plugin.Services;
namespace AntiDickheadChatmodule;
public class Service
{
[PluginService]
public static IClientState ClientState { get; private set; }
[PluginService]
public static IChatGui Chat { get; private set; }
[PluginService]
public static IDataManager Data { get; private set; }
[PluginService]
public static IPluginLog PluginLog { get; private set; }
}
@@ -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("Sufferable chat = insufferable. :)")]
[assembly: AssemblyFileVersion("0.0.6.0")]
[assembly: AssemblyInformationalVersion("0.0.6.0+8c181f19a2ba71e0bee0e08ad8a42953b3276520")]
[assembly: AssemblyProduct("AntiDickheadChatmodule")]
[assembly: AssemblyTitle("AntiDickheadChatmodule")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/aRkker/ffxiv-dalamud-wme.git")]
[assembly: AssemblyVersion("0.0.6.0")]
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>CrystallineConflictWinsTracker</AssemblyName>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<TargetFramework>net7.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="Newtonsoft.Json" />
<Reference Include="Lumina.Excel" />
<Reference Include="Lumina" />
<Reference Include="ImGui.NET" />
</ItemGroup>
</Project>
@@ -0,0 +1,28 @@
using System;
using Dalamud.Configuration;
using Dalamud.Plugin;
namespace CrystallineConflictWinsTracker;
[Serializable]
public class Configuration : IPluginConfiguration
{
[NonSerialized]
private DalamudPluginInterface? pluginInterface;
public int Version { get; set; }
public bool Enabled { get; set; } = true;
public int RightClickDelay { get; set; } = 250;
public void Initialize(DalamudPluginInterface pluginInterface)
{
this.pluginInterface = pluginInterface;
}
public void Save()
{
pluginInterface.SavePluginConfig((IPluginConfiguration)(object)this);
}
}
@@ -0,0 +1,48 @@
using System;
using Dalamud.Game;
using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
namespace CrystallineConflictWinsTracker;
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 DalamudPluginInterface 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 ISigScanner SigScanner { get; private set; }
[PluginService]
public static IGameInteropProvider Hooks { get; private set; }
[PluginService]
public static IPluginLog PluginLog { get; private set; }
public static void Initialize(DalamudPluginInterface pluginInterface)
{
pluginInterface.Create<DalamudApi>(Array.Empty<object>());
}
}
@@ -0,0 +1,378 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Command;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.Logging;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Component.GUI;
using Newtonsoft.Json;
namespace CrystallineConflictWinsTracker;
public sealed class Plugin : IDalamudPlugin, IDisposable
{
private unsafe delegate void* AgentShow(void* a1);
private unsafe delegate void* FireCallbackDelegate(AtkUnitBase* atkUnitBase, int valueCount, AtkValue* atkValues, ulong a4);
private const string commandName = "/ccwins";
public bool dutyFinderVisible;
public bool pvpPageVisible;
public bool casualCCEnabled;
public bool rankedCCEnabled;
public bool alertedDebugWindow;
private Hook<FireCallbackDelegate> addonReceiveEventHook;
public string Name => "Crystaline Conflict Winratio tracker";
private DalamudPluginInterface 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; }
public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Expected O, but got Unknown
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Expected O, but got Unknown
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Expected O, but got Unknown
DalamudApi.Initialize(pluginInterface);
DalamudApi.PluginLog.Debug("Initializing the plugin...", Array.Empty<object>());
PluginInterface = pluginInterface;
CommandManager = DalamudApi.CommandManager;
DalamudApi.Framework.Update += new OnUpdateDelegate(Framework_UpdateNew);
Configuration = (PluginInterface.GetPluginConfig() as Configuration) ?? new Configuration();
Configuration.Initialize(PluginInterface);
DataPath = PluginInterface.ConfigDirectory?.ToString() + "/data/";
try
{
Directory.CreateDirectory(DataPath);
}
catch (Exception ex)
{
PluginLog.LogError(ex, "Failed to create data directory.", Array.Empty<object>());
}
if (!File.Exists(DataPath + "pvpstats.json"))
{
File.Create(DataPath + "pvpstats.json");
}
PluginUi = new PluginUI(Configuration, DataPath);
DalamudApi.CommandManager.AddHandler("/ccwins", new CommandInfo(new HandlerDelegate(OnCommand))
{
HelpMessage = "Show the tracker UI"
});
PluginInterface.UiBuilder.Draw += DrawUI;
PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
DalamudApi.ClientState.EnterPvP += ClientState_EnterPvP;
DalamudApi.ClientState.LeavePvP += ClientState_LeavePvP;
DalamudApi.ChatGui.ChatMessage += new OnMessageDelegate(Chat_ChatMessage);
}
private void Framework_UpdateNew(IFramework framework)
{
if (Configuration.Enabled && DalamudApi.ClientState.IsLoggedIn)
{
CheckForDfSelections();
}
}
private void Chat_ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
if ((int)type != 2112)
{
return;
}
PluginLog.Debug(message.TextValue, Array.Empty<object>());
if (message.TextValue.Contains("900 Series EXP."))
{
PluginLog.Debug("WE WON THE GAME?", Array.Empty<object>());
if (casualCCEnabled)
{
PluginLog.Debug("CASUAL WIN", Array.Empty<object>());
StoreNewPvpRow(ranked: false, win: true);
}
else if (rankedCCEnabled)
{
PluginLog.Debug("RANKED WIN", Array.Empty<object>());
StoreNewPvpRow(ranked: true, win: true);
}
else
{
PluginLog.Error("NEITHER MODE IS UP? WAT?", Array.Empty<object>());
}
}
else if (message.TextValue.Contains("700 Series EXP."))
{
PluginLog.Debug("WE LOST THE GAME?", Array.Empty<object>());
if (casualCCEnabled)
{
PluginLog.Debug("CASUAL LOSS", Array.Empty<object>());
StoreNewPvpRow(ranked: false, win: false);
}
else if (rankedCCEnabled)
{
PluginLog.Debug("RANKED LOSS", Array.Empty<object>());
StoreNewPvpRow(ranked: true, win: false);
}
else
{
PluginLog.Error("NEITHER MODE IS UP? WAT?", Array.Empty<object>());
}
}
}
private void StoreNewPvpRow(bool ranked, bool win)
{
string text = File.ReadAllText(DataPath + "pvpstats.json");
List<PvpWinEntry> obj = JsonConvert.DeserializeObject<List<PvpWinEntry>>(text) ?? new List<PvpWinEntry>();
obj.Add(new PvpWinEntry
{
classId = ((Character)DalamudApi.ClientState.LocalPlayer).ClassJob.Id,
win = win,
ranked = ranked,
className = ((Character)DalamudApi.ClientState.LocalPlayer).ClassJob.GameData.Name.RawString,
matchDate = DateTime.Now
});
text = JsonConvert.SerializeObject((object)obj);
File.WriteAllText(DataPath + "pvpstats.json", text);
}
private void ClientState_LeavePvP()
{
PluginLog.Debug("Yes, we left pvp :)", Array.Empty<object>());
}
private unsafe void* CallbackDetour(AtkUnitBase* atkunitbase, int valuecount, AtkValue* atkvalues, ulong a4)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Expected I4, but got Unknown
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Invalid comparison between Unknown and I4
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Invalid comparison between Unknown and I4
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Invalid comparison between Unknown and I4
if (dutyFinderAtkUnitBase == null)
{
return addonReceiveEventHook.Original(atkunitbase, valuecount, atkvalues, a4);
}
if (atkunitbase == dutyFinderAtkUnitBase)
{
PluginLog.Debug("OMG ITS CONTENTSFINDER :D", Array.Empty<object>());
List<object> list = new List<object>();
List<ValueType> list2 = new List<ValueType>();
try
{
AtkValue* ptr = atkvalues;
for (int i = 0; i < valuecount; i++)
{
list2.Add(((AtkValue)ptr).Type);
ValueType type = ((AtkValue)ptr).Type;
switch (type - 2)
{
case 0:
list.Add(((AtkValue)ptr).Byte > 0);
break;
case 1:
list.Add(((AtkValue)ptr).Int);
break;
case 2:
list.Add(((AtkValue)ptr).UInt);
break;
case 4:
list.Add(Marshal.PtrToStringUTF8(new IntPtr(((AtkValue)ptr).String)));
break;
default:
list.Add($"Unknown Type: {((AtkValue)ptr).Type}");
break;
}
ptr = (AtkValue*)((byte*)ptr + Unsafe.SizeOf<AtkValue>());
}
}
catch
{
return addonReceiveEventHook.Original(atkunitbase, valuecount, atkvalues, a4);
}
if (valuecount > 1)
{
object obj2 = list[1];
ValueType val = list2[1];
if ((int)val == 3)
{
if ((int)obj2 == 8)
{
PluginLog.Debug("HOOO BOY WE GOING PVP", Array.Empty<object>());
pvpPageVisible = true;
}
else
{
pvpPageVisible = false;
}
}
else if ((int)val == 4 && (int)list2[0] == 3 && (int)list[0] == 3)
{
PluginLog.Debug("SOMETHIGNG CLICKED?", Array.Empty<object>());
if (pvpPageVisible)
{
AtkComponentCheckBox* nodeById = (AtkComponentCheckBox*)((AtkUnitBase)(nint)DalamudApi.GameGui.GetAddonByName("ContentsFinder", 1)).GetNodeById(4u);
AtkComponentCheckBox* ptr2 = (AtkComponentCheckBox*)2267615832848uL;
if ((uint)list[1] == 1)
{
PluginLog.Debug("FUCKING CASUAL :D", Array.Empty<object>());
}
else if ((uint)list[1] == 2)
{
PluginLog.Debug("FUCKING HARDCORE RANKED :D", Array.Empty<object>());
}
}
}
}
}
return addonReceiveEventHook.Original(atkunitbase, valuecount, atkvalues, a4);
}
private void ClientState_EnterPvP()
{
PluginLog.Debug("Yes, we entered pvp :)", Array.Empty<object>());
}
private unsafe void InstallAddonReceiveEventHook()
{
string text = "E8 ?? ?? ?? ?? 8B 4C 24 20 0F B6 D8";
nint num = DalamudApi.SigScanner.ScanText(text);
addonReceiveEventHook = DalamudApi.Hooks.HookFromAddress<FireCallbackDelegate>((IntPtr)num, (FireCallbackDelegate)CallbackDetour, (HookBackend)0);
}
private unsafe AtkUnitBase* GetDutyFinderPointer()
{
nint addonByName = DalamudApi.GameGui.GetAddonByName("ContentsFinder", 1);
if (addonByName != IntPtr.Zero)
{
AtkUnitBase* ptr = (AtkUnitBase*)addonByName;
if (((AtkUnitBase)ptr).RootNode != null)
{
return ptr;
}
return null;
}
return null;
}
private void Framework_Update(IFramework framework)
{
if (Configuration.Enabled && DalamudApi.ClientState.IsLoggedIn)
{
CheckForDfSelections();
}
}
private unsafe void CheckForDfSelections()
{
nint addonByName = DalamudApi.GameGui.GetAddonByName("ContentsFinderConfirm", 1);
AtkUnitBase* ptr = (AtkUnitBase*)addonByName;
if (ptr != null && ((AtkUnitBase)ptr).IsVisible)
{
AtkTextNode* nodeById = (AtkTextNode*)((AtkUnitBase)ptr).GetNodeById(49u);
if (nodeById != null && ((Utf8String)(&((AtkTextNode)nodeById).NodeText)).StringPtr != null)
{
string text = Marshal.PtrToStringUTF8(new IntPtr(((Utf8String)(&((AtkTextNode)nodeById).NodeText)).StringPtr));
if (text != null)
{
if (text.Contains("Crystalline Conflict (Casual Match)"))
{
if (!casualCCEnabled)
{
casualCCEnabled = true;
rankedCCEnabled = false;
PluginLog.Debug("CASUAL CC MATCH INCOMING, SETTING TRUE", Array.Empty<object>());
}
}
else if (text.Contains("Crystalline Conflict (Ranked Match)") && !rankedCCEnabled)
{
rankedCCEnabled = true;
casualCCEnabled = false;
PluginLog.Debug("RANKED CC MATCH INCOMING, SETTING TRUE", Array.Empty<object>());
}
}
}
}
nint addonByName2 = DalamudApi.GameGui.GetAddonByName("ContentsFinder", 1);
if (addonByName2 != IntPtr.Zero)
{
AtkUnitBase* ptr2 = (dutyFinderAtkUnitBase = (AtkUnitBase*)addonByName2);
if (((AtkUnitBase)ptr2).RootNode != null && ((AtkUnitBase)ptr2).IsVisible)
{
dutyFinderVisible = true;
}
}
}
public void Dispose()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
PluginUi.Dispose();
DalamudApi.CommandManager.RemoveHandler("/ccwins");
DalamudApi.Framework.Update -= new OnUpdateDelegate(Framework_Update);
DalamudApi.ClientState.LeavePvP -= ClientState_LeavePvP;
DalamudApi.ClientState.EnterPvP -= ClientState_EnterPvP;
DalamudApi.ChatGui.ChatMessage -= new OnMessageDelegate(Chat_ChatMessage);
}
private void OnCommand(string command, string args)
{
PluginUi.Visible = true;
}
private void DrawUI()
{
PluginUi.Draw();
}
private void DrawConfigUI()
{
PluginUi.SettingsVisible = true;
}
}
@@ -0,0 +1,323 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using Dalamud.Game.ClientState.Objects.Types;
using ImGuiNET;
using Lumina.Text;
using Newtonsoft.Json;
namespace CrystallineConflictWinsTracker;
internal class PluginUI : IDisposable
{
private Configuration configuration;
private bool settingsVisible;
private bool visible;
public List<PvpSeason> pvpSeasons = new List<PvpSeason>();
private List<PvpWinEntry>? currentData;
private string currentlySelectedClassName;
private List<PvpWinEntry> currentClassGames;
private bool pickedClass;
private PvpSeason currentlySelectedSeason;
private PvpSeason previouslySelectedSeason;
private string previouslySelectedClassName;
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;
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(1970, 1, 1),
endDate = new DateTime(2095, 1, 1),
season = 0,
seasonLabel = "All"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2022, 4, 12),
endDate = new DateTime(2022, 7, 6),
season = 1,
seasonLabel = "Season 1"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2022, 7, 6),
endDate = new DateTime(2022, 8, 22),
season = 2,
seasonLabel = "Season 2"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2022, 8, 23),
endDate = new DateTime(2022, 10, 31),
season = 3,
seasonLabel = "Season 3"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2022, 10, 31),
endDate = new DateTime(2023, 1, 10),
season = 4,
seasonLabel = "Season 4"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2023, 1, 10),
endDate = new DateTime(2023, 4, 4),
season = 5,
seasonLabel = "Season 5"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2023, 4, 4),
endDate = new DateTime(2024, 10, 3),
season = 6,
seasonLabel = "Season 6"
});
pvpSeasons.Add(new PvpSeason
{
startDate = new DateTime(2023, 10, 3),
season = 7,
seasonLabel = "Season 7"
});
currentlySelectedSeason = pvpSeasons[7];
}
public void DrawMainWindow()
{
if (!Visible)
{
pickedClass = false;
return;
}
List<PvpWinEntry> list = (currentData = JsonConvert.DeserializeObject<List<PvpWinEntry>>(File.ReadAllText(DataPath + "pvpstats.json")) ?? new List<PvpWinEntry>());
List<PvpWinEntry> list2 = list.FindAll((PvpWinEntry c) => !c.matchDate.HasValue);
List<PvpWinEntry> list3 = list.FindAll((PvpWinEntry c) => c.matchDate >= new DateTime(2022, 7, 6) && c.matchDate <= new DateTime(2022, 8, 22));
List<PvpWinEntry> list4 = list.FindAll((PvpWinEntry c) => c.matchDate >= new DateTime(2022, 8, 22) && c.matchDate <= new DateTime(2022, 10, 31));
List<PvpWinEntry> list5 = list.FindAll((PvpWinEntry c) => c.matchDate >= new DateTime(2022, 11, 1) && c.matchDate <= new DateTime(2023, 1, 10));
List<PvpWinEntry> list6 = list.FindAll((PvpWinEntry c) => c.matchDate >= new DateTime(2023, 1, 10) && c.matchDate <= new DateTime(2023, 4, 4));
List<PvpWinEntry> list7 = list.FindAll((PvpWinEntry c) => c.matchDate >= new DateTime(2023, 4, 4) && c.matchDate <= new DateTime(2023, 10, 3));
List<PvpWinEntry> list8 = list.FindAll((PvpWinEntry c) => c.matchDate >= new DateTime(2023, 10, 3));
if (currentlySelectedSeason != null && currentlySelectedSeason.season != 0)
{
List<PvpWinEntry> list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
switch (currentlySelectedSeason.season)
{
case 1:
currentData = list2;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
case 2:
currentData = list3;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
case 3:
currentData = list4;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
case 4:
currentData = list5;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
case 5:
currentData = list6;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
case 6:
currentData = list7;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
case 7:
currentData = list8;
list9 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list9;
break;
}
}
List<string> list10 = new List<string>();
foreach (PvpWinEntry currentDatum in currentData)
{
if (!list10.Contains(currentDatum.className))
{
list10.Add(currentDatum.className);
}
}
if (!pickedClass && DalamudApi.ClientState.IsLoggedIn && (GameObject)(object)DalamudApi.ClientState.LocalPlayer != (GameObject)null && ((Character)DalamudApi.ClientState.LocalPlayer).ClassJob.GameData != null)
{
currentlySelectedClassName = SeString.op_Implicit(((Character)DalamudApi.ClientState.LocalPlayer).ClassJob.GameData.Name);
List<PvpWinEntry> list11 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list11;
}
ImGui.SetNextWindowSize(new Vector2(700f, 330f), (ImGuiCond)4);
ImGui.SetNextWindowSizeConstraints(new Vector2(700f, 330f), new Vector2(float.MaxValue, float.MaxValue));
if (ImGui.Begin("Crystalline Conflict stats", ref visible, (ImGuiWindowFlags)24) && (GameObject)(object)DalamudApi.ClientState.LocalPlayer != (GameObject)null && ((Character)DalamudApi.ClientState.LocalPlayer).ClassJob.GameData != null)
{
if (ImGui.BeginCombo("###seasonSelection", (currentlySelectedSeason == null) ? "All" : currentlySelectedSeason.seasonLabel))
{
foreach (PvpSeason pvpSeason in pvpSeasons)
{
if (ImGui.Selectable(pvpSeason.seasonLabel))
{
currentlySelectedSeason = pvpSeason;
}
}
ImGui.EndCombo();
}
if (ImGui.BeginCombo("###jobSelection", (currentlySelectedClassName == null) ? SeString.op_Implicit(((Character)DalamudApi.ClientState.LocalPlayer).ClassJob.GameData.Name) : currentlySelectedClassName))
{
foreach (string item in list10)
{
if (ImGui.Selectable(item))
{
currentlySelectedClassName = item;
List<PvpWinEntry> list12 = currentData.FindAll((PvpWinEntry b) => b.className == currentlySelectedClassName);
currentClassGames = list12;
pickedClass = true;
}
}
ImGui.EndCombo();
}
}
ImGui.Separator();
if (currentClassGames != null)
{
List<PvpWinEntry> list13 = currentClassGames.FindAll((PvpWinEntry b) => !b.win);
List<PvpWinEntry> list14 = currentClassGames.FindAll((PvpWinEntry b) => b.win);
int count = list14.FindAll((PvpWinEntry b) => b.ranked).Count;
int count2 = list14.FindAll((PvpWinEntry b) => !b.ranked).Count;
int count3 = list13.FindAll((PvpWinEntry b) => b.ranked).Count;
int count4 = list13.FindAll((PvpWinEntry b) => !b.ranked).Count;
decimal num = default(decimal);
if (count3 > 0 || count > 0)
{
num = Math.Round(decimal.Divide(count, count + count3) * 100m, 2);
}
decimal num2 = default(decimal);
if (count2 > 0 || count4 > 0)
{
num2 = Math.Round(decimal.Divide(count2, count2 + count4) * 100m, 2);
}
ImGui.Text(currentlySelectedClassName + " stats");
ImGui.TextColored(new Vector4(0f, 1f, 1f, 1f), "Ranked");
ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "Losses: " + count3);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "Wins: " + count);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "(WR: " + num + " %%)");
ImGui.TextColored(new Vector4(0f, 1f, 1f, 1f), "Casual");
ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "Losses: " + count4);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "Wins: " + count2);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "(WR: " + num2 + " %%)");
ImGui.Separator();
List<PvpWinEntry> list15 = currentData.FindAll((PvpWinEntry w) => w.win && w.ranked);
List<PvpWinEntry> list16 = currentData.FindAll((PvpWinEntry w) => !w.win && w.ranked);
decimal num3 = default(decimal);
if (list15.Count > 0 && list16.Count > 0)
{
num3 = Math.Round(decimal.Divide(list15.Count, list15.Count + list16.Count) * 100m, 2);
}
ImGui.Text("Total stats");
ImGui.TextColored(new Vector4(0f, 1f, 1f, 1f), "Ranked");
ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "Losses: " + list16.Count);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "Wins: " + list15.Count);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "(WR: " + num3 + " %%)");
List<PvpWinEntry> list17 = currentData.FindAll((PvpWinEntry w) => w.win && !w.ranked);
List<PvpWinEntry> list18 = currentData.FindAll((PvpWinEntry w) => !w.win && !w.ranked);
decimal num4 = default(decimal);
if (list17.Count > 0 && list18.Count > 0)
{
num4 = Math.Round(decimal.Divide(list17.Count, list17.Count + list18.Count) * 100m, 2);
}
ImGui.TextColored(new Vector4(0f, 1f, 1f, 1f), "Casual");
ImGui.TextColored(new Vector4(1f, 0f, 0f, 1f), "Losses: " + list18.Count);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "Wins: " + list17.Count);
ImGui.SameLine();
ImGui.TextColored(new Vector4(0f, 1f, 0f, 1f), "(WR: " + num4 + " %%)");
}
ImGui.End();
}
public void Dispose()
{
}
public void Draw()
{
DrawMainWindow();
DrawSettingsWindow();
}
public void DrawSettingsWindow()
{
if (!SettingsVisible)
{
return;
}
ImGui.SetNextWindowSize(new Vector2(450f, 100f), (ImGuiCond)1);
if (ImGui.Begin("World Map Enhancer Settings", ref settingsVisible, (ImGuiWindowFlags)58))
{
bool enabled = configuration.Enabled;
if (ImGui.Checkbox("Enable zooming out with right click", ref enabled))
{
configuration.Enabled = enabled;
configuration.Save();
}
int rightClickDelay = configuration.RightClickDelay;
if (ImGui.InputInt("Right click release delay", ref rightClickDelay, 25, 100))
{
configuration.RightClickDelay = rightClickDelay;
configuration.Save();
}
}
ImGui.End();
}
}
@@ -0,0 +1,14 @@
using System;
namespace CrystallineConflictWinsTracker;
public class PvpSeason
{
public DateTime startDate { get; set; }
public DateTime? endDate { get; set; }
public int season { get; set; }
public string seasonLabel { get; set; }
}
@@ -0,0 +1,16 @@
using System;
namespace CrystallineConflictWinsTracker;
public class PvpWinEntry
{
public bool ranked { get; set; }
public bool win { get; set; }
public uint classId { get; set; }
public string className { get; set; }
public DateTime? matchDate { get; set; }
}
@@ -0,0 +1,5 @@
namespace CrystallineConflictWinsTracker;
public class Service
{
}
@@ -0,0 +1,15 @@
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("Yes, we track winners only here")]
[assembly: AssemblyFileVersion("0.0.2.9")]
[assembly: AssemblyInformationalVersion("0.0.1.4")]
[assembly: AssemblyProduct("CrystallineConflictWinsTracker")]
[assembly: AssemblyTitle("CrystallineConflictWinsTracker")]
[assembly: AssemblyVersion("0.0.2.9")]
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>MultiboxMutexer</AssemblyName>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<TargetFramework>net7.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="ImGui.NET" />
</ItemGroup>
</Project>
@@ -0,0 +1,53 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace MultiboxMutexer.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,289 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace MultiboxMutexer;
public static class HandleManager
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct SYSTEM_HANDLE_INFORMATION
{
public uint OwnerPID;
public byte ObjectType;
public byte HandleFlags;
public ushort HandleValue;
public nuint ObjectPointer;
public nint AccessMask;
}
private struct OBJECT_BASIC_INFORMATION
{
public uint Attributes;
public uint GrantedAccess;
public uint HandleCount;
public uint PointerCount;
public uint PagedPoolUsage;
public uint NonPagedPoolUsage;
public uint Reserved1;
public uint Reserved2;
public uint Reserved3;
public uint NameInformationLength;
public uint TypeInformationLength;
public uint SecurityDescriptorLength;
public FILETIME CreateTime;
}
private struct IO_STATUS_BLOCK
{
public uint Status;
public ulong Information;
}
[Flags]
private enum DuplicateOptions : uint
{
DUPLICATE_CLOSE_SOURCE = 1u,
DUPLICATE_SAME_ACCESS = 2u
}
[Flags]
private enum ProcessAccessFlags : uint
{
All = 0x1F0FFFu,
Terminate = 1u,
CreateThread = 2u,
VMOperation = 8u,
VMRead = 0x10u,
VMWrite = 0x20u,
DupHandle = 0x40u,
SetInformation = 0x200u,
QueryInformation = 0x400u,
Synchronize = 0x100000u
}
[Flags]
private enum NTSTATUS : uint
{
STATUS_SUCCESS = 0u,
STATUS_INFO_LENGTH_MISMATCH = 0xC0000004u
}
[Flags]
private enum OBJECT_INFORMATION_CLASS : uint
{
ObjectBasicInformation = 0u,
ObjectNameInformation = 1u,
ObjectTypeInformation = 2u,
ObjectAllTypesInformation = 3u,
ObjectHandleInformation = 4u
}
[Flags]
private enum SYSTEM_INFORMATION_CLASS : uint
{
SystemHandleInformation = 0x10u
}
[Flags]
private enum FILE_INFORMATION_CLASS
{
FileNameInformation = 9
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(nint hObject);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DuplicateHandle(nint hSourceProcessHandle, nint hSourceHandle, nint hTargetProcessHandle, out nint lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, DuplicateOptions dwOptions);
[DllImport("kernel32.dll")]
private static extern nint OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessID);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern NTSTATUS NtQueryInformationFile(nint FileHandle, ref IO_STATUS_BLOCK IoStatusBlock, nint FileInformation, int FileInformationLength, FILE_INFORMATION_CLASS FileInformationClass);
[DllImport("ntdll.dll")]
private static extern NTSTATUS NtQueryObject(nint ObjectHandle, OBJECT_INFORMATION_CLASS ObjectInformationClass, nint ObjectInformation, int ObjectInformationLength, out int ReturnLength);
[DllImport("ntdll.dll")]
private static extern NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, nint SystemInformation, int SystemInformationLength, out int ReturnLength);
public static bool ClearMutex()
{
bool result = false;
Process[] processes = Process.GetProcesses();
foreach (Process process in processes)
{
if (process.ProcessName.Equals("ffxiv_dx11", StringComparison.OrdinalIgnoreCase) && KillHandle(process, "6AA83AB5-BAC4-4a36-9F66-A309770760CB_ffxiv_game00", isFile: false))
{
result = true;
}
}
return result;
}
public static bool KillHandle(Process targetProcess, string handleName, bool isFile)
{
bool result = false;
nint allHandles = GetAllHandles();
if (allHandles == IntPtr.Zero)
{
return result;
}
List<SYSTEM_HANDLE_INFORMATION> handles = GetHandles(targetProcess, allHandles);
Marshal.FreeHGlobal(allHandles);
nint num = OpenProcess(ProcessAccessFlags.DupHandle, bInheritHandle: false, (uint)targetProcess.Id);
foreach (SYSTEM_HANDLE_INFORMATION item in handles)
{
string text = ((!isFile) ? GetHandleName(item, num) : GetFileName(item, num));
if (text.Contains(handleName) && CloseHandleEx(item.OwnerPID, new IntPtr(item.HandleValue)))
{
result = true;
}
}
CloseHandle(num);
return result;
}
private static bool CloseHandleEx(uint processID, nint handleToClose)
{
nint num = OpenProcess(ProcessAccessFlags.All, bInheritHandle: false, processID);
nint lpTargetHandle;
bool result = DuplicateHandle(num, handleToClose, IntPtr.Zero, out lpTargetHandle, 0u, bInheritHandle: false, DuplicateOptions.DUPLICATE_CLOSE_SOURCE);
CloseHandle(num);
return result;
}
private static string ConvertToString(nint pStringBuffer)
{
long num = ((IntPtr)pStringBuffer).ToInt64();
int num2 = IntPtr.Size * 2;
return Marshal.PtrToStringAnsi(new IntPtr(num + num2));
}
private static nint GetAllHandles()
{
int num = 65536;
nint num2 = Marshal.AllocHGlobal(num);
int ReturnLength;
NTSTATUS nTSTATUS = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, num2, num, out ReturnLength);
while (true)
{
switch (nTSTATUS)
{
case NTSTATUS.STATUS_INFO_LENGTH_MISMATCH:
break;
case NTSTATUS.STATUS_SUCCESS:
return num2;
default:
Marshal.FreeHGlobal(num2);
return IntPtr.Zero;
}
Marshal.FreeHGlobal(num2);
num *= 2;
num2 = Marshal.AllocHGlobal(num);
nTSTATUS = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, num2, num, out ReturnLength);
}
}
private static List<SYSTEM_HANDLE_INFORMATION> GetHandles(Process targetProcess, nint pSysHandles)
{
List<SYSTEM_HANDLE_INFORMATION> list = new List<SYSTEM_HANDLE_INFORMATION>();
long num = ((IntPtr)pSysHandles).ToInt64();
int num2 = Marshal.ReadInt32(pSysHandles);
for (int i = 0; i < num2; i++)
{
long num3 = IntPtr.Size + i * Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));
SYSTEM_HANDLE_INFORMATION item = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(new IntPtr(num + num3), typeof(SYSTEM_HANDLE_INFORMATION));
if (item.OwnerPID == (uint)targetProcess.Id)
{
list.Add(item);
}
}
return list;
}
private static string GetFileName(SYSTEM_HANDLE_INFORMATION handleInfo, nint hProcess)
{
try
{
nint handle = Process.GetCurrentProcess().Handle;
DuplicateHandle(hProcess, new IntPtr(handleInfo.HandleValue), handle, out var lpTargetHandle, 0u, bInheritHandle: false, DuplicateOptions.DUPLICATE_SAME_ACCESS);
int num = 512;
nint num2 = Marshal.AllocHGlobal(num);
IO_STATUS_BLOCK IoStatusBlock = default(IO_STATUS_BLOCK);
NtQueryInformationFile(lpTargetHandle, ref IoStatusBlock, num2, num, FILE_INFORMATION_CLASS.FileNameInformation);
CloseHandle(lpTargetHandle);
int num3 = 4;
string? result = Marshal.PtrToStringUni(new IntPtr(((IntPtr)num2).ToInt64() + num3));
Marshal.FreeHGlobal(num2);
return result;
}
catch (Exception)
{
return string.Empty;
}
}
private static string GetHandleName(SYSTEM_HANDLE_INFORMATION targetHandleInfo, nint hProcess)
{
if (((IntPtr)targetHandleInfo.AccessMask).ToInt64() == 1180063)
{
return string.Empty;
}
nint handle = Process.GetCurrentProcess().Handle;
DuplicateHandle(hProcess, new IntPtr(targetHandleInfo.HandleValue), handle, out var lpTargetHandle, 0u, bInheritHandle: false, DuplicateOptions.DUPLICATE_SAME_ACCESS);
int ReturnLength = GetHandleNameLength(lpTargetHandle);
nint num = Marshal.AllocHGlobal(ReturnLength);
NtQueryObject(lpTargetHandle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, num, ReturnLength, out ReturnLength);
nint zero = IntPtr.Zero;
zero = Marshal.AllocHGlobal(ReturnLength);
string result = "";
if (NtQueryObject(lpTargetHandle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, zero, ReturnLength, out ReturnLength) == NTSTATUS.STATUS_SUCCESS)
{
result = Marshal.PtrToStringUni((nint)((long)zero + (long)(2 * IntPtr.Size)));
Marshal.FreeHGlobal(zero);
}
CloseHandle(lpTargetHandle);
ConvertToString(num);
Marshal.FreeHGlobal(num);
return result;
}
private static int GetHandleNameLength(nint handle)
{
int ReturnLength = Marshal.SizeOf(typeof(OBJECT_BASIC_INFORMATION));
nint num = Marshal.AllocHGlobal(ReturnLength);
NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectBasicInformation, num, ReturnLength, out ReturnLength);
OBJECT_BASIC_INFORMATION oBJECT_BASIC_INFORMATION = (OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(num, typeof(OBJECT_BASIC_INFORMATION));
Marshal.FreeHGlobal(num);
if (oBJECT_BASIC_INFORMATION.NameInformationLength == 0)
{
return 256;
}
return (int)oBJECT_BASIC_INFORMATION.NameInformationLength;
}
}
@@ -0,0 +1,107 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.IoC;
using Dalamud.Logging;
using Dalamud.Plugin;
namespace MultiboxMutexer;
public sealed class Plugin : IDalamudPlugin, IDisposable
{
[Flags]
private enum ProcessAccessFlags : uint
{
All = 0x1F0FFFu,
Terminate = 1u,
CreateThread = 2u,
VMOperation = 8u,
VMRead = 0x10u,
VMWrite = 0x20u,
DupHandle = 0x40u,
SetInformation = 0x200u,
QueryInformation = 0x400u,
Synchronize = 0x100000u
}
[Flags]
private enum DuplicateOptions : uint
{
DUPLICATE_CLOSE_SOURCE = 1u,
DUPLICATE_SAME_ACCESS = 2u
}
private const uint PROCESS_DUP_HANDLE = 64u;
public string Name => "Multibox Mutexer";
public DalamudPluginInterface PluginInterface { get; }
public CommandManager CommandManager { get; }
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(nint hObject);
[DllImport("kernel32.dll")]
private static extern nint OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, nint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DuplicateHandle(nint hSourceProcessHandle, nint hSourceHandle, nint hTargetProcessHandle, out nint lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, DuplicateOptions dwOptions);
public static bool CloseHandleEx(nint pid, nint handle)
{
nint num = OpenProcess(ProcessAccessFlags.DupHandle, bInheritHandle: false, pid);
nint lpTargetHandle = IntPtr.Zero;
bool result = DuplicateHandle(num, handle, IntPtr.Zero, out lpTargetHandle, 0u, bInheritHandle: false, DuplicateOptions.DUPLICATE_CLOSE_SOURCE);
CloseHandle(num);
return result;
}
public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface, [RequiredVersion("1.0")] CommandManager commandManager, [RequiredVersion("1.0")] GameGui gameGui)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
PluginInterface = pluginInterface;
CommandManager = commandManager;
CommandManager.AddHandler("/mutex", new CommandInfo(new HandlerDelegate(OnCommand))
{
HelpMessage = "Fix mutex"
});
PluginLog.Debug("LOADED?", Array.Empty<object>());
Process currentProcess = Process.GetCurrentProcess();
PluginLog.Debug("CURRENT PROCESS PID: " + currentProcess.Id, Array.Empty<object>());
ReleaseAllMutexes(currentProcess);
}
public void ReleaseAllMutexes(Process proc)
{
PluginLog.Debug("MUTEXER CALLED", Array.Empty<object>());
if (HandleManager.ClearMutex())
{
PluginLog.Debug("Succesfully killed the mutex", Array.Empty<object>());
}
else
{
PluginLog.Warning("Failed to kill mutex!", Array.Empty<object>());
}
}
private void OnCommand(string command, string args)
{
PluginLog.Debug("RUNNING MUTEXER", Array.Empty<object>());
Process currentProcess = Process.GetCurrentProcess();
ReleaseAllMutexes(currentProcess);
}
public void Dispose()
{
CommandManager.RemoveHandler("/mutex");
}
}
@@ -0,0 +1,28 @@
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.Gui;
using Dalamud.IoC;
namespace MultiboxMutexer;
public class Service
{
[PluginService]
public static ClientState ClientState { get; private set; }
[PluginService]
public static Framework Framework { get; private set; }
[PluginService]
public static GameGui GameGui { get; private set; }
[PluginService]
public static SigScanner SigScanner { get; private set; }
[PluginService]
public static ChatGui Chat { get; private set; }
[PluginService]
public static DataManager DataManager { get; private set; }
}
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Dalamud.Game;
using Dalamud.Interface;
using ImGuiNET;
namespace MultiboxMutexer;
internal static class Util
{
internal static bool TryScanText(this SigScanner scanner, string sig, out nint result)
{
result = IntPtr.Zero;
try
{
result = scanner.ScanText(sig);
return true;
}
catch (KeyNotFoundException)
{
return false;
}
}
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_000a: Unknown result type (might be due to invalid IL or missing references)
ImGui.PushFont(UiBuilder.IconFont);
bool result = ImGui.Button(FontAwesomeExtensions.ToIconString(icon) + "##" + id);
ImGui.PopFont();
return result;
}
}
@@ -0,0 +1,6 @@
internal class MultiboxMutexer_ProcessedByFody
{
internal const string FodyVersion = "6.6.4.0";
internal const string Resourcer = "1.8.0.0";
}
@@ -0,0 +1,15 @@
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("Why are we still here? Just to suffer?")]
[assembly: AssemblyFileVersion("1.0.1.2")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MultiboxMutexer")]
[assembly: AssemblyTitle("MultiboxMutexer")]
[assembly: AssemblyVersion("1.0.1.2")]
@@ -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")]
@@ -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("WorldMapEnhancer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A plugin to enable right click zoom on the map")]
[assembly: AssemblyFileVersion("1.0.6.2")]
[assembly: AssemblyInformationalVersion("1.0.6.2+8c181f19a2ba71e0bee0e08ad8a42953b3276520")]
[assembly: AssemblyProduct("WorldMapEnhancer")]
[assembly: AssemblyTitle("WorldMapEnhancer")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/aRkker/ffxiv-dalamud-wme.git")]
[assembly: AssemblyVersion("1.0.6.2")]
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>WorldMapEnhancer</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="Dalamud.Bindings.ImGui" />
<Reference Include="InteropGenerator.Runtime" />
</ItemGroup>
</Project>
@@ -0,0 +1,28 @@
using System;
using Dalamud.Configuration;
using Dalamud.Plugin;
namespace WorldMapFixer;
[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 WorldMapFixer;
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,328 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Command;
using Dalamud.Game.NativeWrapper;
using Dalamud.Hooking;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI;
using InteropGenerator.Runtime;
namespace WorldMapFixer;
public sealed class Plugin : IDalamudPlugin, IDisposable
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FireCallbackDelegate(nint atkUnitBase, uint valueCount, nint values, bool close);
public delegate void AreaMapReceiveEventDelegate(long p1, long p2, uint p3, long p4, nint p5);
private const string commandName = "/wme";
public bool alertedDebugWindow;
private bool areaMapVisible;
private IKeyState keyState;
private nint fireCallbackAddress;
private FireCallbackDelegate fireCallback;
public string Name => "World Map Enhancer";
private IDalamudPluginInterface PluginInterface { get; init; }
private ICommandManager CommandManager { get; init; }
private Configuration Configuration { get; init; }
private PluginUI PluginUi { get; init; }
public Hook<AreaMapReceiveEventDelegate> MouseDelegateHook { get; private set; }
public long rcStartTime { get; private set; }
public Plugin(IDalamudPluginInterface pluginInterface)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Expected O, but got Unknown
DalamudApi.Initialize(pluginInterface);
PluginInterface = pluginInterface;
CommandManager = DalamudApi.CommandManager ?? throw new ArgumentNullException("CommandManager");
pluginInterface.Create<Service>(Array.Empty<object>());
DalamudApi.Framework.Update += new OnUpdateDelegate(Framework_UpdateNew);
Configuration = (PluginInterface.GetPluginConfig() as Configuration) ?? new Configuration();
Configuration.Initialize(PluginInterface);
PluginUi = new PluginUI(Configuration);
keyState = DalamudApi.KeyState;
CommandManager.AddHandler("/wme", new CommandInfo(new HandlerDelegate(OnCommand))
{
HelpMessage = "Configuration for the right click behaviour"
});
PluginInterface.UiBuilder.Draw += DrawUI;
PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
string text = "E8 ?? ?? ?? ?? 0F B6 E8 8B 44 24 20";
fireCallbackAddress = DalamudApi.SigScanner.ScanText(text);
fireCallback = (FireCallbackDelegate)Marshal.GetDelegateForFunctionPointer(fireCallbackAddress, typeof(FireCallbackDelegate));
InstallMouseHook();
}
private void Framework_UpdateNew(IFramework framework)
{
if (Configuration != null && Configuration.Enabled && DalamudApi.ClientState != null && DalamudApi.ClientState.IsLoggedIn)
{
CheckForMap();
}
}
private void InstallMouseHook()
{
string text = "40 55 56 57 48 8B EC 48 83 EC 70 0F B7 C2";
nint num = DalamudApi.SigScanner.ScanText(text);
if (num != IntPtr.Zero)
{
DalamudApi.PluginLog.Debug("Hooking!", Array.Empty<object>());
MouseDelegateHook = DalamudApi.Hooks.HookFromAddress<AreaMapReceiveEventDelegate>((IntPtr)num, (AreaMapReceiveEventDelegate)Detour, (HookBackend)0);
MouseDelegateHook?.Enable();
}
}
private void Detour(long p1, long p2, uint p3, long p4, nint p5)
{
Marshal.ReadIntPtr(p5);
byte b = Marshal.ReadByte(p5, 6);
byte b2 = Marshal.ReadByte(p5, 7);
_ = DalamudApi.KeyState[(VirtualKey)162];
if (p2 == 4 && p3 == 16 && b == 1 && b2 != 1)
{
ZoomOutMap();
}
MouseDelegateHook.Original(p1, p2, p3, p4, p5);
}
public unsafe Vector4 GetMapParams()
{
if (areaMapVisible)
{
AtkUnitBase* areaMapPointer = GetAreaMapPointer();
return new Vector4(((AtkResNode)((AtkUnitBase)areaMapPointer).RootNode).X, ((AtkResNode)((AtkUnitBase)areaMapPointer).RootNode).Y, (int)((AtkResNode)((AtkUnitBase)areaMapPointer).RootNode).GetWidth(), (int)((AtkResNode)((AtkUnitBase)areaMapPointer).RootNode).GetHeight());
}
return new Vector4(float.MinValue, float.MinValue, float.MinValue, float.MinValue);
}
public unsafe static AtkValue* CreateAtkValueArray(params object[] values)
{
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
AtkValue* ptr = (AtkValue*)Marshal.AllocHGlobal(values.Length * Unsafe.SizeOf<AtkValue>());
if (ptr == null)
{
return null;
}
try
{
for (int i = 0; i < values.Length; i++)
{
object obj = values[i];
if (!(obj is uint uInt))
{
if (!(obj is int num))
{
if (!(obj is float num2))
{
if (!(obj is bool flag))
{
if (!(obj is string s))
{
throw new ArgumentException($"Unable to convert type {obj.GetType()} to AtkValue");
}
Unsafe.Write(&((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Type, (ValueType)8);
byte[] bytes = Encoding.UTF8.GetBytes(s);
nint num3 = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, num3, bytes.Length);
Marshal.WriteByte(num3, bytes.Length, 0);
Unsafe.Write(&((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).String, CStringPointer.op_Implicit((byte*)num3));
}
else
{
Unsafe.Write(&((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Type, (ValueType)2);
((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Byte = (flag ? ((byte)1) : ((byte)0));
}
}
else
{
Unsafe.Write(&((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Type, (ValueType)7);
((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Float = num2;
}
}
else
{
Unsafe.Write(&((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Type, (ValueType)3);
((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Int = num;
}
}
else
{
Unsafe.Write(&((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Type, (ValueType)5);
((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).UInt = uInt;
}
}
return ptr;
}
catch
{
return null;
}
}
public unsafe static bool GetUnitBase(string name, out AtkUnitBase* unitBase, int index = 1)
{
unitBase = GetUnitBase(name, index);
return unitBase != null;
}
public unsafe static AtkUnitBase* GetUnitBase(string name, int index = 1)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return (AtkUnitBase*)Service.GameGui.GetAddonByName(name, index).Address;
}
public unsafe static void GenerateCallback(AtkUnitBase* unitBase, params object[] values)
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Invalid comparison between Unknown and I4
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
AtkValue* ptr = CreateAtkValueArray(values);
if (ptr == null)
{
return;
}
try
{
((AtkUnitBase)unitBase).FireCallback((uint)values.Length, ptr, false);
}
finally
{
for (int i = 0; i < values.Length; i++)
{
if ((int)((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).Type == 8)
{
Marshal.FreeHGlobal(new IntPtr(CStringPointer.op_Implicit(((AtkValue)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<AtkValue>())).String)));
}
}
Marshal.FreeHGlobal(new IntPtr(ptr));
}
}
private unsafe AtkUnitBase* GetAreaMapPointer()
{
//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_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
AtkUnitBasePtr addonByName = DalamudApi.GameGui.GetAddonByName("AreaMap", 1);
if (addonByName.Address != (IntPtr)IntPtr.Zero)
{
AtkUnitBase* address = (AtkUnitBase*)addonByName.Address;
if (((AtkUnitBase)address).RootNode != null)
{
DalamudApi.PluginLog.Debug("PTR: " + (long)((AtkUnitBase)address).RootNode, Array.Empty<object>());
return address;
}
DalamudApi.PluginLog.Debug("Null pointer.", Array.Empty<object>());
return null;
}
DalamudApi.PluginLog.Debug("Null pointer.", Array.Empty<object>());
return null;
}
private unsafe void CheckForMap()
{
//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_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
AtkUnitBasePtr addonByName = DalamudApi.GameGui.GetAddonByName("AreaMap", 1);
if (addonByName.Address == (IntPtr)IntPtr.Zero)
{
return;
}
AtkUnitBase* address = (AtkUnitBase*)addonByName.Address;
if (((AtkUnitBase)address).RootNode == null)
{
return;
}
if (((AtkUnitBase)address).IsVisible)
{
if (!areaMapVisible)
{
areaMapVisible = true;
}
}
else if (areaMapVisible)
{
areaMapVisible = false;
}
}
private void Framework_Update()
{
if (Configuration.Enabled && DalamudApi.ClientState.IsLoggedIn)
{
CheckForMap();
}
}
public void Dispose()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
PluginUi.Dispose();
CommandManager.RemoveHandler("/wme");
DalamudApi.Framework.Update -= new OnUpdateDelegate(Framework_UpdateNew);
MouseDelegateHook.Dispose();
}
private void OnCommand(string command, string args)
{
PluginUi.SettingsVisible = true;
}
private void DrawUI()
{
PluginUi.Draw();
}
private unsafe void ZoomOutMap()
{
AtkUnitBase* unitBase = GetUnitBase("AreaMap");
if (unitBase == null)
{
DalamudApi.PluginLog.Debug("Null pointer to areamap. Going away", Array.Empty<object>());
return;
}
uint valueCount = 1u;
AtkValue* values = CreateAtkValueArray(5);
fireCallback((nint)unitBase, valueCount, (nint)values, close: false);
}
private void DrawConfigUI()
{
PluginUi.SettingsVisible = true;
}
}
@@ -0,0 +1,68 @@
using System;
using System.Numerics;
using Dalamud.Bindings.ImGui;
namespace WorldMapFixer;
internal class PluginUI : IDisposable
{
private Configuration configuration;
private bool settingsVisible;
public bool SettingsVisible
{
get
{
return settingsVisible;
}
set
{
settingsVisible = value;
}
}
public PluginUI(Configuration configuration)
{
this.configuration = configuration;
}
public void Dispose()
{
}
public void Draw()
{
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,25 @@
using Dalamud.IoC;
using Dalamud.Plugin.Services;
namespace WorldMapFixer;
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 IAddonLifecycle? AddonLifecycle { get; private set; }
[PluginService]
public static IKeyState? KeyState { get; private set; }
}