Compare commits

..

13 Commits
v0.1 ... master

11 changed files with 541 additions and 124 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "ECommons"] [submodule "ECommons"]
path = ECommons path = ECommons
url = https://github.com/NightmareXIV/ECommons.git url = https://github.com/NightmareXIV/ECommons.git
[submodule "LLib"]
path = LLib
url = https://git.carvel.li/liza/LLib.git

@ -1 +1 @@
Subproject commit 6f0aaa55bce6ec79fd4d72f84f21597b39e5445d Subproject commit a63c8e7154e272374ffa03d5c801736d4229e38a

@ -1 +1 @@
Subproject commit f11764e4654148c5d891273053ec02649a5ee9c5 Subproject commit 11fd2f06e1374e846e1aada06071da5fc7ef697a

View File

@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ECommons", "ECommons\ECommo
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRetainerAPI", "AutoRetainerAPI\AutoRetainerAPI\AutoRetainerAPI.csproj", "{FD2D72FE-F7AE-43AF-8453-66A830AA38D7}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRetainerAPI", "AutoRetainerAPI\AutoRetainerAPI\AutoRetainerAPI.csproj", "{FD2D72FE-F7AE-43AF-8453-66A830AA38D7}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLib", "LLib\LLib.csproj", "{FAB49680-A224-4668-A758-7A563F26FAFE}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -24,5 +26,9 @@ Global
{FD2D72FE-F7AE-43AF-8453-66A830AA38D7}.Debug|Any CPU.Build.0 = Debug|x64 {FD2D72FE-F7AE-43AF-8453-66A830AA38D7}.Debug|Any CPU.Build.0 = Debug|x64
{FD2D72FE-F7AE-43AF-8453-66A830AA38D7}.Release|Any CPU.ActiveCfg = Release|x64 {FD2D72FE-F7AE-43AF-8453-66A830AA38D7}.Release|Any CPU.ActiveCfg = Release|x64
{FD2D72FE-F7AE-43AF-8453-66A830AA38D7}.Release|Any CPU.Build.0 = Release|x64 {FD2D72FE-F7AE-43AF-8453-66A830AA38D7}.Release|Any CPU.Build.0 = Release|x64
{FAB49680-A224-4668-A758-7A563F26FAFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAB49680-A224-4668-A758-7A563F26FAFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAB49680-A224-4668-A758-7A563F26FAFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAB49680-A224-4668-A758-7A563F26FAFE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -8,7 +8,7 @@ using Dalamud.Game.Command;
using Dalamud.Game.Gui.Dtr; using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text; using Dalamud.Game.Text;
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Plugin.Ipc.Exceptions;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
@ -25,7 +25,7 @@ internal sealed class CharacterSwitch : IDisposable
private readonly INotificationManager _notificationManager; private readonly INotificationManager _notificationManager;
private readonly ICondition _condition; private readonly ICondition _condition;
private readonly IPluginLog _pluginLog; private readonly IPluginLog _pluginLog;
private readonly DtrBarEntry _dtrBarEntry; private readonly IDtrBarEntry _dtrBarEntry;
public CharacterSwitch(AutoRetainerApi autoRetainerApi, ICommandManager commandManager, IClientState clientState, public CharacterSwitch(AutoRetainerApi autoRetainerApi, ICommandManager commandManager, IClientState clientState,
IChatGui chatGui, INotificationManager notificationManager, IDtrBar dtrBar, ICondition condition, IChatGui chatGui, INotificationManager notificationManager, IDtrBar dtrBar, ICondition condition,
@ -55,11 +55,18 @@ internal sealed class CharacterSwitch : IDisposable
{ {
unsafe unsafe
{ {
UIInputData* uiInputData = UIInputData.Instance(); uint? homeWorldId = _clientState.LocalPlayer?.HomeWorld.Id;
MouseButtonFlags mouseButtonFlags = uint? currentWorldId = _clientState.LocalPlayer?.CurrentWorld.Id;
uiInputData != null ? uiInputData->MouseButtonReleasedFlags : MouseButtonFlags.LBUTTON; if (homeWorldId == currentWorldId)
var target = FindCharacter(mouseButtonFlags.HasFlag(MouseButtonFlags.RBUTTON) ? -1 : 1); {
SwitchCharacter(target); UIInputData* uiInputData = UIInputData.Instance();
MouseButtonFlags mouseButtonFlags =
uiInputData != null ? uiInputData->MouseButtonReleasedFlags : MouseButtonFlags.LBUTTON;
var target = FindCharacter(mouseButtonFlags.HasFlag(MouseButtonFlags.RBUTTON) ? -1 : 1);
SwitchCharacter(target);
}
else
_commandManager.ProcessCommand("/li");
} }
}; };
@ -68,34 +75,44 @@ internal sealed class CharacterSwitch : IDisposable
UpdateDtrBar(); UpdateDtrBar();
} }
private Target? FindCharacter(int direction) private Target? FindCharacter(int direction, bool showError = true)
{ {
_pluginLog.Verbose($"Switching characters ({direction})"); try
var characterIds = _autoRetainerApi.GetRegisteredCharacters();
int index = characterIds.IndexOf(_clientState.LocalContentId);
if (index < 0)
{ {
_chatGui.PrintError("[KitchenSink] Current character not known."); _pluginLog.Verbose($"Switching characters ({direction})");
return null;
}
OfflineCharacterData? target; var characterIds = _autoRetainerApi.GetRegisteredCharacters();
do int index = characterIds.IndexOf(_clientState.LocalContentId);
{ if (index < 0)
index = (index + direction + characterIds.Count) % characterIds.Count;
target = _autoRetainerApi.GetOfflineCharacterData(characterIds[index]);
if (target?.CID == _clientState.LocalContentId)
{ {
_chatGui.PrintError("[KitchenSink] No character to switch to found."); if (showError)
_chatGui.PrintError("[KitchenSink] Current character not known.");
return null; return null;
} }
if (target is { ExcludeRetainer: true, ExcludeWorkshop: true }) OfflineCharacterData? target;
target = null; do
} while (target == null); {
index = (index + direction + characterIds.Count) % characterIds.Count;
target = _autoRetainerApi.GetOfflineCharacterData(characterIds[index]);
if (target?.CID == _clientState.LocalContentId)
{
if (showError)
_chatGui.PrintError("[KitchenSink] No character to switch to found.");
return null;
}
return new Target(target.Name, target.World); if (target is { ExcludeRetainer: true, ExcludeWorkshop: true })
target = null;
} while (target == null);
return new Target(target.Name, target.World);
}
catch (IpcError)
{
_chatGui.PrintError("Could not switch character, AutoRetainer API isn't available.");
return null;
}
} }
private void NextCharacter(string command, string arguments) => SwitchCharacter(FindCharacter(1)); private void NextCharacter(string command, string arguments) => SwitchCharacter(FindCharacter(1));
@ -110,26 +127,34 @@ internal sealed class CharacterSwitch : IDisposable
return; return;
} }
string[] args = arguments.Split(' ', 2); try
if (args.Length < 2 || !int.TryParse(args[1], CultureInfo.InvariantCulture, out int index))
index = 1;
var targets = _autoRetainerApi.GetRegisteredCharacters()
.Select(characterId => _autoRetainerApi.GetOfflineCharacterData(characterId))
.Where(x => !x.ExcludeRetainer || !x.ExcludeWorkshop)
.Select(x => new { x.Name, x.World })
.ToList();
var target = targets.Where(x => x.World.StartsWith(args[0], StringComparison.OrdinalIgnoreCase)).Skip(index - 1)
.FirstOrDefault() ??
targets.FirstOrDefault(x => x.Name.Contains(arguments, StringComparison.OrdinalIgnoreCase));
if (target == null)
{ {
_chatGui.PrintError($"[KitchenSink] No character found on world {args[0]} with #{index}."); string[] args = arguments.Split(' ', 2);
return; if (args.Length < 2 || !int.TryParse(args[1], CultureInfo.InvariantCulture, out int index))
} index = 1;
SwitchCharacter(new Target(target.Name, target.World)); var targets = _autoRetainerApi.GetRegisteredCharacters()
.Select(characterId => _autoRetainerApi.GetOfflineCharacterData(characterId))
.Where(x => !x.ExcludeRetainer || !x.ExcludeWorkshop)
.Select(x => new { x.Name, x.World })
.ToList();
var target = targets.Where(x => x.World.StartsWith(args[0], StringComparison.OrdinalIgnoreCase))
.Skip(index - 1)
.FirstOrDefault() ??
targets.FirstOrDefault(x => x.Name.Contains(arguments, StringComparison.OrdinalIgnoreCase));
if (target == null)
{
_chatGui.PrintError($"[KitchenSink] No character found on world {args[0]} with #{index}.");
return;
}
SwitchCharacter(new Target(target.Name, target.World));
}
catch (IpcError)
{
_chatGui.PrintError("Could not switch character, AutoRetainer API isn't available.");
}
} }
private void SwitchCharacter(Target? target) private void SwitchCharacter(Target? target)
@ -166,30 +191,52 @@ internal sealed class CharacterSwitch : IDisposable
private void UpdateDtrBar() private void UpdateDtrBar()
{ {
string? currentWorld = _clientState.LocalPlayer?.CurrentWorld.GameData?.Name?.ToString(); if (_dtrBarEntry.UserHidden)
var characterIds = _autoRetainerApi.GetRegisteredCharacters() ?? new(); return;
var characterIdsOnCurrentWorld = characterIds
.Where(x => _autoRetainerApi.GetOfflineCharacterData(x)?.World == currentWorld).ToList();
SeIconChar seIconChar = SeIconChar.Instance1 + characterIdsOnCurrentWorld.IndexOf(_clientState.LocalContentId); try
_dtrBarEntry.Text = seIconChar.ToIconString(); {
string? currentWorld = _clientState.LocalPlayer?.CurrentWorld.GameData?.Name?.ToString();
string? homeWorld = _clientState.LocalPlayer?.HomeWorld.GameData?.Name?.ToString();
var characterIds = _autoRetainerApi.GetRegisteredCharacters() ?? new();
var characterIdsOnHomeWorld = characterIds
.Where(x => _autoRetainerApi.GetOfflineCharacterData(x)?.World == homeWorld).ToList();
var previous = FindCharacter(-1); SeIconChar seIconChar = SeIconChar.Instance1 + characterIdsOnHomeWorld.IndexOf(_clientState.LocalContentId);
var next = FindCharacter(1); if (currentWorld == homeWorld)
if (previous != null && next != null) {
_dtrBarEntry.Tooltip = $"Prev: {previous.Name}\nNext: {next.Name}"; _dtrBarEntry.Text = seIconChar.ToIconString();
else if (previous != null)
_dtrBarEntry.Tooltip = $"Prev: {previous.Name}"; var previous = FindCharacter(-1, showError: false);
else if (next != null) var next = FindCharacter(1, showError: false);
_dtrBarEntry.Tooltip = $"Next: {next.Name}"; if (previous != null && next != null)
else _dtrBarEntry.Tooltip = $"Prev: {previous.ToString(homeWorld)}\nNext: {next.ToString(homeWorld)}";
_dtrBarEntry.Tooltip = null; else if (previous != null)
_dtrBarEntry.Tooltip = $"Prev: {previous.ToString(homeWorld)}";
else if (next != null)
_dtrBarEntry.Tooltip = $"Next: {next.ToString(homeWorld)}";
else
_dtrBarEntry.Tooltip = null;
}
else
{
_dtrBarEntry.Text = $"{homeWorld} {seIconChar.ToIconString()}";
_dtrBarEntry.Tooltip = $"Return to {homeWorld}";
}
if (!_dtrBarEntry.Shown)
_dtrBarEntry.Shown = true;
}
catch (IpcError)
{
_dtrBarEntry.Shown = false;
}
} }
public void Dispose() public void Dispose()
{ {
_clientState.Login -= UpdateDtrBar; _clientState.Login -= UpdateDtrBar;
_dtrBarEntry.Dispose(); _dtrBarEntry.Remove();
_commandManager.RemoveHandler("/ks"); _commandManager.RemoveHandler("/ks");
_commandManager.RemoveHandler("/k-"); _commandManager.RemoveHandler("/k-");
_commandManager.RemoveHandler("/k+"); _commandManager.RemoveHandler("/k+");
@ -198,5 +245,10 @@ internal sealed class CharacterSwitch : IDisposable
private sealed record Target(string Name, string World) private sealed record Target(string Name, string World)
{ {
public override string ToString() => $"{Name}@{World}"; public override string ToString() => $"{Name}@{World}";
public string ToString(string? currentWorld)
{
return currentWorld != World ? ToString() : Name;
}
} }
} }

