commit 11456513666f8b62a3a930d0cbed8041bcf45367 Author: verniy Date: Thu Aug 6 21:32:53 2026 -0400 feat: add Auto Fishing Stool plugin diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..057d471 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +**/bin/ +**/obj/ +.vs/ +*.user diff --git a/AutoFishingStool/AutoFishingStool.csproj b/AutoFishingStool/AutoFishingStool.csproj new file mode 100644 index 0000000..97b8922 --- /dev/null +++ b/AutoFishingStool/AutoFishingStool.csproj @@ -0,0 +1,17 @@ + + + + 1.1.3.0 + Bep + Automatically uses /sit after fishing becomes ready. + MIT + false + true + + + + + PreserveNewest + + + diff --git a/AutoFishingStool/AutoFishingStool.json b/AutoFishingStool/AutoFishingStool.json new file mode 100644 index 0000000..fa1affb --- /dev/null +++ b/AutoFishingStool/AutoFishingStool.json @@ -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" + ] +} diff --git a/AutoFishingStool/Plugin.cs b/AutoFishingStool/Plugin.cs new file mode 100644 index 0000000..e89fc44 --- /dev/null +++ b/AutoFishingStool/Plugin.cs @@ -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; + } +} diff --git a/AutoFishingStool/README.md b/AutoFishingStool/README.md new file mode 100644 index 0000000..cefc8a7 --- /dev/null +++ b/AutoFishingStool/README.md @@ -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. diff --git a/AutoFishingStool/icon.png b/AutoFishingStool/icon.png new file mode 100644 index 0000000..505c3aa Binary files /dev/null and b/AutoFishingStool/icon.png differ diff --git a/AutoFishingStool/packages.lock.json b/AutoFishingStool/packages.lock.json new file mode 100644 index 0000000..c291724 --- /dev/null +++ b/AutoFishingStool/packages.lock.json @@ -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==" + } + } + } +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..34509fb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Bep + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c0230e --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# XIV Plugins + +Small Dalamud plugins by Bep. + +## Plugins + +- [Auto Fishing Stool](AutoFishingStool/README.md): automatically uses `/sit` after entering fishing mode.