feat: add friend list

This commit is contained in:
Anna 2021-10-08 15:06:47 -04:00
parent 30d370c63b
commit ddccc18ae8
3 changed files with 142 additions and 0 deletions

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
namespace XivCommon.Functions.FriendList {
/// <summary>
/// The class containing friend list functionality
/// </summary>
public class FriendList {
// Updated: 5.58-HF1
private const uint FriendListAgentId = 54;
private const int InfoOffset = 0x28;
private const int LengthOffset = 0x10;
private const int ListOffset = 0x98;
private GameFunctions Functions { get; }
/// <summary>
/// <para>
/// A live list of the currently-logged-in player's friends.
/// </para>
/// <para>
/// The list is empty if not logged in.
/// </para>
/// </summary>
public IList<FriendListEntry> List {
get {
var friendListAgent = this.Functions.GetAgentByInternalId(FriendListAgentId);
if (friendListAgent == IntPtr.Zero) {
return Array.Empty<FriendListEntry>();
}
unsafe {
var info = *(IntPtr*) (friendListAgent + InfoOffset);
if (info == IntPtr.Zero) {
return Array.Empty<FriendListEntry>();
}
var length = *(ushort*) (info + LengthOffset);
if (length == 0) {
return Array.Empty<FriendListEntry>();
}
var list = *(IntPtr*) (info + ListOffset);
if (list == IntPtr.Zero) {
return Array.Empty<FriendListEntry>();
}
var entries = new List<FriendListEntry>(length);
for (var i = 0; i < length; i++) {
var entry = *(FriendListEntry*) (list + i * FriendListEntry.Size);
entries.Add(entry);
}
return entries;
}
}
}
internal FriendList(GameFunctions functions) {
this.Functions = functions;
}
}
}

View File

@ -0,0 +1,72 @@
using System;
using System.Runtime.InteropServices;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Memory;
namespace XivCommon.Functions.FriendList {
/// <summary>
/// An entry in a player's friend list.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = Size)]
public unsafe struct FriendListEntry {
internal const int Size = 96;
/// <summary>
/// The content ID of the friend.
/// </summary>
[FieldOffset(0x00)]
public readonly ulong ContentId;
/// <summary>
/// The home world of the friend.
/// </summary>
[FieldOffset(0x16)]
public readonly ushort HomeWorld;
/// <summary>
/// The current world of the friend.
/// </summary>
[FieldOffset(0x18)]
public readonly ushort CurrentWorld;
/// <summary>
/// The job the friend is currently on.
/// </summary>
[FieldOffset(0x21)]
public readonly byte Job;
/// <summary>
/// The friend's raw SeString name. See <see cref="Name"/>.
/// </summary>
[FieldOffset(0x22)]
public fixed byte RawName[32];
/// <summary>
/// The friend's raw SeString free company tag. See <see cref="FreeCompany"/>.
/// </summary>
[FieldOffset(0x42)]
public fixed byte RawFreeCompany[5];
/// <summary>
/// The friend's name.
/// </summary>
public SeString Name {
get {
fixed (byte* ptr = this.RawName) {
return MemoryHelper.ReadSeStringNullTerminated((IntPtr) ptr);
}
}
}
/// <summary>
/// The friend's free company tag.
/// </summary>
public SeString FreeCompany {
get {
fixed (byte* ptr = this.RawFreeCompany) {
return MemoryHelper.ReadSeStringNullTerminated((IntPtr) ptr);
}
}
}
}
}

View File

@ -8,6 +8,7 @@ using Dalamud.Game.Gui;
using Dalamud.Game.Gui.PartyFinder;
using XivCommon.Functions;
using XivCommon.Functions.ContextMenu;
using XivCommon.Functions.FriendList;
using XivCommon.Functions.NamePlates;
using XivCommon.Functions.Tooltips;
@ -87,6 +88,11 @@ namespace XivCommon {
/// </summary>
public DutyFinder DutyFinder { get; }
/// <summary>
/// Friend list functions
/// </summary>
public FriendList FriendList { get; }
/// <summary>
/// Journal functions
/// </summary>
@ -112,6 +118,7 @@ namespace XivCommon {
this.NamePlates = new NamePlates(this, scanner, hooks.HasFlag(Hooks.NamePlates));
this.DutyFinder = new DutyFinder(this, scanner);
this.Journal = new Journal(this, scanner);
this.FriendList = new FriendList(this);
if (scanner.TryScanText(Signatures.GetAgentByInternalId, out var byInternalIdPtr, "GetAgentByInternalId")) {
this.GetAgentByInternalIdInternal = Marshal.GetDelegateForFunctionPointer<GetAgentByInternalIdDelegate>(byInternalIdPtr);