catastropy averted?

This commit is contained in:
aRkker 2026-04-30 11:18:02 +03:00
parent 3e19aac2c2
commit 585abc7132
149 changed files with 25785 additions and 14 deletions

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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; }
}

View File

@ -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")]

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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>());
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -0,0 +1,5 @@
namespace CrystallineConflictWinsTracker;
public class Service
{
}

View File

@ -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")]

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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; }
}

View File

@ -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;
}
}

View File

@ -0,0 +1,6 @@
internal class MultiboxMutexer_ProcessedByFody
{
internal const string FodyVersion = "6.6.4.0";
internal const string Resourcer = "1.8.0.0";
}

View File

@ -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")]

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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>());
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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>());
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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
}

View File

@ -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; }
}

View File

@ -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>();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,14 @@
namespace OmicronMountMusicFixer;
public struct SongStrings
{
public string Name;
public string AlternateName;
public string SpecialModeName;
public string Locations;
public string AdditionalInfo;
}

View File

@ -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;
}
}

View File

@ -0,0 +1,6 @@
internal class OmicronMountMusicFixer_ProcessedByFody
{
internal const string FodyVersion = "6.6.4.0";
internal const string Resourcer = "1.8.0.0";
}

View File

@ -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")]

View File

@ -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")]

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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>());
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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; }
}

View File

@ -0,0 +1,23 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"AntiDickheadChatmodule/0.0.6.0": {
"runtime": {
"AntiDickheadChatmodule.dll": {}
}
}
}
},
"libraries": {
"AntiDickheadChatmodule/0.0.6.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@ -0,0 +1,20 @@
{
"Author": "aRkker",
"Name": "Anti-Dickhead ChatModule",
"InternalName": "AntiDickheadChatmodule",
"AssemblyVersion": "0.0.6.0",
"Description": "Makes your chat more sufferable. :)",
"ApplicableVersion": "any",
"Tags": [
"other",
"social"
],
"DalamudApiLevel": 14,
"LoadRequiredState": 0,
"LoadSync": false,
"CanUnloadAsync": false,
"LoadPriority": 0,
"Punchline": "Removes periods, and capitals",
"Changelog": "0.0.1.1\nReuploadto fix?\n0.0.1.0\nProbably broken 6.3",
"AcceptsFeedback": true
}

View File

@ -0,0 +1,64 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v7.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v7.0": {
"CrystallineConflictWinsTracker/0.0.1.4": {
"dependencies": {
"DalamudPackager": "2.1.8",
"System.Runtime": "4.3.1"
},
"runtime": {
"CrystallineConflictWinsTracker.dll": {}
}
},
"DalamudPackager/2.1.8": {},
"Microsoft.NETCore.Platforms/1.1.1": {},
"Microsoft.NETCore.Targets/1.1.3": {},
"System.Runtime/4.3.1": {
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.1",
"Microsoft.NETCore.Targets": "1.1.3"
}
}
}
},
"libraries": {
"CrystallineConflictWinsTracker/0.0.1.4": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"DalamudPackager/2.1.8": {
"type": "package",
"serviceable": true,
"sha512": "sha512-YqagNXs9InxmqkXzq7kLveImxnodkBEicAhydMXVp7dFjC7xb76U6zGgAax4/BWIWfZeWzr5DJyQSev31kj81A==",
"path": "dalamudpackager/2.1.8",
"hashPath": "dalamudpackager.2.1.8.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/1.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ==",
"path": "microsoft.netcore.platforms/1.1.1",
"hashPath": "microsoft.netcore.platforms.1.1.1.nupkg.sha512"
},
"Microsoft.NETCore.Targets/1.1.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ==",
"path": "microsoft.netcore.targets/1.1.3",
"hashPath": "microsoft.netcore.targets.1.1.3.nupkg.sha512"
},
"System.Runtime/4.3.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
"path": "system.runtime/4.3.1",
"hashPath": "system.runtime.4.3.1.nupkg.sha512"
}
}
}

View File

