feat: add Auto Fishing Stool plugin

This commit is contained in:
2026-08-06 21:32:53 -04:00
commit 1145651366
9 changed files with 256 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
<PropertyGroup>
<Version>1.1.3.0</Version>
<Authors>Bep</Authors>
<Description>Automatically uses /sit after fishing becomes ready.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<IsPackable>false</IsPackable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Content Include="icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,13 @@
{
"Author": "Bep",
"Name": "Auto Fishing Stool",
"Punchline": "Automatically sits after entering fishing mode.",
"Description": "Uses /sit once after fishing becomes active and the current fishing action finishes.",
"ApplicableVersion": "any",
"RepoUrl": "https://git.bep.moe/verniy/xiv-plugins",
"IconUrl": "https://git.bep.moe/verniy/xiv-plugins/raw/branch/main/AutoFishingStool/icon.png",
"Tags": [
"fishing",
"utility"
]
}

152
AutoFishingStool/Plugin.cs Normal file
View File

@@ -0,0 +1,152 @@
using System;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Client.UI;
namespace AutoFishingStool;
public sealed unsafe class Plugin : IDalamudPlugin
{
private const int SitDelayMilliseconds = 2500;
private const int ActionSettleMilliseconds = 500;
private const uint FisherClassJobId = 18;
[PluginService]
internal static ICondition Condition { get; private set; } = null!;
[PluginService]
internal static IFramework Framework { get; private set; } = null!;
[PluginService]
internal static IPlayerState PlayerState { get; private set; } = null!;
[PluginService]
internal static IPluginLog Log { get; private set; } = null!;
private DateTime? sitAt;
private bool satThisSession;
private bool waitingForActionToFinish;
public Plugin()
{
Condition.ConditionChange += OnConditionChange;
Framework.Update += OnFrameworkUpdate;
Log.Information("Auto Fishing Stool loaded");
}
private void OnConditionChange(ConditionFlag flag, bool value)
{
if (flag == ConditionFlag.Fishing)
{
Log.Information("Fishing condition changed to {Value}", value);
if (value && Condition[ConditionFlag.Gathering] && IsFisher() && !satThisSession)
{
sitAt = DateTime.UtcNow.AddMilliseconds(SitDelayMilliseconds);
waitingForActionToFinish = false;
Log.Information("Fishing became active; stable Sit timer started");
}
else if (!value && !satThisSession)
{
sitAt = null;
waitingForActionToFinish = false;
Log.Information("Fishing became inactive; stable Sit timer reset");
}
return;
}
if (flag != ConditionFlag.Gathering)
return;
Log.Information("Gathering condition changed to {Value}", value);
if (value)
{
if (!IsFisher())
return;
satThisSession = false;
sitAt = null;
waitingForActionToFinish = false;
Log.Information("Fisher gathering session started");
return;
}
sitAt = null;
satThisSession = false;
waitingForActionToFinish = false;
}
private void OnFrameworkUpdate(IFramework framework)
{
if (satThisSession || sitAt is null)
return;
if (!Condition[ConditionFlag.Gathering] || !Condition[ConditionFlag.Fishing] || !IsFisher())
{
sitAt = null;
satThisSession = false;
waitingForActionToFinish = false;
return;
}
if (DateTime.UtcNow < sitAt.Value)
return;
if (Condition[ConditionFlag.ExecutingGatheringAction])
{
if (!waitingForActionToFinish)
{
waitingForActionToFinish = true;
Log.Information("Sit timer elapsed during a fishing action; waiting for it to finish");
}
return;
}
if (waitingForActionToFinish)
{
waitingForActionToFinish = false;
sitAt = DateTime.UtcNow.AddMilliseconds(ActionSettleMilliseconds);
Log.Information("Fishing action finished; Sit command scheduled after settling");
return;
}
var uiModule = UIModule.Instance();
if (uiModule is null)
{
Log.Warning("Could not access the game's UI module");
sitAt = null;
return;
}
var command = Utf8String.FromString("/sit");
try
{
uiModule->ProcessChatBoxEntry(command);
Log.Information("Submitted /sit after fishing started");
}
finally
{
command->Dtor(true);
}
satThisSession = true;
sitAt = null;
waitingForActionToFinish = false;
}
private static bool IsFisher()
{
return PlayerState.IsLoaded && PlayerState.ClassJob.RowId == FisherClassJobId;
}
public void Dispose()
{
Condition.ConditionChange -= OnConditionChange;
Framework.Update -= OnFrameworkUpdate;
}
}

View File

@@ -0,0 +1,23 @@
# Auto Fishing Stool
Auto Fishing Stool is a small Dalamud plugin that uses `/sit` once after the player enters fishing mode. It waits for fishing to remain active and for any fishing action to finish before sitting.
## Build
From this directory, run:
```powershell
dotnet build
```
The development DLL is produced at `bin/Debug/AutoFishingStool.dll`.
## Load in Dalamud
1. Start Final Fantasy XIV through XIVLauncher with Dalamud enabled.
2. Run `/xlsettings` and open the Experimental tab.
3. Select `bin/Debug/AutoFishingStool.dll` under Dev Plugin Locations.
4. Run `/xlplugins` and open Dev Tools, then Installed Dev Plugins.
5. Enable Auto Fishing Stool.
The development plugin location only needs to be added once. Rebuild the plugin and reload it from the installed development plugins screen after future changes.

BIN
AutoFishingStool/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -0,0 +1,19 @@
{
"version": 1,
"dependencies": {
"net10.0-windows7.0": {
"DalamudPackager": {
"type": "Direct",
"requested": "[15.0.0, )",
"resolved": "15.0.0",
"contentHash": "411vwC8/X8Z/sQ2TI6v3SvOn66xFPeOjFn3Zn+h0d3Ox2t1kFm66AhDvmx/qcMwVrR+Hidxj0dadpQ2dgyXMBQ=="
},
"DotNet.ReproducibleBuilds": {
"type": "Direct",
"requested": "[1.2.39, )",
"resolved": "1.2.39",
"contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg=="
}
}
}
}