feat: stand during spectral currents
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>1.1.3.0</Version>
|
<Version>1.2.0.0</Version>
|
||||||
<Authors>Bep</Authors>
|
<Authors>Bep</Authors>
|
||||||
<Description>Automatically uses /sit after fishing becomes ready.</Description>
|
<Description>Automatically uses /sit while fishing, with an option to stand during Spectral Currents.</Description>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"Author": "Bep",
|
"Author": "Bep",
|
||||||
"Name": "Auto Fishing Stool",
|
"Name": "Auto Fishing Stool",
|
||||||
"Punchline": "Automatically sits after entering fishing mode.",
|
"Punchline": "Automatically sits after entering fishing mode.",
|
||||||
"Description": "Uses /sit once after fishing becomes active and the current fishing action finishes.",
|
"Description": "Automatically uses /sit while fishing, with an option to stand during Spectral Currents.",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"RepoUrl": "https://git.bep.moe/verniy/xiv-plugins",
|
"RepoUrl": "https://git.bep.moe/verniy/xiv-plugins",
|
||||||
"IconUrl": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/AutoFishingStool/icon.png",
|
"IconUrl": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/AutoFishingStool/icon.png",
|
||||||
|
|||||||
10
AutoFishingStool/Configuration.cs
Normal file
10
AutoFishingStool/Configuration.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Dalamud.Configuration;
|
||||||
|
|
||||||
|
namespace AutoFishingStool;
|
||||||
|
|
||||||
|
public sealed class Configuration : IPluginConfiguration
|
||||||
|
{
|
||||||
|
public int Version { get; set; } = 1;
|
||||||
|
|
||||||
|
public bool StandDuringSpectralCurrents { get; set; } = true;
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Configuration;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Event;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
|
|
||||||
@@ -10,10 +14,20 @@ namespace AutoFishingStool;
|
|||||||
|
|
||||||
public sealed unsafe class Plugin : IDalamudPlugin
|
public sealed unsafe class Plugin : IDalamudPlugin
|
||||||
{
|
{
|
||||||
|
private enum PostureAction
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Sit,
|
||||||
|
Stand,
|
||||||
|
}
|
||||||
|
|
||||||
private const int SitDelayMilliseconds = 2500;
|
private const int SitDelayMilliseconds = 2500;
|
||||||
private const int ActionSettleMilliseconds = 500;
|
private const int ActionSettleMilliseconds = 500;
|
||||||
private const uint FisherClassJobId = 18;
|
private const uint FisherClassJobId = 18;
|
||||||
|
|
||||||
|
[PluginService]
|
||||||
|
internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
|
|
||||||
[PluginService]
|
[PluginService]
|
||||||
internal static ICondition Condition { get; private set; } = null!;
|
internal static ICondition Condition { get; private set; } = null!;
|
||||||
|
|
||||||
@@ -26,14 +40,25 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
[PluginService]
|
[PluginService]
|
||||||
internal static IPluginLog Log { get; private set; } = null!;
|
internal static IPluginLog Log { get; private set; } = null!;
|
||||||
|
|
||||||
private DateTime? sitAt;
|
private readonly Configuration configuration;
|
||||||
private bool satThisSession;
|
private DateTime? postureAt;
|
||||||
|
private PostureAction pendingPosture;
|
||||||
|
private bool satByPlugin;
|
||||||
|
private bool stoodForSpectral;
|
||||||
|
private bool spectralCurrentActive;
|
||||||
private bool waitingForActionToFinish;
|
private bool waitingForActionToFinish;
|
||||||
|
private bool configWindowOpen;
|
||||||
|
|
||||||
public Plugin()
|
public Plugin()
|
||||||
{
|
{
|
||||||
|
configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
|
spectralCurrentActive = IsSpectralCurrentActive();
|
||||||
|
|
||||||
Condition.ConditionChange += OnConditionChange;
|
Condition.ConditionChange += OnConditionChange;
|
||||||
Framework.Update += OnFrameworkUpdate;
|
Framework.Update += OnFrameworkUpdate;
|
||||||
|
PluginInterface.UiBuilder.Draw += DrawConfigWindow;
|
||||||
|
PluginInterface.UiBuilder.OpenConfigUi += OpenConfigWindow;
|
||||||
|
PluginInterface.UiBuilder.OpenMainUi += OpenConfigWindow;
|
||||||
Log.Information("Auto Fishing Stool loaded");
|
Log.Information("Auto Fishing Stool loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,16 +68,14 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
Log.Information("Fishing condition changed to {Value}", value);
|
Log.Information("Fishing condition changed to {Value}", value);
|
||||||
|
|
||||||
if (value && Condition[ConditionFlag.Gathering] && IsFisher() && !satThisSession)
|
if (value && Condition[ConditionFlag.Gathering] && IsFisher() && !satByPlugin && !ShouldStandForSpectral())
|
||||||
{
|
{
|
||||||
sitAt = DateTime.UtcNow.AddMilliseconds(SitDelayMilliseconds);
|
SchedulePosture(PostureAction.Sit, SitDelayMilliseconds);
|
||||||
waitingForActionToFinish = false;
|
|
||||||
Log.Information("Fishing became active; stable Sit timer started");
|
Log.Information("Fishing became active; stable Sit timer started");
|
||||||
}
|
}
|
||||||
else if (!value && !satThisSession)
|
else if (!value && !satByPlugin)
|
||||||
{
|
{
|
||||||
sitAt = null;
|
CancelPendingPosture();
|
||||||
waitingForActionToFinish = false;
|
|
||||||
Log.Information("Fishing became inactive; stable Sit timer reset");
|
Log.Information("Fishing became inactive; stable Sit timer reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,32 +92,44 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
if (!IsFisher())
|
if (!IsFisher())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
satThisSession = false;
|
satByPlugin = false;
|
||||||
sitAt = null;
|
stoodForSpectral = false;
|
||||||
waitingForActionToFinish = false;
|
CancelPendingPosture();
|
||||||
Log.Information("Fisher gathering session started");
|
Log.Information("Fisher gathering session started");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sitAt = null;
|
satByPlugin = false;
|
||||||
satThisSession = false;
|
stoodForSpectral = false;
|
||||||
waitingForActionToFinish = false;
|
CancelPendingPosture();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFrameworkUpdate(IFramework framework)
|
private void OnFrameworkUpdate(IFramework framework)
|
||||||
{
|
{
|
||||||
if (satThisSession || sitAt is null)
|
UpdateSpectralCurrentState();
|
||||||
|
|
||||||
|
if (pendingPosture == PostureAction.None || postureAt is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!Condition[ConditionFlag.Gathering] || !Condition[ConditionFlag.Fishing] || !IsFisher())
|
if (!Condition[ConditionFlag.Gathering] || !Condition[ConditionFlag.Fishing] || !IsFisher())
|
||||||
{
|
{
|
||||||
sitAt = null;
|
CancelPendingPosture();
|
||||||
satThisSession = false;
|
|
||||||
waitingForActionToFinish = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DateTime.UtcNow < sitAt.Value)
|
if (pendingPosture == PostureAction.Sit && ShouldStandForSpectral())
|
||||||
|
{
|
||||||
|
CancelPendingPosture();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingPosture == PostureAction.Stand && !ShouldStandForSpectral())
|
||||||
|
{
|
||||||
|
CancelPendingPosture();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DateTime.UtcNow < postureAt.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Condition[ConditionFlag.ExecutingGatheringAction])
|
if (Condition[ConditionFlag.ExecutingGatheringAction])
|
||||||
@@ -111,16 +146,18 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
if (waitingForActionToFinish)
|
if (waitingForActionToFinish)
|
||||||
{
|
{
|
||||||
waitingForActionToFinish = false;
|
waitingForActionToFinish = false;
|
||||||
sitAt = DateTime.UtcNow.AddMilliseconds(ActionSettleMilliseconds);
|
postureAt = DateTime.UtcNow.AddMilliseconds(ActionSettleMilliseconds);
|
||||||
Log.Information("Fishing action finished; Sit command scheduled after settling");
|
Log.Information("Fishing action finished; posture command scheduled after settling");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var completedPosture = pendingPosture;
|
||||||
|
|
||||||
var uiModule = UIModule.Instance();
|
var uiModule = UIModule.Instance();
|
||||||
if (uiModule is null)
|
if (uiModule is null)
|
||||||
{
|
{
|
||||||
Log.Warning("Could not access the game's UI module");
|
Log.Warning("Could not access the game's UI module");
|
||||||
sitAt = null;
|
CancelPendingPosture();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,17 +165,142 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
uiModule->ProcessChatBoxEntry(command);
|
uiModule->ProcessChatBoxEntry(command);
|
||||||
Log.Information("Submitted /sit after fishing started");
|
Log.Information("Submitted /sit to {Posture}", completedPosture);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
command->Dtor(true);
|
command->Dtor(true);
|
||||||
}
|
}
|
||||||
satThisSession = true;
|
|
||||||
sitAt = null;
|
if (completedPosture == PostureAction.Sit)
|
||||||
|
{
|
||||||
|
satByPlugin = true;
|
||||||
|
stoodForSpectral = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
satByPlugin = false;
|
||||||
|
stoodForSpectral = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CancelPendingPosture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSpectralCurrentState()
|
||||||
|
{
|
||||||
|
var active = IsSpectralCurrentActive();
|
||||||
|
if (active == spectralCurrentActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spectralCurrentActive = active;
|
||||||
|
Log.Information("Spectral Current changed to {Value}", active);
|
||||||
|
|
||||||
|
if (!configuration.StandDuringSpectralCurrents)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
if (pendingPosture == PostureAction.Sit)
|
||||||
|
CancelPendingPosture();
|
||||||
|
|
||||||
|
if (satByPlugin)
|
||||||
|
SchedulePosture(PostureAction.Stand, 0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stoodForSpectral && Condition[ConditionFlag.Gathering] && Condition[ConditionFlag.Fishing] && IsFisher())
|
||||||
|
SchedulePosture(PostureAction.Sit, ActionSettleMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsSpectralCurrentActive()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var eventFramework = EventFramework.Instance();
|
||||||
|
var oceanFishing = eventFramework is null ? null : eventFramework->GetInstanceContentOceanFishing();
|
||||||
|
return oceanFishing is not null && oceanFishing->SpectralCurrentActive;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Log.Warning(exception, "Could not read Ocean Fishing state");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldStandForSpectral()
|
||||||
|
{
|
||||||
|
return configuration.StandDuringSpectralCurrents && spectralCurrentActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SchedulePosture(PostureAction posture, int delayMilliseconds)
|
||||||
|
{
|
||||||
|
pendingPosture = posture;
|
||||||
|
postureAt = DateTime.UtcNow.AddMilliseconds(delayMilliseconds);
|
||||||
waitingForActionToFinish = false;
|
waitingForActionToFinish = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CancelPendingPosture()
|
||||||
|
{
|
||||||
|
pendingPosture = PostureAction.None;
|
||||||
|
postureAt = null;
|
||||||
|
waitingForActionToFinish = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenConfigWindow()
|
||||||
|
{
|
||||||
|
configWindowOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawConfigWindow()
|
||||||
|
{
|
||||||
|
if (!configWindowOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(430, 0), ImGuiCond.FirstUseEver);
|
||||||
|
if (!ImGui.Begin("Auto Fishing Stool Settings###AutoFishingStoolSettings", ref configWindowOpen, ImGuiWindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGui.End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var standDuringSpectralCurrents = configuration.StandDuringSpectralCurrents;
|
||||||
|
if (ImGui.Checkbox("Stand during Spectral Currents", ref standDuringSpectralCurrents))
|
||||||
|
{
|
||||||
|
configuration.StandDuringSpectralCurrents = standDuringSpectralCurrents;
|
||||||
|
PluginInterface.SavePluginConfig(configuration);
|
||||||
|
ApplySpectralSettingChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TextWrapped("Stand while a Spectral Current is active, then sit again when it ends.");
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Text($"Spectral Current detected: {(spectralCurrentActive ? "Yes" : "No")}");
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySpectralSettingChange()
|
||||||
|
{
|
||||||
|
if (!spectralCurrentActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (configuration.StandDuringSpectralCurrents)
|
||||||
|
{
|
||||||
|
if (pendingPosture == PostureAction.Sit)
|
||||||
|
CancelPendingPosture();
|
||||||
|
|
||||||
|
if (satByPlugin)
|
||||||
|
SchedulePosture(PostureAction.Stand, 0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingPosture == PostureAction.Stand)
|
||||||
|
CancelPendingPosture();
|
||||||
|
|
||||||
|
if (stoodForSpectral && Condition[ConditionFlag.Gathering] && Condition[ConditionFlag.Fishing] && IsFisher())
|
||||||
|
SchedulePosture(PostureAction.Sit, ActionSettleMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsFisher()
|
private static bool IsFisher()
|
||||||
{
|
{
|
||||||
return PlayerState.IsLoaded && PlayerState.ClassJob.RowId == FisherClassJobId;
|
return PlayerState.IsLoaded && PlayerState.ClassJob.RowId == FisherClassJobId;
|
||||||
@@ -148,5 +310,8 @@ public sealed unsafe class Plugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
Condition.ConditionChange -= OnConditionChange;
|
Condition.ConditionChange -= OnConditionChange;
|
||||||
Framework.Update -= OnFrameworkUpdate;
|
Framework.Update -= OnFrameworkUpdate;
|
||||||
|
PluginInterface.UiBuilder.Draw -= DrawConfigWindow;
|
||||||
|
PluginInterface.UiBuilder.OpenConfigUi -= OpenConfigWindow;
|
||||||
|
PluginInterface.UiBuilder.OpenMainUi -= OpenConfigWindow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
"Author": "Bep",
|
"Author": "Bep",
|
||||||
"Name": "Auto Fishing Stool",
|
"Name": "Auto Fishing Stool",
|
||||||
"InternalName": "AutoFishingStool",
|
"InternalName": "AutoFishingStool",
|
||||||
"AssemblyVersion": "1.1.3.0",
|
"AssemblyVersion": "1.2.0.0",
|
||||||
"TestingAssemblyVersion": null,
|
"TestingAssemblyVersion": null,
|
||||||
"Description": "Uses /sit once after fishing becomes active and the current fishing action finishes.",
|
"Description": "Automatically uses /sit while fishing, with an option to stand during Spectral Currents.",
|
||||||
"Punchline": "Automatically sits after entering fishing mode.",
|
"Punchline": "Automatically sits after entering fishing mode.",
|
||||||
"RepoUrl": "https://git.bep.moe/verniy/xiv-plugins",
|
"RepoUrl": "https://git.bep.moe/verniy/xiv-plugins",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
"IsTestingExclusive": false,
|
"IsTestingExclusive": false,
|
||||||
"DownloadLinkInstall": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/repo/AutoFishingStool/latest.zip",
|
"DownloadLinkInstall": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/repo/AutoFishingStool/latest.zip",
|
||||||
"DownloadLinkUpdate": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/repo/AutoFishingStool/latest.zip",
|
"DownloadLinkUpdate": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/repo/AutoFishingStool/latest.zip",
|
||||||
"LastUpdate": "1786068591",
|
"LastUpdate": "1786130579",
|
||||||
"IconUrl": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/AutoFishingStool/icon.png",
|
"IconUrl": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/AutoFishingStool/icon.png",
|
||||||
"Tags": [
|
"Tags": [
|
||||||
"fishing",
|
"fishing",
|
||||||
"utility"
|
"utility"
|
||||||
],
|
],
|
||||||
"Changelog": "Initial custom repository release."
|
"Changelog": "Add a setting to stand during Spectral Currents and sit again afterward."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user