mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-17 13:07:44 +01:00
More stuff.
This commit is contained in:
parent
dad146d043
commit
1a4672a901
23 changed files with 616 additions and 1005 deletions
|
|
@ -1,375 +0,0 @@
|
|||
using System;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Utility;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.ByteString;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
public unsafe partial struct Actor
|
||||
{
|
||||
public interface IIdentifier : IEquatable<IIdentifier>
|
||||
{
|
||||
Utf8String Name { get; }
|
||||
public bool IsValid { get; }
|
||||
|
||||
public IIdentifier CreatePermanent();
|
||||
|
||||
public static readonly InvalidIdentifier Invalid = new();
|
||||
|
||||
public void ToJson(JsonTextWriter j);
|
||||
|
||||
public static IIdentifier? FromJson(JObject j)
|
||||
{
|
||||
switch (j["Type"]?.Value<string>() ?? string.Empty)
|
||||
{
|
||||
case nameof(PlayerIdentifier):
|
||||
{
|
||||
var name = j[nameof(Name)]?.Value<string>();
|
||||
if (name.IsNullOrEmpty())
|
||||
return null;
|
||||
|
||||
var serverId = j[nameof(PlayerIdentifier.HomeWorld)]?.Value<ushort>() ?? ushort.MaxValue;
|
||||
return new PlayerIdentifier(Utf8String.FromStringUnsafe(name, false), serverId);
|
||||
}
|
||||
case nameof(SpecialIdentifier):
|
||||
{
|
||||
var index = j[nameof(SpecialIdentifier.Index)]?.Value<ushort>() ?? ushort.MaxValue;
|
||||
return new SpecialIdentifier(index);
|
||||
}
|
||||
case nameof(OwnedIdentifier):
|
||||
{
|
||||
var name = j[nameof(Name)]?.Value<string>();
|
||||
if (name.IsNullOrEmpty())
|
||||
return null;
|
||||
|
||||
var ownerName = j[nameof(OwnedIdentifier.OwnerName)]?.Value<string>();
|
||||
if (ownerName.IsNullOrEmpty())
|
||||
return null;
|
||||
|
||||
var ownerHomeWorld = j[nameof(OwnedIdentifier.OwnerHomeWorld)]?.Value<ushort>() ?? ushort.MaxValue;
|
||||
var dataId = j[nameof(OwnedIdentifier.DataId)]?.Value<ushort>() ?? ushort.MaxValue;
|
||||
var kind = j[nameof(OwnedIdentifier.Kind)]?.Value<ObjectKind>() ?? ObjectKind.Player;
|
||||
|
||||
return new OwnedIdentifier(Utf8String.FromStringUnsafe(name, false), Utf8String.FromStringUnsafe(ownerName, false),
|
||||
ownerHomeWorld, dataId, kind);
|
||||
}
|
||||
case nameof(NpcIdentifier):
|
||||
{
|
||||
var name = j[nameof(Name)]?.Value<string>();
|
||||
if (name.IsNullOrEmpty())
|
||||
return null;
|
||||
|
||||
var dataId = j[nameof(NpcIdentifier.DataId)]?.Value<uint>() ?? uint.MaxValue;
|
||||
|
||||
return new NpcIdentifier(Utf8String.FromStringUnsafe(name, false), ushort.MaxValue, dataId);
|
||||
}
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class InvalidIdentifier : IIdentifier
|
||||
{
|
||||
public Utf8String Name
|
||||
=> Utf8String.Empty;
|
||||
|
||||
public bool IsValid
|
||||
=> false;
|
||||
|
||||
public bool Equals(IIdentifier? other)
|
||||
=> false;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> 0;
|
||||
|
||||
public override string ToString()
|
||||
=> "Invalid";
|
||||
|
||||
public IIdentifier CreatePermanent()
|
||||
=> this;
|
||||
|
||||
public void ToJson(JsonTextWriter j)
|
||||
{ }
|
||||
}
|
||||
|
||||
public class PlayerIdentifier : IIdentifier, IEquatable<PlayerIdentifier>
|
||||
{
|
||||
public Utf8String Name { get; }
|
||||
public readonly ushort HomeWorld;
|
||||
|
||||
public bool IsValid
|
||||
=> true;
|
||||
|
||||
public PlayerIdentifier(Utf8String name, ushort homeWorld)
|
||||
{
|
||||
Name = name;
|
||||
HomeWorld = homeWorld;
|
||||
}
|
||||
|
||||
public bool Equals(IIdentifier? other)
|
||||
=> Equals(other as PlayerIdentifier);
|
||||
|
||||
public bool Equals(PlayerIdentifier? other)
|
||||
=> other?.HomeWorld == HomeWorld && other.Name.Equals(Name);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> HashCode.Combine(Name.Crc32, HomeWorld);
|
||||
|
||||
public override string ToString()
|
||||
=> $"{Name} ({HomeWorld})";
|
||||
|
||||
public IIdentifier CreatePermanent()
|
||||
=> new PlayerIdentifier(Name.Clone(), HomeWorld);
|
||||
|
||||
public void ToJson(JsonTextWriter j)
|
||||
{
|
||||
j.WriteStartObject();
|
||||
j.WritePropertyName("Type");
|
||||
j.WriteValue(GetType().Name);
|
||||
j.WritePropertyName(nameof(Name));
|
||||
j.WriteValue(Name);
|
||||
j.WritePropertyName(nameof(HomeWorld));
|
||||
j.WriteValue(HomeWorld);
|
||||
j.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
public class SpecialIdentifier : IIdentifier, IEquatable<SpecialIdentifier>
|
||||
{
|
||||
public Utf8String Name
|
||||
=> Utf8String.Empty;
|
||||
|
||||
public readonly ushort Index;
|
||||
|
||||
public bool IsValid
|
||||
=> true;
|
||||
|
||||
public SpecialIdentifier(ushort index)
|
||||
=> Index = index;
|
||||
|
||||
public bool Equals(IIdentifier? other)
|
||||
=> Equals(other as SpecialIdentifier);
|
||||
|
||||
public bool Equals(SpecialIdentifier? other)
|
||||
=> other?.Index == Index;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Index;
|
||||
|
||||
public override string ToString()
|
||||
=> $"Special Actor {Index}";
|
||||
|
||||
public IIdentifier CreatePermanent()
|
||||
=> this;
|
||||
|
||||
public void ToJson(JsonTextWriter j)
|
||||
{
|
||||
j.WriteStartObject();
|
||||
j.WritePropertyName("Type");
|
||||
j.WriteValue(GetType().Name);
|
||||
j.WritePropertyName(nameof(Index));
|
||||
j.WriteValue(Index);
|
||||
j.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class OwnedIdentifier : IIdentifier, IEquatable<OwnedIdentifier>
|
||||
{
|
||||
public Utf8String Name { get; }
|
||||
public readonly Utf8String OwnerName;
|
||||
public readonly uint DataId;
|
||||
public readonly ushort OwnerHomeWorld;
|
||||
public readonly ObjectKind Kind;
|
||||
|
||||
public bool IsValid
|
||||
=> true;
|
||||
|
||||
public OwnedIdentifier(Utf8String actorName, Utf8String ownerName, ushort ownerHomeWorld, uint dataId, ObjectKind kind)
|
||||
{
|
||||
OwnerName = ownerName;
|
||||
OwnerHomeWorld = ownerHomeWorld;
|
||||
DataId = dataId;
|
||||
Kind = kind;
|
||||
Name = actorName;
|
||||
switch (Kind)
|
||||
{
|
||||
case ObjectKind.MountType:
|
||||
var mount = Dalamud.GameData.GetExcelSheet<Mount>()!.GetRow(dataId);
|
||||
if (mount != null)
|
||||
Name = Utf8String.FromSpanUnsafe(mount.Singular.RawData, false).AsciiToMixed();
|
||||
break;
|
||||
case ObjectKind.Companion:
|
||||
var companion = Dalamud.GameData.GetExcelSheet<Companion>()!.GetRow(dataId);
|
||||
if (companion != null)
|
||||
Name = Utf8String.FromSpanUnsafe(companion.Singular.RawData, false).AsciiToMixed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(IIdentifier? other)
|
||||
=> Equals(other as OwnedIdentifier);
|
||||
|
||||
public bool Equals(OwnedIdentifier? other)
|
||||
=> other?.DataId == DataId
|
||||
&& other.OwnerHomeWorld == OwnerHomeWorld
|
||||
&& other.Kind == Kind
|
||||
&& other.OwnerName.Equals(OwnerName);
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
=> HashCode.Combine(OwnerName.Crc32, OwnerHomeWorld, DataId, Kind);
|
||||
|
||||
public override string ToString()
|
||||
=> $"{OwnerName}s {Name}";
|
||||
|
||||
public IIdentifier CreatePermanent()
|
||||
=> new OwnedIdentifier(Name.Clone(), OwnerName.Clone(), OwnerHomeWorld, DataId, Kind);
|
||||
|
||||
public void ToJson(JsonTextWriter j)
|
||||
{
|
||||
j.WriteStartObject();
|
||||
j.WritePropertyName("Type");
|
||||
j.WriteValue(GetType().Name);
|
||||
j.WritePropertyName(nameof(Name));
|
||||
j.WriteValue(Name);
|
||||
j.WritePropertyName(nameof(OwnerName));
|
||||
j.WriteValue(OwnerName);
|
||||
j.WritePropertyName(nameof(OwnerHomeWorld));
|
||||
j.WriteValue(OwnerHomeWorld);
|
||||
j.WritePropertyName(nameof(Kind));
|
||||
j.WriteValue(Kind);
|
||||
j.WritePropertyName(nameof(DataId));
|
||||
j.WriteValue(DataId);
|
||||
j.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
public class NpcIdentifier : IIdentifier, IEquatable<NpcIdentifier>
|
||||
{
|
||||
public Utf8String Name { get; }
|
||||
public readonly uint DataId;
|
||||
public readonly ushort ObjectIndex;
|
||||
|
||||
public bool IsValid
|
||||
=> true;
|
||||
|
||||
public NpcIdentifier(Utf8String actorName, ushort objectIndex = ushort.MaxValue, uint dataId = uint.MaxValue)
|
||||
{
|
||||
Name = actorName;
|
||||
ObjectIndex = objectIndex;
|
||||
DataId = dataId;
|
||||
}
|
||||
|
||||
public bool Equals(IIdentifier? other)
|
||||
=> Equals(other as NpcIdentifier);
|
||||
|
||||
public bool Equals(NpcIdentifier? other)
|
||||
=> (other?.Name.Equals(Name) ?? false)
|
||||
&& (other.DataId == uint.MaxValue || DataId == uint.MaxValue || other.DataId == DataId)
|
||||
&& (other.ObjectIndex == ushort.MaxValue || ObjectIndex == ushort.MaxValue || other.ObjectIndex == ObjectIndex);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Name.Crc32;
|
||||
|
||||
public override string ToString()
|
||||
=> DataId == uint.MaxValue ? ObjectIndex == ushort.MaxValue ? Name.ToString() : $"{Name} at {ObjectIndex}" :
|
||||
ObjectIndex == ushort.MaxValue ? $"{Name} ({DataId})" : $"{Name} ({DataId}) at {ObjectIndex}";
|
||||
|
||||
public IIdentifier CreatePermanent()
|
||||
=> new NpcIdentifier(Name.Clone(), ObjectIndex, DataId);
|
||||
|
||||
public void ToJson(JsonTextWriter j)
|
||||
{
|
||||
j.WriteStartObject();
|
||||
j.WritePropertyName("Type");
|
||||
j.WriteValue(GetType().Name);
|
||||
j.WritePropertyName(nameof(Name));
|
||||
j.WriteValue(Name);
|
||||
j.WritePropertyName(nameof(DataId));
|
||||
j.WriteValue(DataId);
|
||||
j.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
private static IIdentifier CreateIdentifier(Actor actor)
|
||||
{
|
||||
if (!actor.Valid)
|
||||
return IIdentifier.Invalid;
|
||||
|
||||
var objectIdx = actor.Pointer->GameObject.ObjectIndex;
|
||||
if (objectIdx is >= 200 and < 240)
|
||||
{
|
||||
var parentIdx = Glamourer.Penumbra.CutsceneParent(objectIdx);
|
||||
if (parentIdx >= 0)
|
||||
{
|
||||
var parent = (Actor)Dalamud.Objects.GetObjectAddress(parentIdx);
|
||||
if (!parent)
|
||||
return IIdentifier.Invalid;
|
||||
|
||||
return CreateIdentifier(parent);
|
||||
}
|
||||
}
|
||||
|
||||
switch (actor.ObjectKind)
|
||||
{
|
||||
case ObjectKind.Player:
|
||||
{
|
||||
var name = actor.Utf8Name;
|
||||
if (name.Length > 0 && actor.Pointer->HomeWorld is > 0 and < ushort.MaxValue)
|
||||
return new PlayerIdentifier(actor.Utf8Name, actor.Pointer->HomeWorld);
|
||||
|
||||
return IIdentifier.Invalid;
|
||||
}
|
||||
case ObjectKind.BattleNpc:
|
||||
{
|
||||
var ownerId = actor.Pointer->GameObject.OwnerID;
|
||||
if (ownerId != 0xE0000000)
|
||||
{
|
||||
var owner = (Actor)Dalamud.Objects.SearchById(ownerId)?.Address;
|
||||
if (!owner)
|
||||
return new InvalidIdentifier();
|
||||
|
||||
return new OwnedIdentifier(actor.Utf8Name, owner.Utf8Name, owner.Pointer->HomeWorld,
|
||||
actor.Pointer->GameObject.DataID, ObjectKind.BattleNpc);
|
||||
}
|
||||
|
||||
return new NpcIdentifier(actor.Utf8Name, actor.Pointer->GameObject.ObjectIndex,
|
||||
actor.Pointer->GameObject.DataID);
|
||||
}
|
||||
case ObjectKind.Retainer:
|
||||
case ObjectKind.EventNpc:
|
||||
return new NpcIdentifier(actor.Utf8Name, actor.Pointer->GameObject.ObjectIndex,
|
||||
actor.Pointer->GameObject.DataID);
|
||||
case ObjectKind.MountType:
|
||||
case ObjectKind.Companion:
|
||||
{
|
||||
var idx = actor.Pointer->GameObject.ObjectIndex;
|
||||
if (idx % 2 == 0)
|
||||
return new InvalidIdentifier();
|
||||
|
||||
var owner = (Actor)Dalamud.Objects[idx - 1]?.Address;
|
||||
if (!owner)
|
||||
return new InvalidIdentifier();
|
||||
|
||||
var dataId = actor.ObjectKind switch
|
||||
{
|
||||
ObjectKind.MountType => owner.UsedMountId,
|
||||
ObjectKind.Companion => actor.CompanionId,
|
||||
_ => actor.Pointer->GameObject.DataID,
|
||||
};
|
||||
|
||||
var name = actor.Utf8Name;
|
||||
if (name.IsEmpty && dataId == 0)
|
||||
return new InvalidIdentifier();
|
||||
|
||||
return new OwnedIdentifier(name, owner.Utf8Name, owner.Pointer->HomeWorld,
|
||||
dataId, actor.ObjectKind);
|
||||
}
|
||||
default: return new InvalidIdentifier();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||
using Glamourer.Customization;
|
||||
using Penumbra.GameData.ByteString;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
@ -23,10 +25,10 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
|||
public static implicit operator IntPtr(Actor actor)
|
||||
=> actor.Pointer == null ? IntPtr.Zero : (IntPtr)actor.Pointer;
|
||||
|
||||
public IIdentifier GetIdentifier()
|
||||
=> CreateIdentifier(this);
|
||||
public ActorIdentifier GetIdentifier()
|
||||
=> Glamourer.Actors.FromObject((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)Pointer);
|
||||
|
||||
public bool Identifier(out IIdentifier ident)
|
||||
public bool Identifier(out ActorIdentifier ident)
|
||||
{
|
||||
if (Valid)
|
||||
{
|
||||
|
|
@ -34,7 +36,7 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
|||
return true;
|
||||
}
|
||||
|
||||
ident = IIdentifier.Invalid;
|
||||
ident = ActorIdentifier.Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
|||
set => Pointer->GameObject.ObjectKind = (byte)value;
|
||||
}
|
||||
|
||||
public Utf8String Utf8Name
|
||||
public ByteString Utf8Name
|
||||
=> new(Pointer->GameObject.Name);
|
||||
|
||||
public byte Job
|
||||
|
|
@ -123,6 +125,8 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsWet { get; set; }
|
||||
|
||||
|
||||
public void SetModelId(int value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ public unsafe partial struct DrawObject : IEquatable<DrawObject>, IDesignable
|
|||
public uint ModelId
|
||||
=> 0;
|
||||
|
||||
public bool IsWet
|
||||
=> false;
|
||||
|
||||
public uint Type
|
||||
=> (*(delegate* unmanaged<Human*, uint>**)Pointer)[50](Pointer);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ public interface IDesignable
|
|||
public CharacterWeapon OffHand { get; }
|
||||
public bool VisorEnabled { get; }
|
||||
public bool WeaponEnabled { get; }
|
||||
public bool IsWet { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Text;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.GameData.Actors;
|
||||
using static Glamourer.Interop.Actor;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
@ -42,67 +43,29 @@ public static class ObjectManager
|
|||
public static bool IsInGPose { get; private set; }
|
||||
public static ushort World { get; private set; }
|
||||
|
||||
public static IReadOnlyDictionary<IIdentifier, ActorData> Actors
|
||||
public static IReadOnlyDictionary<ActorIdentifier, ActorData> Actors
|
||||
=> Identifiers;
|
||||
|
||||
public static IReadOnlyList<(IIdentifier, ActorData)> List
|
||||
public static IReadOnlyList<(ActorIdentifier, ActorData)> List
|
||||
=> ListData;
|
||||
|
||||
private static readonly Dictionary<IIdentifier, ActorData> Identifiers = new(200);
|
||||
private static readonly List<(IIdentifier, ActorData)> ListData = new(Dalamud.Objects.Length);
|
||||
private static readonly Dictionary<ActorIdentifier, ActorData> Identifiers = new(200);
|
||||
private static readonly List<(ActorIdentifier, ActorData)> ListData = new(Dalamud.Objects.Length);
|
||||
|
||||
private static void HandleIdentifier(IIdentifier identifier, Actor character)
|
||||
private static void HandleIdentifier(ActorIdentifier identifier, Actor character)
|
||||
{
|
||||
if (!character.DrawObject)
|
||||
if (!character.DrawObject || !identifier.IsValid)
|
||||
return;
|
||||
|
||||
switch (identifier)
|
||||
if (!Identifiers.TryGetValue(identifier, out var data))
|
||||
{
|
||||
case PlayerIdentifier p:
|
||||
if (!Identifiers.TryGetValue(p, out var data))
|
||||
{
|
||||
data = new ActorData(character,
|
||||
World != p.HomeWorld
|
||||
? $"{p.Name} ({Dalamud.GameData.GetExcelSheet<World>()!.GetRow(p.HomeWorld)!.Name})"
|
||||
: p.Name.ToString());
|
||||
Identifiers[p] = data;
|
||||
ListData.Add((p, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Objects.Add(character);
|
||||
}
|
||||
|
||||
break;
|
||||
case NpcIdentifier n when !n.Name.IsEmpty:
|
||||
if (!Identifiers.TryGetValue(n, out data))
|
||||
{
|
||||
data = new ActorData(character, $"{n.Name} (at {n.ObjectIndex})");
|
||||
Identifiers[n] = data;
|
||||
ListData.Add((n, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Objects.Add(character);
|
||||
}
|
||||
|
||||
break;
|
||||
case OwnedIdentifier o:
|
||||
if (!Identifiers.TryGetValue(o, out data))
|
||||
{
|
||||
data = new ActorData(character,
|
||||
World != o.OwnerHomeWorld
|
||||
? $"{o.OwnerName}s {o.Name} ({Dalamud.GameData.GetExcelSheet<World>()!.GetRow(o.OwnerHomeWorld)!.Name})"
|
||||
: $"{o.OwnerName}s {o.Name}");
|
||||
Identifiers[o] = data;
|
||||
ListData.Add((o, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Objects.Add(character);
|
||||
}
|
||||
|
||||
break;
|
||||
data = new ActorData(character, identifier.ToString());
|
||||
Identifiers[identifier] = data;
|
||||
ListData.Add((identifier, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Objects.Add(character);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue