Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .jules/scribe.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
## 2026-07-15 - [ProductPatterns] Learning: Multi-region memory support is implemented via a central registry that maps regional identifiers (Global, China, Korea) to product-specific pattern dictionaries. Action: When documenting pattern-related types, clarify that these strings are raw signatures used by the assembly loader to resolve memory offsets across different game versions.
## 2026-06-24 - [RemoteAgents] Learning: "Dawn" is the internal game name for the Duty Support and Trust systems. Action: When documenting "Dawn" related agents or offsets, explicitly reference both Duty Support and Trust to ensure clarity for developers familiar with the in-game terminology.
## 2026-06-25 - [AetherialWheel] Learning: FC Aetherial Wheel data includes multiple item IDs (Starting, Current, Resulting) to track the transformation of a wheel as it primes. Action: When documenting aetherial wheel structures, distinguish between the unprimed source item and the final primed result to clarify the priming lifecycle.
## 2026-08-01 - [Build Integrity] Learning: Using `<see cref="..." />` for generic methods defined in external libraries (e.g., `ff14bot`) can cause CS1574 (unresolved cref) warnings if the generic signature is not correctly resolved. Action: Avoid `cref` for external generic wrappers and instead use plain text to describe function calls to ensure build stability.
## 2026-08-02 - [Scribe Constraints] Learning: Identifying functional bugs (like missing vendor registry entries) during documentation exploration is common, but fixing them violates the "Never modify functional logic" boundary. Action: Document the existing state accurately and record the bug in memory or a separate task, but do not include functional fixes in a Scribe PR.
30 changes: 25 additions & 5 deletions RemoteAgents/AgentBankaCraftworksSupply.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
using System;
using System;
using ff14bot;
using ff14bot.Managers;
using LlamaLibrary.Memory;
using LlamaLibrary.Utilities;

namespace LlamaLibrary.RemoteAgents;


/// <summary>
/// Remote agent for the Banka Craftworks supply interface.
/// Handles the exchange of crafted items for rewards within the Banka Craftworks system.
/// </summary>
public class AgentBankaCraftworksSupply : AgentInterface<AgentBankaCraftworksSupply>, IAgent
{


/// <summary>
/// Initializes a new instance of the <see cref="AgentBankaCraftworksSupply"/> class.
/// </summary>
/// <param name="pointer">The memory address of the agent.</param>
protected AgentBankaCraftworksSupply(IntPtr pointer) : base(pointer)
{
}

/// <inheritdoc/>
public IntPtr RegisteredVtable => AgentBankaCraftworksSupplyOffsets.Vtable;

/// <summary>
/// Gets the primary memory pointer for the agent instance.
/// </summary>
public IntPtr InstancePointer
{
get
{
var temp1 = Core.Memory.Read<IntPtr>(Pointer ) ;
var temp1 = Core.Memory.Read<IntPtr>(Pointer);
return temp1;
}
}

/// <summary>
/// Gets the memory pointer for the agent instance adjusted by its internal offset.
/// Used as the target for hand-in function calls.
/// </summary>
public IntPtr InstancePointerWithOffset
{
get
Expand All @@ -35,6 +48,13 @@ public IntPtr InstancePointerWithOffset
}
}

/// <summary>
/// Hands in the specified <see cref="BagSlot"/> to the Banka Craftworks interface.
/// </summary>
/// <param name="slot">The inventory slot containing the item to be handed in.</param>
/// <remarks>
/// This method calls an internal game function using the offset-adjusted instance pointer and the target slot's index and bag ID.
/// </remarks>
public void HandIn(BagSlot slot)
{
//var instance = Core.Memory.Read<IntPtr>(Pointer) + Offsets.PointerOffset;
Expand Down
22 changes: 18 additions & 4 deletions RemoteAgents/AgentDeepDungeonStatus.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
using System;
using System;
using ff14bot.Managers;
using LlamaLibrary.Memory;

namespace LlamaLibrary.RemoteAgents;

public class AgentDeepDungeonStatus: AgentInterface
/// <summary>
/// Remote agent for the Deep Dungeon status and progress interface.
/// Manages information about current Deep Dungeon floor, score, and state.
/// </summary>
public class AgentDeepDungeonStatus : AgentInterface
{
/// <inheritdoc/>
public IntPtr RegisteredVtable => AgentDeepDungeonStatusOffsets.VTable;

private static AgentInterface? _instance;

/// <summary>
/// Gets the raw agent ID for the Deep Dungeon status agent by looking up its VTable.
/// </summary>
public static int IdRaw { get; } = AgentModule.FindAgentIdByVtable(AgentDeepDungeonStatusOffsets.VTable);

/// <summary>
/// Gets the singleton instance of the <see cref="AgentDeepDungeonStatus"/> by resolving its pointer from the <see cref="AgentModule"/>.
/// </summary>
public static AgentInterface Instance => _instance ??= new AgentDeepDungeonStatus(AgentModule.AgentPointers[AgentModule.FindAgentIdByVtable(AgentDeepDungeonStatusOffsets.VTable)]);

/// <summary>
/// Initializes a new instance of the <see cref="AgentDeepDungeonStatus"/> class.
/// </summary>
/// <param name="pointer">The memory address of the agent.</param>
protected AgentDeepDungeonStatus(IntPtr pointer) : base(pointer)
{
}

}
}
83 changes: 73 additions & 10 deletions RemoteAgents/AgentFishGuide2.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Buddy.Coroutines;
Expand All @@ -10,38 +10,82 @@

