master v5.0
Liza 2024-03-21 21:59:58 +01:00
parent 1ee347f0ba
commit 3c986562b2
Signed by: liza
GPG Key ID: 7199F8D727D55F67
14 changed files with 1140 additions and 97 deletions

1017
ARDiscard/.editorconfig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<Version>4.7</Version> <Version>5.0</Version>
<LangVersion>11.0</LangVersion> <LangVersion>12</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@ -30,7 +30,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dalamud.ContextMenu" Version="1.3.1"/>
<PackageReference Include="DalamudPackager" Version="2.1.12"/> <PackageReference Include="DalamudPackager" Version="2.1.12"/>
</ItemGroup> </ItemGroup>

View File

@ -20,7 +20,7 @@ using LLib;
namespace ARDiscard; namespace ARDiscard;
[SuppressMessage("ReSharper", "UnusedType.Global")] [SuppressMessage("ReSharper", "UnusedType.Global")]
public class AutoDiscardPlogon : IDalamudPlugin public sealed class AutoDiscardPlogon : IDalamudPlugin
{ {
private readonly WindowSystem _windowSystem = new(nameof(AutoDiscardPlogon)); private readonly WindowSystem _windowSystem = new(nameof(AutoDiscardPlogon));
private readonly Configuration _configuration; private readonly Configuration _configuration;
@ -36,7 +36,10 @@ public class AutoDiscardPlogon : IDalamudPlugin
private readonly InventoryUtils _inventoryUtils; private readonly InventoryUtils _inventoryUtils;
private readonly IconCache _iconCache; private readonly IconCache _iconCache;
private readonly AutoRetainerApi _autoRetainerApi; private readonly AutoRetainerApi _autoRetainerApi;
[SuppressMessage("Usage", "CA2213:Disposable fields should be disposed", Justification = "Obsolete in ECommons")]
private readonly TaskManager _taskManager; private readonly TaskManager _taskManager;
private readonly ContextMenuIntegration _contextMenuIntegration; private readonly ContextMenuIntegration _contextMenuIntegration;
private readonly AutoDiscardIpc _autoDiscardIpc; private readonly AutoDiscardIpc _autoDiscardIpc;
@ -44,8 +47,9 @@ public class AutoDiscardPlogon : IDalamudPlugin
public AutoDiscardPlogon(DalamudPluginInterface pluginInterface, ICommandManager commandManager, IChatGui chatGui, public AutoDiscardPlogon(DalamudPluginInterface pluginInterface, ICommandManager commandManager, IChatGui chatGui,
IDataManager dataManager, IClientState clientState, ICondition condition, IPluginLog pluginLog, IDataManager dataManager, IClientState clientState, ICondition condition, IPluginLog pluginLog,
IGameGui gameGui, ITextureProvider textureProvider) IGameGui gameGui, ITextureProvider textureProvider, IContextMenu contextMenu)
{ {
ArgumentNullException.ThrowIfNull(dataManager);
ItemCache itemCache = new ItemCache(dataManager); ItemCache itemCache = new ItemCache(dataManager);
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
@ -89,7 +93,7 @@ public class AutoDiscardPlogon : IDalamudPlugin
ECommonsMain.Init(_pluginInterface, this); ECommonsMain.Init(_pluginInterface, this);
_autoRetainerApi = new(); _autoRetainerApi = new();
_taskManager = new(); _taskManager = new();
_contextMenuIntegration = new(_pluginInterface, _chatGui, itemCache, _configuration, _configWindow, _gameGui); _contextMenuIntegration = new(_chatGui, itemCache, _configuration, _configWindow, _gameGui, contextMenu);
_autoDiscardIpc = new(_pluginInterface, _configuration); _autoDiscardIpc = new(_pluginInterface, _configuration);
_clientState.Login += _discardWindow.Login; _clientState.Login += _discardWindow.Login;
@ -315,7 +319,7 @@ public class AutoDiscardPlogon : IDalamudPlugin
var textNode = addon->UldManager.NodeList[15]->GetAsAtkTextNode(); var textNode = addon->UldManager.NodeList[15]->GetAsAtkTextNode();
var text = MemoryHelper.ReadSeString(&textNode->NodeText).ExtractText(); var text = MemoryHelper.ReadSeString(&textNode->NodeText).ExtractText();
_pluginLog.Information($"YesNo prompt: {text}"); _pluginLog.Information($"YesNo prompt: {text}");
if (text.StartsWith("Discard")) if (text.StartsWith("Discard", StringComparison.Ordinal))
{ {
return addon; return addon;
} }

View File

@ -26,17 +26,17 @@ internal sealed class Configuration : IPluginConfiguration
public sealed class ArmouryConfiguration public sealed class ArmouryConfiguration
{ {
public bool DiscardFromArmouryChest { get; set; } = false; public bool DiscardFromArmouryChest { get; set; }
public bool CheckMainHandOffHand { get; set; } = false; public bool CheckMainHandOffHand { get; set; }
public bool CheckLeftSideGear { get; set; } = false; public bool CheckLeftSideGear { get; set; }
public bool CheckRightSideGear { get; set; } = false; public bool CheckRightSideGear { get; set; }
public int MaximumGearItemLevel { get; set; } = 45; public int MaximumGearItemLevel { get; set; } = 45;
} }
public sealed class ContextMenuConfiguration public sealed class ContextMenuConfiguration
{ {
public bool Enabled { get; set; } = true; public bool Enabled { get; set; } = true;
public bool OnlyWhenConfigIsOpen { get; set; } = false; public bool OnlyWhenConfigIsOpen { get; set; }
} }
public sealed class PreviewConfiguration public sealed class PreviewConfiguration

View File

@ -1,10 +1,10 @@
using System; using System;
using ARDiscard.GameData; using ARDiscard.GameData;
using ARDiscard.Windows; using ARDiscard.Windows;
using Dalamud.ContextMenu; using Dalamud.Game.Gui.ContextMenu;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
namespace ARDiscard; namespace ARDiscard;
@ -16,76 +16,96 @@ internal sealed class ContextMenuIntegration : IDisposable
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly ConfigWindow _configWindow; private readonly ConfigWindow _configWindow;
private readonly IGameGui _gameGui; private readonly IGameGui _gameGui;
private readonly SeString _addItemPayload; private readonly IContextMenu _contextMenu;
private readonly SeString _removeItemPayload; private readonly MenuItem _addInventoryItem;
private readonly InventoryContextMenuItem _addInventoryItem; private readonly MenuItem _removeInventoryItem;
private readonly InventoryContextMenuItem _removeInventoryItem;
private readonly DalamudContextMenu _dalamudContextMenu;
public ContextMenuIntegration(DalamudPluginInterface pluginInterface, IChatGui chatGui, ItemCache itemCache, public ContextMenuIntegration(IChatGui chatGui, ItemCache itemCache, Configuration configuration,
Configuration configuration, ConfigWindow configWindow, IGameGui gameGui) ConfigWindow configWindow, IGameGui gameGui, IContextMenu contextMenu)
{ {
_chatGui = chatGui; _chatGui = chatGui;
_itemCache = itemCache; _itemCache = itemCache;
_configuration = configuration; _configuration = configuration;
_configWindow = configWindow; _configWindow = configWindow;
_gameGui = gameGui; _gameGui = gameGui;
_addItemPayload = _contextMenu = contextMenu;
new SeString(new UIForegroundPayload(52)) _addInventoryItem = new MenuItem
.Append($"\ue05f ") {
.Append(new UIForegroundPayload(0)).Append("Add to Auto Discard List"); Prefix = (SeIconChar)57439,
_removeItemPayload = new SeString(new UIForegroundPayload(52)) PrefixColor = 52,
.Append($"\ue05f ") Name = "Add to Auto Discard List",
.Append(new UIForegroundPayload(0)).Append("Remove from Auto Discard List"); OnClicked = AddToDiscardList,
_addInventoryItem = new InventoryContextMenuItem(_addItemPayload, AddToDiscardList); };
_removeInventoryItem = new InventoryContextMenuItem(_removeItemPayload, RemoveFromDiscardList); _removeInventoryItem = new MenuItem
{
Prefix = (SeIconChar)57439,
PrefixColor = 52,
Name = "Remove from Auto Discard List",
OnClicked = RemoveFromDiscardList,
};
_dalamudContextMenu = new(pluginInterface); _contextMenu.OnMenuOpened += MenuOpened;
_dalamudContextMenu.OnOpenInventoryContextMenu += OpenInventoryContextMenu;
_dalamudContextMenu.OnOpenGameObjectContextMenu += OpenGameObjectContextMenu;
} }
private void OpenInventoryContextMenu(InventoryContextMenuOpenArgs args) private void MenuOpened(MenuOpenedArgs args)
{ {
if (!IsEnabled()) if (!IsEnabled())
return; return;
if (args.ParentAddonName is not ("Inventory" or "InventoryExpansion" or "InventoryLarge" or "ArmouryBoard")) if (args.Target is MenuTargetInventory targetInventory)
return; {
if (args.AddonName is not ("Inventory" or "InventoryExpansion" or "InventoryLarge" or "ArmouryBoard") ||
targetInventory.TargetItem == null)
return;
if (!_configWindow.CanItemBeConfigured(args.ItemId)) var item = targetInventory.TargetItem.Value;
return; if (!_configWindow.CanItemBeConfigured(item.ItemId))
return;
if (_configuration.DiscardingItems.Contains(args.ItemId)) if (_configuration.DiscardingItems.Contains(item.ItemId))
args.AddCustomItem(_removeInventoryItem); args.AddMenuItem(_removeInventoryItem);
else if (_itemCache.TryGetItem(args.ItemId, out ItemCache.CachedItemInfo? cachedItemInfo) && else if (_itemCache.TryGetItem(item.ItemId, out ItemCache.CachedItemInfo? cachedItemInfo) &&
cachedItemInfo.CanBeDiscarded()) cachedItemInfo.CanBeDiscarded())
args.AddCustomItem(_addInventoryItem); args.AddMenuItem(_addInventoryItem);
}
else
{
if (args.AddonName is not "ChatLog")
return;
uint itemId = (uint)_gameGui.HoveredItem;
if (itemId > 1_000_000)
itemId -= 1_000_000;
if (itemId > 500_000)
itemId -= 500_000;
if (_configuration.DiscardingItems.Contains(itemId))
{
args.AddMenuItem(new MenuItem
{
Prefix = _removeInventoryItem.Prefix,
PrefixColor = _removeInventoryItem.PrefixColor,
Name = _removeInventoryItem.Name,
OnClicked = _ => RemoveFromDiscardList(itemId),
});
}
else if (_itemCache.TryGetItem(itemId, out ItemCache.CachedItemInfo? cachedItemInfo) &&
cachedItemInfo.CanBeDiscarded())
{
args.AddMenuItem(new MenuItem
{
Prefix = _addInventoryItem.Prefix,
PrefixColor = _addInventoryItem.PrefixColor,
Name = _addInventoryItem.Name,
OnClicked = _ => AddToDiscardList(itemId),
});
}
}
} }
private void OpenGameObjectContextMenu(GameObjectContextMenuOpenArgs args) private void AddToDiscardList(MenuItemClickedArgs args) =>
{ AddToDiscardList(((MenuTargetInventory)args.Target).TargetItem!.Value.ItemId);
if (!IsEnabled())
return;
if (args.ParentAddonName is not "ChatLog")
return;
uint itemId = (uint)_gameGui.HoveredItem;
if (itemId > 1_000_000)
itemId -= 1_000_000;
if (itemId > 500_000)
itemId -= 500_000;
if (_configuration.DiscardingItems.Contains(itemId))
args.AddCustomItem(new GameObjectContextMenuItem(_removeItemPayload, _ => RemoveFromDiscardList(itemId)));
else if (_itemCache.TryGetItem(itemId, out ItemCache.CachedItemInfo? cachedItemInfo) &&
cachedItemInfo.CanBeDiscarded())
args.AddCustomItem(new GameObjectContextMenuItem(_addItemPayload, _ => AddToDiscardList(itemId)));
}
private void AddToDiscardList(InventoryContextMenuItemSelectedArgs args) => AddToDiscardList(args.ItemId);
private void AddToDiscardList(uint itemId) private void AddToDiscardList(uint itemId)
{ {
@ -104,7 +124,8 @@ internal sealed class ContextMenuIntegration : IDisposable
} }
} }
private void RemoveFromDiscardList(InventoryContextMenuItemSelectedArgs args) => RemoveFromDiscardList(args.ItemId); private void RemoveFromDiscardList(MenuItemClickedArgs args) =>
RemoveFromDiscardList(((MenuTargetInventory)args.Target).TargetItem!.Value.ItemId);
private void RemoveFromDiscardList(uint itemId) private void RemoveFromDiscardList(uint itemId)
{ {
@ -136,8 +157,6 @@ internal sealed class ContextMenuIntegration : IDisposable
public void Dispose() public void Dispose()
{ {
_dalamudContextMenu.OnOpenGameObjectContextMenu -= OpenGameObjectContextMenu; _contextMenu.OnMenuOpened -= MenuOpened;
_dalamudContextMenu.OnOpenInventoryContextMenu -= OpenInventoryContextMenu;
_dalamudContextMenu.Dispose();
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
@ -79,7 +80,7 @@ internal sealed class InventoryUtils
.ToList(); .ToList();
} }
private unsafe IEnumerable<ItemWrapper> GetArmouryItemsToDiscard(bool condition, InventoryManager* inventoryManager, private unsafe ReadOnlyCollection<ItemWrapper> GetArmouryItemsToDiscard(bool condition, InventoryManager* inventoryManager,
InventoryType[] inventoryTypes, Dictionary<uint, uint> itemCounts, List<uint>? gearsetItems) InventoryType[] inventoryTypes, Dictionary<uint, uint> itemCounts, List<uint>? gearsetItems)
{ {
List<ItemWrapper> items = new(); List<ItemWrapper> items = new();
@ -89,7 +90,7 @@ internal sealed class InventoryUtils
items.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts, gearsetItems)); items.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts, gearsetItems));
} }
return items; return items.AsReadOnly();
} }
public unsafe InventoryItem* GetNextItemToDiscard(ItemFilter? itemFilter) public unsafe InventoryItem* GetNextItemToDiscard(ItemFilter? itemFilter)
@ -100,7 +101,7 @@ internal sealed class InventoryUtils
return toDiscard != null ? toDiscard.InventoryItem : null; return toDiscard != null ? toDiscard.InventoryItem : null;
} }
private unsafe IReadOnlyList<ItemWrapper> GetItemsToDiscard(InventoryManager* inventoryManager, private unsafe ReadOnlyCollection<ItemWrapper> GetItemsToDiscard(InventoryManager* inventoryManager,
InventoryType inventoryType, Dictionary<uint, uint> itemCounts, InventoryType inventoryType, Dictionary<uint, uint> itemCounts,
IReadOnlyList<uint>? gearsetItems) IReadOnlyList<uint>? gearsetItems)
{ {
@ -150,7 +151,7 @@ internal sealed class InventoryUtils
} }
} }
return toDiscard; return toDiscard.AsReadOnly();
} }
private unsafe List<uint>? GetAllGearsetItems() private unsafe List<uint>? GetAllGearsetItems()
@ -195,7 +196,7 @@ internal sealed class InventoryUtils
{ {
if (InternalConfiguration.BlacklistedItems.Contains(item->ItemID) || if (InternalConfiguration.BlacklistedItems.Contains(item->ItemID) ||
InternalConfiguration.UltimateWeapons.Contains(item->ItemID)) InternalConfiguration.UltimateWeapons.Contains(item->ItemID))
throw new Exception($"Can't discard {item->ItemID}"); throw new ArgumentException($"Can't discard {item->ItemID}", nameof(item));
AgentInventoryContext.Instance()->DiscardItem(item, item->Container, item->Slot, 0); AgentInventoryContext.Instance()->DiscardItem(item, item->Container, item->Slot, 0);
} }