View File

@ -0,0 +1,323 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using Dalamud.Game.Command;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using LLib;
namespace KitchenSink.Commands;
internal sealed class DropboxQueue : IDisposable
{
private static readonly InventoryType[] DefaultInventoryTypes =
[
InventoryType.Inventory1,
InventoryType.Inventory2,
InventoryType.Inventory3,
InventoryType.Inventory4,
InventoryType.Crystals,
InventoryType.Currency,
InventoryType.ArmoryMainHand,
InventoryType.ArmoryOffHand,
InventoryType.ArmoryHead,
InventoryType.ArmoryBody,
InventoryType.ArmoryHands,
InventoryType.ArmoryLegs,
InventoryType.ArmoryFeets,
InventoryType.ArmoryEar,
InventoryType.ArmoryNeck,
InventoryType.ArmoryWrist,
InventoryType.ArmoryRings,
];
private readonly ICommandManager _commandManager;
private readonly IChatGui _chatGui;
private readonly DropboxApi _dropboxApi;
public DropboxQueue(IDalamudPluginInterface pluginInterface,
DalamudReflector reflector,
ICommandManager commandManager,
IChatGui chatGui,
IPluginLog pluginLog)
{
_commandManager = commandManager;
_chatGui = chatGui;
_dropboxApi = new DropboxApi(pluginInterface, reflector, pluginLog);
_commandManager.AddHandler("/dbq", new CommandInfo(Queue)
{
HelpMessage =
$"Queue items to be imported into dropbox{Environment.NewLine}" +
$"\t/dbq item1:qty1 item2:qty2 [...] - queues items for the next trade (use * as quantity for 'all'){Environment.NewLine}" +
$"\t/dbq clear - remove all items in the queue{Environment.NewLine}" +
$"\t/dbq request item1:qty1 item2:qty2 [...] - show the command to fill your inventory with the specific item quantities{Environment.NewLine}" +
$"\t/dbq [shards/crystals/shards+crystals] - show the command to fill shards and/or crystals to 9999"
});
}
private void Queue(string command, string arguments)
{
string[] parts = arguments.Split(" ", 2);
switch (parts[0])
{
case "*s":
case "shards":
BuildRequest(string.Join(" ", Enumerable.Range(2, 6).Select(x => $"{x}:9999")));
break;
case "*c":
case "crystals":
BuildRequest(string.Join(" ", Enumerable.Range(8, 6).Select(x => $"{x}:9999")));
break;
case "*x":
case "clusters":
BuildRequest(string.Join(" ", Enumerable.Range(14, 6).Select(x => $"{x}:9999")));
break;
case "*sc":
case "shards+crystals":
BuildRequest(string.Join(" ", Enumerable.Range(2, 12).Select(x => $"{x}:9999")));
break;
case "*cx":
case "crystals+clusters":
BuildRequest(string.Join(" ", Enumerable.Range(8, 12).Select(x => $"{x}:9999")));
break;
case "*scx":
case "shards+crystals+clusters":
BuildRequest(string.Join(" ", Enumerable.Range(2, 18).Select(x => $"{x}:9999")));
break;
case "request":
BuildRequest(parts.Length == 2 ? parts[1] : string.Empty);
break;
case "clear":
_dropboxApi.ClearQueue();
break;
default:
AddToQueue(arguments);
break;
}
}
private unsafe void BuildRequest(string arguments)
{
if (string.IsNullOrEmpty(arguments))
{
_chatGui.PrintError("Usage: /dbq request item1:qty1 item2:qty2 [...]");
}
InventoryManager* inventoryManger = InventoryManager.Instance();
if (inventoryManger == null)
return;
IReadOnlyList<NeededItem>? parsedItems = ParseArguments(arguments);
if (parsedItems == null)
return;
var missingItems = parsedItems
.Select(item => item with
{
Needed = item.Needed - DefaultInventoryTypes.Sum(y =>
inventoryManger->GetItemCountInContainer(item.ItemId, y) +
inventoryManger->GetItemCountInContainer(item.ItemId, y, true))
})
.Where(x => x.Needed > 0)
.ToList();
if (missingItems.Count == 0)
{
_chatGui.Print("No items need to be filled");
return;
}
_chatGui.Print(new SeStringBuilder().AddUiForeground("[KitchenSink] ", 504)
.Append($"/dbq {string.Join(" ", missingItems)}").Build());
}
private void AddToQueue(string arguments)
{
IReadOnlyList<NeededItem>? parsedItems = ParseArguments(arguments);
if (parsedItems == null)
return;
Dictionary<uint, ItemCount> allItems = GetItemCounts();
foreach (var neededItem in parsedItems)
{
if (!allItems.TryGetValue(neededItem.ItemId, out ItemCount? itemCount))
continue;
int normalQualityQuantity = Math.Min(neededItem.Needed, itemCount.NormalQualityQuantity);
int highQualityQuantity = Math.Min(neededItem.Needed - normalQualityQuantity,
itemCount.HighQualityQuantity);
if (normalQualityQuantity > 0)
_dropboxApi.EnqueueItem(neededItem.ItemId, false, normalQualityQuantity);
if (highQualityQuantity > 0)
_dropboxApi.EnqueueItem(neededItem.ItemId, true, highQualityQuantity);
if (normalQualityQuantity > 0 || highQualityQuantity > 0)
{
allItems[neededItem.ItemId] =
new ItemCount(
itemCount.NormalQualityQuantity - normalQualityQuantity,
itemCount.HighQualityQuantity - highQualityQuantity);
}
}
_dropboxApi.BeginTrade();
}
private ReadOnlyCollection<NeededItem>? ParseArguments(string arguments)
{
var parsedItems = arguments.Split(' ')
.Select(x => x.Split(':'))
.Select<string[], (string, NeededItem?)>(x =>
{
if (x.Length != 2)
return ($"Unable to parse {string.Join(" ", x)}.", null);
if (!uint.TryParse(x[0], out uint itemId))
return ($"Unable to parse item id {x[0]}.", null);
int needed;
if (x[1] == "*")
needed = int.MaxValue;
else if (!int.TryParse(x[1], out needed))
return ($"Unable to parse quantity {x[1]}.", null);
return (string.Empty, new NeededItem(itemId, needed));
}).ToList();
if (parsedItems.Count == 0)
return null;
var problematic = parsedItems.Where(x => !string.IsNullOrEmpty(x.Item1)).Select(x => x.Item1).ToList();
if (problematic.Count == 1)
{
_chatGui.PrintError($"dbq: {problematic.First()}");
return null;
}
else if (problematic.Count >= 2)
{
_chatGui.PrintError("dbq: Multiple errors occured:");
foreach (string problem in problematic)
_chatGui.PrintError($" - {problem}");
return null;
}
else
return parsedItems.Select(x => x.Item2!).ToList().AsReadOnly();
}
private unsafe Dictionary<uint, ItemCount> GetItemCounts()
{
Dictionary<uint, ItemCount> allItems = new();
InventoryManager* inventoryManager = InventoryManager.Instance();
if (inventoryManager == null)
return allItems;
foreach (var type in DefaultInventoryTypes)
{
InventoryContainer* container = inventoryManager->GetInventoryContainer(type);
for (int i = 0; i < container->Size; ++i)
{
var item = container->GetInventorySlot(i);
if (item != null && item->ItemId != 0)
{
if (item->Spiritbond > 0)
continue;
if (!allItems.TryGetValue(item->ItemId, out ItemCount? itemCount))
itemCount = new(0, 0);
if (item->Flags.HasFlag(InventoryItem.ItemFlags.HighQuality))
itemCount = itemCount with
{
HighQualityQuantity = itemCount.HighQualityQuantity + (int)item->Quantity
};
else
itemCount = itemCount with
{
NormalQualityQuantity = itemCount.NormalQualityQuantity + (int)item->Quantity
};
allItems[item->ItemId] = itemCount;
}
}
}
return allItems;
}
public void Dispose()
{
_commandManager.RemoveHandler("/dbq");
}
private sealed record NeededItem(uint ItemId, int Needed)
{
public override string ToString() => $"{ItemId}:{Needed}";
}
private sealed record ItemCount(int NormalQualityQuantity, int HighQualityQuantity);
private sealed class DropboxApi
{
private readonly DalamudReflector _reflector;
private readonly IPluginLog _pluginLog;
private readonly ICallGateSubscriber<object> _beginTradingQueue;
private readonly ICallGateSubscriber<uint, bool, int> _getItemQuantity;
private readonly ICallGateSubscriber<uint, bool, int, object> _setItemQuantity;
public DropboxApi(IDalamudPluginInterface pluginInterface, DalamudReflector reflector, IPluginLog pluginLog)
{
_reflector = reflector;
_pluginLog = pluginLog;
_beginTradingQueue = pluginInterface.GetIpcSubscriber<object>("Dropbox.BeginTradingQueue");
_getItemQuantity = pluginInterface.GetIpcSubscriber<uint, bool, int>("Dropbox.GetItemQuantity");
_setItemQuantity = pluginInterface.GetIpcSubscriber<uint, bool, int, object>("Dropbox.SetItemQuantity");
}
public void BeginTrade() => _beginTradingQueue.InvokeAction();
public void EnqueueItem(uint itemId, bool hq, int quantity)
{
_pluginLog.Verbose($"Preparing to queue {itemId}, {hq}, {quantity}");
if (quantity < 0)
return;
int currentQuantity = _getItemQuantity.InvokeFunc(itemId, hq);
_setItemQuantity.InvokeAction(itemId, hq, quantity + currentQuantity);
}
public void ClearQueue()
{
if (TryGetItemQuantities(out _, out IDictionary? itemQuantities))
itemQuantities.Clear();
}
private bool TryGetItemQuantities([NotNullWhen(true)] out IDalamudPlugin? dropboxPlugin,
[NotNullWhen(true)] out IDictionary? itemQuantities)
{
if (!_reflector.TryGetDalamudPlugin("Dropbox", out dropboxPlugin))
{
itemQuantities = null;
return false;
}
var itemQueueUiType = dropboxPlugin.GetType().Assembly.GetType("Dropbox.ItemQueueUI")!;
itemQuantities =
(IDictionary?)itemQueueUiType.GetField("ItemQuantities", BindingFlags.Public | BindingFlags.Static)!
.GetValue(null);
return itemQuantities != null;
}
}
}