@ -0,0 +1,17 @@
{
"Author": "aRkker",
"Name": "Crystalline Conflict Winratio tracker",
"InternalName": "CrystallineConflictWinsTracker",
"AssemblyVersion": "0.0.2.9",
"Description": "Tracks your CC wins and losses",
"ApplicableVersion": "any",
"Tags": [
"pvp",
"stats",
"other"
],
"DalamudApiLevel": 9,
"LoadPriority": 0,
"Punchline": "See how shite you are",
"Changelog": "0.0.1.4\nSeason 6\n0.0.1.1\nFixes for something dno\n0.0.1.0\nDalamud API 8, NET 7.0"
}

View File

@ -0,0 +1,64 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v5.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v5.0": {
"PvpWinsTracker/0.0.0.1": {
"dependencies": {
"DalamudPackager": "2.1.7",
"System.Runtime": "4.3.1"
},
"runtime": {
"PvpWinsTracker.dll": {}
}
},
"DalamudPackager/2.1.7": {},
"Microsoft.NETCore.Platforms/1.1.1": {},
"Microsoft.NETCore.Targets/1.1.3": {},
"System.Runtime/4.3.1": {
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.1",
"Microsoft.NETCore.Targets": "1.1.3"
}
}
}
},
"libraries": {
"PvpWinsTracker/0.0.0.1": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"DalamudPackager/2.1.7": {
"type": "package",
"serviceable": true,
"sha512": "sha512-jnZ/sdInyn07ycuWI+pPOtP/xE3v+c4+jYJfDt36FWnBF9NKqkpzfviJtPl/jGLgbaCmFIXu+Yid0N8GvdKefg==",
"path": "dalamudpackager/2.1.7",
"hashPath": "dalamudpackager.2.1.7.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/1.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ==",
"path": "microsoft.netcore.platforms/1.1.1",
"hashPath": "microsoft.netcore.platforms.1.1.1.nupkg.sha512"
},
"Microsoft.NETCore.Targets/1.1.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ==",
"path": "microsoft.netcore.targets/1.1.3",
"hashPath": "microsoft.netcore.targets.1.1.3.nupkg.sha512"
},
"System.Runtime/4.3.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
"path": "system.runtime/4.3.1",
"hashPath": "system.runtime.4.3.1.nupkg.sha512"
}
}
}

View File

@ -0,0 +1,42 @@
{
"Disabled": true,
"Testing": false,
"ScheduledForDeletion": false,
"InstalledFromUrl": "",
"IsThirdParty": false,
"EffectiveVersion": "0.0.0.1",
"IsAvailableForTesting": false,
"Author": "aRkker",
"Name": "CC wins tracker",
"Punchline": "See how shite you are",
"Description": "Tracks your CC wins and losses",
"Changelog": "0.0.0.1",
"Tags": [
"pvp",
"stats"
],
"CategoryTags": null,
"IsHide": false,
"InternalName": "PvpWinsTracker",
"AssemblyVersion": "0.0.0.1",
"TestingAssemblyVersion": null,
"IsTestingExclusive": false,
"RepoUrl": null,
"ApplicableVersion": "any",
"DalamudApiLevel": 6,
"DownloadCount": 0,
"LastUpdate": 0,
"DownloadLinkInstall": null,
"DownloadLinkUpdate": null,
"DownloadLinkTesting": null,
"LoadRequiredState": 0,
"LoadSync": false,
"LoadPriority": 0,
"CanUnloadAsync": false,
"ImageUrls": null,
"IconUrl": null,
"AcceptsFeedback": true,
"FeedbackMessage": null,
"_isDip17Plugin": false,
"_Dip17Channel": null
}

View File

@ -0,0 +1,16 @@
{
"Author": "aRkker",
"Name": "CC wins tracker",
"InternalName": "PvpWinsTracker",
"AssemblyVersion": "0.0.0.1",
"Description": "Tracks your CC wins and losses",
"ApplicableVersion": "any",
"Tags": [
"pvp",
"stats"
],
"DalamudApiLevel": 6,
"LoadPriority": 0,
"Punchline": "See how shite you are",
"Changelog": "0.0.0.1"
}

View File

