2023-10-01 20:50:21 +00:00
using System ;
2023-10-04 22:57:44 +00:00
using System.Collections.Generic ;
2023-10-01 20:50:21 +00:00
using System.Linq ;
using System.Numerics ;
using Dalamud.Interface ;
2023-10-04 22:07:36 +00:00
using Dalamud.Interface.Colors ;
2023-10-01 20:50:21 +00:00
using Dalamud.Interface.Components ;
using Dalamud.Interface.Windowing ;
using Dalamud.Plugin ;
2023-10-04 22:07:36 +00:00
using Dalamud.Plugin.Services ;
using FFXIVClientStructs.FFXIV.Client.Game ;
2023-10-01 20:50:21 +00:00
using ImGuiNET ;
2023-10-11 08:52:48 +00:00
using LLib ;
2023-10-01 20:50:21 +00:00
using Workshoppa.GameData ;
namespace Workshoppa.Windows ;
internal sealed class MainWindow : Window
{
private readonly WorkshopPlugin _plugin ;
private readonly DalamudPluginInterface _pluginInterface ;
2023-10-04 22:07:36 +00:00
private readonly IClientState _clientState ;
2023-10-01 20:50:21 +00:00
private readonly Configuration _configuration ;
private readonly WorkshopCache _workshopCache ;
private string _searchString = string . Empty ;
2023-10-04 22:07:36 +00:00
public MainWindow ( WorkshopPlugin plugin , DalamudPluginInterface pluginInterface , IClientState clientState , Configuration configuration , WorkshopCache workshopCache )
2023-10-01 20:50:21 +00:00
: base ( "Workshoppa###WorkshoppaMainWindow" )
{
_plugin = plugin ;
_pluginInterface = pluginInterface ;
2023-10-01 21:50:08 +00:00
_clientState = clientState ;
2023-10-01 20:50:21 +00:00
_configuration = configuration ;
_workshopCache = workshopCache ;
Position = new Vector2 ( 100 , 100 ) ;
PositionCondition = ImGuiCond . FirstUseEver ;
SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new Vector2 ( 350 , 50 ) ,
MaximumSize = new Vector2 ( 500 , 500 ) ,
} ;
Flags = ImGuiWindowFlags . AlwaysAutoResize | ImGuiWindowFlags . NoCollapse ;
}
2023-10-11 09:05:16 +00:00
public EOpenReason OpenReason { get ; set ; } = EOpenReason . None ;
2023-10-04 22:57:44 +00:00
public bool NearFabricationStation { get ; set ; }
2023-10-01 20:50:21 +00:00
public ButtonState State { get ; set ; } = ButtonState . None ;
2023-10-01 21:50:08 +00:00
public bool IsDiscipleOfHand = >
_clientState . LocalPlayer ! = null & & _clientState . LocalPlayer . ClassJob . Id is > = 8 and < = 15 ;
2023-10-01 20:50:21 +00:00
public override void Draw ( )
{
2023-10-11 08:52:48 +00:00
LImGui . AddPatreonIcon ( _pluginInterface ) ;
2023-10-01 20:50:21 +00:00
var currentItem = _configuration . CurrentlyCraftedItem ;
if ( currentItem ! = null )
{
var currentCraft = _workshopCache . Crafts . Single ( x = > x . WorkshopItemId = = currentItem . WorkshopItemId ) ;
ImGui . Text ( $"Currently Crafting: {currentCraft.Name}" ) ;
if ( _plugin . CurrentStage = = Stage . Stopped )
{
2023-10-04 22:57:44 +00:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Search , "Check Inventory" ) )
2023-10-04 22:07:36 +00:00
ImGui . OpenPopup ( nameof ( CheckMaterial ) ) ;
ImGui . SameLine ( ) ;
ImGui . BeginDisabled ( ! NearFabricationStation ) ;
2023-10-01 21:50:08 +00:00
ImGui . BeginDisabled ( ! IsDiscipleOfHand ) ;
2023-10-01 20:50:21 +00:00
if ( currentItem . StartedCrafting )
{
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Play , "Resume" ) )
State = ButtonState . Resume ;
}
else
{
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Play , "Start Crafting" ) )
State = ButtonState . Start ;
}
2023-10-01 21:50:08 +00:00
ImGui . EndDisabled ( ) ;
2023-10-01 20:50:21 +00:00
ImGui . SameLine ( ) ;
ImGui . BeginDisabled ( ! ImGui . GetIO ( ) . KeyCtrl ) ;
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Times , "Cancel" ) )
{
State = ButtonState . Pause ;
_configuration . CurrentlyCraftedItem = null ;
Save ( ) ;
}
ImGui . EndDisabled ( ) ;
if ( ImGui . IsItemHovered ( ImGuiHoveredFlags . AllowWhenDisabled ) & & ! ImGui . GetIO ( ) . KeyCtrl )
ImGui . SetTooltip (
$"Hold CTRL to remove this as craft. You have to manually use the fabrication station to cancel or finish this craft before you can continue using the queue." ) ;
2023-10-04 22:07:36 +00:00
ImGui . EndDisabled ( ) ;
2023-10-05 19:56:12 +00:00
ShowErrorConditions ( ) ;
2023-10-01 20:50:21 +00:00
}
else
{
ImGui . BeginDisabled ( _plugin . CurrentStage = = Stage . RequestStop ) ;
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Pause , "Pause" ) )
State = ButtonState . Pause ;
ImGui . EndDisabled ( ) ;
}
}
else
{
ImGui . Text ( "Currently Crafting: ---" ) ;
2023-10-04 22:57:44 +00:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Search , "Check Inventory" ) )
2023-10-04 22:07:36 +00:00
ImGui . OpenPopup ( nameof ( CheckMaterial ) ) ;
ImGui . SameLine ( ) ;
2023-10-01 21:50:08 +00:00
ImGui . BeginDisabled ( ! NearFabricationStation | | _configuration . ItemQueue . Sum ( x = > x . Quantity ) = = 0 | | _plugin . CurrentStage ! = Stage . Stopped | | ! IsDiscipleOfHand ) ;
2023-10-01 20:50:21 +00:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Play , "Start Crafting" ) )
State = ButtonState . Start ;
ImGui . EndDisabled ( ) ;
2023-10-04 22:07:36 +00:00
2023-10-05 19:56:12 +00:00
ShowErrorConditions ( ) ;
2023-10-04 22:07:36 +00:00
}
if ( ImGui . BeginPopup ( nameof ( CheckMaterial ) ) )
{
CheckMaterial ( ) ;
ImGui . EndPopup ( ) ;
2023-10-01 20:50:21 +00:00
}
ImGui . Separator ( ) ;
ImGui . Text ( "Queue:" ) ;
2023-10-01 21:33:09 +00:00
ImGui . BeginDisabled ( _plugin . CurrentStage ! = Stage . Stopped ) ;
2023-10-01 21:50:08 +00:00
Configuration . QueuedItem ? itemToRemove = null ;
2023-10-01 20:50:21 +00:00
for ( int i = 0 ; i < _configuration . ItemQueue . Count ; + + i )
{
ImGui . PushID ( $"ItemQueue{i}" ) ;
var item = _configuration . ItemQueue [ i ] ;
var craft = _workshopCache . Crafts . Single ( x = > x . WorkshopItemId = = item . WorkshopItemId ) ;
ImGui . SetNextItemWidth ( 100 ) ;
int quantity = item . Quantity ;
if ( ImGui . InputInt ( craft . Name , ref quantity ) )
{
item . Quantity = Math . Max ( 0 , quantity ) ;
Save ( ) ;
}
2023-10-01 21:50:08 +00:00
ImGui . OpenPopupOnItemClick ( $"###Context{i}" ) ;
if ( ImGui . BeginPopupContextItem ( $"###Context{i}" ) )
{
if ( ImGui . MenuItem ( $"Remove {craft.Name}" ) )
itemToRemove = item ;
ImGui . EndPopup ( ) ;
}
2023-10-01 20:50:21 +00:00
ImGui . PopID ( ) ;
}
2023-10-01 21:50:08 +00:00
if ( itemToRemove ! = null )
{
_configuration . ItemQueue . Remove ( itemToRemove ) ;
Save ( ) ;
}
2023-10-01 20:50:21 +00:00
ImGui . SetNextItemWidth ( ImGui . GetContentRegionAvail ( ) . X ) ;
if ( ImGui . BeginCombo ( "##CraftSelection" , "Add Craft..." ) )
{
ImGui . SetNextItemWidth ( ImGui . GetContentRegionAvail ( ) . X ) ;
ImGui . InputTextWithHint ( "" , "Filter..." , ref _searchString , 256 ) ;
foreach ( var craft in _workshopCache . Crafts
. Where ( x = > x . Name . ToLower ( ) . Contains ( _searchString . ToLower ( ) ) )
. OrderBy ( x = > x . WorkshopItemId ) )
{
if ( ImGui . Selectable ( $"{craft.Name}##SelectCraft{craft.WorkshopItemId}" ) )
{
_configuration . ItemQueue . Add ( new Configuration . QueuedItem
{
WorkshopItemId = craft . WorkshopItemId ,
Quantity = 1 ,
} ) ;
Save ( ) ;
}
}
ImGui . EndCombo ( ) ;
}
2023-10-01 21:33:09 +00:00
ImGui . EndDisabled ( ) ;
2023-10-01 20:50:21 +00:00
ImGui . Separator ( ) ;
2023-10-01 21:33:09 +00:00
ImGui . Text ( $"Debug (Stage): {_plugin.CurrentStage}" ) ;
2023-10-01 20:50:21 +00:00
}
private void Save ( )
{
_pluginInterface . SavePluginConfig ( _configuration ) ;
}
2023-10-11 09:05:16 +00:00
public void Toggle ( EOpenReason reason )
{
if ( ! IsOpen )
{
IsOpen = true ;
OpenReason = reason ;
}
else
IsOpen = false ;
}
public override void OnClose ( )
{
OpenReason = EOpenReason . None ;
}
2023-10-04 22:07:36 +00:00
private unsafe void CheckMaterial ( )
{
2023-10-04 22:57:44 +00:00
ImGui . Text ( "Items needed for all crafts in queue:" ) ;
List < uint > workshopItemIds = _configuration . ItemQueue
. SelectMany ( x = > Enumerable . Range ( 0 , x . Quantity ) . Select ( _ = > x . WorkshopItemId ) )
. ToList ( ) ;
Dictionary < uint , int > completedForCurrentCraft = new ( ) ;
var currentItem = _configuration . CurrentlyCraftedItem ;
if ( currentItem ! = null )
{
workshopItemIds . Add ( currentItem . WorkshopItemId ) ;
2023-10-04 22:07:36 +00:00
2023-10-04 22:57:44 +00:00
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 ) )
2023-10-04 22:07:36 +00:00
. SelectMany ( x = > x . Phases )
. SelectMany ( x = > x . Items )
. GroupBy ( x = > new { x . Name , x . ItemId } )
2023-10-04 22:57:44 +00:00
. 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 ) ,
} ) ;
2023-10-04 22:07:36 +00:00
ImGui . Indent ( 20 ) ;
InventoryManager * inventoryManager = InventoryManager . Instance ( ) ;
foreach ( var item in items )
{
2023-10-04 22:57:44 +00:00
int inInventory = inventoryManager - > GetInventoryItemCount ( item . ItemId , true , false , false ) +
inventoryManager - > GetInventoryItemCount ( item . ItemId , false , false , false ) ;
ImGui . TextColored ( inInventory > = item . TotalQuantity ? ImGuiColors . HealerGreen : ImGuiColors . DalamudRed ,
$"{item.Name} ({inInventory} / {item.TotalQuantity})" ) ;
2023-10-04 22:07:36 +00:00
}
ImGui . Unindent ( 20 ) ;
}
2023-10-04 22:57:44 +00:00
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 ;
}
2023-10-05 19:56:12 +00:00
private void ShowErrorConditions ( )
{
if ( ! _plugin . WorkshopTerritories . Contains ( _clientState . TerritoryType ) )
ImGui . TextColored ( ImGuiColors . DalamudRed , "You are not in the Company Workshop." ) ;
else if ( ! NearFabricationStation )
ImGui . TextColored ( ImGuiColors . DalamudRed , "You are not near a Farbrication Station." ) ;
if ( ! IsDiscipleOfHand )
ImGui . TextColored ( ImGuiColors . DalamudRed , "You need to be a Disciple of the Hand to start crafting." ) ;
}
2023-10-01 20:50:21 +00:00
public enum ButtonState
{
None ,
Start ,
Resume ,
Pause ,
Stop ,
}
2023-10-11 09:05:16 +00:00
public enum EOpenReason
{
None ,
Command ,
NearFabricationStation ,
PluginInstaller ,
}
2023-10-01 20:50:21 +00:00
}