2023-10-01 22:50:21 +02:00
using System ;
2023-10-05 00:57:44 +02:00
using System.Collections.Generic ;
2023-10-01 22:50:21 +02:00
using System.Linq ;
using System.Numerics ;
2024-01-19 08:50:53 +01:00
using System.Text ;
2024-01-21 06:46:11 +01:00
using System.Text.RegularExpressions ;
2023-10-01 22:50:21 +02:00
using Dalamud.Interface ;
2023-10-05 00:07:36 +02:00
using Dalamud.Interface.Colors ;
2023-10-01 22:50:21 +02:00
using Dalamud.Interface.Components ;
2024-07-04 12:04:50 +02:00
using Dalamud.Interface.Textures.TextureWraps ;
2023-10-01 22:50:21 +02:00
using Dalamud.Plugin ;
2023-10-05 00:07:36 +02:00
using Dalamud.Plugin.Services ;
using FFXIVClientStructs.FFXIV.Client.Game ;
2023-10-01 22:50:21 +02:00
using ImGuiNET ;
2023-10-11 10:52:48 +02:00
using LLib ;
2024-03-20 19:52:54 +01:00
using LLib.ImGui ;
2023-10-01 22:50:21 +02:00
using Workshoppa.GameData ;
namespace Workshoppa.Windows ;
2023-10-19 20:46:01 +02:00
// FIXME The close button doesn't work near the workshop, either hide it or make it work
2024-05-11 14:02:25 +02:00
internal sealed class MainWindow : LWindow , IPersistableWindowConfig
2023-10-01 22:50:21 +02:00
{
2024-01-21 06:46:11 +01:00
private static readonly Regex CountAndName = new ( @"^(\d{1,5})x?\s+(.*)$" , RegexOptions . Compiled ) ;
2024-01-19 08:50:53 +01:00
2023-10-01 22:50:21 +02:00
private readonly WorkshopPlugin _plugin ;
2024-07-04 12:04:50 +02:00
private readonly IDalamudPluginInterface _pluginInterface ;
2023-10-05 00:07:36 +02:00
private readonly IClientState _clientState ;
2023-10-01 22:50:21 +02:00
private readonly Configuration _configuration ;
private readonly WorkshopCache _workshopCache ;
2023-11-01 10:51:53 +01:00
private readonly IconCache _iconCache ;
2024-01-19 08:50:53 +01:00
private readonly IChatGui _chatGui ;
2024-01-25 08:33:32 +01:00
private readonly RecipeTree _recipeTree ;
2024-01-19 08:50:53 +01:00
private readonly IPluginLog _pluginLog ;
2023-10-01 22:50:21 +02:00
private string _searchString = string . Empty ;
2023-10-19 20:46:01 +02:00
private bool _checkInventory ;
2024-01-19 09:41:04 +01:00
private string _newPresetName = string . Empty ;
2023-10-01 22:50:21 +02:00
2024-07-04 12:04:50 +02:00
public MainWindow ( WorkshopPlugin plugin , IDalamudPluginInterface pluginInterface , IClientState clientState ,
2024-01-19 08:50:53 +01:00
Configuration configuration , WorkshopCache workshopCache , IconCache iconCache , IChatGui chatGui ,
2024-01-25 08:33:32 +01:00
RecipeTree recipeTree , IPluginLog pluginLog )
2023-10-01 22:50:21 +02:00
: base ( "Workshoppa###WorkshoppaMainWindow" )
{
_plugin = plugin ;
_pluginInterface = pluginInterface ;
2023-10-01 23:50:08 +02:00
_clientState = clientState ;
2023-10-01 22:50:21 +02:00
_configuration = configuration ;
_workshopCache = workshopCache ;
2023-11-01 10:51:53 +01:00
_iconCache = iconCache ;
2024-01-19 08:50:53 +01:00
_chatGui = chatGui ;
2024-01-25 08:33:32 +01:00
_recipeTree = recipeTree ;
2024-01-19 08:50:53 +01:00
_pluginLog = pluginLog ;
2023-10-01 22:50:21 +02:00
Position = new Vector2 ( 100 , 100 ) ;
PositionCondition = ImGuiCond . FirstUseEver ;
SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new Vector2 ( 350 , 50 ) ,
2023-10-30 01:44:42 +01:00
MaximumSize = new Vector2 ( 500 , 9999 ) ,
2023-10-01 22:50:21 +02:00
} ;
2024-03-22 22:32:49 +01:00
Flags = ImGuiWindowFlags . AlwaysAutoResize | ImGuiWindowFlags . MenuBar ;
2023-11-09 11:46:26 +01:00
AllowClickthrough = false ;
2023-10-01 22:50:21 +02:00
}
2023-10-11 11:05:16 +02:00
public EOpenReason OpenReason { get ; set ; } = EOpenReason . None ;
2023-10-05 00:57:44 +02:00
public bool NearFabricationStation { get ; set ; }
2023-10-01 22:50:21 +02:00
public ButtonState State { get ; set ; } = ButtonState . None ;
2023-10-30 01:44:42 +01:00
private bool IsDiscipleOfHand = >
2023-10-01 23:50:08 +02:00
_clientState . LocalPlayer ! = null & & _clientState . LocalPlayer . ClassJob . Id is > = 8 and < = 15 ;
2024-05-11 14:02:25 +02:00
public WindowConfig WindowConfig = > _configuration . MainWindowConfig ;
2023-10-01 22:50:21 +02:00
public override void Draw ( )
{
2024-01-19 09:41:04 +01:00
if ( ImGui . BeginMenuBar ( ) )
{
ImGui . BeginDisabled ( _plugin . CurrentStage ! = Stage . Stopped ) ;
DrawPresetsMenu ( ) ;
DrawClipboardMenu ( ) ;
ImGui . EndDisabled ( ) ;
ImGui . EndMenuBar ( ) ;
}
2023-10-01 22:50:21 +02:00
var currentItem = _configuration . CurrentlyCraftedItem ;
if ( currentItem ! = null )
{
var currentCraft = _workshopCache . Crafts . Single ( x = > x . WorkshopItemId = = currentItem . WorkshopItemId ) ;
2023-11-01 10:51:53 +01:00
ImGui . Text ( $"Currently Crafting:" ) ;
IDalamudTextureWrap ? icon = _iconCache . GetIcon ( currentCraft . IconId ) ;
if ( icon ! = null )
{
2024-03-27 19:21:41 +01:00
ImGui . Image ( icon . ImGuiHandle , new Vector2 ( ImGui . GetFrameHeight ( ) ) ) ;
ImGui . SameLine ( 0 , ImGui . GetStyle ( ) . ItemInnerSpacing . X ) ;
ImGui . SetCursorPosY ( ImGui . GetCursorPosY ( ) + ( ImGui . GetFrameHeight ( ) - ImGui . GetTextLineHeight ( ) ) / 2 ) ;
2023-11-01 10:51:53 +01:00
}
ImGui . TextUnformatted ( $"{currentCraft.Name}" ) ;
ImGui . Spacing ( ) ;
2023-10-01 22:50:21 +02:00
if ( _plugin . CurrentStage = = Stage . Stopped )
{
2023-10-05 00:57:44 +02:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Search , "Check Inventory" ) )
2023-10-19 20:46:01 +02:00
_checkInventory = ! _checkInventory ;
2023-10-05 00:07:36 +02:00
ImGui . SameLine ( ) ;
2024-03-28 14:36:20 +01:00
ImGui . BeginDisabled ( ! NearFabricationStation | | ! IsDiscipleOfHand ) ;
2023-10-01 22:50:21 +02:00
if ( currentItem . StartedCrafting )
{
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Play , "Resume" ) )
2023-10-19 20:46:01 +02:00
{
2023-10-01 22:50:21 +02:00
State = ButtonState . Resume ;
2023-10-19 20:46:01 +02:00
_checkInventory = false ;
}
2023-10-01 22:50:21 +02:00
}
else
{
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Play , "Start Crafting" ) )
2023-10-19 20:46:01 +02:00
{
2023-10-01 22:50:21 +02:00
State = ButtonState . Start ;
2023-10-19 20:46:01 +02:00
_checkInventory = false ;
}
2023-10-01 22:50:21 +02:00
}
2023-10-30 01:44:42 +01:00
2023-10-01 23:50:08 +02:00
ImGui . EndDisabled ( ) ;
2023-10-01 22:50:21 +02:00
ImGui . SameLine ( ) ;
2024-03-28 14:36:20 +01:00
bool keysHeld = ImGui . GetIO ( ) . KeyCtrl & & ImGui . GetIO ( ) . KeyShift ;
ImGui . BeginDisabled ( ! keysHeld ) ;
2023-10-01 22:50:21 +02:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Times , "Cancel" ) )
{
State = ButtonState . Pause ;
_configuration . CurrentlyCraftedItem = null ;
Save ( ) ;
}
2023-10-30 01:44:42 +01:00
2023-10-01 22:50:21 +02:00
ImGui . EndDisabled ( ) ;
2024-03-28 14:36:20 +01:00
if ( ImGui . IsItemHovered ( ImGuiHoveredFlags . AllowWhenDisabled ) & & ! keysHeld )
2023-10-01 22:50:21 +02:00
ImGui . SetTooltip (
2024-03-28 14:36:20 +01:00
$"Hold CTRL+SHIFT to remove this as craft. You have to manually use the fabrication station to cancel or finish the workshop project before you can continue using the queue." ) ;
2023-10-05 00:07:36 +02:00
2023-10-05 21:56:12 +02:00
ShowErrorConditions ( ) ;
2023-10-01 22:50:21 +02: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-05 00:57:44 +02:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Search , "Check Inventory" ) )
2023-10-19 20:46:01 +02:00
_checkInventory = ! _checkInventory ;
2023-10-05 00:07:36 +02:00
ImGui . SameLine ( ) ;
2023-10-30 01:44:42 +01:00
ImGui . BeginDisabled ( ! NearFabricationStation | | _configuration . ItemQueue . Sum ( x = > x . Quantity ) = = 0 | |
_plugin . CurrentStage ! = Stage . Stopped | | ! IsDiscipleOfHand ) ;
2023-10-01 22:50:21 +02:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Play , "Start Crafting" ) )
2023-10-19 20:46:01 +02:00
{
2023-10-01 22:50:21 +02:00
State = ButtonState . Start ;
2023-10-19 20:46:01 +02:00
_checkInventory = false ;
}
2023-10-01 22:50:21 +02:00
ImGui . EndDisabled ( ) ;
2023-10-05 00:07:36 +02:00
2023-10-05 21:56:12 +02:00
ShowErrorConditions ( ) ;
2023-10-05 00:07:36 +02:00
}
2023-10-19 20:46:01 +02:00
if ( _checkInventory )
2023-10-05 00:07:36 +02:00
{
2023-10-19 20:46:01 +02:00
ImGui . Separator ( ) ;
2023-10-05 00:07:36 +02:00
CheckMaterial ( ) ;
2023-10-01 22:50:21 +02:00
}
ImGui . Separator ( ) ;
ImGui . Text ( "Queue:" ) ;
2023-10-01 23:33:09 +02:00
ImGui . BeginDisabled ( _plugin . CurrentStage ! = Stage . Stopped ) ;
2023-10-01 23:50:08 +02:00
Configuration . QueuedItem ? itemToRemove = null ;
2023-10-30 01:44:42 +01:00
for ( int i = 0 ; i < _configuration . ItemQueue . Count ; + + i )
2023-10-01 22:50:21 +02:00
{
ImGui . PushID ( $"ItemQueue{i}" ) ;
var item = _configuration . ItemQueue [ i ] ;
var craft = _workshopCache . Crafts . Single ( x = > x . WorkshopItemId = = item . WorkshopItemId ) ;
2023-11-01 10:51:53 +01:00
IDalamudTextureWrap ? icon = _iconCache . GetIcon ( craft . IconId ) ;
if ( icon ! = null )
{
2024-03-27 19:21:41 +01:00
ImGui . Image ( icon . ImGuiHandle , new Vector2 ( ImGui . GetFrameHeight ( ) ) ) ;
ImGui . SameLine ( 0 , ImGui . GetStyle ( ) . ItemInnerSpacing . X ) ;
2023-11-01 10:51:53 +01:00
}
2024-03-27 19:21:41 +01:00
ImGui . SetNextItemWidth ( Math . Max ( 100 * ImGui . GetIO ( ) . FontGlobalScale , 4 * ( ImGui . GetFrameHeight ( ) + ImGui . GetStyle ( ) . FramePadding . X ) ) ) ;
2023-10-01 22:50:21 +02:00
int quantity = item . Quantity ;
if ( ImGui . InputInt ( craft . Name , ref quantity ) )
{
item . Quantity = Math . Max ( 0 , quantity ) ;
Save ( ) ;
}
2023-10-01 23:50:08 +02:00
ImGui . OpenPopupOnItemClick ( $"###Context{i}" ) ;
if ( ImGui . BeginPopupContextItem ( $"###Context{i}" ) )
{
if ( ImGui . MenuItem ( $"Remove {craft.Name}" ) )
itemToRemove = item ;
ImGui . EndPopup ( ) ;
}
2023-10-01 22:50:21 +02:00
ImGui . PopID ( ) ;
}
2023-10-01 23:50:08 +02:00
if ( itemToRemove ! = null )
{
_configuration . ItemQueue . Remove ( itemToRemove ) ;
Save ( ) ;
}
2023-10-01 22:50:21 +02:00
ImGui . SetNextItemWidth ( ImGui . GetContentRegionAvail ( ) . X ) ;
2023-11-01 10:51:53 +01:00
if ( ImGui . BeginCombo ( "##CraftSelection" , "Add Craft..." , ImGuiComboFlags . HeightLarge ) )
2023-10-01 22:50:21 +02:00
{
ImGui . SetNextItemWidth ( ImGui . GetContentRegionAvail ( ) . X ) ;
ImGui . InputTextWithHint ( "" , "Filter..." , ref _searchString , 256 ) ;
foreach ( var craft in _workshopCache . Crafts
2024-03-20 19:52:54 +01:00
. Where ( x = > x . Name . Contains ( _searchString , StringComparison . OrdinalIgnoreCase ) )
2023-10-01 22:50:21 +02:00
. OrderBy ( x = > x . WorkshopItemId ) )
{
2023-11-01 10:51:53 +01:00
IDalamudTextureWrap ? icon = _iconCache . GetIcon ( craft . IconId ) ;
2024-03-27 19:21:41 +01:00
Vector2 pos = ImGui . GetCursorPos ( ) ;
Vector2 iconSize = new Vector2 ( ImGui . GetTextLineHeight ( ) + ImGui . GetStyle ( ) . ItemSpacing . Y ) ;
2023-11-01 10:51:53 +01:00
if ( icon ! = null )
{
2024-03-27 19:21:41 +01:00
ImGui . SetCursorPos ( pos + new Vector2 ( iconSize . X + ImGui . GetStyle ( ) . FramePadding . X , ImGui . GetStyle ( ) . ItemSpacing . Y / 2 ) ) ;
2023-11-01 10:51:53 +01:00
}
2024-01-19 08:50:53 +01:00
2024-03-27 19:21:41 +01:00
if ( ImGui . Selectable ( $"{craft.Name}##SelectCraft{craft.WorkshopItemId}" , false , ImGuiSelectableFlags . SpanAllColumns ) )
2023-10-01 22:50:21 +02:00
{
_configuration . ItemQueue . Add ( new Configuration . QueuedItem
{
WorkshopItemId = craft . WorkshopItemId ,
Quantity = 1 ,
} ) ;
Save ( ) ;
}
2024-03-27 19:21:41 +01:00
if ( icon ! = null )
{
ImGui . SameLine ( 0 , 0 ) ;
ImGui . SetCursorPos ( pos ) ;
ImGui . Image ( icon . ImGuiHandle , iconSize ) ;
}
2023-10-01 22:50:21 +02:00
}
ImGui . EndCombo ( ) ;
}
2023-10-30 01:44:42 +01:00
2023-10-01 23:33:09 +02:00
ImGui . EndDisabled ( ) ;
2023-10-01 22:50:21 +02:00
ImGui . Separator ( ) ;
2023-10-01 23:33:09 +02:00
ImGui . Text ( $"Debug (Stage): {_plugin.CurrentStage}" ) ;
2023-10-01 22:50:21 +02:00
}
2024-01-19 09:41:04 +01:00
private void DrawPresetsMenu ( )
2024-01-19 08:50:53 +01:00
{
2024-01-19 09:41:04 +01:00
if ( ImGui . BeginMenu ( "Presets" ) )
2024-01-19 08:50:53 +01:00
{
2024-01-19 09:41:04 +01:00
if ( _configuration . Presets . Count = = 0 )
{
ImGui . BeginDisabled ( ) ;
ImGui . MenuItem ( "Import Queue from Preset" ) ;
ImGui . EndDisabled ( ) ;
}
else if ( ImGui . BeginMenu ( "Import Queue from Preset" ) )
{
if ( _configuration . Presets . Count = = 0 )
ImGui . MenuItem ( "You have no presets." ) ;
foreach ( var preset in _configuration . Presets )
2024-01-19 08:50:53 +01:00
{
2024-01-19 09:41:04 +01:00
ImGui . PushID ( $"Preset{preset.Id}" ) ;
if ( ImGui . MenuItem ( preset . Name ) )
{
foreach ( var item in preset . ItemQueue )
{
var queuedItem =
_configuration . ItemQueue . FirstOrDefault ( x = > x . WorkshopItemId = = item . WorkshopItemId ) ;
if ( queuedItem ! = null )
queuedItem . Quantity + = item . Quantity ;
else
{
_configuration . ItemQueue . Add ( new Configuration . QueuedItem
{
WorkshopItemId = item . WorkshopItemId ,
Quantity = item . Quantity ,
} ) ;
}
}
Save ( ) ;
_chatGui . Print ( $"Imported {preset.ItemQueue.Count} items from preset." ) ;
}
2024-01-19 08:50:53 +01:00
2024-01-19 09:41:04 +01:00
ImGui . PopID ( ) ;
}
2024-01-19 08:50:53 +01:00
2024-01-19 09:41:04 +01:00
ImGui . EndMenu ( ) ;
}
2024-01-19 08:50:53 +01:00
2024-01-19 09:41:04 +01:00
if ( _configuration . ItemQueue . Count = = 0 )
{
ImGui . BeginDisabled ( ) ;
ImGui . MenuItem ( "Export Queue to Preset" ) ;
ImGui . EndDisabled ( ) ;
}
else if ( ImGui . BeginMenu ( "Export Queue to Preset" ) )
{
ImGui . InputTextWithHint ( "" , "Preset Name..." , ref _newPresetName , 64 ) ;
2024-01-19 08:50:53 +01:00
2024-01-19 09:41:04 +01:00
ImGui . BeginDisabled ( _configuration . Presets . Any ( x = >
2024-03-20 19:52:54 +01:00
x . Name . Equals ( _newPresetName , StringComparison . OrdinalIgnoreCase ) ) ) ;
2024-01-19 09:41:04 +01:00
if ( ImGuiComponents . IconButtonWithText ( FontAwesomeIcon . Save , "Save" ) )
{
_configuration . Presets . Add ( new Configuration . Preset
{
Id = Guid . NewGuid ( ) ,
Name = _newPresetName ,
ItemQueue = _configuration . ItemQueue . Select ( x = > new Configuration . QueuedItem
{
WorkshopItemId = x . WorkshopItemId ,
Quantity = x . Quantity
} ) . ToList ( )
} ) ;
Save ( ) ;
_chatGui . Print ( $"Saved queue as preset '{_newPresetName}'." ) ;
_newPresetName = string . Empty ;
}
ImGui . EndDisabled ( ) ;
ImGui . EndMenu ( ) ;
}
if ( _configuration . Presets . Count = = 0 )
{
ImGui . BeginDisabled ( ) ;
ImGui . MenuItem ( "Delete Preset" ) ;
ImGui . EndDisabled ( ) ;
}
else if ( ImGui . BeginMenu ( "Delete Preset" ) )
2024-01-19 08:50:53 +01:00
{
2024-01-19 09:41:04 +01:00
if ( _configuration . Presets . Count = = 0 )
ImGui . MenuItem ( "You have no presets." ) ;
Guid ? presetToRemove = null ;
foreach ( var preset in _configuration . Presets )
{
ImGui . PushID ( $"Preset{preset.Id}" ) ;
if ( ImGui . MenuItem ( preset . Name ) )
{
presetToRemove = preset . Id ;
}
ImGui . PopID ( ) ;
}
if ( presetToRemove ! = null )
2024-01-19 08:50:53 +01:00
{
2024-01-19 09:41:04 +01:00
var preset = _configuration . Presets . First ( x = > x . Id = = presetToRemove ) ;
_configuration . Presets . Remove ( preset ) ;
Save ( ) ;
_chatGui . Print ( $"Deleted preset '{preset.Name}'." ) ;
2024-01-19 08:50:53 +01:00
}
2024-01-19 09:41:04 +01:00
ImGui . EndMenu ( ) ;
2024-01-19 08:50:53 +01:00
}
2024-01-19 09:41:04 +01:00
ImGui . EndMenu ( ) ;
2024-01-19 08:50:53 +01:00
}
2024-01-19 09:41:04 +01:00
}
2024-01-19 08:50:53 +01:00
2024-01-19 09:41:04 +01:00
private void DrawClipboardMenu ( )
{
if ( ImGui . BeginMenu ( "Clipboard" ) )
2024-01-19 08:50:53 +01:00
{
2024-01-21 06:46:11 +01:00
List < Configuration . QueuedItem > fromClipboardItems = new ( ) ;
2024-01-19 09:41:04 +01:00
try
2024-01-19 08:50:53 +01:00
{
2024-01-19 09:41:04 +01:00
string? clipboardText = GetClipboardText ( ) ;
if ( ! string . IsNullOrWhiteSpace ( clipboardText ) )
2024-01-19 08:50:53 +01:00
{
2024-01-21 06:46:11 +01:00
foreach ( var clipboardLine in clipboardText . ReplaceLineEndings ( ) . Split ( Environment . NewLine ) )
2024-01-19 08:50:53 +01:00
{
2024-01-21 06:46:11 +01:00
var match = CountAndName . Match ( clipboardLine ) ;
if ( ! match . Success )
continue ;
var craft = _workshopCache . Crafts . FirstOrDefault ( x = >
2024-03-20 19:52:54 +01:00
x . Name . Equals ( match . Groups [ 2 ] . Value , StringComparison . OrdinalIgnoreCase ) ) ;
2024-01-21 06:46:11 +01:00
if ( craft ! = null & & int . TryParse ( match . Groups [ 1 ] . Value , out int quantity ) )
{
fromClipboardItems . Add ( new Configuration . QueuedItem
{
WorkshopItemId = craft . WorkshopItemId ,
Quantity = quantity ,
} ) ;
}
2024-01-19 09:41:04 +01:00
}
}
}
catch ( Exception )
{
//_pluginLog.Warning(e, "Unable to extract clipboard text");
}
ImGui . BeginDisabled ( fromClipboardItems . Count = = 0 ) ;
if ( ImGui . MenuItem ( "Import Queue from Clipboard" ) )
{
_pluginLog . Information ( $"Importing {fromClipboardItems.Count} items..." ) ;
int count = 0 ;
foreach ( var item in fromClipboardItems )
{
2024-01-21 06:46:11 +01:00
var queuedItem =
_configuration . ItemQueue . FirstOrDefault ( x = > x . WorkshopItemId = = item . WorkshopItemId ) ;
if ( queuedItem ! = null )
queuedItem . Quantity + = item . Quantity ;
else
2024-01-19 09:41:04 +01:00
{
2024-01-21 06:46:11 +01:00
_configuration . ItemQueue . Add ( new Configuration . QueuedItem
2024-01-19 08:50:53 +01:00
{
2024-01-21 06:46:11 +01:00
WorkshopItemId = item . WorkshopItemId ,
Quantity = item . Quantity ,
} ) ;
2024-01-19 08:50:53 +01:00
}
2024-01-21 06:46:11 +01:00
+ + count ;
2024-01-19 08:50:53 +01:00
}
2024-01-19 09:41:04 +01:00
Save ( ) ;
_chatGui . Print ( $"Imported {count} items from clipboard." ) ;
2024-01-19 08:50:53 +01:00
}
2024-01-19 09:41:04 +01:00
ImGui . EndDisabled ( ) ;
2024-01-19 08:50:53 +01:00
2024-01-19 09:41:04 +01:00
ImGui . BeginDisabled ( _configuration . ItemQueue . Count = = 0 ) ;
if ( ImGui . MenuItem ( "Export Queue to Clipboard" ) )
{
2024-01-21 06:46:11 +01:00
var toClipboardItems = _configuration . ItemQueue . Select ( x = >
new
{
_workshopCache . Crafts . Single ( y = > x . WorkshopItemId = = y . WorkshopItemId ) . Name ,
x . Quantity
} )
. Select ( x = > $"{x.Quantity}x {x.Name}" ) ;
ImGui . SetClipboardText ( string . Join ( Environment . NewLine , toClipboardItems ) ) ;
2024-01-19 09:41:04 +01:00
_chatGui . Print ( "Copied queue content to clipboard." ) ;
}
2024-01-25 08:33:32 +01:00
if ( ImGui . MenuItem ( "Export Material List to Clipboard" ) )
{
var toClipboardItems = _recipeTree . ResolveRecipes ( GetMaterialList ( ) ) . Where ( x = > x . Type = = Ingredient . EType . Craftable ) ;
ImGui . SetClipboardText ( string . Join ( Environment . NewLine , toClipboardItems . Select ( x = > $"{x.TotalQuantity}x {x.Name}" ) ) ) ;
_chatGui . Print ( "Copied material list to clipboard." ) ;
}
if ( ImGui . MenuItem ( "Export Gathered/Venture materials to Clipboard" ) )
{
var toClipboardItems = _recipeTree . ResolveRecipes ( GetMaterialList ( ) ) . Where ( x = > x . Type = = Ingredient . EType . Gatherable ) ;
ImGui . SetClipboardText ( string . Join ( Environment . NewLine , toClipboardItems . Select ( x = > $"{x.TotalQuantity}x {x.Name}" ) ) ) ;
_chatGui . Print ( "Copied material list to clipboard." ) ;
}
2024-01-19 09:41:04 +01:00
ImGui . EndDisabled ( ) ;
ImGui . EndMenu ( ) ;
}
2024-01-19 08:50:53 +01:00
}
/// <summary>
/// The default implementation for <see cref="ImGui.GetClipboardText"/> throws an NullReferenceException if the clipboard is empty, maybe also if it doesn't contain text.
/// </summary>
private unsafe string? GetClipboardText ( )
{
byte * ptr = ImGuiNative . igGetClipboardText ( ) ;
if ( ptr = = null )
return null ;
int byteCount = 0 ;
while ( ptr [ byteCount ] ! = 0 )
+ + byteCount ;
return Encoding . UTF8 . GetString ( ptr , byteCount ) ;
}
2023-10-01 22:50:21 +02:00
private void Save ( )
{
_pluginInterface . SavePluginConfig ( _configuration ) ;
}
2023-10-11 11:05:16 +02:00
public void Toggle ( EOpenReason reason )
{
if ( ! IsOpen )
{
IsOpen = true ;
OpenReason = reason ;
}
else
IsOpen = false ;
}
public override void OnClose ( )
{
OpenReason = EOpenReason . None ;
}
2023-10-05 00:07:36 +02:00
private unsafe void CheckMaterial ( )
{
2023-10-05 00:57:44 +02:00
ImGui . Text ( "Items needed for all crafts in queue:" ) ;
2024-01-25 08:33:32 +01:00
var items = GetMaterialList ( ) ;
ImGui . Indent ( 20 ) ;
InventoryManager * inventoryManager = InventoryManager . Instance ( ) ;
foreach ( var item in items )
{
int inInventory = inventoryManager - > GetInventoryItemCount ( item . ItemId , true , false , false ) +
inventoryManager - > GetInventoryItemCount ( item . ItemId , false , false , false ) ;
IDalamudTextureWrap ? icon = _iconCache . GetIcon ( item . IconId ) ;
if ( icon ! = null )
{
2024-03-27 19:21:41 +01:00
ImGui . Image ( icon . ImGuiHandle , new Vector2 ( ImGui . GetFrameHeight ( ) ) ) ;
ImGui . SameLine ( 0 , ImGui . GetStyle ( ) . ItemInnerSpacing . X ) ;
ImGui . SetCursorPosY ( ImGui . GetCursorPosY ( ) + ( ImGui . GetFrameHeight ( ) - ImGui . GetTextLineHeight ( ) ) / 2 ) ;
2024-07-04 12:04:50 +02:00
icon . Dispose ( ) ;
2024-01-25 08:33:32 +01:00
}
ImGui . TextColored ( inInventory > = item . TotalQuantity ? ImGuiColors . HealerGreen : ImGuiColors . DalamudRed ,
$"{item.Name} ({inInventory} / {item.TotalQuantity})" ) ;
}
2023-10-05 00:57:44 +02:00
2024-01-25 08:33:32 +01:00
ImGui . Unindent ( 20 ) ;
}
private List < Ingredient > GetMaterialList ( )
{
2023-10-05 00:57:44 +02:00
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-05 00:07:36 +02:00
2023-10-05 00:57:44 +02: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 ) ;
}
}
2024-01-25 08:33:32 +01:00
return workshopItemIds . Select ( x = > _workshopCache . Crafts . Single ( y = > y . WorkshopItemId = = x ) )
2023-10-05 00:07:36 +02:00
. SelectMany ( x = > x . Phases )
. SelectMany ( x = > x . Items )
2023-11-01 10:51:53 +01:00
. GroupBy ( x = > new { x . Name , x . ItemId , x . IconId } )
2023-10-05 00:57:44 +02:00
. OrderBy ( x = > x . Key . Name )
2024-01-25 08:33:32 +01:00
. Select ( x = > new Ingredient
2023-10-05 00:57:44 +02:00
{
2024-01-25 08:33:32 +01:00
ItemId = x . Key . ItemId ,
IconId = x . Key . IconId ,
Name = x . Key . Name ,
2023-10-05 00:57:44 +02:00
TotalQuantity = completedForCurrentCraft . TryGetValue ( x . Key . ItemId , out var completed )
? x . Sum ( y = > y . TotalQuantity ) - completed
: x . Sum ( y = > y . TotalQuantity ) ,
2024-01-25 08:33:32 +01:00
Type = Ingredient . EType . Craftable ,
} )
. ToList ( ) ;
2023-10-05 00:07:36 +02:00
}
2024-03-20 19:52:54 +01:00
private static void AddMaterial ( Dictionary < uint , int > completedForCurrentCraft , uint itemId , int quantity )
2023-10-05 00:57:44 +02:00
{
if ( completedForCurrentCraft . TryGetValue ( itemId , out var existingQuantity ) )
completedForCurrentCraft [ itemId ] = quantity + existingQuantity ;
else
completedForCurrentCraft [ itemId ] = quantity ;
}
2023-10-05 21:56:12 +02:00
private void ShowErrorConditions ( )
{
if ( ! _plugin . WorkshopTerritories . Contains ( _clientState . TerritoryType ) )
ImGui . TextColored ( ImGuiColors . DalamudRed , "You are not in the Company Workshop." ) ;
else if ( ! NearFabricationStation )
2024-02-04 09:43:03 +01:00
ImGui . TextColored ( ImGuiColors . DalamudRed , "You are not near a Fabrication Station." ) ;
2023-10-05 21:56:12 +02:00
if ( ! IsDiscipleOfHand )
ImGui . TextColored ( ImGuiColors . DalamudRed , "You need to be a Disciple of the Hand to start crafting." ) ;
}
2024-05-11 14:02:25 +02:00
public void SaveWindowConfig ( ) = > Save ( ) ;
2023-10-01 22:50:21 +02:00
public enum ButtonState
{
None ,
Start ,
Resume ,
Pause ,
Stop ,
}
2023-10-11 11:05:16 +02:00
public enum EOpenReason
{
None ,
Command ,
NearFabricationStation ,
PluginInstaller ,
}
2023-10-01 22:50:21 +02:00
}