View File

@ -1,64 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Dalamud.NET.Sdk/9.0.2">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <Version>1.2</Version>
<Version>0.1</Version>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>dist</OutputPath> <OutputPath>dist</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<DebugType>portable</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <Import Project="..\LLib\LLib.targets"/>
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath> <Import Project="..\LLib\RenameZip.targets"/>
</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.12"/>
</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="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>
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\AutoRetainerAPI\AutoRetainerAPI\AutoRetainerAPI.csproj"/> <ProjectReference Include="..\AutoRetainerAPI\AutoRetainerAPI\AutoRetainerAPI.csproj"/>
<ProjectReference Include="..\ECommons\ECommons\ECommons.csproj"/> <ProjectReference Include="..\ECommons\ECommons\ECommons.csproj"/>
<ProjectReference Include="..\LLib\LLib.csproj" />
</ItemGroup> </ItemGroup>
<Target Name="RenameLatestZip" AfterTargets="PackagePlugin">
<Exec Command="rename $(OutDir)$(AssemblyName)\latest.zip $(AssemblyName)-$(Version).zip"/>
</Target>
</Project> </Project>

View File

@ -4,5 +4,6 @@
"Punchline": "A plugin for things that aren't worth their own plugins.", "Punchline": "A plugin for things that aren't worth their own plugins.",
"Description": "A plugin for things that aren't worth their own plugins; see commands for details.", "Description": "A plugin for things that aren't worth their own plugins; see commands for details.",
"Tags": ["character switch"], "Tags": ["character switch"],
"RepoUrl": "https://git.carvel.li/liza/KitchenSink",
"IconUrl": "https://plugins.carvel.li/icons/KitchenSink.png" "IconUrl": "https://plugins.carvel.li/icons/KitchenSink.png"
} }

