feat: add Auto Fishing Stool plugin
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
.vs/
|
||||||
|
*.user
|
||||||
17
AutoFishingStool/AutoFishingStool.csproj
Normal file
17
AutoFishingStool/AutoFishingStool.csproj
Normal 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>
|
||||||
13
AutoFishingStool/AutoFishingStool.json
Normal file
13
AutoFishingStool/AutoFishingStool.json
Normal 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
152
AutoFishingStool/Plugin.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
AutoFishingStool/README.md
Normal file
23
AutoFishingStool/README.md
Normal 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
BIN
AutoFishingStool/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
19
AutoFishingStool/packages.lock.json
Normal file
19
AutoFishingStool/packages.lock.json
Normal 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=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -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.
|
||||||
Reference in New Issue
Block a user