@ -0,0 +1,64 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v5.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v5.0": {
"WinTracker/0.0.0.1": {
"dependencies": {
"DalamudPackager": "2.1.7",
"System.Runtime": "4.3.1"
},
"runtime": {
"WinTracker.dll": {}
}
},
"DalamudPackager/2.1.7": {},
"Microsoft.NETCore.Platforms/1.1.1": {},
"Microsoft.NETCore.Targets/1.1.3": {},
"System.Runtime/4.3.1": {
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.1",
"Microsoft.NETCore.Targets": "1.1.3"
}
}
}
},
"libraries": {
"WinTracker/0.0.0.1": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"DalamudPackager/2.1.7": {
"type": "package",
"serviceable": true,
"sha512": "sha512-jnZ/sdInyn07ycuWI+pPOtP/xE3v+c4+jYJfDt36FWnBF9NKqkpzfviJtPl/jGLgbaCmFIXu+Yid0N8GvdKefg==",
"path": "dalamudpackager/2.1.7",
"hashPath": "dalamudpackager.2.1.7.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/1.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ==",
"path": "microsoft.netcore.platforms/1.1.1",
"hashPath": "microsoft.netcore.platforms.1.1.1.nupkg.sha512"
},
"Microsoft.NETCore.Targets/1.1.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ==",
"path": "microsoft.netcore.targets/1.1.3",
"hashPath": "microsoft.netcore.targets.1.1.3.nupkg.sha512"
},
"System.Runtime/4.3.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
"path": "system.runtime/4.3.1",
"hashPath": "system.runtime.4.3.1.nupkg.sha512"
}
}
}

View File

@ -0,0 +1,39 @@
{
"Disabled": true,
"Testing": false,
"ScheduledForDeletion": false,
"InstalledFromUrl": "",
"IsThirdParty": false,
"EffectiveVersion": "0.0.0.1",
"IsAvailableForTesting": false,
"Author": "developer",
"Name": "WinTracker",
"Punchline": null,
"Description": "",
"Changelog": null,
"Tags": null,
"CategoryTags": null,
"IsHide": false,
"InternalName": "WinTracker",
"AssemblyVersion": "0.0.0.1",
"TestingAssemblyVersion": null,
"IsTestingExclusive": false,
"RepoUrl": null,
"ApplicableVersion": "any",
"DalamudApiLevel": 7,
"DownloadCount": 0,
"LastUpdate": 0,
"DownloadLinkInstall": null,
"DownloadLinkUpdate": null,
"DownloadLinkTesting": null,
"LoadRequiredState": 0,
"LoadSync": false,
"LoadPriority": 0,
"CanUnloadAsync": false,
"ImageUrls": null,
"IconUrl": null,
"AcceptsFeedback": true,
"FeedbackMessage": null,
"_isDip17Plugin": false,
"_Dip17Channel": null
}

View File

@ -0,0 +1,34 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v5.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v5.0": {
"WorldMapEnhancer/1.0.0.4": {
"dependencies": {
"DalamudPackager": "2.1.7"
},
"runtime": {
"WorldMapEnhancer.dll": {}
}
},
"DalamudPackager/2.1.7": {}
}
},
"libraries": {
"WorldMapEnhancer/1.0.0.4": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"DalamudPackager/2.1.7": {
"type": "package",
"serviceable": true,
"sha512": "sha512-jnZ/sdInyn07ycuWI+pPOtP/xE3v+c4+jYJfDt36FWnBF9NKqkpzfviJtPl/jGLgbaCmFIXu+Yid0N8GvdKefg==",
"path": "dalamudpackager/2.1.7",
"hashPath": "dalamudpackager.2.1.7.nupkg.sha512"
}
}
}

View File

