Polishing

master
Liza 2023-10-05 00:57:44 +02:00
parent 76d5db1542
commit c0106709ac
Signed by: liza
GPG Key ID: 7199F8D727D55F67
5 changed files with 165 additions and 21 deletions

View File

@ -1,5 +1,8 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Configuration; using Dalamud.Configuration;
using Workshoppa.GameData;
namespace Workshoppa; namespace Workshoppa;
@ -20,6 +23,55 @@ internal sealed class Configuration : IPluginConfiguration
{ {
public uint WorkshopItemId { get; set; } public uint WorkshopItemId { get; set; }
public bool StartedCrafting { get; set; } public bool StartedCrafting { get; set; }
public bool FinishedCrafting { get; set; }
public uint PhasesComplete { get; set; } = 0;
public List<PhaseItem> ContributedItemsInCurrentPhase { get; set; } = new();
public bool UpdateFromCraftState(CraftState craftState)
{
bool changed = false;
if (PhasesComplete != craftState.StepsComplete)
{
PhasesComplete = craftState.StepsComplete;
changed = true;
}
if (ContributedItemsInCurrentPhase.Count != craftState.Items.Count)
{
ContributedItemsInCurrentPhase = craftState.Items.Select(x => new PhaseItem
{
ItemId = x.ItemId,
QuantityComplete = x.QuantityComplete,
}).ToList();
changed = true;
}
else
{
for (int i = 0; i < ContributedItemsInCurrentPhase.Count; ++i)
{
var contributedItem = ContributedItemsInCurrentPhase[i];
var craftItem = craftState.Items[i];
if (contributedItem.ItemId != craftItem.ItemId)
{
contributedItem.ItemId = craftItem.ItemId;
changed = true;
}
if (contributedItem.QuantityComplete != craftItem.QuantityComplete)
{
contributedItem.QuantityComplete = craftItem.QuantityComplete;
changed = true;
}
}
}
return changed;
}
}
internal sealed class PhaseItem
{
public uint ItemId { get; set; }
public uint QuantityComplete { get; set; }
} }
} }

View File