namespace LlamaLibrary.RemoteAgents
{
/// <summary>
/// Remote agent for the Fishing Guide (Fishing Log) interface.
/// Provides access to the player's catch history and facilitates interaction with the fishing log UI.
/// </summary>
public class AgentFishGuide2 : AgentInterface<AgentFishGuide2>, IAgent
{
/// <inheritdoc/>
public IntPtr RegisteredVtable => AgentFishGuide2Offsets.Vtable;

/// <summary>
/// The total number of tabs (categories) available in the fishing guide.
/// </summary>
public const int TabCount = 37;



/// <summary>
/// Initializes a new instance of the <see cref="AgentFishGuide2"/> class.
/// </summary>
/// <param name="pointer">The memory address of the agent.</param>
protected AgentFishGuide2(IntPtr pointer) : base(pointer)
{
}

/// <summary>
/// Gets the pointer to the internal information structure for the fishing guide.
/// </summary>
public IntPtr InfoPointer => Core.Memory.Read<IntPtr>(Pointer + AgentFishGuide2Offsets.InfoOffset);

/// <summary>
/// Gets the pointer to the start of the fish list array in memory.
/// </summary>
public IntPtr StartingPointer => Core.Memory.Read<IntPtr>(InfoPointer + AgentFishGuide2Offsets.StartingPointer);

/// <summary>
/// Gets the pointer to the end of the fish list array in memory.
/// </summary>
public IntPtr EndingPointer => Core.Memory.Read<IntPtr>(InfoPointer + AgentFishGuide2Offsets.EndingPointer);

/// <summary>
/// Retrieves the memory pointer for a specific fish entry in the list.
/// </summary>
/// <param name="start">The zero-based index of the fish entry.</param>
/// <returns>The memory pointer to the fish entry.</returns>
public IntPtr FishListPointer(int start = 0) => Core.Memory.Read<IntPtr>(StartingPointer + (8 * start));

/// <summary>
/// Gets the total number of fish slots available in the current log context.
/// </summary>
public int SlotCount => (int)((EndingPointer.ToInt64() - StartingPointer.ToInt64()) / 8);

/// <summary>
/// Reads all fish entries from the current fishing log context.
/// </summary>
/// <returns>An array of <see cref="FishGuide2Item"/> structures.</returns>
public FishGuide2Item[] GetFishListRaw()
{
return Core.Memory.ReadArray<FishGuide2Item>(Core.Memory.Read<IntPtr>(StartingPointer), SlotCount); //.Select(x => x.FishItem) as List<uint>;
}

/// <summary>
/// Reads a specific range of fish entries from the fishing log.
/// </summary>
/// <param name="start">The zero-based starting index.</param>
/// <param name="count">The number of entries to read.</param>
/// <returns>An array of <see cref="FishGuide2Item"/> structures.</returns>
public FishGuide2Item[] GetFishListRaw(int start, int count)
{
return Core.Memory.ReadArray<FishGuide2Item>(FishListPointer(start), count); //.Select(x => x.FishItem) as List<uint>;
}

/// <summary>
/// Asynchronously opens the fishing log UI, refreshes its state, and retrieves the specified fish entries.
/// Closes the window when finished.
/// </summary>
/// <param name="start">The zero-based starting index to retrieve.</param>
/// <param name="count">The number of entries to retrieve. If 0, retrieves all available entries.</param>
/// <returns>A task representing the asynchronous operation, containing the array of fish entries.</returns>
public async Task<FishGuide2Item[]> GetFishList(int start = 0, int count = 0)
{
if (!FishGuide2.Instance.IsOpen)
Expand Down Expand Up @@ -71,38 +115,57 @@ public async Task<FishGuide2Item[]> GetFishList(int start = 0, int count = 0)
}
}

/// <summary>
/// Represents a single fish entry within the Fishing Guide memory structure.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 0x14)]
public struct FishGuide2Item
{
//0
/// <summary>
/// Gets the item ID of the fish.
/// </summary>
[FieldOffset(0x0)]
public uint FishItem;

//0x4
/// <summary>
/// Gets the zero-based index of the fish within the log.
/// </summary>
[FieldOffset(0X4)]
public ushort Index;

//0x6
/// <summary>
/// An unknown value at offset 0x6.
/// </summary>
[FieldOffset(0x6)]
public ushort Unknown;

//0x8
/// <summary>
/// An unknown value at offset 0x8.
/// </summary>
[FieldOffset(0x8)]
public ushort Unknown2;

//0xA
/// <summary>
/// An unknown value at offset 0xA.
/// </summary>
[FieldOffset(0xA)]
public ushort Unknown5;

//0xE
/// <summary>
/// The raw status byte indicating if the fish has been caught.
/// </summary>
[FieldOffset(0xE)]
public byte bHasCaught;

/// <summary>
/// Gets a value indicating whether the fish has been caught by the player.
/// </summary>
public bool HasCaught => bHasCaught == 1;

/// <inheritdoc/>
public override string ToString()
{
return $"{DataManager.GetItem(FishItem)} : {HasCaught}";
}
}
}
}
5 changes: 3 additions & 2 deletions Utilities/GilShopping.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Media;
Expand Down Expand Up @@ -26,6 +26,7 @@ public class GilShopping

/// <summary>
/// Maps material item IDs to the NPC ID of the vendor that sells them.
/// Includes items for Anden, Margrat, Nitowikwe, and Tiisol Ja.
/// </summary>
public static Dictionary<uint, uint> ItemVendors = new()
{
Expand Down Expand Up @@ -148,4 +149,4 @@ public static async Task<bool> PurchaseIngredients(uint itemId, uint amount)

return ConditionParser.HasAtLeast(itemId, (int)amount);
}
}
}