Deliveroo/Deliveroo/DeliverooPlugin.cs

364 lines
13 KiB
C#
Raw Normal View History

2023-09-21 13:43:22 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
2023-10-08 15:21:43 +00:00
using Dalamud.Game.Addon.Lifecycle;
2023-09-25 19:36:06 +00:00
using Dalamud.Game.ClientState.Conditions;
2023-09-21 13:43:22 +00:00
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
2023-09-25 19:40:10 +00:00
using Dalamud.Game.Command;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
2023-09-21 13:43:22 +00:00
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
2023-10-04 08:49:39 +00:00
using Dalamud.Plugin.Services;
2023-09-22 19:44:56 +00:00
using Deliveroo.External;
2023-09-21 21:17:46 +00:00
using Deliveroo.GameData;
using Deliveroo.Windows;
2023-09-21 13:43:22 +00:00
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI;
2023-10-11 01:22:02 +00:00
using LLib.GameUI;
using Lumina.Excel.GeneratedSheets;
2023-09-21 13:43:22 +00:00
namespace Deliveroo;
public sealed partial class DeliverooPlugin : IDalamudPlugin
2023-09-21 13:43:22 +00:00
{
private readonly WindowSystem _windowSystem = new(typeof(DeliverooPlugin).AssemblyQualifiedName);
private readonly DalamudPluginInterface _pluginInterface;
2023-10-04 08:49:39 +00:00
private readonly IChatGui _chatGui;
private readonly IGameGui _gameGui;
private readonly IFramework _framework;
private readonly IClientState _clientState;
private readonly IObjectTable _objectTable;
private readonly ITargetManager _targetManager;
private readonly ICondition _condition;
private readonly ICommandManager _commandManager;
private readonly IPluginLog _pluginLog;
2023-10-08 15:21:43 +00:00
private readonly IAddonLifecycle _addonLifecycle;
2023-09-21 13:43:22 +00:00
2023-09-21 21:17:46 +00:00
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly Configuration _configuration;
2023-10-08 15:21:43 +00:00
private readonly GameStrings _gameStrings;
private readonly ExternalPluginHandler _externalPluginHandler;
2023-09-22 19:44:56 +00:00
2023-09-21 21:17:46 +00:00
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly GcRewardsCache _gcRewardsCache;
2023-09-22 19:44:56 +00:00
2023-09-21 21:17:46 +00:00
private readonly ConfigWindow _configWindow;
2023-09-21 13:43:22 +00:00
private readonly TurnInWindow _turnInWindow;
private readonly IReadOnlyDictionary<uint, uint> _sealCaps;
2023-09-21 13:43:22 +00:00
2023-09-22 19:44:56 +00:00
private Stage _currentStageInternal = Stage.Stopped;
2023-09-21 13:43:22 +00:00
private DateTime _continueAt = DateTime.MinValue;
private int _lastTurnInListSize = int.MaxValue;
private uint _turnInErrors = 0;
2023-09-24 10:14:43 +00:00
private List<PurchaseItemRequest> _itemsToPurchaseNow = new();
2023-09-21 13:43:22 +00:00
2023-10-04 08:49:39 +00:00
public DeliverooPlugin(DalamudPluginInterface pluginInterface, IChatGui chatGui, IGameGui gameGui,
IFramework framework, IClientState clientState, IObjectTable objectTable, ITargetManager targetManager,
2023-10-08 15:21:43 +00:00
IDataManager dataManager, ICondition condition, ICommandManager commandManager, IPluginLog pluginLog,
IAddonLifecycle addonLifecycle)
2023-09-21 13:43:22 +00:00
{
_pluginInterface = pluginInterface;
_chatGui = chatGui;
_gameGui = gameGui;
_framework = framework;
_clientState = clientState;
_objectTable = objectTable;
_targetManager = targetManager;
2023-09-25 19:36:06 +00:00
_condition = condition;
2023-09-25 19:40:10 +00:00
_commandManager = commandManager;
2023-10-04 08:49:39 +00:00
_pluginLog = pluginLog;
2023-10-08 15:21:43 +00:00
_addonLifecycle = addonLifecycle;
2023-09-21 13:43:22 +00:00
2023-10-08 15:21:43 +00:00
_gameStrings = new GameStrings(dataManager, _pluginLog);
2023-11-07 19:06:16 +00:00
_externalPluginHandler = new ExternalPluginHandler(_pluginInterface, _pluginLog);
2023-09-21 21:17:46 +00:00
_configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration();
_gcRewardsCache = new GcRewardsCache(dataManager);
2023-10-04 08:49:39 +00:00
_configWindow = new ConfigWindow(_pluginInterface, this, _configuration, _gcRewardsCache, _clientState, _pluginLog);
2023-09-21 21:17:46 +00:00
_windowSystem.AddWindow(_configWindow);
_turnInWindow = new TurnInWindow(this, _pluginInterface, _configuration, _condition, _gcRewardsCache, _configWindow);
2023-09-21 13:43:22 +00:00
_windowSystem.AddWindow(_turnInWindow);
_sealCaps = dataManager.GetExcelSheet<GrandCompanyRank>()!.Where(x => x.RowId > 0)
.ToDictionary(x => x.RowId, x => x.MaxSeals);
2023-09-21 13:43:22 +00:00
_framework.Update += FrameworkUpdate;
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
2023-09-21 21:17:46 +00:00
_pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle;
2023-09-25 20:27:19 +00:00
_clientState.Login += Login;
_clientState.Logout += Logout;
_chatGui.ChatMessage += ChatMessage;
2023-09-25 19:40:10 +00:00
_commandManager.AddHandler("/deliveroo", new CommandInfo(ProcessCommand)
{
HelpMessage = "Open the configuration"
});
2023-09-25 20:27:19 +00:00
if (_clientState.IsLoggedIn)
2023-10-04 08:49:39 +00:00
Login();
if (_configuration.AddVentureIfNoItemToPurchaseSelected())
_pluginInterface.SavePluginConfig(_configuration);
2023-10-08 15:21:43 +00:00
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup);
2023-09-21 13:43:22 +00:00
}
private void ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
{
if (_configuration.PauseAtRank <= 0)
return;
if (type != _gameStrings.RankUpFcType)
return;
var match = _gameStrings.RankUpFc.Match(message.ToString());
if (!match.Success)
return;
foreach (var group in match.Groups.Values)
{
if (int.TryParse(group.Value, out int rank) && rank == _configuration.PauseAtRank)
{
_turnInWindow.State = false;
_pluginLog.Information($"Pausing GC delivery, FC reached rank {rank}");
_chatGui.Print($"Pausing Deliveroo, your FC reached rank {rank}.");
return;
}
}
}
2023-09-25 20:27:19 +00:00
internal CharacterConfiguration? CharacterConfiguration { get; set; }
2023-09-21 21:28:35 +00:00
internal Stage CurrentStage
2023-09-21 13:43:22 +00:00
{
get => _currentStageInternal;
set
{
if (_currentStageInternal != value)
{
2023-10-07 10:13:33 +00:00
_pluginLog.Verbose($"Changing stage from {_currentStageInternal} to {value}");
2023-09-21 13:43:22 +00:00
_currentStageInternal = value;
}
}
}
public int EffectiveReservedSealCount =>
_configuration.ReserveDifferentSealCountAtMaxRank && GetSealCap() == GetMaxSealCap()
? _configuration.ReservedSealCountAtMaxRank
: _configuration.ReservedSealCount;
2023-10-04 08:49:39 +00:00
private void Login()
2023-09-25 20:27:19 +00:00
{
try
{
CharacterConfiguration = CharacterConfiguration.Load(_pluginInterface, _clientState.LocalContentId);
if (CharacterConfiguration != null)
{
if (CharacterConfiguration.CachedPlayerName != _clientState.LocalPlayer!.Name.ToString() ||
CharacterConfiguration.CachedWorldName !=
_clientState.LocalPlayer.HomeWorld.GameData!.Name.ToString())
{
CharacterConfiguration.CachedPlayerName = _clientState.LocalPlayer!.Name.ToString();
CharacterConfiguration.CachedWorldName =
_clientState.LocalPlayer.HomeWorld.GameData!.Name.ToString();
CharacterConfiguration.Save(_pluginInterface);
}
2023-10-04 08:49:39 +00:00
_pluginLog.Information($"Loaded character-specific information for {_clientState.LocalContentId}");
2023-09-25 20:27:19 +00:00
}
else
{
2023-10-04 08:49:39 +00:00
_pluginLog.Verbose(
2023-09-25 20:27:19 +00:00
$"No character-specific information for {_clientState.LocalContentId}");
}
}
catch (Exception ex)
{
2023-10-04 08:49:39 +00:00
_pluginLog.Error(ex, "Unable to load character configuration");
2023-09-25 20:27:19 +00:00
CharacterConfiguration = null;
}
}
2023-10-04 08:49:39 +00:00
private void Logout()
2023-09-25 20:27:19 +00:00
{
CharacterConfiguration = null;
}
2023-10-04 08:49:39 +00:00
private unsafe void FrameworkUpdate(IFramework f)
2023-09-21 13:43:22 +00:00
{
_turnInWindow.Error = string.Empty;
2023-09-25 20:27:19 +00:00
if (!_clientState.IsLoggedIn ||
_clientState.TerritoryType is not 128 and not 130 and not 132 ||
2023-09-25 19:36:06 +00:00
_condition[ConditionFlag.OccupiedInCutSceneEvent] ||
2023-09-21 13:43:22 +00:00
GetDistanceToNpc(GetQuartermasterId(), out GameObject? quartermaster) >= 7f ||
2023-09-21 21:17:46 +00:00
GetDistanceToNpc(GetPersonnelOfficerId(), out GameObject? personnelOfficer) >= 7f ||
2023-09-25 20:27:19 +00:00
CharacterConfiguration is { DisableForCharacter: true } ||
2023-09-21 21:17:46 +00:00
_configWindow.IsOpen)
2023-09-21 13:43:22 +00:00
{
_turnInWindow.IsOpen = false;
2023-09-21 21:17:46 +00:00
_turnInWindow.State = false;
2023-09-22 19:44:56 +00:00
if (CurrentStage != Stage.Stopped)
{
_externalPluginHandler.Restore();
2023-09-22 19:44:56 +00:00
CurrentStage = Stage.Stopped;
}
2023-09-21 13:43:22 +00:00
}
else if (DateTime.Now > _continueAt)
{
_turnInWindow.IsOpen = true;
_turnInWindow.Multiplier = GetSealMultiplier();
if (!_turnInWindow.State)
{
2023-09-22 19:44:56 +00:00
if (CurrentStage != Stage.Stopped)
{
_externalPluginHandler.Restore();
2023-09-22 19:44:56 +00:00
CurrentStage = Stage.Stopped;
}
2023-09-21 13:43:22 +00:00
return;
}
2023-09-22 19:44:56 +00:00
else if (_turnInWindow.State && CurrentStage == Stage.Stopped)
2023-09-21 13:43:22 +00:00
{
CurrentStage = Stage.TargetPersonnelOfficer;
2023-09-24 10:14:43 +00:00
_itemsToPurchaseNow = _turnInWindow.SelectedItems;
if (_itemsToPurchaseNow.Count > 0)
{
2023-10-04 08:49:39 +00:00
_pluginLog.Information("Items to purchase:");
2023-09-24 10:14:43 +00:00
foreach (var item in _itemsToPurchaseNow)
2023-10-04 08:49:39 +00:00
_pluginLog.Information($" {item.Name} (limit = {item.EffectiveLimit})");
2023-09-24 10:14:43 +00:00
}
else
2023-10-04 08:49:39 +00:00
_pluginLog.Information("No items to purchase configured or available");
2023-09-21 21:17:46 +00:00
2023-09-24 10:14:43 +00:00
var nextItem = GetNextItemToPurchase();
if (nextItem != null && GetCurrentSealCount() >= EffectiveReservedSealCount + nextItem.SealCost)
2023-09-21 18:18:05 +00:00
CurrentStage = Stage.TargetQuartermaster;
2023-10-11 01:22:02 +00:00
if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyList>("GrandCompanySupplyList", out var gcSupplyList) &&
LAddon.IsAddonReady(&gcSupplyList->AtkUnitBase))
CurrentStage = Stage.SelectExpertDeliveryTab;
2023-09-21 18:18:05 +00:00
2023-10-11 01:22:02 +00:00
if (_gameGui.TryGetAddonByName<AtkUnitBase>("GrandCompanyExchange", out var gcExchange) &&
LAddon.IsAddonReady(gcExchange))
2023-09-24 10:14:43 +00:00
CurrentStage = Stage.SelectRewardTier;
2023-09-21 13:43:22 +00:00
}
if (CurrentStage != Stage.Stopped && CurrentStage != Stage.RequestStop && !_externalPluginHandler.Saved)
_externalPluginHandler.Save();
2023-09-22 19:44:56 +00:00
2023-09-21 13:43:22 +00:00
switch (CurrentStage)
{
case Stage.TargetPersonnelOfficer:
InteractWithPersonnelOfficer(personnelOfficer!, quartermaster!);
2023-09-21 13:43:22 +00:00
break;
2023-09-21 13:43:22 +00:00
case Stage.OpenGcSupply:
2023-10-08 15:21:43 +00:00
// see SelectStringPostSetup
break;
2023-09-21 13:43:22 +00:00
case Stage.SelectExpertDeliveryTab:
SelectExpertDeliveryTab();
2023-09-21 13:43:22 +00:00
break;
case Stage.SelectItemToTurnIn:
SelectItemToTurnIn();
2023-09-21 13:43:22 +00:00
break;
case Stage.TurnInSelected:
TurnInSelectedItem();
2023-09-21 13:43:22 +00:00
break;
case Stage.FinalizeTurnIn:
FinalizeTurnInItem();
2023-09-21 13:43:22 +00:00
break;
case Stage.CloseGcSupply:
2023-10-08 15:21:43 +00:00
// see SelectStringPostSetup
2023-09-21 13:43:22 +00:00
break;
case Stage.CloseGcSupplyThenStop:
2023-10-08 15:21:43 +00:00
// see SelectStringPostSetup
2023-09-21 13:43:22 +00:00
break;
case Stage.TargetQuartermaster:
InteractWithQuartermaster(personnelOfficer!, quartermaster!);
2023-09-21 13:43:22 +00:00
break;
2023-09-21 21:17:46 +00:00
case Stage.SelectRewardTier:
SelectRewardTier();
2023-09-21 13:43:22 +00:00
break;
2023-09-21 21:17:46 +00:00
case Stage.SelectRewardSubCategory:
SelectRewardSubCategory();
2023-09-21 13:43:22 +00:00
break;
case Stage.SelectReward:
SelectReward();
2023-09-21 13:43:22 +00:00
break;
2023-09-21 18:18:05 +00:00
case Stage.ConfirmReward:
2023-10-08 15:21:43 +00:00
// see SelectYesNoPostSetup
2023-09-21 18:18:05 +00:00
break;
2023-09-21 13:43:22 +00:00
case Stage.CloseGcExchange:
CloseGcExchange();
2023-09-21 13:43:22 +00:00
break;
2023-09-22 19:44:56 +00:00
case Stage.RequestStop:
_externalPluginHandler.Restore();
2023-09-22 19:44:56 +00:00
CurrentStage = Stage.Stopped;
break;
case Stage.Stopped:
2023-09-21 13:43:22 +00:00
break;
2023-10-01 21:52:24 +00:00
2023-09-21 13:43:22 +00:00
default:
2023-10-04 08:49:39 +00:00
_pluginLog.Warning($"Unknown stage {CurrentStage}");
2023-09-21 13:43:22 +00:00
break;
}
}
}
public void Dispose()
{
2023-10-08 15:21:43 +00:00
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup);
2023-09-25 19:40:10 +00:00
_commandManager.RemoveHandler("/deliveroo");
_chatGui.ChatMessage -= ChatMessage;
2023-09-25 20:27:19 +00:00
_clientState.Logout -= Logout;
_clientState.Login -= Login;
2023-09-21 21:17:46 +00:00
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
2023-09-21 13:43:22 +00:00
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
_framework.Update -= FrameworkUpdate;
2023-09-22 19:44:56 +00:00
_externalPluginHandler.Restore();
2023-09-21 13:43:22 +00:00
}
private void ProcessCommand(string command, string arguments)
{
switch (arguments)
{
case "e" or "enable":
if (_turnInWindow.IsOpen)
_turnInWindow.State = true;
break;
case "d" or "disable":
_turnInWindow.State = false;
break;
default:
_configWindow.Toggle();
break;
}
}
2023-09-21 13:43:22 +00:00
}