View File

@ -4,6 +4,7 @@ using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using ECommons; using ECommons;
using KitchenSink.Commands; using KitchenSink.Commands;
using LLib;
namespace KitchenSink; namespace KitchenSink;
@ -13,19 +14,24 @@ internal sealed class KitchenSinkPlugin : IDalamudPlugin
{ {
private readonly AutoRetainerApi _autoRetainerApi; private readonly AutoRetainerApi _autoRetainerApi;
private readonly CharacterSwitch _characterSwitch; private readonly CharacterSwitch _characterSwitch;
private readonly DropboxQueue _dropboxQueue;
public KitchenSinkPlugin(DalamudPluginInterface pluginInterface, ICommandManager commandManager, public KitchenSinkPlugin(IDalamudPluginInterface pluginInterface, ICommandManager commandManager,
IClientState clientState, IChatGui chatGui, INotificationManager notificationManager, IDtrBar dtrBar, IClientState clientState, IChatGui chatGui, INotificationManager notificationManager, IDtrBar dtrBar,
ICondition condition, IPluginLog pluginLog) ICondition condition, IFramework framework, IPluginLog pluginLog)
{ {
DalamudReflector reflector = new DalamudReflector(pluginInterface, framework, pluginLog);
ECommonsMain.Init(pluginInterface, this); ECommonsMain.Init(pluginInterface, this);
_autoRetainerApi = new AutoRetainerApi(); _autoRetainerApi = new AutoRetainerApi();
_characterSwitch = new CharacterSwitch(_autoRetainerApi, commandManager, clientState, chatGui, _characterSwitch = new CharacterSwitch(_autoRetainerApi, commandManager, clientState, chatGui,
notificationManager, dtrBar, condition, pluginLog); notificationManager, dtrBar, condition, pluginLog);
_dropboxQueue = new DropboxQueue(pluginInterface, reflector, commandManager, chatGui, pluginLog);
} }
public void Dispose() public void Dispose()
{ {
_dropboxQueue.Dispose();
_characterSwitch.Dispose(); _characterSwitch.Dispose();
_autoRetainerApi.Dispose(); _autoRetainerApi.Dispose();
ECommonsMain.Dispose(); ECommonsMain.Dispose();

View File

@ -4,18 +4,92 @@
"net8.0-windows7.0": { "net8.0-windows7.0": {
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[2.1.12, )", "requested": "[2.1.13, )",
"resolved": "2.1.12", "resolved": "2.1.13",
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg==" "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ=="
},
"DotNet.ReproducibleBuilds": {
"type": "Direct",
"requested": "[1.1.1, )",
"resolved": "1.1.1",
"contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==",
"dependencies": {
"Microsoft.SourceLink.AzureRepos.Git": "1.1.1",
"Microsoft.SourceLink.Bitbucket.Git": "1.1.1",
"Microsoft.SourceLink.GitHub": "1.1.1",
"Microsoft.SourceLink.GitLab": "1.1.1"
}
},
"Microsoft.SourceLink.Gitea": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "KOBodmDnlWGIqZt2hT47Q69TIoGhIApDVLCyyj9TT5ct8ju16AbHYcB4XeknoHX562wO1pMS/1DfBIZK+V+sxg==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.SourceLink.AzureRepos.Git": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.Bitbucket.Git": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.GitLab": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
}, },
"autoretainerapi": { "autoretainerapi": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"ECommons": "[2.2.0.1, )" "ECommons": "[2.2.0.2, )"
} }
}, },
"ecommons": { "ecommons": {
"type": "Project" "type": "Project"
},
"llib": {
"type": "Project",
"dependencies": {
"DalamudPackager": "[2.1.13, )"
}
} }
} }
} }

1
LLib Submodule

@ -0,0 +1 @@
Subproject commit 93fac6efb01a1272192d929fd863328271512ea4