forked from liza/ARDiscard
Initial Commit
This commit is contained in:
commit
c15f511f2b
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/.idea
|
||||
*.user
|
16
ARDiscard.sln
Normal file
16
ARDiscard.sln
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ARDiscard", "ARDiscard\ARDiscard.csproj", "{A9B4C542-1C83-4F46-81E7-5BAFCA109767}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A9B4C542-1C83-4F46-81E7-5BAFCA109767}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9B4C542-1C83-4F46-81E7-5BAFCA109767}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9B4C542-1C83-4F46-81E7-5BAFCA109767}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9B4C542-1C83-4F46-81E7-5BAFCA109767}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
3
ARDiscard/.gitignore
vendored
Normal file
3
ARDiscard/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/dist
|
||||
/obj
|
||||
/bin
|
77
ARDiscard/ARDiscard.csproj
Normal file
77
ARDiscard/ARDiscard.csproj
Normal file
@ -0,0 +1,77 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<Version>1.0</Version>
|
||||
<LangVersion>11.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<OutputPath>dist</OutputPath>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>portable</DebugType>
|
||||
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<DebugType>portable</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'">
|
||||
<DalamudLibPath>$(DALAMUD_HOME)/</DalamudLibPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.11"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGui.NET">
|
||||
<HintPath>$(DalamudLibPath)ImGui.NET.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGuiScene">
|
||||
<HintPath>$(DalamudLibPath)ImGuiScene.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina">
|
||||
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina.Excel">
|
||||
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoRetainerAPI">
|
||||
<HintPath>$(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.1.0.6\AutoRetainerAPI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ECommons">
|
||||
<HintPath>$(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.1.0.6\ECommons.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ClickLib">
|
||||
<HintPath>$(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.1.0.6\ClickLib.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="RenameLatestZip" AfterTargets="PackagePlugin">
|
||||
<Exec Command="rename $(OutDir)$(AssemblyName)\latest.zip $(AssemblyName)-$(Version).zip"/>
|
||||
</Target>
|
||||
</Project>
|
7
ARDiscard/ARDiscard.json
Normal file
7
ARDiscard/ARDiscard.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"Name": "Discard after AutoRetainer",
|
||||
"Author": "Liza Carvelli",
|
||||
"Punchline": "",
|
||||
"Description": "",
|
||||
"RepoUrl": "https://git.carvel.li/liza/ARDiscard"
|
||||
}
|
182
ARDiscard/AutoDiscardPlogon.cs
Normal file
182
ARDiscard/AutoDiscardPlogon.cs
Normal file
@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using AutoRetainerAPI;
|
||||
using ClickLib.Clicks;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin;
|
||||
using ECommons;
|
||||
using ECommons.Automation;
|
||||
using ECommons.DalamudServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace ARDiscard;
|
||||
|
||||
public class AutoDiscardPlogon : IDalamudPlugin
|
||||
{
|
||||
private readonly WindowSystem _windowSystem = new(nameof(AutoDiscardPlogon));
|
||||
private readonly Configuration _configuration;
|
||||
private readonly ConfigWindow _configWindow;
|
||||
|
||||
private readonly DalamudPluginInterface _pluginInterface;
|
||||
private readonly ChatGui _chatGui;
|
||||
private readonly CommandManager _commandManager;
|
||||
private readonly InventoryUtils _inventoryUtils;
|
||||
private readonly AutoRetainerApi _autoRetainerApi;
|
||||
private readonly TaskManager _taskManager;
|
||||
|
||||
public AutoDiscardPlogon(DalamudPluginInterface pluginInterface, CommandManager commandManager, ChatGui chatGui,
|
||||
DataManager dataManager)
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration();
|
||||
_chatGui = chatGui;
|
||||
_commandManager = commandManager;
|
||||
_commandManager.AddHandler("/discardconfig", new CommandInfo(OpenConfig));
|
||||
_commandManager.AddHandler("/discardall", new CommandInfo(ProcessCommand));
|
||||
_inventoryUtils = new(_configuration);
|
||||
|
||||
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
||||
_pluginInterface.UiBuilder.OpenConfigUi += OpenConfigUi;
|
||||
_configWindow = new(_pluginInterface, _configuration, dataManager);
|
||||
_configWindow.IsOpen = true;
|
||||
_windowSystem.AddWindow(_configWindow);
|
||||
|
||||
ECommonsMain.Init(_pluginInterface, this);
|
||||
_autoRetainerApi = new();
|
||||
_taskManager = new();
|
||||
|
||||
_autoRetainerApi.OnRetainerReadyToPostprocess += DoPostProcess;
|
||||
_autoRetainerApi.OnRetainerPostprocessStep += CheckPostProcess;
|
||||
}
|
||||
|
||||
public string Name => "Discard after AutoRetainer";
|
||||
|
||||
private unsafe void CheckPostProcess(string retainerName)
|
||||
{
|
||||
if (_inventoryUtils.GetNextItemToDiscard() != null)
|
||||
_autoRetainerApi.RequestPostprocess();
|
||||
}
|
||||
|
||||
private void DoPostProcess(string retainerName)
|
||||
{
|
||||
_taskManager.Enqueue(() => DiscardNextItem(true));
|
||||
}
|
||||
|
||||
private void OpenConfig(string command, string arguments) => OpenConfigUi();
|
||||
|
||||
private void OpenConfigUi()
|
||||
{
|
||||
_configWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
private void ProcessCommand(string command, string arguments)
|
||||
{
|
||||
_taskManager.Enqueue(() => DiscardNextItem(false));
|
||||
}
|
||||
|
||||
private unsafe void DiscardNextItem(bool finishRetainerAction)
|
||||
{
|
||||
InventoryItem* nextItem = _inventoryUtils.GetNextItemToDiscard();
|
||||
if (nextItem == null)
|
||||
{
|
||||
if (finishRetainerAction)
|
||||
_autoRetainerApi.FinishPostProcess();
|
||||
else
|
||||
_chatGui.Print("Done discarding.");
|
||||
return;
|
||||
}
|
||||
|
||||
var (inventoryType, slot) = (nextItem->Container, nextItem->Slot);
|
||||
|
||||
//_chatGui.Print($"Discarding {nextItem->ItemID}, {nextItem->Container}, {nextItem->Slot}.");
|
||||
_inventoryUtils.Discard(nextItem);
|
||||
|
||||
|
||||
_taskManager.DelayNext(5);
|
||||
_taskManager.Enqueue(ConfirmDiscardItem);
|
||||
_taskManager.DelayNext(2000);
|
||||
_taskManager.Enqueue(() => ContinueAfterDiscard(finishRetainerAction, inventoryType, slot));
|
||||
}
|
||||
|
||||
private unsafe void ConfirmDiscardItem()
|
||||
{
|
||||
var addon = GetDiscardAddon();
|
||||
if (addon != null)
|
||||
{
|
||||
((AddonSelectYesno*)addon)->YesButton->AtkComponentBase.SetEnabledState(true);
|
||||
ClickSelectYesNo.Using((nint)addon).Yes();
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void ContinueAfterDiscard(bool finishRetainerAction, InventoryType inventoryType, short slot)
|
||||
{
|
||||
InventoryItem* nextItem = _inventoryUtils.GetNextItemToDiscard();
|
||||
if (nextItem == null)
|
||||
{
|
||||
if (finishRetainerAction)
|
||||
_autoRetainerApi.FinishPostProcess();
|
||||
else
|
||||
_chatGui.Print("Done discarding.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nextItem->Container == inventoryType && nextItem->Slot == slot)
|
||||
{
|
||||
_taskManager.DelayNext(100);
|
||||
_taskManager.Enqueue(() => ContinueAfterDiscard(finishRetainerAction, inventoryType, slot));
|
||||
}
|
||||
else
|
||||
{
|
||||
_taskManager.EnqueueImmediate(() => DiscardNextItem(finishRetainerAction));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_autoRetainerApi.Dispose();
|
||||
ECommonsMain.Dispose();
|
||||
|
||||
_inventoryUtils.Dispose();
|
||||
_pluginInterface.UiBuilder.OpenConfigUi -= OpenConfigUi;
|
||||
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
||||
_commandManager.RemoveHandler("/discardall");
|
||||
_commandManager.RemoveHandler("/discardconfig");
|
||||
}
|
||||
|
||||
private static unsafe AtkUnitBase* GetDiscardAddon()
|
||||
{
|
||||
for (int i = 1; i < 100; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var addon = (AtkUnitBase*)Svc.GameGui.GetAddonByName("SelectYesno", i);
|
||||
if (addon == null) return null;
|
||||
if (addon->IsVisible)
|
||||
{
|
||||
var textNode = addon->UldManager.NodeList[15]->GetAsAtkTextNode();
|
||||
var text = MemoryHelper.ReadSeString(&textNode->NodeText).ExtractText();
|
||||
PluginLog.Information($"TEt → {text}");
|
||||
if (text.StartsWith("Discard"))
|
||||
{
|
||||
return addon;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
125
ARDiscard/ConfigWindow.cs
Normal file
125
ARDiscard/ConfigWindow.cs
Normal file
@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Plugin;
|
||||
using ECommons;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace ARDiscard;
|
||||
|
||||
public class ConfigWindow : Window
|
||||
{
|
||||
private readonly DalamudPluginInterface _pluginInterface;
|
||||
private readonly Configuration _configuration;
|
||||
private readonly DataManager _dataManager;
|
||||
private string _itemName = string.Empty;
|
||||
|
||||
private List<(uint ItemId, string Name)> _searchResults = new();
|
||||
private List<(uint ItemId, string Name)> _discarding = new();
|
||||
|
||||
public ConfigWindow(DalamudPluginInterface pluginInterface, Configuration configuration, DataManager dataManager)
|
||||
: base("Auto Discard###AutoDiscardConfig")
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_configuration = configuration;
|
||||
_dataManager = dataManager;
|
||||
|
||||
Size = new Vector2(600, 400);
|
||||
SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(600, 400),
|
||||
MaximumSize = new Vector2(9999, 9999),
|
||||
};
|
||||
|
||||
_discarding = _configuration.DiscardingItems
|
||||
.Select(x => (x, dataManager.GetExcelSheet<Item>()?.GetRow(x)?.Name?.ToString() ?? x.ToString())).ToList();
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
var ws = ImGui.GetWindowSize();
|
||||
if (ImGui.BeginChild("Left", new Vector2(Math.Max(10, ws.X / 2), -1), true))
|
||||
{
|
||||
ImGui.Text("Search");
|
||||
ImGui.SetNextItemWidth(ws.X / 2 - 20);
|
||||
if (ImGui.InputText("", ref _itemName, 256))
|
||||
UpdateResults();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
if (_searchResults.Count == 0)
|
||||
{
|
||||
ImGui.Text("Type item name...");
|
||||
}
|
||||
|
||||
foreach (var (id, name) in _searchResults)
|
||||
{
|
||||
bool selected = _discarding.Any(x => x.Item1 == id);
|
||||
if (ImGui.Selectable(name, selected))
|
||||
{
|
||||
if (!selected)
|
||||
{
|
||||
_discarding.Add((id, name));
|
||||
}
|
||||
else
|
||||
{
|
||||
_discarding.Remove((id, name));
|
||||
}
|
||||
|
||||
_configuration.DiscardingItems = _discarding.Select(x => x.ItemId).ToList();
|
||||
_pluginInterface.SavePluginConfig(_configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.BeginChild("Right", new Vector2(-1, -1), true, ImGuiWindowFlags.NoSavedSettings))
|
||||
{
|
||||
ImGui.Text("Items that will be automatically discarded");
|
||||
ImGui.Separator();
|
||||
|
||||
List<(uint, string)> toRemove = new();
|
||||
foreach (var (id, name) in _discarding.OrderBy(x => x.Name.ToLower()))
|
||||
{
|
||||
if (ImGui.Selectable(name, true))
|
||||
toRemove.Add((id, name));
|
||||
}
|
||||
|
||||
if (toRemove.Count > 0)
|
||||
{
|
||||
foreach (var tr in toRemove)
|
||||
_discarding.Remove(tr);
|
||||
|
||||
_configuration.DiscardingItems = _discarding.Select(x => x.ItemId).ToList();
|
||||
_pluginInterface.SavePluginConfig(_configuration);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
private void UpdateResults()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_itemName))
|
||||
_searchResults = new();
|
||||
else
|
||||
{
|
||||
_searchResults = _dataManager.GetExcelSheet<Item>()
|
||||
.Where(x => x.RowId != 0)
|
||||
.Where(x => !x.IsUnique && !x.IsUntradable)
|
||||
.Where(x => x.ItemUICategory?.Value?.Name?.ToString() != "Currency")
|
||||
.Where(x => !string.IsNullOrEmpty(x.Name) &&
|
||||
x.Name.ToString().Contains(_itemName, StringComparison.CurrentCultureIgnoreCase))
|
||||
.Select(x => (x.RowId, x.Name.ToString()))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
10
ARDiscard/Configuration.cs
Normal file
10
ARDiscard/Configuration.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Configuration;
|
||||
|
||||
namespace ARDiscard;
|
||||
|
||||
public class Configuration : IPluginConfiguration
|
||||
{
|
||||
public int Version { get; set; } = 1;
|
||||
public List<uint> DiscardingItems = new();
|
||||
}
|
59
ARDiscard/InventoryUtils.cs
Normal file
59
ARDiscard/InventoryUtils.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
|
||||
namespace ARDiscard;
|
||||
|
||||
public class InventoryUtils : IDisposable
|
||||
{
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
private static readonly InventoryType[] InventoryTypes =
|
||||
{ InventoryType.Inventory1, InventoryType.Inventory2, InventoryType.Inventory3, InventoryType.Inventory4 };
|
||||
|
||||
private unsafe delegate void DiscardItemDelegate(AgentInventoryContext* inventoryManager, InventoryItem* itemSlot,
|
||||
InventoryType inventory, int slot, uint addonId, int position = -1);
|
||||
|
||||
[Signature("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0 74 ?? 0F B7 48")]
|
||||
private DiscardItemDelegate _discardItem = null!;
|
||||
|
||||
public InventoryUtils(Configuration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
SignatureHelper.Initialise(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe InventoryItem* GetNextItemToDiscard()
|
||||
{
|
||||
InventoryManager* inventoryManager = InventoryManager.Instance();
|
||||
foreach (InventoryType inventoryType in InventoryTypes)
|
||||
{
|
||||
InventoryContainer* container = inventoryManager->GetInventoryContainer(inventoryType);
|
||||
for (int i = 0; i < container->Size; ++i)
|
||||
{
|
||||
var item = container->GetInventorySlot(i);
|
||||
if (item != null)
|
||||
{
|
||||
if (_configuration.DiscardingItems.Contains(item->ItemID))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public unsafe void Discard(InventoryItem* item)
|
||||
{
|
||||
_discardItem(AgentInventoryContext.Instance(), item, item->Container, item->Slot, 0);
|
||||
}
|
||||
}
|
13
ARDiscard/packages.lock.json
Normal file
13
ARDiscard/packages.lock.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net7.0-windows7.0": {
|
||||
"DalamudPackager": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.1.11, )",
|
||||
"resolved": "2.1.11",
|
||||
"contentHash": "9qlAWoRRTiL/geAvuwR/g6Bcbrd/bJJgVnB/RurBiyKs6srsP0bvpoo8IK+Eg8EA6jWeM6/YJWs66w4FIAzqPw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user