2023-10-01 20:50:21 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
using System.Linq;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
using Dalamud.Game.Addon.Lifecycle;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
using Dalamud.Game.ClientState.Conditions;
|
|
|
|
|
using Dalamud.Game.Command;
|
|
|
|
|
using Dalamud.Interface.Windowing;
|
|
|
|
|
using Dalamud.Plugin;
|
2023-10-04 22:07:36 +00:00
|
|
|
|
using Dalamud.Plugin.Services;
|
2024-03-22 21:32:49 +00:00
|
|
|
|
using ImGuiNET;
|
2023-11-01 09:51:53 +00:00
|
|
|
|
using LLib;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
using Workshoppa.External;
|
|
|
|
|
using Workshoppa.GameData;
|
|
|
|
|
using Workshoppa.Windows;
|
|
|
|
|
|
|
|
|
|
namespace Workshoppa;
|
|
|
|
|
|
2024-03-20 18:52:54 +00:00
|
|
|
|
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
2023-10-01 20:50:21 +00:00
|
|
|
|
public sealed partial class WorkshopPlugin : IDalamudPlugin
|
|
|
|
|
{
|
2023-11-01 09:51:53 +00:00
|
|
|
|
private readonly IReadOnlyList<uint> _fabricationStationIds =
|
|
|
|
|
new uint[] { 2005236, 2005238, 2005240, 2007821, 2011588 }.AsReadOnly();
|
|
|
|
|
|
2023-10-05 19:56:12 +00:00
|
|
|
|
internal readonly IReadOnlyList<ushort> WorkshopTerritories = new ushort[] { 423, 424, 425, 653, 984 }.AsReadOnly();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
private readonly WindowSystem _windowSystem = new WindowSystem(nameof(WorkshopPlugin));
|
|
|
|
|
|
2024-07-04 10:04:50 +00:00
|
|
|
|
private readonly IDalamudPluginInterface _pluginInterface;
|
2023-10-04 22:07:36 +00:00
|
|
|
|
private readonly IGameGui _gameGui;
|
|
|
|
|
private readonly IFramework _framework;
|
|
|
|
|
private readonly ICondition _condition;
|
|
|
|
|
private readonly IClientState _clientState;
|
|
|
|
|
private readonly IObjectTable _objectTable;
|
|
|
|
|
private readonly ICommandManager _commandManager;
|
|
|
|
|
private readonly IPluginLog _pluginLog;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
private readonly IAddonLifecycle _addonLifecycle;
|
2023-10-30 00:44:42 +00:00
|
|
|
|
private readonly IChatGui _chatGui;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
|
|
|
|
private readonly Configuration _configuration;
|
2023-10-19 18:46:01 +00:00
|
|
|
|
private readonly ExternalPluginHandler _externalPluginHandler;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
private readonly WorkshopCache _workshopCache;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
private readonly GameStrings _gameStrings;
|
|
|
|
|
|
2023-10-01 20:50:21 +00:00
|
|
|
|
private readonly MainWindow _mainWindow;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
private readonly ConfigWindow _configWindow;
|
|
|
|
|
private readonly RepairKitWindow _repairKitWindow;
|
2023-10-24 22:19:42 +00:00
|
|
|
|
private readonly CeruleumTankWindow _ceruleumTankWindow;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
|
|
|
|
private Stage _currentStageInternal = Stage.Stopped;
|
|
|
|
|
private DateTime _continueAt = DateTime.MinValue;
|
2023-10-19 18:46:01 +00:00
|
|
|
|
private DateTime _fallbackAt = DateTime.MaxValue;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
2024-07-04 10:04:50 +00:00
|
|
|
|
public WorkshopPlugin(IDalamudPluginInterface pluginInterface, IGameGui gameGui, IFramework framework,
|
2023-10-04 22:07:36 +00:00
|
|
|
|
ICondition condition, IClientState clientState, IObjectTable objectTable, IDataManager dataManager,
|
2023-11-01 09:51:53 +00:00
|
|
|
|
ICommandManager commandManager, IPluginLog pluginLog, IAddonLifecycle addonLifecycle, IChatGui chatGui,
|
|
|
|
|
ITextureProvider textureProvider)
|
2023-10-01 20:50:21 +00:00
|
|
|
|
{
|
|
|
|
|
_pluginInterface = pluginInterface;
|
|
|
|
|
_gameGui = gameGui;
|
|
|
|
|
_framework = framework;
|
|
|
|
|
_condition = condition;
|
|
|
|
|
_clientState = clientState;
|
|
|
|
|
_objectTable = objectTable;
|
|
|
|
|
_commandManager = commandManager;
|
2023-10-04 22:07:36 +00:00
|
|
|
|
_pluginLog = pluginLog;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_addonLifecycle = addonLifecycle;
|
2023-10-30 00:44:42 +00:00
|
|
|
|
_chatGui = chatGui;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
2023-11-07 19:07:22 +00:00
|
|
|
|
_externalPluginHandler = new ExternalPluginHandler(_pluginInterface, _pluginLog);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration();
|
2023-10-04 22:07:36 +00:00
|
|
|
|
_workshopCache = new WorkshopCache(dataManager, _pluginLog);
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_gameStrings = new(dataManager, _pluginLog);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
2023-11-01 09:51:53 +00:00
|
|
|
|
_mainWindow = new(this, _pluginInterface, _clientState, _configuration, _workshopCache,
|
2024-07-12 16:33:10 +00:00
|
|
|
|
new IconCache(textureProvider), _chatGui, new RecipeTree(dataManager, _pluginLog), _pluginLog);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_windowSystem.AddWindow(_mainWindow);
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_configWindow = new(_pluginInterface, _configuration);
|
|
|
|
|
_windowSystem.AddWindow(_configWindow);
|
2023-11-09 10:46:26 +00:00
|
|
|
|
_repairKitWindow = new(this, _pluginLog, _gameGui, addonLifecycle, _configuration,
|
2023-11-01 09:51:53 +00:00
|
|
|
|
_externalPluginHandler);
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_windowSystem.AddWindow(_repairKitWindow);
|
2023-11-09 10:46:26 +00:00
|
|
|
|
_ceruleumTankWindow = new(this, _pluginLog, _gameGui, addonLifecycle, _configuration,
|
2024-05-11 11:56:39 +00:00
|
|
|
|
_externalPluginHandler, _chatGui);
|
2023-10-24 22:19:42 +00:00
|
|
|
|
_windowSystem.AddWindow(_ceruleumTankWindow);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
|
|
|
|
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
2023-10-11 09:05:16 +00:00
|
|
|
|
_pluginInterface.UiBuilder.OpenMainUi += OpenMainUi;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_framework.Update += FrameworkUpdate;
|
2023-10-04 22:07:36 +00:00
|
|
|
|
_commandManager.AddHandler("/ws", new CommandInfo(ProcessCommand)
|
|
|
|
|
{
|
|
|
|
|
HelpMessage = "Open UI"
|
|
|
|
|
});
|
2024-05-11 11:56:39 +00:00
|
|
|
|
_commandManager.AddHandler("/workshoppa", new CommandInfo(ProcessCommand)
|
|
|
|
|
{
|
|
|
|
|
ShowInHelp = false,
|
|
|
|
|
});
|
|
|
|
|
_commandManager.AddHandler("/buy-tanks", new CommandInfo(ProcessBuyCommand)
|
|
|
|
|
{
|
|
|
|
|
HelpMessage = "Buy a given number of ceruleum tank stacks.",
|
|
|
|
|
});
|
|
|
|
|
_commandManager.AddHandler("/fill-tanks", new CommandInfo(ProcessFillCommand)
|
|
|
|
|
{
|
|
|
|
|
HelpMessage = "Fill your inventory with a given number of ceruleum tank stacks.",
|
|
|
|
|
});
|
2023-10-13 20:08:22 +00:00
|
|
|
|
|
|
|
|
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup);
|
2023-10-19 18:46:01 +00:00
|
|
|
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "Request", RequestPostSetup);
|
|
|
|
|
_addonLifecycle.RegisterListener(AddonEvent.PostRefresh, "Request", RequestPostRefresh);
|
|
|
|
|
_addonLifecycle.RegisterListener(AddonEvent.PostUpdate, "ContextIconMenu", ContextIconMenuPostReceiveEvent);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal Stage CurrentStage
|
|
|
|
|
{
|
|
|
|
|
get => _currentStageInternal;
|
|
|
|
|
private set
|
|
|
|
|
{
|
|
|
|
|
if (_currentStageInternal != value)
|
|
|
|
|
{
|
2023-10-19 18:46:01 +00:00
|
|
|
|
_pluginLog.Debug($"Changing stage from {_currentStageInternal} to {value}");
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_currentStageInternal = value;
|
|
|
|
|
}
|
2024-03-22 21:32:49 +00:00
|
|
|
|
|
|
|
|
|
if (value != Stage.Stopped)
|
|
|
|
|
_mainWindow.Flags |= ImGuiWindowFlags.NoCollapse;
|
|
|
|
|
else
|
|
|
|
|
_mainWindow.Flags &= ~ImGuiWindowFlags.NoCollapse;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-04 22:07:36 +00:00
|
|
|
|
private void FrameworkUpdate(IFramework framework)
|
2023-10-01 20:50:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (!_clientState.IsLoggedIn ||
|
2023-10-05 19:56:12 +00:00
|
|
|
|
!WorkshopTerritories.Contains(_clientState.TerritoryType) ||
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_condition[ConditionFlag.BoundByDuty] ||
|
2023-10-14 14:26:06 +00:00
|
|
|
|
_condition[ConditionFlag.BetweenAreas] ||
|
|
|
|
|
_condition[ConditionFlag.BetweenAreas51] ||
|
2023-10-24 22:19:42 +00:00
|
|
|
|
GetDistanceToEventObject(_fabricationStationIds, out var fabricationStation) >= 3f)
|
2023-10-01 20:50:21 +00:00
|
|
|
|
{
|
|
|
|
|
_mainWindow.NearFabricationStation = false;
|
2023-10-11 09:05:16 +00:00
|
|
|
|
|
|
|
|
|
if (_mainWindow.IsOpen &&
|
|
|
|
|
_mainWindow.OpenReason == MainWindow.EOpenReason.NearFabricationStation &&
|
|
|
|
|
_configuration.CurrentlyCraftedItem == null &&
|
|
|
|
|
_configuration.ItemQueue.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
_mainWindow.IsOpen = false;
|
|
|
|
|
}
|
2023-10-01 20:50:21 +00:00
|
|
|
|
}
|
|
|
|
|
else if (DateTime.Now >= _continueAt)
|
|
|
|
|
{
|
|
|
|
|
_mainWindow.NearFabricationStation = true;
|
|
|
|
|
|
2023-10-11 09:05:16 +00:00
|
|
|
|
if (!_mainWindow.IsOpen)
|
|
|
|
|
{
|
|
|
|
|
_mainWindow.IsOpen = true;
|
|
|
|
|
_mainWindow.OpenReason = MainWindow.EOpenReason.NearFabricationStation;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-01 20:50:21 +00:00
|
|
|
|
if (_mainWindow.State is MainWindow.ButtonState.Pause or MainWindow.ButtonState.Stop)
|
|
|
|
|
{
|
|
|
|
|
_mainWindow.State = MainWindow.ButtonState.None;
|
|
|
|
|
if (CurrentStage != Stage.Stopped)
|
|
|
|
|
{
|
2023-10-19 18:46:01 +00:00
|
|
|
|
_externalPluginHandler.Restore();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
CurrentStage = Stage.Stopped;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-11-01 09:51:53 +00:00
|
|
|
|
else if (_mainWindow.State is MainWindow.ButtonState.Start or MainWindow.ButtonState.Resume &&
|
|
|
|
|
CurrentStage == Stage.Stopped)
|
2023-10-01 20:50:21 +00:00
|
|
|
|
{
|
2023-10-04 22:57:44 +00:00
|
|
|
|
// TODO Error checking, we should ensure the player has the required job level for *all* crafting parts
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_mainWindow.State = MainWindow.ButtonState.None;
|
|
|
|
|
CurrentStage = Stage.TakeItemFromQueue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-19 18:46:01 +00:00
|
|
|
|
if (CurrentStage != Stage.Stopped && CurrentStage != Stage.RequestStop && !_externalPluginHandler.Saved)
|
|
|
|
|
_externalPluginHandler.Save();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
|
|
|
|
switch (CurrentStage)
|
|
|
|
|
{
|
|
|
|
|
case Stage.TakeItemFromQueue:
|
2023-10-04 22:57:44 +00:00
|
|
|
|
if (CheckContinueWithDelivery())
|
|
|
|
|
CurrentStage = Stage.ContributeMaterials;
|
|
|
|
|
else
|
|
|
|
|
TakeItemFromQueue();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.TargetFabricationStation:
|
2023-11-01 09:51:53 +00:00
|
|
|
|
if (_configuration.CurrentlyCraftedItem is { StartedCrafting: true })
|
|
|
|
|
CurrentStage = Stage.SelectCraftBranch;
|
|
|
|
|
else
|
|
|
|
|
CurrentStage = Stage.OpenCraftingLog;
|
2023-10-19 18:46:01 +00:00
|
|
|
|
|
2023-11-01 09:51:53 +00:00
|
|
|
|
InteractWithFabricationStation(fabricationStation!);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.OpenCraftingLog:
|
2023-10-19 19:18:51 +00:00
|
|
|
|
OpenCraftingLog();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.SelectCraftCategory:
|
|
|
|
|
SelectCraftCategory();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.SelectCraft:
|
|
|
|
|
SelectCraft();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.ConfirmCraft:
|
|
|
|
|
ConfirmCraft();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.RequestStop:
|
2023-10-19 18:46:01 +00:00
|
|
|
|
_externalPluginHandler.Restore();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
CurrentStage = Stage.Stopped;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.SelectCraftBranch:
|
|
|
|
|
SelectCraftBranch();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.ContributeMaterials:
|
|
|
|
|
ContributeMaterials();
|
|
|
|
|
break;
|
|
|
|
|
|
2023-10-19 18:46:01 +00:00
|
|
|
|
case Stage.OpenRequestItemWindow:
|
|
|
|
|
// see RequestPostSetup and related
|
|
|
|
|
if (DateTime.Now > _fallbackAt)
|
|
|
|
|
goto case Stage.ContributeMaterials;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.OpenRequestItemSelect:
|
|
|
|
|
case Stage.ConfirmRequestItemWindow:
|
|
|
|
|
// see RequestPostSetup and related
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
2023-10-01 20:50:21 +00:00
|
|
|
|
case Stage.ConfirmMaterialDelivery:
|
2023-10-19 18:46:01 +00:00
|
|
|
|
// see SelectYesNoPostSetup
|
2023-10-01 20:50:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.ConfirmCollectProduct:
|
2023-10-19 19:18:51 +00:00
|
|
|
|
// see SelectYesNoPostSetup
|
2023-10-01 20:50:21 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Stage.Stopped:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2023-10-04 22:07:36 +00:00
|
|
|
|
_pluginLog.Warning($"Unknown stage {CurrentStage}");
|
2023-10-01 20:50:21 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private WorkshopCraft GetCurrentCraft()
|
|
|
|
|
{
|
2023-11-01 09:51:53 +00:00
|
|
|
|
return _workshopCache.Crafts.Single(
|
|
|
|
|
x => x.WorkshopItemId == _configuration.CurrentlyCraftedItem!.WorkshopItemId);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-11 09:05:16 +00:00
|
|
|
|
private void ProcessCommand(string command, string arguments)
|
2023-10-13 20:08:22 +00:00
|
|
|
|
{
|
|
|
|
|
if (arguments is "c" or "config")
|
|
|
|
|
_configWindow.Toggle();
|
|
|
|
|
else
|
|
|
|
|
_mainWindow.Toggle(MainWindow.EOpenReason.Command);
|
|
|
|
|
}
|
2023-10-11 09:05:16 +00:00
|
|
|
|
|
2024-05-11 11:56:39 +00:00
|
|
|
|
private void ProcessBuyCommand(string command, string arguments)
|
|
|
|
|
{
|
|
|
|
|
if (_ceruleumTankWindow.TryParseBuyRequest(arguments, out int missingQuantity))
|
|
|
|
|
_ceruleumTankWindow.StartPurchase(missingQuantity);
|
|
|
|
|
else
|
|
|
|
|
_chatGui.PrintError($"Usage: {command} <stacks>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ProcessFillCommand(string command, string arguments)
|
|
|
|
|
{
|
|
|
|
|
if (_ceruleumTankWindow.TryParseFillRequest(arguments, out int missingQuantity))
|
|
|
|
|
_ceruleumTankWindow.StartPurchase(missingQuantity);
|
|
|
|
|
else
|
|
|
|
|
_chatGui.PrintError($"Usage: {command} <stacks>");
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-11 09:05:16 +00:00
|
|
|
|
private void OpenMainUi()
|
|
|
|
|
=> _mainWindow.Toggle(MainWindow.EOpenReason.PluginInstaller);
|
2023-10-01 20:50:21 +00:00
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2023-10-19 18:46:01 +00:00
|
|
|
|
_addonLifecycle.UnregisterListener(AddonEvent.PostUpdate, "ContextIconMenu", ContextIconMenuPostReceiveEvent);
|
|
|
|
|
_addonLifecycle.UnregisterListener(AddonEvent.PostRefresh, "Request", RequestPostRefresh);
|
|
|
|
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "Request", RequestPostSetup);
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup);
|
2024-05-11 11:56:39 +00:00
|
|
|
|
_commandManager.RemoveHandler("/fill-tanks");
|
|
|
|
|
_commandManager.RemoveHandler("/buy-tanks");
|
|
|
|
|
_commandManager.RemoveHandler("/workshoppa");
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_commandManager.RemoveHandler("/ws");
|
|
|
|
|
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
|
2023-10-11 09:05:16 +00:00
|
|
|
|
_pluginInterface.UiBuilder.OpenMainUi -= OpenMainUi;
|
2023-10-01 20:50:21 +00:00
|
|
|
|
_framework.Update -= FrameworkUpdate;
|
|
|
|
|
|
2023-10-24 22:19:42 +00:00
|
|
|
|
_ceruleumTankWindow.Dispose();
|
2023-10-13 20:08:22 +00:00
|
|
|
|
_repairKitWindow.Dispose();
|
|
|
|
|
|
2023-10-19 18:46:01 +00:00
|
|
|
|
_externalPluginHandler.RestoreTextAdvance();
|
|
|
|
|
_externalPluginHandler.Restore();
|
2023-10-01 20:50:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|