@ -14,4 +14,6 @@ public class CraftItem
public uint StepsTotal { get; set; } public uint StepsTotal { get; set; }
public bool Finished { get; set; } public bool Finished { get; set; }
public uint CrafterMinimumLevel { get; set; } public uint CrafterMinimumLevel { get; set; }
public uint QuantityComplete => StepsComplete * ItemCountPerStep;
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
@ -44,7 +45,7 @@ internal sealed class MainWindow : Window
Flags = ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoCollapse; Flags = ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoCollapse;
} }
public bool NearFabricationStation { get; set; } = false; public bool NearFabricationStation { get; set; }
public ButtonState State { get; set; } = ButtonState.None; public ButtonState State { get; set; } = ButtonState.None;
public bool IsDiscipleOfHand => public bool IsDiscipleOfHand =>
@ -60,7 +61,7 @@ internal sealed class MainWindow : Window
if (_plugin.CurrentStage == Stage.Stopped) if (_plugin.CurrentStage == Stage.Stopped)
{ {
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Search, "Check Material")) if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Search, "Check Inventory"))
ImGui.OpenPopup(nameof(CheckMaterial)); ImGui.OpenPopup(nameof(CheckMaterial));
ImGui.SameLine(); ImGui.SameLine();
@ -109,7 +110,7 @@ internal sealed class MainWindow : Window
{ {
ImGui.Text("Currently Crafting: ---"); ImGui.Text("Currently Crafting: ---");
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Search, "Check Material")) if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Search, "Check Inventory"))
ImGui.OpenPopup(nameof(CheckMaterial)); ImGui.OpenPopup(nameof(CheckMaterial));
ImGui.SameLine(); ImGui.SameLine();
@ -200,34 +201,67 @@ internal sealed class MainWindow : Window
private unsafe void CheckMaterial() private unsafe void CheckMaterial()
{ {
if (_configuration.CurrentlyCraftedItem != null) ImGui.Text("Items needed for all crafts in queue:");
ImGui.Text("Items needed for all crafts in queue (not including current in-progress craft):");
else
ImGui.Text("Items needed for all crafts in queue:");
var items = _configuration.ItemQueue List<uint> workshopItemIds = _configuration.ItemQueue
.SelectMany(x => .SelectMany(x => Enumerable.Range(0, x.Quantity).Select(_ => x.WorkshopItemId))
Enumerable.Range(0, x.Quantity).Select(_ => .ToList();
_workshopCache.Crafts.Single(y => y.WorkshopItemId == x.WorkshopItemId))) Dictionary<uint, int> completedForCurrentCraft = new();
var currentItem = _configuration.CurrentlyCraftedItem;
if (currentItem != null)
{
workshopItemIds.Add(currentItem.WorkshopItemId);
var craft = _workshopCache.Crafts.Single(x =>
x.WorkshopItemId == currentItem.WorkshopItemId);
for (int i = 0; i < currentItem.PhasesComplete; ++i)
{
foreach (var item in craft.Phases[i].Items)
AddMaterial(completedForCurrentCraft, item.ItemId, item.TotalQuantity);
}
if (currentItem.PhasesComplete < craft.Phases.Count)
{
foreach (var item in currentItem.ContributedItemsInCurrentPhase)
AddMaterial(completedForCurrentCraft, item.ItemId, (int)item.QuantityComplete);
}
}
var items = workshopItemIds.Select(x => _workshopCache.Crafts.Single(y => y.WorkshopItemId == x))
.SelectMany(x => x.Phases) .SelectMany(x => x.Phases)
.SelectMany(x => x.Items) .SelectMany(x => x.Items)
.GroupBy(x => new { x.Name, x.ItemId }) .GroupBy(x => new { x.Name, x.ItemId })
.OrderBy(x => x.Key.Name); .OrderBy(x => x.Key.Name)
.Select(x => new
{
x.Key.ItemId,
x.Key.Name,
TotalQuantity = completedForCurrentCraft.TryGetValue(x.Key.ItemId, out var completed)
? x.Sum(y => y.TotalQuantity) - completed
: x.Sum(y => y.TotalQuantity),
});
ImGui.Indent(20); ImGui.Indent(20);
InventoryManager* inventoryManager = InventoryManager.Instance(); InventoryManager* inventoryManager = InventoryManager.Instance();
foreach (var item in items) foreach (var item in items)
{ {
int inInventory = inventoryManager->GetInventoryItemCount(item.Key.ItemId, true, false, false) + int inInventory = inventoryManager->GetInventoryItemCount(item.ItemId, true, false, false) +
inventoryManager->GetInventoryItemCount(item.Key.ItemId, false, false, false); inventoryManager->GetInventoryItemCount(item.ItemId, false, false, false);
int required = item.Sum(x => x.TotalQuantity); ImGui.TextColored(inInventory >= item.TotalQuantity ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed,
ImGui.TextColored(inInventory >= required ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed, $"{item.Name} ({inInventory} / {item.TotalQuantity})");
$"{item.Key.Name} ({inInventory} / {required})");
} }
ImGui.Unindent(20); ImGui.Unindent(20);
} }
private void AddMaterial(Dictionary<uint, int> completedForCurrentCraft, uint itemId, int quantity)
{
if (completedForCurrentCraft.TryGetValue(itemId, out var existingQuantity))
completedForCurrentCraft[itemId] = quantity + existingQuantity;
else
completedForCurrentCraft[itemId] = quantity;
}
public enum ButtonState public enum ButtonState
{ {
None, None,

View File

@ -10,6 +10,41 @@ partial class WorkshopPlugin
{ {
private uint? _contributingItemId; private uint? _contributingItemId;
/// <summary>
/// Check if delivery window is open when we clicked resume.
/// </summary>
private unsafe bool CheckContinueWithDelivery()
{
if (_configuration.CurrentlyCraftedItem != null)
{
AtkUnitBase* addonMaterialDelivery = GetMaterialDeliveryAddon();
if (addonMaterialDelivery == null)
return false;
_pluginLog.Warning("Material delivery window is open, although unexpected... checking current craft");
CraftState? craftState = ReadCraftState(addonMaterialDelivery);
if (craftState == null || craftState.ResultItem == 0)
{
_pluginLog.Error("Unable to read craft state");
_continueAt = DateTime.Now.AddSeconds(1);
return false;
}
var craft = _workshopCache.Crafts.SingleOrDefault(x => x.ResultItem == craftState.ResultItem);
if (craft == null || craft.WorkshopItemId != _configuration.CurrentlyCraftedItem.WorkshopItemId)
{
_pluginLog.Error("Unable to match currently crafted item with game state");
_continueAt = DateTime.Now.AddSeconds(1);
return false;
}
_pluginLog.Information("Delivering materials for current active craft, switching to delivery");
return true;
}
return false;
}
private void SelectCraftBranch() private void SelectCraftBranch()
{ {
if (SelectSelectString("contrib", 0, s => s.StartsWith("Contribute materials."))) if (SelectSelectString("contrib", 0, s => s.StartsWith("Contribute materials.")))
@ -20,6 +55,11 @@ partial class WorkshopPlugin
else if (SelectSelectString("advance", 0, s => s.StartsWith("Advance to the next phase of production."))) else if (SelectSelectString("advance", 0, s => s.StartsWith("Advance to the next phase of production.")))
{ {
_pluginLog.Information("Phase is complete"); _pluginLog.Information("Phase is complete");
_configuration.CurrentlyCraftedItem!.PhasesComplete++;
_configuration.CurrentlyCraftedItem!.ContributedItemsInCurrentPhase = new();
_pluginInterface.SavePluginConfig(_configuration);
CurrentStage = Stage.TargetFabricationStation; CurrentStage = Stage.TargetFabricationStation;
_continueAt = DateTime.Now.AddSeconds(3); _continueAt = DateTime.Now.AddSeconds(3);
} }
@ -51,6 +91,12 @@ partial class WorkshopPlugin
return; return;
} }
if (_configuration.CurrentlyCraftedItem!.UpdateFromCraftState(craftState))
{
_pluginLog.Information("Saving updated current craft information");
_pluginInterface.SavePluginConfig(_configuration);
}
for (int i = 0; i < craftState.Items.Count; ++i) for (int i = 0; i < craftState.Items.Count; ++i)
{ {
var item = craftState.Items[i]; var item = craftState.Items[i];
@ -59,7 +105,8 @@ partial class WorkshopPlugin
if (!HasItemInSingleSlot(item.ItemId, item.ItemCountPerStep)) if (!HasItemInSingleSlot(item.ItemId, item.ItemCountPerStep))
{ {
_pluginLog.Error($"Can't contribute item {item.ItemId} to craft, couldn't find {item.ItemCountPerStep}x in a single inventory slot"); _pluginLog.Error(
$"Can't contribute item {item.ItemId} to craft, couldn't find {item.ItemCountPerStep}x in a single inventory slot");
CurrentStage = Stage.RequestStop; CurrentStage = Stage.RequestStop;
break; break;
} }
@ -113,6 +160,11 @@ partial class WorkshopPlugin
} }
else else
{ {
_configuration.CurrentlyCraftedItem!.ContributedItemsInCurrentPhase
.Single(x => x.ItemId == item.ItemId)
.QuantityComplete = item.QuantityComplete;
_pluginInterface.SavePluginConfig(_configuration);
CurrentStage = Stage.ContributeMaterials; CurrentStage = Stage.ContributeMaterials;
_continueAt = DateTime.Now.AddSeconds(1); _continueAt = DateTime.Now.AddSeconds(1);
} }

View File

@ -107,6 +107,7 @@ public sealed partial class WorkshopPlugin : IDalamudPlugin
} }
else if (_mainWindow.State is MainWindow.ButtonState.Start or MainWindow.ButtonState.Resume && CurrentStage == Stage.Stopped) else if (_mainWindow.State is MainWindow.ButtonState.Start or MainWindow.ButtonState.Resume && CurrentStage == Stage.Stopped)
{ {
// TODO Error checking, we should ensure the player has the required job level for *all* crafting parts
_mainWindow.State = MainWindow.ButtonState.None; _mainWindow.State = MainWindow.ButtonState.None;
CurrentStage = Stage.TakeItemFromQueue; CurrentStage = Stage.TakeItemFromQueue;
} }
@ -117,7 +118,10 @@ public sealed partial class WorkshopPlugin : IDalamudPlugin
switch (CurrentStage) switch (CurrentStage)
{ {
case Stage.TakeItemFromQueue: case Stage.TakeItemFromQueue:
TakeItemFromQueue(); if (CheckContinueWithDelivery())
CurrentStage = Stage.ContributeMaterials;
else
TakeItemFromQueue();
break; break;
case Stage.TargetFabricationStation: case Stage.TargetFabricationStation: