feat: add Auto Fishing Stool plugin
This commit is contained in:
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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user