mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-02 13:53:42 +01:00
Continued work on actor identification, migration seems to work.
This commit is contained in:
parent
0444c28187
commit
bda3c1f1ac
11 changed files with 407 additions and 115 deletions
|
|
@ -59,7 +59,7 @@ public readonly struct ActorIdentifier : IEquatable<ActorIdentifier>
|
|||
{
|
||||
IdentifierType.Player => $"{PlayerName} ({HomeWorld})",
|
||||
IdentifierType.Owned => $"{PlayerName}s {Kind} {DataId} ({HomeWorld})",
|
||||
IdentifierType.Special => ActorManager.ToName(Special),
|
||||
IdentifierType.Special => Special.ToName(),
|
||||
IdentifierType.Npc =>
|
||||
Index == ushort.MaxValue
|
||||
? $"{Kind} #{DataId}"
|
||||
|
|
@ -147,4 +147,39 @@ public static class ActorManagerExtensions
|
|||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public static string ToName(this ObjectKind kind)
|
||||
=> kind switch
|
||||
{
|
||||
ObjectKind.None => "Unknown",
|
||||
ObjectKind.BattleNpc => "Battle NPC",
|
||||
ObjectKind.EventNpc => "Event NPC",
|
||||
ObjectKind.MountType => "Mount",
|
||||
ObjectKind.Companion => "Companion",
|
||||
_ => kind.ToString(),
|
||||
};
|
||||
|
||||
public static string ToName(this IdentifierType type)
|
||||
=> type switch
|
||||
{
|
||||
IdentifierType.Player => "Player",
|
||||
IdentifierType.Owned => "Owned NPC",
|
||||
IdentifierType.Special => "Special Actor",
|
||||
IdentifierType.Npc => "NPC",
|
||||
_ => "Invalid",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Fixed names for special actors.
|
||||
/// </summary>
|
||||
public static string ToName(this SpecialActor actor)
|
||||
=> actor switch
|
||||
{
|
||||
SpecialActor.CharacterScreen => "Character Screen Actor",
|
||||
SpecialActor.ExamineScreen => "Examine Screen Actor",
|
||||
SpecialActor.FittingRoom => "Fitting Room Actor",
|
||||
SpecialActor.DyePreview => "Dye Preview Actor",
|
||||
SpecialActor.Portrait => "Portrait Actor",
|
||||
_ => "Invalid",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,17 @@ using Dalamud;
|
|||
using Dalamud.Data;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.String;
|
||||
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;
|
||||
|
||||
namespace Penumbra.GameData.Actors;
|
||||
|
||||
|
|
@ -30,16 +37,17 @@ public sealed partial class ActorManager : DataSharer
|
|||
/// <summary> Valid ENPC names in title case by ENPC id. </summary>
|
||||
public IReadOnlyDictionary<uint, string> ENpcs { get; }
|
||||
|
||||
public ActorManager(DalamudPluginInterface pluginInterface, ObjectTable objects, ClientState state, DataManager gameData,
|
||||
public ActorManager(DalamudPluginInterface pluginInterface, ObjectTable objects, ClientState state, DataManager gameData, GameGui gameGui,
|
||||
Func<ushort, short> toParentIdx)
|
||||
: this(pluginInterface, objects, state, gameData, gameData.Language, toParentIdx)
|
||||
: this(pluginInterface, objects, state, gameData, gameGui, gameData.Language, toParentIdx)
|
||||
{ }
|
||||
|
||||
public ActorManager(DalamudPluginInterface pluginInterface, ObjectTable objects, ClientState state, DataManager gameData,
|
||||
public ActorManager(DalamudPluginInterface pluginInterface, ObjectTable objects, ClientState state, DataManager gameData, GameGui gameGui,
|
||||
ClientLanguage language, Func<ushort, short> toParentIdx)
|
||||
: base(pluginInterface, language, 1)
|
||||
{
|
||||
_objects = objects;
|
||||
_gameGui = gameGui;
|
||||
_clientState = state;
|
||||
_toParentIdx = toParentIdx;
|
||||
|
||||
|
|
@ -50,6 +58,39 @@ public sealed partial class ActorManager : DataSharer
|
|||
ENpcs = TryCatchData("ENpcs", () => CreateENpcData(gameData));
|
||||
|
||||
ActorIdentifier.Manager = this;
|
||||
|
||||
SignatureHelper.Initialise(this);
|
||||
}
|
||||
|
||||
public unsafe ActorIdentifier GetCurrentPlayer()
|
||||
{
|
||||
var address = (Character*)(_objects[0]?.Address ?? IntPtr.Zero);
|
||||
return address == null ? ActorIdentifier.Invalid : CreatePlayer(new ByteString(address->GameObject.Name), address->HomeWorld);
|
||||
}
|
||||
|
||||
public ActorIdentifier GetInspectPlayer()
|
||||
{
|
||||
var addon = _gameGui.GetAddonByName("CharacterInspect", 1);
|
||||
if (addon == IntPtr.Zero)
|
||||
return ActorIdentifier.Invalid;
|
||||
|
||||
return CreatePlayer(InspectName, InspectWorldId);
|
||||
}
|
||||
|
||||
public unsafe ActorIdentifier GetCardPlayer()
|
||||
{
|
||||
var agent = AgentCharaCard.Instance();
|
||||
if (agent == null || agent->Data == null)
|
||||
return ActorIdentifier.Invalid;
|
||||
|
||||
var worldId = *(ushort*)((byte*)agent->Data + 0xC0);
|
||||
return CreatePlayer(new ByteString(agent->Data->Name.StringPtr), worldId);
|
||||
}
|
||||
|
||||
public ActorIdentifier GetGlamourPlayer()
|
||||
{
|
||||
var addon = _gameGui.GetAddonByName("MiragePrismMiragePlate", 1);
|
||||
return addon == IntPtr.Zero ? ActorIdentifier.Invalid : GetCurrentPlayer();
|
||||
}
|
||||
|
||||
protected override void DisposeInternal()
|
||||
|
|
@ -66,6 +107,7 @@ public sealed partial class ActorManager : DataSharer
|
|||
|
||||
private readonly ObjectTable _objects;
|
||||
private readonly ClientState _clientState;
|
||||
private readonly GameGui _gameGui;
|
||||
|
||||
private readonly Func<ushort, short> _toParentIdx;
|
||||
|
||||
|
|
@ -93,4 +135,20 @@ public sealed partial class ActorManager : DataSharer
|
|||
=> gameData.GetExcelSheet<ENpcResident>(Language)!
|
||||
.Where(e => e.Singular.RawData.Length > 0)
|
||||
.ToDictionary(e => e.RowId, e => CultureInfo.InvariantCulture.TextInfo.ToTitleCase(e.Singular.ToDalamudString().ToString()));
|
||||
|
||||
|
||||
[Signature("0F B7 0D ?? ?? ?? ?? C7 85", ScanType = ScanType.StaticAddress)]
|
||||
private static unsafe ushort* _inspectTitleId = null!;
|
||||
|
||||
[Signature("0F B7 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B D0", ScanType = ScanType.StaticAddress)]
|
||||
private static unsafe ushort* _inspectWorldId = null!;
|
||||
|
||||
private static unsafe ushort InspectTitleId
|
||||
=> *_inspectTitleId;
|
||||
|
||||
private static unsafe ByteString InspectName
|
||||
=> new((byte*)(_inspectWorldId + 1));
|
||||
|
||||
private static unsafe ushort InspectWorldId
|
||||
=> *_inspectWorldId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,12 @@ public partial class ActorManager
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the world name including the All Worlds option.
|
||||
/// </summary>
|
||||
public string ToWorldName(ushort worldId)
|
||||
=> worldId == ushort.MaxValue ? "Any World" : Worlds.TryGetValue(worldId, out var name) ? name : "Invalid";
|
||||
|
||||
/// <summary>
|
||||
/// Use stored data to convert an ActorIdentifier to a string.
|
||||
/// </summary>
|
||||
|
|
@ -59,12 +65,12 @@ public partial class ActorManager
|
|||
return id.Type switch
|
||||
{
|
||||
IdentifierType.Player => id.HomeWorld != _clientState.LocalPlayer?.HomeWorld.Id
|
||||
? $"{id.PlayerName} ({Worlds[id.HomeWorld]})"
|
||||
? $"{id.PlayerName} ({ToWorldName(id.HomeWorld)})"
|
||||
: id.PlayerName.ToString(),
|
||||
IdentifierType.Owned => id.HomeWorld != _clientState.LocalPlayer?.HomeWorld.Id
|
||||
? $"{id.PlayerName} ({Worlds[id.HomeWorld]})'s {ToName(id.Kind, id.DataId)}"
|
||||
: $"{id.PlayerName}s {ToName(id.Kind, id.DataId)}",
|
||||
IdentifierType.Special => ToName(id.Special),
|
||||
? $"{id.PlayerName} ({ToWorldName(id.HomeWorld)})'s {ToName(id.Kind, id.DataId)}"
|
||||
: $"{id.PlayerName}s {ToName(id.Kind, id.DataId)}",
|
||||
IdentifierType.Special => id.Special.ToName(),
|
||||
IdentifierType.Npc =>
|
||||
id.Index == ushort.MaxValue
|
||||
? ToName(id.Kind, id.DataId)
|
||||
|
|
@ -74,20 +80,6 @@ public partial class ActorManager
|
|||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Fixed names for special actors.
|
||||
/// </summary>
|
||||
public static string ToName(SpecialActor actor)
|
||||
=> actor switch
|
||||
{
|
||||
SpecialActor.CharacterScreen => "Character Screen Actor",
|
||||
SpecialActor.ExamineScreen => "Examine Screen Actor",
|
||||
SpecialActor.FittingRoom => "Fitting Room Actor",
|
||||
SpecialActor.DyePreview => "Dye Preview Actor",
|
||||
SpecialActor.Portrait => "Portrait Actor",
|
||||
_ => "Invalid",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Convert a given ID for a certain ObjectKind to a name.
|
||||
/// </summary>
|
||||
|
|
@ -328,7 +320,7 @@ public partial class ActorManager
|
|||
|
||||
/// <summary> Checks if the world is a valid public world or ushort.MaxValue (any world). </summary>
|
||||
public bool VerifyWorld(ushort worldId)
|
||||
=> Worlds.ContainsKey(worldId);
|
||||
=> worldId == ushort.MaxValue || Worlds.ContainsKey(worldId);
|
||||
|
||||
/// <summary> Verify that the enum value is a specific actor and return the name if it is. </summary>
|
||||
public static bool VerifySpecial(SpecialActor actor)
|
||||
|
|
@ -339,6 +331,7 @@ public partial class ActorManager
|
|||
{
|
||||
return index switch
|
||||
{
|
||||
ushort.MaxValue => true,
|
||||
< 200 => index % 2 == 0,
|
||||
> (ushort)SpecialActor.Portrait => index < 426,
|
||||
_ => false,
|
||||
|
|
@ -360,6 +353,8 @@ public partial class ActorManager
|
|||
public bool VerifyNpcData(ObjectKind kind, uint dataId)
|
||||
=> kind switch
|
||||
{
|
||||
ObjectKind.MountType => Mounts.ContainsKey(dataId),
|
||||
ObjectKind.Companion => Companions.ContainsKey(dataId),
|
||||
ObjectKind.BattleNpc => BNpcs.ContainsKey(dataId),
|
||||
ObjectKind.EventNpc => ENpcs.ContainsKey(dataId),
|
||||
_ => false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue