diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj index c1313a741..0ac4cccf8 100644 --- a/Dalamud.Injector/Dalamud.Injector.csproj +++ b/Dalamud.Injector/Dalamud.Injector.csproj @@ -14,16 +14,16 @@ true - 4.1.0.8 - 4.1.0.8 + 4.3.1.0 + 4.3.1.0 XIVLauncher addon injection - 4.1.0.8 + 4.3.1.0 - + diff --git a/Dalamud/Configuration/CustomComboPreset.cs b/Dalamud/Configuration/CustomComboPreset.cs index bee8895c9..5f92d857d 100644 --- a/Dalamud/Configuration/CustomComboPreset.cs +++ b/Dalamud/Configuration/CustomComboPreset.cs @@ -7,13 +7,19 @@ using System.Threading.Tasks; namespace XIVLauncher.Dalamud { - //CURRENT HIGHEST FLAG IS 44 + //CURRENT HIGHEST FLAG IS 46 [Flags] public enum CustomComboPreset : long { None = 0, // DRAGOON + [CustomComboInfo("Jump + Mirage Dive", "Replace Jump with Mirage Dive when Dive Ready", 22)] + DragoonJumpFeature = 1L << 44, + + [CustomComboInfo("BOTD Into Stardiver", "Replace Blood of the Dragon with Stardiver when in Life of the Dragon", 22)] + DragoonBOTDFeature = 1L << 46, + [CustomComboInfo("Coerthan Torment Combo", "Replace Coerthan Torment with its combo chain", 22)] DragoonCoerthanTormentCombo = 1L << 0, @@ -77,19 +83,22 @@ namespace XIVLauncher.Dalamud [CustomComboInfo("Hakke Mujinsatsu Combo", "Replace Hakke Mujinsatsu with its combo chain", 30)] NinjaHakkeMujinsatsuCombo = 1L << 19, + [CustomComboInfo("Dream to Assassinate", "Replace Dream Within a Dream with Assassinate when Assassinate Ready", 30)] + NinjaAssassinateFeature = 1L << 45, + // GUNBREAKER [CustomComboInfo("Solid Barrel Combo", "Replace Solid Barrel with its combo chain", 37)] GunbreakerSolidBarrelCombo = 1L << 20, - [CustomComboInfo("Gnashing Fang Combo", "Replace Gnashing Fang with its combo chain", 37)] + [CustomComboInfo("Gnashing Fang Combo", "Replace Wicked Talon with its combo chain", 37)] GunbreakerGnashingFangCombo = 1L << 21, [CustomComboInfo("Demon Slaughter Combo", "Replace Demon Slaughter with its combo chain", 37)] GunbreakerDemonSlaughterCombo = 1L << 22, // MACHINIST - [CustomComboInfo("Heated Clan Shot Combo/Heat", "Replace Heated Clan Shot with its combo chain or with Heat Blast when overheated.", 31)] - MachinistHeatedClanShotFeature = 1L << 23, + [CustomComboInfo("(Heated) Shot Combo", "Replace UNHEATED Split Shot with its combo chain or with Heat Blast when overheated.", 31)] + MachinistMainCombo = 1L << 23, [CustomComboInfo("Spread Shot Heat", "Replace Spread Shot with Auto Crossbow when overheated.", 31)] MachinistSpreadShotFeature = 1L << 24, @@ -112,10 +121,10 @@ namespace XIVLauncher.Dalamud [CustomComboInfo("Brand of Purgatory Combo", "Replaces Fountain of Fire with Brand of Purgatory when under the affect of Hellish Conduit.", 27)] SummonerBoPCombo = 1L << 38, - [CustomComboInfo("ED Fester", "Change Energy Drain into Fester while you have Aetherflow stacks.", 27)] + [CustomComboInfo("ED Fester", "Change Fester into Energy Drain when out of Aetherflow stacks.", 27)] SummonerEDFesterCombo = 1L << 39, - [CustomComboInfo("ES Painflare", "Change Energy Siphon into Painflare while you have Aetherflow stacks.", 27)] + [CustomComboInfo("ES Painflare", "Change Painflare into Energy Syphon when out of Aetherflow stacks.", 27)] SummonerESPainflareCombo = 1L << 40, [CustomComboInfo("DWT", "DWT.", 27)] diff --git a/Dalamud/Configuration/DalamudConfiguration.cs b/Dalamud/Configuration/DalamudConfiguration.cs index 6bbce4d8a..ceb3fd84e 100644 --- a/Dalamud/Configuration/DalamudConfiguration.cs +++ b/Dalamud/Configuration/DalamudConfiguration.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using Dalamud.Configuration; using Dalamud.DiscordBot; using Newtonsoft.Json; using XIVLauncher.Dalamud; @@ -31,6 +32,8 @@ namespace Dalamud public string LastVersion { get; set; } + public Dictionary PluginConfigurations { get; set; } + public static DalamudConfiguration Load(string path) { return JsonConvert.DeserializeObject(File.ReadAllText(path)); } diff --git a/Dalamud/Configuration/IPluginConfiguration.cs b/Dalamud/Configuration/IPluginConfiguration.cs new file mode 100644 index 000000000..f2a782960 --- /dev/null +++ b/Dalamud/Configuration/IPluginConfiguration.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Dalamud.Configuration +{ + public interface IPluginConfiguration + { + int Version { get; set; } + } +} diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 64f25c9e1..17cbbba04 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -183,7 +183,7 @@ namespace Dalamud { CommandManager.AddHandler("/xlitem", new CommandInfo(OnItemLinkCommand) { - HelpMessage = "Link an item by name. Usage: /xlitem " + HelpMessage = "Link an item by name. Usage: /xlitem . For matching an item exactly, use /xlitem +" }); #if DEBUG @@ -196,7 +196,7 @@ namespace Dalamud { CommandManager.AddHandler("/xlbonus", new CommandInfo(OnRouletteBonusNotifyCommand) { - HelpMessage = "Notify when a roulette has a bonus you specified. Usage: /xlitem " + HelpMessage = "Notify when a roulette has a bonus you specified. Run without parameters for more info. Usage: /xlbonus " }); } @@ -396,9 +396,16 @@ namespace Dalamud { } private void OnItemLinkCommand(string command, string arguments) { + var exactSearch = false; + if (arguments.StartsWith("+")) + { + exactSearch = true; + arguments = arguments.Substring(1); + } + Task.Run(async () => { try { - dynamic results = await XivApi.Search(arguments, "Item", 1); + dynamic results = await XivApi.Search(arguments, "Item", 1, exactSearch); var itemId = (short) results.Results[0].ID; var itemName = (string)results.Results[0].Name; @@ -473,7 +480,7 @@ namespace Dalamud { InvalidArgs: Framework.Gui.Chat.PrintError("Unrecognized arguments."); Framework.Gui.Chat.Print("Possible values for roulette: leveling, 506070, msq, guildhests, expert, trials, mentor, alliance, normal\n" + - "Possible values for role: tank, dps, healer, all"); + "Possible values for role: tank, dps, healer, all, none/reset"); } private int RouletteSlugToKey(string slug) => slug.ToLower() switch { diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 537b7db8d..f447ac7ac 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -14,9 +14,9 @@ true - 4.3.0.0 - 4.3.0.0 - 4.3.0.0 + 4.3.1.0 + 4.3.1.0 + 4.3.1.0 diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs index 04838b2c9..08f858d0c 100644 --- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs +++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs @@ -13,9 +13,9 @@ namespace Dalamud.Game.ClientState public IntPtr JobGaugeData { get; set; } protected override void Setup64Bit(SigScanner sig) { - ActorTable = sig.Module.BaseAddress + 0x1BFBA38; + ActorTable = sig.Module.BaseAddress + 0x1BFFD90; LocalContentId = sig.Module.BaseAddress + 0x1C2E000; - JobGaugeData = sig.Module.BaseAddress + 0x1C00110; + JobGaugeData = sig.Module.BaseAddress + 0x1BFB110; } } } diff --git a/Dalamud/Game/Internal/Gui/IconReplacer.cs b/Dalamud/Game/Internal/Gui/IconReplacer.cs index 16c89702e..a84928dc2 100644 --- a/Dalamud/Game/Internal/Gui/IconReplacer.cs +++ b/Dalamud/Game/Internal/Gui/IconReplacer.cs @@ -36,11 +36,11 @@ namespace Dalamud.Game.Internal.Gui { this.Address.Setup(scanner); this.byteBase = scanner.Module.BaseAddress; - this.comboTimer = byteBase + 0x1BB8B50; + this.comboTimer = byteBase + 0x1BB3B50; //this.comboTimer = scanner.ScanText("E8 ?? ?? ?? ?? 80 7E 21 00") + 0x178; this.lastComboMove = this.comboTimer + 0x4; - this.playerLevel = byteBase + 0x1C30FA8 + 0x78; + this.playerLevel = byteBase + 0x1C2BFA8 + 0x78; //this.playerLevel = scanner.ScanText("E8 ?? ?? ?? ?? 88 45 EF") + 0x4D; CustomIDs = new HashSet(); @@ -107,7 +107,29 @@ namespace Dalamud.Game.Internal.Gui { var level = Marshal.ReadByte(this.playerLevel); // DRAGOON - // TODO: Jump/High Jump into Mirage Dive + + // Change Jump/High Jump into Mirage Dive when Dive Ready + if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DragoonJumpFeature)) { + if (actionID == 92) { + if (SearchBuffArray(1243)) { + return 7399; + } + if (level >= 74) return 16478; + return 92; + } + } + + // Change Blood of the Dragon into Stardiver when in Life of the Dragon + if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DragoonBOTDFeature)) { + if (actionID == 3553) { + if (level >= 80) { + if (this.dalamud.ClientState.JobGauges.Get().BOTDState == BOTDState.LOTD) { + return 16480; + } + } + return 3553; + } + } // Replace Coerthan Torment with Coerthan Torment combo chain if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DragoonCoerthanTormentCombo)) { @@ -345,6 +367,14 @@ namespace Dalamud.Game.Internal.Gui { } } + //Replace Dream Within a Dream with Assassinate when Assassinate Ready + if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.NinjaAssassinateFeature)) { + if(actionID == 3566) { + if (SearchBuffArray(1955)) return 2246; + return 3566; + } + } + // GUNBREAKER // Replace Solid Barrel with Solid Barrel combo @@ -358,10 +388,10 @@ namespace Dalamud.Game.Internal.Gui { } } - // Replace Gnashing Fang with Gnashing Fang combo + // Replace Wicked Talon with Gnashing Fang combo // TODO: Potentially add Contuation moves as well? if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.GunbreakerGnashingFangCombo)) { - if (actionID == 16146) { + if (actionID == 16150) { byte ammoComboState = this.dalamud.ClientState.JobGauges.Get().AmmoComboStepNumber; if (ammoComboState == 1) return 16147; if (ammoComboState == 2) return 16150; @@ -381,11 +411,11 @@ namespace Dalamud.Game.Internal.Gui { // MACHINIST - // Replace Heated Clean Shot with Heated Clean Shot combo + // Replace Clean Shot with Heated Clean Shot combo // Or with Heat Blast when overheated. // For some reason the shots use their unheated IDs as combo moves - if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MachinistHeatedClanShotFeature)) { - if (actionID == 7413) { + if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MachinistMainCombo)) { + if (actionID == 2873) { MCHGauge gauge = this.dalamud.ClientState.JobGauges.Get(); // End overheat slightly early to prevent eager button mashing clipping your gcd with a fake 6th HB. if (gauge.IsOverheated() && level >= 35 && gauge.OverheatTimeRemaining > 30) return 7410; @@ -399,7 +429,8 @@ namespace Dalamud.Game.Internal.Gui { if (level >= 26) return 2873; } } - return 7411; + if (level >= 54) return 7411; + return 2866; } } @@ -482,7 +513,10 @@ namespace Dalamud.Game.Internal.Gui { } else { if (gauge.IsBahamutReady()) return 7427; - if (gauge.IsPhoenixReady()) return 16513; + if (gauge.IsPhoenixReady()) { + if (level == 80) return 16549; + return 16513; + } return 3581; } } @@ -524,20 +558,21 @@ namespace Dalamud.Game.Internal.Gui { } } - // Change Energy Drain into Fester + // Change Fester into Energy Drain if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerEDFesterCombo)) { - if (actionID == 16508) { - if (this.dalamud.ClientState.JobGauges.Get().HasAetherflowStacks()) - return 181; - return 16508; + if (actionID == 181) { + if (!this.dalamud.ClientState.JobGauges.Get().HasAetherflowStacks()) + return 16508; + return 181; } } - //Change Energy Siphon into Painflare + //Change Painflare into Energy Syphon if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerESPainflareCombo)) { - if (actionID == 16510) { - if (this.dalamud.ClientState.JobGauges.Get().HasAetherflowStacks()) - if (level >= 52) return 3578; + if (actionID == 3578) { + if (!this.dalamud.ClientState.JobGauges.Get().HasAetherflowStacks()) + return 16510; + if (level >= 52) return 3578; return 16510; } } @@ -849,7 +884,7 @@ namespace Dalamud.Game.Internal.Gui { private unsafe delegate int* getArray(long* address); private unsafe IntPtr FindBuffAddress() { - IntPtr randomAddress = byteBase + 0x1C07BE0; + IntPtr randomAddress = byteBase + 0x1C02BE0; IntPtr num = Marshal.ReadIntPtr(randomAddress); IntPtr step2 = (IntPtr)(Marshal.ReadInt64(num) + 0x248); IntPtr step3 = Marshal.ReadIntPtr(step2); @@ -879,7 +914,7 @@ namespace Dalamud.Game.Internal.Gui { CustomIDs.Add(2255); CustomIDs.Add(16488); CustomIDs.Add(16145); - CustomIDs.Add(16146); + CustomIDs.Add(16150); CustomIDs.Add(16149); CustomIDs.Add(7413); CustomIDs.Add(2870); @@ -889,8 +924,8 @@ namespace Dalamud.Game.Internal.Gui { CustomIDs.Add(3582); CustomIDs.Add(3581); CustomIDs.Add(163); - CustomIDs.Add(16508); - CustomIDs.Add(16510); + CustomIDs.Add(181); + CustomIDs.Add(3578); CustomIDs.Add(16543); CustomIDs.Add(167); CustomIDs.Add(15994); @@ -904,6 +939,10 @@ namespace Dalamud.Game.Internal.Gui { CustomIDs.Add(16525); CustomIDs.Add(16524); CustomIDs.Add(7516); + CustomIDs.Add(3566); + CustomIDs.Add(92); + CustomIDs.Add(3553); + CustomIDs.Add(2873); VanillaIDs.Add(0x3e75); VanillaIDs.Add(0x3e76); VanillaIDs.Add(0x3e77); @@ -1064,7 +1103,6 @@ namespace Dalamud.Game.Internal.Gui { VanillaIDs.Add(0xb32); VanillaIDs.Add(0xb34); VanillaIDs.Add(0xb38); - VanillaIDs.Add(0xb39); VanillaIDs.Add(0xb3e); VanillaIDs.Add(0x12d); VanillaIDs.Add(0x15); @@ -1072,7 +1110,6 @@ namespace Dalamud.Game.Internal.Gui { VanillaIDs.Add(0x31); VanillaIDs.Add(0x33); VanillaIDs.Add(0x4b); - VanillaIDs.Add(0x5c); VanillaIDs.Add(0x62); VanillaIDs.Add(0x64); VanillaIDs.Add(0x71); diff --git a/Dalamud/Game/Network/NetworkHandlers.cs b/Dalamud/Game/Network/NetworkHandlers.cs index cf71e43c4..4613e03de 100644 --- a/Dalamud/Game/Network/NetworkHandlers.cs +++ b/Dalamud/Game/Network/NetworkHandlers.cs @@ -221,12 +221,12 @@ namespace Dalamud.Game.Network { } private enum ZoneOpCode { - CfNotifyPop = 0x135, - CfPreferredRole = 0x2a2, - MarketTaxRates = 0x16a, - MarketBoardItemRequestStart = 0x349, - MarketBoardOfferings = 0x130, - MarketBoardHistory = 0x1f7 + CfNotifyPop = 0x1F8, + CfPreferredRole = 0x32A, + MarketTaxRates = 0x25E, + MarketBoardItemRequestStart = 0x328, + MarketBoardOfferings = 0x15F, + MarketBoardHistory = 0x113 } private DalamudConfiguration.PreferredRole RoleKeyToPreferredRole(int key) => key switch diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index 8c2cb38eb..38be7d39c 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using Dalamud.Configuration; using Dalamud.Game.ClientState; using Dalamud.Game.Command; using Dalamud.Game.Internal; @@ -29,14 +32,51 @@ namespace Dalamud.Plugin /// public readonly Framework Framework; + private readonly Dalamud dalamud; + private readonly string pluginName; + /// /// Set up the interface and populate all fields needed. /// /// - public DalamudPluginInterface(Dalamud dalamud) { + public DalamudPluginInterface(Dalamud dalamud, string pluginName) { this.CommandManager = dalamud.CommandManager; this.Framework = dalamud.Framework; this.ClientState = dalamud.ClientState; + + this.dalamud = dalamud; + this.pluginName = pluginName; + } + + /// + /// Save a plugin configuration(inheriting IPluginConfiguration). + /// + /// The current configuration. + public void SavePluginConfig(IPluginConfiguration currentConfig) { + if (this.dalamud.Configuration.PluginConfigurations == null) + this.dalamud.Configuration.PluginConfigurations = new Dictionary(); + + if (this.dalamud.Configuration.PluginConfigurations.ContainsKey(this.pluginName)) { + this.dalamud.Configuration.PluginConfigurations[this.pluginName] = currentConfig; + return; + } + + this.dalamud.Configuration.PluginConfigurations.Add(this.pluginName, currentConfig); + this.dalamud.Configuration.Save(this.dalamud.StartInfo.ConfigurationPath); + } + + /// + /// Get a previously saved plugin configuration or null if none was saved before. + /// + /// A previously saved config or null if none was saved before. + public IPluginConfiguration GetPluginConfig() { + if (this.dalamud.Configuration.PluginConfigurations == null) + this.dalamud.Configuration.PluginConfigurations = new Dictionary(); + + if (!this.dalamud.Configuration.PluginConfigurations.ContainsKey(this.pluginName)) + return null; + + return this.dalamud.Configuration.PluginConfigurations[this.pluginName]; } } } diff --git a/Dalamud/Plugin/PluginManager.cs b/Dalamud/Plugin/PluginManager.cs index 370bbae54..204931dfe 100644 --- a/Dalamud/Plugin/PluginManager.cs +++ b/Dalamud/Plugin/PluginManager.cs @@ -14,16 +14,12 @@ namespace Dalamud.Plugin private readonly string pluginDirectory; private readonly string defaultPluginDirectory; - private readonly DalamudPluginInterface dalamudInterface; - private List plugins; public PluginManager(Dalamud dalamud, string pluginDirectory, string defaultPluginDirectory) { this.dalamud = dalamud; this.pluginDirectory = pluginDirectory; this.defaultPluginDirectory = defaultPluginDirectory; - - this.dalamudInterface = new DalamudPluginInterface(dalamud); } public void UnloadPlugins() { @@ -79,7 +75,10 @@ namespace Dalamud.Plugin foreach (var pluginType in foundImplementations) { var plugin = (IDalamudPlugin)Activator.CreateInstance(pluginType); - plugin.Initialize(this.dalamudInterface); + + var dalamudInterface = new DalamudPluginInterface(this.dalamud, pluginType.Assembly.GetName().Name); + + plugin.Initialize(dalamudInterface); Log.Information("Loaded plugin: {0}", plugin.Name); this.plugins.Add(plugin); } diff --git a/Dalamud/XivApi.cs b/Dalamud/XivApi.cs index dc5e5fa8b..9d2374281 100644 --- a/Dalamud/XivApi.cs +++ b/Dalamud/XivApi.cs @@ -49,10 +49,16 @@ namespace Dalamud return await Get("ContentFinderCondition/" + contentFinderCondition); } - public static async Task Search(string query, string indexes, int limit = 100) { + public static async Task Search(string query, string indexes, int limit = 100, bool exact = false) { query = System.Net.WebUtility.UrlEncode(query); - return await Get("search" + $"?string={query}&indexes={indexes}&limit={limit}"); + var queryString = $"?string={query}&indexes={indexes}&limit={limit}"; + if (exact) + { + queryString += "&string_algo=match"; + } + + return await Get("search" + queryString); } public static async Task GetMarketInfoWorld(int itemId, string worldName) {