using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using Dalamud.IoC; using Dalamud.IoC.Internal; using Dalamud.Plugin.Services; using Serilog; namespace Dalamud.Game.ClientState.Buddy; /// /// This collection represents the buddies present in your squadron or trust party. /// It does not include the local player. /// [PluginInterface] [InterfaceVersion("1.0")] [ServiceManager.BlockingEarlyLoadedService] #pragma warning disable SA1015 [ResolveVia] #pragma warning restore SA1015 internal sealed partial class BuddyList : IServiceType, IBuddyList { private const uint InvalidObjectID = 0xE0000000; [ServiceManager.ServiceDependency] private readonly ClientState clientState = Service.Get(); private readonly ClientStateAddressResolver address; [ServiceManager.ServiceConstructor] private BuddyList() { this.address = this.clientState.AddressResolver; Log.Verbose($"Buddy list address 0x{this.address.BuddyList.ToInt64():X}"); } /// public int Length { get { var i = 0; for (; i < 3; i++) { var addr = this.GetBattleBuddyMemberAddress(i); var member = this.CreateBuddyMemberReference(addr); if (member == null) break; } return i; } } /// /// Gets a value indicating whether the local player's companion is present. /// [Obsolete("Use CompanionBuddy != null", false)] public bool CompanionBuddyPresent => this.CompanionBuddy != null; /// /// Gets a value indicating whether the local player's pet is present. /// [Obsolete("Use PetBuddy != null", false)] public bool PetBuddyPresent => this.PetBuddy != null; /// public BuddyMember? CompanionBuddy { get { var addr = this.GetCompanionBuddyMemberAddress(); return this.CreateBuddyMemberReference(addr); } } /// public BuddyMember? PetBuddy { get { var addr = this.GetPetBuddyMemberAddress(); return this.CreateBuddyMemberReference(addr); } } /// /// Gets the address of the buddy list. /// internal IntPtr BuddyListAddress => this.address.BuddyList; private static int BuddyMemberSize { get; } = Marshal.SizeOf(); private unsafe FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy* BuddyListStruct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy*)this.BuddyListAddress; /// public BuddyMember? this[int index] { get { var address = this.GetBattleBuddyMemberAddress(index); return this.CreateBuddyMemberReference(address); } } /// public unsafe IntPtr GetCompanionBuddyMemberAddress() { return (IntPtr)(&this.BuddyListStruct->Companion); } /// public unsafe IntPtr GetPetBuddyMemberAddress() { return (IntPtr)(&this.BuddyListStruct->Pet); } /// public unsafe IntPtr GetBattleBuddyMemberAddress(int index) { if (index < 0 || index >= 3) return IntPtr.Zero; return (IntPtr)(this.BuddyListStruct->BattleBuddies + (index * BuddyMemberSize)); } /// public BuddyMember? CreateBuddyMemberReference(IntPtr address) { if (this.clientState.LocalContentId == 0) return null; if (address == IntPtr.Zero) return null; var buddy = new BuddyMember(address); if (buddy.ObjectId == InvalidObjectID) return null; return buddy; } } /// /// This collection represents the buddies present in your squadron or trust party. /// internal sealed partial class BuddyList { /// int IReadOnlyCollection.Count => this.Length; /// public IEnumerator GetEnumerator() { for (var i = 0; i < this.Length; i++) { yield return this[i]; } } /// IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); }