diff --git a/Deliveroo/DeliverooPlugin.cs b/Deliveroo/DeliverooPlugin.cs index b2c0b5a..3fa358e 100644 --- a/Deliveroo/DeliverooPlugin.cs +++ b/Deliveroo/DeliverooPlugin.cs @@ -14,6 +14,7 @@ using Dalamud.Interface.Windowing; using Dalamud.Logging; using Dalamud.Memory; using Dalamud.Plugin; +using Deliveroo.External; using Deliveroo.GameData; using Deliveroo.Windows; using FFXIVClientStructs.FFXIV.Client.Game; @@ -44,15 +45,20 @@ public sealed class DeliverooPlugin : IDalamudPlugin // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly Configuration _configuration; + // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable + private readonly YesAlreadyIpc _yesAlreadyIpc; + // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly GcRewardsCache _gcRewardsCache; + private readonly ConfigWindow _configWindow; private readonly TurnInWindow _turnInWindow; private readonly IReadOnlyDictionary _sealCaps; - private Stage _currentStageInternal = Stage.Stop; + private Stage _currentStageInternal = Stage.Stopped; private DateTime _continueAt = DateTime.MinValue; private GcRewardItem _selectedRewardItem = GcRewardItem.None; + private (bool Saved, bool? PreviousState) _yesAlreadyState = (false, null); public DeliverooPlugin(DalamudPluginInterface pluginInterface, ChatGui chatGui, GameGui gameGui, Framework framework, ClientState clientState, ObjectTable objectTable, TargetManager targetManager, @@ -66,6 +72,8 @@ public sealed class DeliverooPlugin : IDalamudPlugin _objectTable = objectTable; _targetManager = targetManager; + var dalamudReflector = new DalamudReflector(_pluginInterface, _framework); + _yesAlreadyIpc = new YesAlreadyIpc(dalamudReflector); _configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration(); _gcRewardsCache = new GcRewardsCache(dataManager); _configWindow = new ConfigWindow(_pluginInterface, this, _configuration, _gcRewardsCache); @@ -104,7 +112,11 @@ public sealed class DeliverooPlugin : IDalamudPlugin { _turnInWindow.IsOpen = false; _turnInWindow.State = false; - CurrentStage = Stage.Stop; + if (CurrentStage != Stage.Stopped) + { + RestoreYesAlready(); + CurrentStage = Stage.Stopped; + } } else if (DateTime.Now > _continueAt) { @@ -113,11 +125,15 @@ public sealed class DeliverooPlugin : IDalamudPlugin if (!_turnInWindow.State) { - CurrentStage = Stage.Stop; + if (CurrentStage != Stage.Stopped) + { + RestoreYesAlready(); + CurrentStage = Stage.Stopped; + } + return; } - - if (_turnInWindow.State && CurrentStage == Stage.Stop) + else if (_turnInWindow.State && CurrentStage == Stage.Stopped) { CurrentStage = Stage.TargetPersonnelOfficer; _selectedRewardItem = _turnInWindow.SelectedItem; @@ -136,6 +152,9 @@ public sealed class DeliverooPlugin : IDalamudPlugin CurrentStage = Stage.CloseGcExchange; } + if (CurrentStage != Stage.Stopped && CurrentStage != Stage.RequestStop && !_yesAlreadyState.Saved) + SaveYesAlready(); + switch (CurrentStage) { case Stage.TargetPersonnelOfficer: @@ -238,7 +257,7 @@ public sealed class DeliverooPlugin : IDalamudPlugin if (!_selectedRewardItem.IsValid()) { _turnInWindow.State = false; - CurrentStage = Stage.Stop; + CurrentStage = Stage.RequestStop; } else { @@ -256,13 +275,13 @@ public sealed class DeliverooPlugin : IDalamudPlugin if (!_selectedRewardItem.IsValid()) { _turnInWindow.State = false; - CurrentStage = Stage.Stop; + CurrentStage = Stage.RequestStop; } else if (GetCurrentSealCount() <= _configuration.ReservedSealCount + _selectedRewardItem.SealCost) { _turnInWindow.State = false; - CurrentStage = Stage.Stop; + CurrentStage = Stage.RequestStop; } else { @@ -276,7 +295,7 @@ public sealed class DeliverooPlugin : IDalamudPlugin case Stage.TargetQuartermaster: if (GetCurrentSealCount() < _configuration.ReservedSealCount) { - CurrentStage = Stage.Stop; + CurrentStage = Stage.RequestStop; break; } @@ -381,7 +400,12 @@ public sealed class DeliverooPlugin : IDalamudPlugin break; } - case Stage.Stop: + case Stage.RequestStop: + RestoreYesAlready(); + CurrentStage = Stage.Stopped; + + break; + case Stage.Stopped: break; default: PluginLog.Warning($"Unknown stage {CurrentStage}"); @@ -418,6 +442,8 @@ public sealed class DeliverooPlugin : IDalamudPlugin _pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; _framework.Update -= FrameworkUpdate; + + RestoreYesAlready(); } private unsafe List BuildTurnInList(AgentGrandCompanySupply* agent) @@ -514,7 +540,7 @@ public sealed class DeliverooPlugin : IDalamudPlugin if (toBuy == 0) { _turnInWindow.State = false; - CurrentStage = Stage.Stop; + CurrentStage = Stage.RequestStop; break; } @@ -645,6 +671,30 @@ public sealed class DeliverooPlugin : IDalamudPlugin (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Address, false); } + private void SaveYesAlready() + { + if (_yesAlreadyState.Saved) + { + PluginLog.Information("Not overwriting yesalready state"); + return; + } + + _yesAlreadyState = (true, _yesAlreadyIpc.DisableIfNecessary()); + PluginLog.Information($"Previous yesalready state: {_yesAlreadyState.PreviousState}"); + } + + private void RestoreYesAlready() + { + if (_yesAlreadyState.Saved) + { + PluginLog.Information($"Restoring previous yesalready state: {_yesAlreadyState.PreviousState}"); + if (_yesAlreadyState.PreviousState == true) + _yesAlreadyIpc.Enable(); + } + + _yesAlreadyState = (false, null); + } + internal enum Stage { TargetPersonnelOfficer, @@ -662,6 +712,7 @@ public sealed class DeliverooPlugin : IDalamudPlugin ConfirmReward, CloseGcExchange, - Stop, + RequestStop, + Stopped, } } diff --git a/Deliveroo/External/DalamudReflector.cs b/Deliveroo/External/DalamudReflector.cs new file mode 100644 index 0000000..a147ff5 --- /dev/null +++ b/Deliveroo/External/DalamudReflector.cs @@ -0,0 +1,114 @@ +using Dalamud.Game; +using Dalamud.Logging; + + +using Dalamud.Plugin; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Deliveroo.External; + +/// +/// Originally part of ECommons by NightmareXIV. +/// +/// https://github.com/NightmareXIV/ECommons/blob/master/ECommons/Reflection/DalamudReflector.cs +/// +internal sealed class DalamudReflector : IDisposable +{ + private readonly DalamudPluginInterface _pluginInterface; + private readonly Framework _framework; + private readonly Dictionary _pluginCache = new(); + private bool _pluginsChanged = false; + + public DalamudReflector(DalamudPluginInterface pluginInterface, Framework framework) + { + _pluginInterface = pluginInterface; + _framework = framework; + var pm = GetPluginManager(); + pm.GetType().GetEvent("OnInstalledPluginsChanged")!.AddEventHandler(pm, OnInstalledPluginsChanged); + + _framework.Update += FrameworkUpdate; + } + + public void Dispose() + { + _framework.Update -= FrameworkUpdate; + + var pm = GetPluginManager(); + pm.GetType().GetEvent("OnInstalledPluginsChanged")!.RemoveEventHandler(pm, OnInstalledPluginsChanged); + } + + private void FrameworkUpdate(Framework framework) + { + if (_pluginsChanged) + { + _pluginsChanged = false; + _pluginCache.Clear(); + } + } + + private object GetPluginManager() + { + return _pluginInterface.GetType().Assembly.GetType("Dalamud.Service`1", true)! + .MakeGenericType( + _pluginInterface.GetType().Assembly.GetType("Dalamud.Plugin.Internal.PluginManager", true)!) + .GetMethod("Get")!.Invoke(null, BindingFlags.Default, null, Array.Empty(), null)!; + } + + public bool TryGetDalamudPlugin(string internalName, out IDalamudPlugin? instance, bool suppressErrors = false, + bool ignoreCache = false) + { + if (!ignoreCache && _pluginCache.TryGetValue(internalName, out instance)) + { + return true; + } + + try + { + var pluginManager = GetPluginManager(); + var installedPlugins = + (System.Collections.IList)pluginManager.GetType().GetProperty("InstalledPlugins")!.GetValue( + pluginManager)!; + + foreach (var t in installedPlugins) + { + if ((string?)t.GetType().GetProperty("Name")!.GetValue(t) == internalName) + { + var type = t.GetType().Name == "LocalDevPlugin" ? t.GetType().BaseType : t.GetType(); + var plugin = (IDalamudPlugin?)type! + .GetField("instance", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(t); + if (plugin == null) + { + PluginLog.Warning($"[DalamudReflector] Found requested plugin {internalName} but it was null"); + } + else + { + instance = plugin; + _pluginCache[internalName] = plugin; + return true; + } + } + } + + instance = null; + return false; + } + catch (Exception e) + { + if (!suppressErrors) + { + PluginLog.Error(e, $"Can't find {internalName} plugin: {e.Message}"); + } + + instance = null; + return false; + } + } + + private void OnInstalledPluginsChanged() + { + PluginLog.Verbose("Installed plugins changed event fired"); + _pluginsChanged = true; + } +} diff --git a/Deliveroo/External/YesAlreadyIpc.cs b/Deliveroo/External/YesAlreadyIpc.cs new file mode 100644 index 0000000..0de845f --- /dev/null +++ b/Deliveroo/External/YesAlreadyIpc.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using Dalamud.Logging; + +namespace Deliveroo.External; + +internal sealed class YesAlreadyIpc +{ + private readonly DalamudReflector _dalamudReflector; + + public YesAlreadyIpc(DalamudReflector dalamudReflector) + { + _dalamudReflector = dalamudReflector; + } + + private object? GetConfiguration() + { + if (_dalamudReflector.TryGetDalamudPlugin("Yes Already", out var plugin)) + { + var pluginService = plugin!.GetType().Assembly.GetType("YesAlready.Service"); + return pluginService!.GetProperty("Configuration", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null); + } + + return null; + } + + public bool? DisableIfNecessary() + { + object? configuration = GetConfiguration(); + if (configuration == null) + return null; + + var property = configuration.GetType().GetProperty("Enabled")!; + bool enabled = (bool)property.GetValue(configuration)!; + if (enabled) + { + property.SetValue(configuration, false); + return true; + } + + return false; + } + + public void Enable() + { + object? configuration = GetConfiguration(); + if (configuration == null) + return; + + + var property = configuration.GetType().GetProperty("Enabled")!; + property.SetValue(configuration, true); + } +}