@ -0,0 +1,44 @@
{
"Disabled": true,
"Testing": false,
"ScheduledForDeletion": false,
"InstalledFromUrl": "",
"IsThirdParty": false,
"EffectiveVersion": "1.0.0.4",
"Author": "aRkker",
"Name": "World Map Enhancer",
"Punchline": "Right click to zoom out the big map",
"Description": "Simply zoom out by right clicking the world map, like God intended it",
"Changelog": "1.0.0.3\n Testing changelog :)",
"Tags": [
"world",
"map",
"enhance",
"rightclick",
"zoom"
],
"CategoryTags": null,
"IsHide": false,
"InternalName": "WorldMapEnhancer",
"AssemblyVersion": "1.0.0.4",
"TestingAssemblyVersion": null,
"IsTestingExclusive": false,
"RepoUrl": null,
"ApplicableVersion": "any",
"DalamudApiLevel": 6,
"DownloadCount": 0,
"LastUpdate": 0,
"DownloadLinkInstall": null,
"DownloadLinkUpdate": null,
"DownloadLinkTesting": null,
"LoadRequiredState": 0,
"LoadSync": false,
"LoadPriority": 0,
"CanUnloadAsync": false,
"ImageUrls": null,
"IconUrl": null,
"AcceptsFeedback": true,
"FeedbackMessage": null,
"_isDip17Plugin": false,
"_Dip17Channel": null
}

View File