View File

@ -2,9 +2,9 @@
namespace ARDiscard.GameData; namespace ARDiscard.GameData;
internal class ItemFilter internal sealed class ItemFilter
{ {
public static ItemFilter? None = null; public const ItemFilter? None = null;
public required List<uint> ItemIds { get; init; } public required List<uint> ItemIds { get; init; }
} }

View File

@ -10,11 +10,11 @@ using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using ECommons; using ECommons;
using ImGuiNET; using ImGuiNET;
using LLib; using LLib.ImGui;
namespace ARDiscard.Windows; namespace ARDiscard.Windows;
internal sealed class ConfigWindow : LImGui.LWindow internal sealed class ConfigWindow : LWindow
{ {
private const int ResultLimit = 200; private const int ResultLimit = 200;
@ -27,7 +27,7 @@ internal sealed class ConfigWindow : LImGui.LWindow
private List<(uint ItemId, string Name)> _searchResults = new(); private List<(uint ItemId, string Name)> _searchResults = new();
private List<(uint ItemId, string Name)> _discarding = new(); private List<(uint ItemId, string Name)> _discarding = new();
private List<(uint ItemId, string Name)>? _allItems = null; private List<(uint ItemId, string Name)>? _allItems;
private bool _resetKeyboardFocus = true; private bool _resetKeyboardFocus = true;
public event EventHandler? DiscardNowClicked; public event EventHandler? DiscardNowClicked;
@ -172,7 +172,7 @@ internal sealed class ConfigWindow : LImGui.LWindow
ImGui.Separator(); ImGui.Separator();
List<(uint, string)> toRemove = new(); List<(uint, string)> toRemove = new();
foreach (var (id, name) in _discarding.OrderBy(x => x.Name.ToLower())) foreach (var (id, name) in _discarding.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase))
{ {
if (ImGui.Selectable(name, true)) if (ImGui.Selectable(name, true))
toRemove.Add((id, name)); toRemove.Add((id, name));

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using ARDiscard.GameData; using ARDiscard.GameData;
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
@ -9,10 +10,11 @@ using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Common.Math; using FFXIVClientStructs.FFXIV.Common.Math;
using ImGuiNET; using ImGuiNET;
using LLib; using LLib;
using LLib.ImGui;
namespace ARDiscard.Windows; namespace ARDiscard.Windows;
internal sealed class DiscardWindow : LImGui.LWindow internal sealed class DiscardWindow : LWindow
{ {
private readonly InventoryUtils _inventoryUtils; private readonly InventoryUtils _inventoryUtils;
private readonly ItemCache _itemCache; private readonly ItemCache _itemCache;
@ -47,7 +49,7 @@ internal sealed class DiscardWindow : LImGui.LWindow
}; };
} }
public bool Locked { get; set; } = false; public bool Locked { get; set; }
public override void Draw() public override void Draw()
{ {
@ -98,7 +100,7 @@ internal sealed class DiscardWindow : LImGui.LWindow
ImGui.BeginDisabled(Locked || ImGui.BeginDisabled(Locked ||
!_clientState.IsLoggedIn || !_clientState.IsLoggedIn ||
!(_condition[ConditionFlag.NormalConditions] || _condition[ConditionFlag.Mounted]) || !(_condition[ConditionFlag.NormalConditions] || _condition[ConditionFlag.Mounted]) ||
_displayedItems.Count(x => x.Selected) == 0 || !_displayedItems.Any(x => x.Selected) ||
DiscardAllClicked == null); DiscardAllClicked == null);
if (ImGui.Button("Discard all selected items")) if (ImGui.Button("Discard all selected items"))
{ {
@ -162,7 +164,7 @@ internal sealed class DiscardWindow : LImGui.LWindow
UiCategoryName = x.Key.ItemInfo!.UiCategoryName, UiCategoryName = x.Key.ItemInfo!.UiCategoryName,
Selected = !notSelected.Contains(x.Key.ItemId), Selected = !notSelected.Contains(x.Key.ItemId),
}) })
.OrderBy(x => x.Name.ToLower()) .OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase)
.ToList(); .ToList();
} }

View File

@ -1,13 +1,7 @@
{ {
"version": 1, "version": 1,
"dependencies": { "dependencies": {
"net7.0-windows7.0": { "net8.0-windows7.0": {
"Dalamud.ContextMenu": {
"type": "Direct",
"requested": "[1.3.1, )",
"resolved": "1.3.1",
"contentHash": "ptAxut5PiLnzZ4G/KQdHJVcyklC/BF3otHJ7zYVUPiKBjsOCoF0n/6h2jK7e+8ev2Y1yAY3Wtx2GuXLFQgt9Uw=="
},
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[2.1.12, )", "requested": "[2.1.12, )",
@ -17,7 +11,7 @@
"autoretainerapi": { "autoretainerapi": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"ECommons": "[2.1.0, )" "ECommons": "[2.1.0.7, )"
} }
}, },
"ecommons": { "ecommons": {

@ -1 +1 @@
Subproject commit 7cb54772e3a4a60ad02520e898d1ed0e82b2a751 Subproject commit 6f0aaa55bce6ec79fd4d72f84f21597b39e5445d

@ -1 +1 @@
Subproject commit f1c688a0599b41d70230021328a575da7351cf91 Subproject commit d238d4188e8b47b11252d75cb5e4b678b8da2756

2
LLib

@ -1 +1 @@
Subproject commit 865a6080319f8ccbcd5fd5b0004404822b6e60d4 Subproject commit 3792244261a9f5426a7916f5a6dd1966238ba84a

7
global.json Normal file
View File

@ -0,0 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"rollForward": "latestMajor",
"allowPrerelease": true
}
}