@ -0,0 +1,19 @@
{
"Author": "aRkker",
"Name": "World Map Enhancer",
"InternalName": "WorldMapEnhancer",
"AssemblyVersion": "1.0.0.4",
"Description": "Simply zoom out by right clicking the world map, like God intended it",
"ApplicableVersion": "any",
"Tags": [
"world",
"map",
"enhance",
"rightclick",
"zoom"
],
"DalamudApiLevel": 6,
"LoadPriority": 0,
"Punchline": "Right click to zoom out the big map",
"Changelog": "1.0.0.3\n Testing changelog :)"
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,16 @@
{
"Author": "aRkker",
"Name": "Multibox Mutexer",
"InternalName": "MultiboxMutexer",
"AssemblyVersion": "1.0.1.2",
"Description": "This plugin does magic to release the mutexes held by XIV to prevent more than 2 game instances launching",
"ApplicableVersion": "any",
"Tags": [
"other",
"social"
],
"DalamudApiLevel": 8,
"LoadPriority": 0,
"Punchline": "Let there be more than 2 instances of game",
"Changelog": "0.0.0.1 Initial release"
}

View File

@ -0,0 +1,23 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"OmicronMountMusicFixer/1.0.0": {
"runtime": {
"OmicronMountMusicFixer.dll": {}
}
}
}
},
"libraries": {
"OmicronMountMusicFixer/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@ -0,0 +1,20 @@
{
"Author": "aRkker",
"Name": "Omicron music enabler",
"InternalName": "OmicronMountMusicFixer",
"AssemblyVersion": "1.0.7.0",
"Description": "This plugin swaps the Miiw Miisv mount music to the Elysion theme from the Omicron beast tribe dailies. I found that this should have been the music from the get-go, but alas it wasnt. Now, with this plugin, it can be so",
"ApplicableVersion": "any",
"Tags": [
"other",
"social"
],
"DalamudApiLevel": 14,
"LoadRequiredState": 0,
"LoadSync": false,
"CanUnloadAsync": false,
"LoadPriority": 0,
"Punchline": "Swap the Miiw Miisv music for Cradle of Hope",
"Changelog": "1.0.4.2\nPVP stuff\n1.0.2.0\n6.4 fixes\n1.0.1.0\nPreliminary version for 6.3. Probably broken",
"AcceptsFeedback": true
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"WorldMapEnhancer/1.0.6.2": {
"runtime": {
"WorldMapEnhancer.dll": {}
}
}
}
},
"libraries": {
"WorldMapEnhancer/1.0.6.2": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@ -0,0 +1,23 @@
{
"Author": "aRkker",
"Name": "World Map Enhancer",
"InternalName": "WorldMapEnhancer",
"AssemblyVersion": "1.0.6.2",
"Description": "Simply zoom out by right clicking the world map, like God intended it",
"ApplicableVersion": "any",
"Tags": [
"world",
"map",
"enhance",
"rightclick",
"zoom"
],
"DalamudApiLevel": 14,
"LoadRequiredState": 0,
"LoadSync": false,
"CanUnloadAsync": false,
"LoadPriority": 0,
"Punchline": "Right click to zoom out the big map",
"Changelog": "1.0.3.0\nDawntrail support 2.0\n\n1.0.1.0\nAPI 8, NET7",
"AcceptsFeedback": true
}

6
.recovery/inventory.csv Normal file
View File

@ -0,0 +1,6 @@
"PluginFolder","AssemblyName","RuntimeTarget","ZipPath","DllPath","HasPdb","ExtractPath","ProjectPath"
"AntiDickheadChatmodule","AntiDickheadChatmodule",".NETCoreApp,Version=v10.0","H:\src\aRkker-XIV-Plugins\plugins\AntiDickheadChatmodule\latest.zip","H:\src\aRkker-XIV-Plugins\.recovery\extract\AntiDickheadChatmodule\AntiDickheadChatmodule.dll","False","H:\src\aRkker-XIV-Plugins\.recovery\extract\AntiDickheadChatmodule","H:\src\aRkker-XIV-Plugins\.recovery\decompiled\AntiDickheadChatmodule"
"CrystallineConflictWinsTracker","CrystallineConflictWinsTracker",".NETCoreApp,Version=v7.0","H:\src\aRkker-XIV-Plugins\plugins\CrystallineConflictWinsTracker\latest.zip","H:\src\aRkker-XIV-Plugins\.recovery\extract\CrystallineConflictWinsTracker\CrystallineConflictWinsTracker.dll","True","H:\src\aRkker-XIV-Plugins\.recovery\extract\CrystallineConflictWinsTracker","H:\src\aRkker-XIV-Plugins\.recovery\decompiled\CrystallineConflictWinsTracker"
"MultiboxMutexer","MultiboxMutexer",".NETCoreApp,Version=v7.0","H:\src\aRkker-XIV-Plugins\plugins\MultiboxMutexer\latest.zip","H:\src\aRkker-XIV-Plugins\.recovery\extract\MultiboxMutexer\MultiboxMutexer.dll","True","H:\src\aRkker-XIV-Plugins\.recovery\extract\MultiboxMutexer","H:\src\aRkker-XIV-Plugins\.recovery\decompiled\MultiboxMutexer"
"OmicronMountMusicFixer","OmicronMountMusicFixer",".NETCoreApp,Version=v10.0","H:\src\aRkker-XIV-Plugins\plugins\OmicronMountMusicFixer\latest.zip","H:\src\aRkker-XIV-Plugins\.recovery\extract\OmicronMountMusicFixer\OmicronMountMusicFixer.dll","False","H:\src\aRkker-XIV-Plugins\.recovery\extract\OmicronMountMusicFixer","H:\src\aRkker-XIV-Plugins\.recovery\decompiled\OmicronMountMusicFixer"
"WorldMapEnhancer","WorldMapEnhancer",".NETCoreApp,Version=v10.0","H:\src\aRkker-XIV-Plugins\plugins\WorldMapEnhancer\latest.zip","H:\src\aRkker-XIV-Plugins\.recovery\extract\WorldMapEnhancer\WorldMapEnhancer.dll","False","H:\src\aRkker-XIV-Plugins\.recovery\extract\WorldMapEnhancer","H:\src\aRkker-XIV-Plugins\.recovery\decompiled\WorldMapEnhancer"
1 PluginFolder AssemblyName RuntimeTarget ZipPath DllPath HasPdb ExtractPath ProjectPath
2 AntiDickheadChatmodule AntiDickheadChatmodule .NETCoreApp,Version=v10.0 H:\src\aRkker-XIV-Plugins\plugins\AntiDickheadChatmodule\latest.zip H:\src\aRkker-XIV-Plugins\.recovery\extract\AntiDickheadChatmodule\AntiDickheadChatmodule.dll False H:\src\aRkker-XIV-Plugins\.recovery\extract\AntiDickheadChatmodule H:\src\aRkker-XIV-Plugins\.recovery\decompiled\AntiDickheadChatmodule
3 CrystallineConflictWinsTracker CrystallineConflictWinsTracker .NETCoreApp,Version=v7.0 H:\src\aRkker-XIV-Plugins\plugins\CrystallineConflictWinsTracker\latest.zip H:\src\aRkker-XIV-Plugins\.recovery\extract\CrystallineConflictWinsTracker\CrystallineConflictWinsTracker.dll True H:\src\aRkker-XIV-Plugins\.recovery\extract\CrystallineConflictWinsTracker H:\src\aRkker-XIV-Plugins\.recovery\decompiled\CrystallineConflictWinsTracker
4 MultiboxMutexer MultiboxMutexer .NETCoreApp,Version=v7.0 H:\src\aRkker-XIV-Plugins\plugins\MultiboxMutexer\latest.zip H:\src\aRkker-XIV-Plugins\.recovery\extract\MultiboxMutexer\MultiboxMutexer.dll True H:\src\aRkker-XIV-Plugins\.recovery\extract\MultiboxMutexer H:\src\aRkker-XIV-Plugins\.recovery\decompiled\MultiboxMutexer
5 OmicronMountMusicFixer OmicronMountMusicFixer .NETCoreApp,Version=v10.0 H:\src\aRkker-XIV-Plugins\plugins\OmicronMountMusicFixer\latest.zip H:\src\aRkker-XIV-Plugins\.recovery\extract\OmicronMountMusicFixer\OmicronMountMusicFixer.dll False H:\src\aRkker-XIV-Plugins\.recovery\extract\OmicronMountMusicFixer H:\src\aRkker-XIV-Plugins\.recovery\decompiled\OmicronMountMusicFixer
6 WorldMapEnhancer WorldMapEnhancer .NETCoreApp,Version=v10.0 H:\src\aRkker-XIV-Plugins\plugins\WorldMapEnhancer\latest.zip H:\src\aRkker-XIV-Plugins\.recovery\extract\WorldMapEnhancer\WorldMapEnhancer.dll False H:\src\aRkker-XIV-Plugins\.recovery\extract\WorldMapEnhancer H:\src\aRkker-XIV-Plugins\.recovery\decompiled\WorldMapEnhancer

View File

@ -0,0 +1,4 @@
{
"version": 2,
"contentHash": "E8/f/CbiQ5PAbb69NyKd946yAc/Ru2cI5IUBdRVQesf+GY68/VF8QM/wCzFhsXCasTwWk+lmnc4n4h6sQw0UdA=="
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,195 @@
# ilspycmd .NET Tool
To install:
```
dotnet tool install --global ilspycmd
```
Help output (`ilspycmd --help`):
```
ilspycmd: 9.0.0.7847
ICSharpCode.Decompiler: 9.0.0.7847
dotnet tool for decompiling .NET assemblies and generating portable PDBs
Usage: ilspycmd [options] <Assembly file name(s)>
Arguments:
Assembly file name(s) The list of assemblies that is being decompiled. This argument is mandatory.
Options:
-v|--version Show version of ICSharpCode.Decompiler used.
-h|--help Show help information.
-o|--outputdir <directory> The output directory, if omitted decompiler output is written to standard out.
-p|--project Decompile assembly as compilable project. This requires the output directory
option.
-t|--type <type-name> The fully qualified name of the type to decompile.
-il|--ilcode Show IL code.
--il-sequence-points Show IL with sequence points. Implies -il.
-genpdb|--generate-pdb Generate PDB.
-usepdb|--use-varnames-from-pdb Use variable names from PDB.
-l|--list <entity-type(s)> Lists all entities of the specified type(s). Valid types: c(lass),
i(nterface), s(truct), d(elegate), e(num)
-lv|--languageversion <version> C# Language version: CSharp1, CSharp2, CSharp3, CSharp4, CSharp5, CSharp6,
CSharp7, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0, CSharp9_0, CSharp10_0,
Preview or Latest
Allowed values are: CSharp1, CSharp2, CSharp3, CSharp4, CSharp5, CSharp6,
CSharp7, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0, CSharp9_0, CSharp10_0,
CSharp11_0, Preview, CSharp12_0, Latest.
Default value is: Latest.
-r|--referencepath <path> Path to a directory containing dependencies of the assembly that is being
decompiled.
--no-dead-code Remove dead code.
--no-dead-stores Remove dead stores.
-d|--dump-package Dump package assemblies into a folder. This requires the output directory
option.
--nested-directories Use nested directories for namespaces.
--disable-updatecheck If using ilspycmd in a tight loop or fully automated scenario, you might want
to disable the automatic update check.
--generate-diagrammer Generates an interactive HTML diagrammer app from selected types in the target
assembly - to the --outputdir or in a 'diagrammer' folder next to to the
assembly by default.
--generate-diagrammer-include An optional regular expression matching Type.FullName used to whitelist types
to include in the generated diagrammer.
--generate-diagrammer-exclude An optional regular expression matching Type.FullName used to blacklist types
to exclude from the generated diagrammer.
--generate-diagrammer-report-excluded Outputs a report of types excluded from the generated diagrammer - whether by
default because compiler-generated, explicitly by
'--generate-diagrammer-exclude' or implicitly by
'--generate-diagrammer-include'. You may find this useful to develop and debug
your regular expressions.
--generate-diagrammer-docs The path or file:// URI of the XML file containing the target assembly's
documentation comments. You only need to set this if a) you want your diagrams
annotated with them and b) the file name differs from that of the assmbly. To
enable XML documentation output for your assmbly, see
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/#create-xml-documentation-output
--generate-diagrammer-strip-namespaces Optional space-separated namespace names that are removed for brevity from XML
documentation comments. Note that the order matters: e.g. replace
'System.Collections' before 'System' to remove both of them completely.
Remarks:
-o is valid with every option and required when using -p.
Examples:
Decompile assembly to console out.
ilspycmd sample.dll
Decompile assembly to destination directory (single C# file).
ilspycmd -o c:\decompiled sample.dll
Decompile assembly to destination directory, create a project file, one source file per type.
ilspycmd -p -o c:\decompiled sample.dll
Decompile assembly to destination directory, create a project file, one source file per type,
into nicely nested directories.
ilspycmd --nested-directories -p -o c:\decompiled sample.dll
Generate a HTML diagrammer containing all type info into a folder next to the input assembly
ilspycmd sample.dll --generate-diagrammer
Generate a HTML diagrammer containing filtered type info into a custom output folder
(including types in the LightJson namespace while excluding types in nested LightJson.Serialization namespace)
ilspycmd sample.dll --generate-diagrammer -o c:\diagrammer --generate-diagrammer-include LightJson\\..+ --generate-diagrammer-exclude LightJson\\.Serialization\\..+
```
## Generate HTML diagrammers
Once you have an output folder in mind, you can adopt either of the following strategies
to generate a HTML diagrammer from a .Net assembly using the console app.
### Manually before use
**Create the output folder** in your location of choice and inside it **a new shell script**.
Using the CMD shell in a Windows environment for example, you'd create a `regenerate.cmd` looking somewhat like this:
<pre>
..\..\path\to\ilspycmd.exe ..\path\to\your\assembly.dll --generate-diagrammer --outputdir .
</pre>
With this script in place, run it to (re-)generate the HTML diagrammer at your leisure. Note that `--outputdir .` directs the output to the current directory.
### Automatically
If you want to deploy an up-to-date HTML diagrammer as part of your live documentation,
you'll want to automate its regeneration to keep it in sync with your code base.
For example, you might like to share the diagrammer on a web server or - in general - with users
who cannot or may not regenerate it; lacking either access to the ilspycmd console app or permission to use it.
In such cases, you can dangle the regeneration off the end of either your build or deployment pipeline.
Note that the macros used here apply to [MSBuild](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild) for [Visual Studio](https://learn.microsoft.com/en-us/visualstudio/ide/reference/pre-build-event-post-build-event-command-line-dialog-box) and your mileage may vary with VS for Mac or VS Code.
#### After building
To regenerate the HTML diagrammer from your output assembly after building,
add something like the following to your project file.
Note that the `Condition` here is optional and configures this step to only run after `Release` builds.
```xml
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
<Exec Command="$(SolutionDir)..\path\to\ilspycmd.exe $(TargetPath) --generate-diagrammer --outputdir $(ProjectDir)diagrammer" />
</Target>
```
#### After publishing
If you'd rather regenerate the diagram after publishing instead of building, all you have to do is change the `AfterTargets` to `Publish`.
Note that the `Target` `Name` doesn't matter here and that the diagrammer is generated into a folder in the `PublishDir` instead of the `ProjectDir`.
```xml
<Target Name="GenerateHtmlDiagrammer" AfterTargets="Publish">
<Exec Command="$(SolutionDir)..\path\to\ilspycmd.exe $(TargetPath) --generate-diagrammer --outputdir $(PublishDir)diagrammer" />
</Target>
```
### Usage tips
**Compiler-generated** types and their nested types are **excluded by default**.
Consider sussing out **big source assemblies** using [ILSpy](https://github.com/icsharpcode/ILSpy) first to get an idea about which subdomains to include in your diagrammers. Otherwise you may experience long build times and large file sizes for the diagrammer as well as a looong type selection opening it. At some point, mermaid may refuse to render all types in your selection because their definitions exceed the maximum input size. If that's where you find yourself, you may want to consider
- using `--generate-diagrammer-include` and `--generate-diagrammer-exclude` to **limit the scope of the individual diagrammer to a certain subdomain**
- generating **multiple diagrammers for different subdomains**.
### Advanced configuration examples
Above examples show how the most important options are used. Let's have a quick look at the remaining ones, which allow for customization in your project setup and diagrams.
#### Filter extracted types
Sometimes the source assembly contains way more types than are sensible to diagram. Types with metadata for validation or mapping for example. Or auto-generated types.
Especially if you want to tailor a diagrammer for a certain target audience and hide away most of the supporting type system to avoid noise and unnecessary questions.
In these scenarios you can supply Regular Expressions for types to `--generate-diagrammer-include` (white-list) and `--generate-diagrammer-exclude` (black-list).
A third option `--generate-diagrammer-report-excluded` will output a `.txt` containing the list of effectively excluded types next to the HTML diagrammer containing the effectively included types.
<pre>
ilspycmd.exe <b>--generate-diagrammer-include Your\.Models\..+ --generate-diagrammer-exclude .+\+Metadata|.+\.Data\..+Map --generate-diagrammer-report-excluded</b> ..\path\to\your\assembly.dll --generate-diagrammer --outputdir .
</pre>
This example
- includes all types in the top-level namespace `Your.Models`
- while excluding
- nested types called `Metadata` and
- types ending in `Map` in descendant `.Data.` namespaces.
#### Strip namespaces from XML comments
You can reduce the noise in the XML documentation comments on classes on your diagrams by supplying a space-separated list of namespaces to omit from the output like so:
<pre>
ilspycmd.exe <b>--generate-diagrammer-strip-namespaces System.Collections.Generic System</b> ..\path\to\your\assembly.dll --generate-diagrammer --output-folder .
</pre>
Note how `System` is replaced **after** other namespaces starting with `System.` to achieve complete removal.
Otherwise `System.Collections.Generic` wouldn't match the `Collections.Generic` left over after removing `System.`, resulting in partial removal only.
#### Adjust for custom XML documentation file names
If - for whatever reason - you have customized your XML documentation file output name, you can specify a custom path to pick it up from.
<pre>
ilspycmd.exe <b>--generate-diagrammer-docs ..\path\to\your\docs.xml</b> ..\path\to\your\assembly.dll --generate-diagrammer --output-folder .
</pre>

View File

@ -0,0 +1 @@
oTQvPJnDlVh4dqXAAiWPft700WXXkXoePmRPNN9fMqcbEqrfwEhmq6gz1yFWpAjbVgHAbSsRmxJXO8f9cuQ6ag==

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>ilspycmd</id>
<version>10.0.1.8346</version>
<authors>ILSpy Team</authors>
<license type="expression">MIT</license>
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
<icon>ILSpyCmdNuGetPackageIcon.png</icon>
<readme>README.md</readme>
<projectUrl>https://github.com/icsharpcode/ILSpy/</projectUrl>
<description>Command-line decompiler using the ILSpy decompilation engine</description>
<copyright>Copyright 2011-2026 AlphaSierraPapa</copyright>
<packageTypes>
<packageType name="DotnetTool" />
</packageTypes>
<repository type="git" url="https://github.com/icsharpcode/ILSpy/" commit="aad16c66e96eb887eb05887d6b5a9e0522637906" />
</metadata>
</package>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<DotNetCliTool Version="1">
<Commands>
<Command Name="ilspycmd" EntryPoint="ilspycmd.dll" Runner="dotnet" />
</Commands>
</DotNetCliTool>

Some files were not shown because too many files have changed in this diff Show More