Glamourer-related changes.

This commit is contained in:
Ottermandias 2023-07-12 02:45:40 +02:00
parent a7ace8a8c8
commit 9e0c38169f
15 changed files with 184 additions and 90 deletions

@ -1 +1 @@
Subproject commit e47c15c0496d1afad41cc7b2854dfc43d9b82eee Subproject commit e43a0f00661f319be27f606b1aa841d3234dfb0f

View file

@ -95,6 +95,9 @@ public readonly struct ActorIdentifier : IEquatable<ActorIdentifier>
_ => "Invalid", _ => "Invalid",
}; };
public string ToName()
=> Manager?.ToName(this) ?? "Unknown Object";
public override int GetHashCode() public override int GetHashCode()
=> Type switch => Type switch
{ {

View file

@ -91,6 +91,23 @@ public partial class ActorManager
}; };
} }
/// <summary>
/// Use stored data to convert an ActorIdentifier to a name only.
/// </summary>
public string ToName(ActorIdentifier id)
{
return id.Type switch
{
IdentifierType.Player => id.PlayerName.ToString(),
IdentifierType.Retainer => id.PlayerName.ToString(),
IdentifierType.Owned => $"{id.PlayerName}s {Data.ToName(id.Kind, id.DataId)}",
IdentifierType.Special => id.Special.ToName(),
IdentifierType.Npc => Data.ToName(id.Kind, id.DataId),
IdentifierType.UnkObject => id.PlayerName.IsEmpty ? id.PlayerName.ToString() : "Unknown Object",
_ => "Invalid",
};
}
private unsafe FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* HandleCutscene( private unsafe FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* HandleCutscene(
FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* main) FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* main)
{ {

View file

@ -6,7 +6,7 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>; using PseudoEquipItem = System.ValueTuple<string, ulong, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Data; namespace Penumbra.GameData.Data;
@ -51,6 +51,14 @@ internal sealed class EquipmentIdentificationList : KeyList<PseudoEquipItem>
private static IEnumerable<PseudoEquipItem> CreateEquipmentList(DataManager gameData, ClientLanguage language) private static IEnumerable<PseudoEquipItem> CreateEquipmentList(DataManager gameData, ClientLanguage language)
{ {
var items = gameData.GetExcelSheet<Item>(language)!; var items = gameData.GetExcelSheet<Item>(language)!;
return items.Where(i => ((EquipSlot)i.EquipSlotCategory.Row).IsEquipmentPiece()).Select(i => (PseudoEquipItem)EquipItem.FromArmor(i)); return items.Where(i => ((EquipSlot)i.EquipSlotCategory.Row).IsEquipmentPiece())
.Select(i => (PseudoEquipItem)EquipItem.FromArmor(i))
.Concat(CustomList);
} }
private static IEnumerable<PseudoEquipItem> CustomList
=> new[]
{
(PseudoEquipItem)EquipItem.FromIds(0, 0, 8100, 0, 1, FullEquipType.Body, "Reaper Shroud"),
};
} }

View file

@ -24,6 +24,9 @@ public sealed class HumanModelList : DataSharer
public bool IsHuman(uint modelId) public bool IsHuman(uint modelId)
=> modelId < _humanModels.Count && _humanModels[(int)modelId]; => modelId < _humanModels.Count && _humanModels[(int)modelId];
public int Count
=> _humanModels.Count;
protected override void DisposeInternal() protected override void DisposeInternal()
{ {
DisposeTag(Tag); DisposeTag(Tag);

View file

@ -8,7 +8,7 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>; using PseudoEquipItem = System.ValueTuple<string, ulong, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Data; namespace Penumbra.GameData.Data;
@ -54,7 +54,7 @@ public sealed class ItemData : DataSharer, IReadOnlyDictionary<FullEquipType, IR
{ {
var list = items[(int)type]; var list = items[(int)type];
foreach (var item in list) foreach (var item in list)
dict.TryAdd(item.Item2, item); dict.TryAdd((uint) item.Item2, item);
} }
dict.TrimExcess(); dict.TrimExcess();
@ -68,7 +68,7 @@ public sealed class ItemData : DataSharer, IReadOnlyDictionary<FullEquipType, IR
{ {
var list = items[(int)type]; var list = items[(int)type];
foreach (var item in list) foreach (var item in list)
dict.TryAdd(item.Item2, item); dict.TryAdd((uint) item.Item2, item);
} }
dict.TrimExcess(); dict.TrimExcess();

View file

@ -6,7 +6,6 @@ using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Enums;
@ -25,7 +24,7 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
public IGamePathParser GamePathParser { get; } = new GamePathParser(); public IGamePathParser GamePathParser { get; } = new GamePathParser();
public readonly IReadOnlyList<IReadOnlyList<uint>> BnpcNames; public readonly IReadOnlyList<IReadOnlyList<uint>> BnpcNames;
public readonly IReadOnlyList<IReadOnlyList<(string Name, ObjectKind Kind)>> ModelCharaToObjects; public readonly IReadOnlyList<IReadOnlyList<(string Name, ObjectKind Kind, uint Id)>> ModelCharaToObjects;
public readonly IReadOnlyDictionary<string, IReadOnlyList<Action>> Actions; public readonly IReadOnlyDictionary<string, IReadOnlyList<Action>> Actions;
private readonly ActorManager.ActorManagerData _actorData; private readonly ActorManager.ActorManagerData _actorData;
@ -49,10 +48,8 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
public void Identify(IDictionary<string, object?> set, string path) public void Identify(IDictionary<string, object?> set, string path)
{ {
if (path.EndsWith(".pap", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".tmb", StringComparison.OrdinalIgnoreCase)) if (path.EndsWith(".pap", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".tmb", StringComparison.OrdinalIgnoreCase))
{
if (IdentifyVfx(set, path)) if (IdentifyVfx(set, path))
return; return;
}
var info = GamePathParser.GetFileInfo(path); var info = GamePathParser.GetFileInfo(path);
IdentifyParsed(set, info); IdentifyParsed(set, info);
@ -73,6 +70,15 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
_ => _equipment.Between(setId, slot, (byte)variant), _ => _equipment.Between(setId, slot, (byte)variant),
}; };
public IReadOnlyList<uint> GetBnpcNames(uint bNpcId)
=> bNpcId >= BnpcNames.Count ? Array.Empty<uint>() : BnpcNames[(int)bNpcId];
public IReadOnlyList<(string Name, ObjectKind Kind, uint Id)> ModelCharaNames(uint modelId)
=> modelId >= ModelCharaToObjects.Count ? Array.Empty<(string Name, ObjectKind Kind, uint Id)>() : ModelCharaToObjects[(int)modelId];
public int NumModelChara
=> ModelCharaToObjects.Count;
protected override void DisposeInternal() protected override void DisposeInternal()
{ {
_actorData.Dispose(); _actorData.Dispose();
@ -125,14 +131,14 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
{ {
var items = _equipment.Between(info.PrimaryId, info.EquipSlot, info.Variant); var items = _equipment.Between(info.PrimaryId, info.EquipSlot, info.Variant);
foreach (var item in items) foreach (var item in items)
set[item.Name.ToString()] = item; set[item.Name] = item;
} }
private void FindWeapon(IDictionary<string, object?> set, GameObjectInfo info) private void FindWeapon(IDictionary<string, object?> set, GameObjectInfo info)
{ {
var items = _weapons.Between(info.PrimaryId, info.SecondaryId, info.Variant); var items = _weapons.Between(info.PrimaryId, info.SecondaryId, info.Variant);
foreach (var item in items) foreach (var item in items)
set[item.Name.ToString()] = item; set[item.Name] = item;
} }
private void FindModel(IDictionary<string, object?> set, GameObjectInfo info) private void FindModel(IDictionary<string, object?> set, GameObjectInfo info)
@ -142,10 +148,10 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
return; return;
var models = _modelIdentifierToModelChara.Between(type, info.PrimaryId, (byte)info.SecondaryId, info.Variant); var models = _modelIdentifierToModelChara.Between(type, info.PrimaryId, (byte)info.SecondaryId, info.Variant);
foreach (var model in models.Where(m => m.RowId < ModelCharaToObjects.Count)) foreach (var model in models.Where(m => m.RowId != 0 && m.RowId < ModelCharaToObjects.Count))
{ {
var objectList = ModelCharaToObjects[(int)model.RowId]; var objectList = ModelCharaToObjects[(int)model.RowId];
foreach (var (name, kind) in objectList) foreach (var (name, kind, _) in objectList)
set[$"{name} ({kind.ToName()})"] = model; set[$"{name} ({kind.ToName()})"] = model;
} }
} }
@ -246,46 +252,46 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
return true; return true;
} }
private IReadOnlyList<IReadOnlyList<(string Name, ObjectKind Kind)>> CreateModelObjects(ActorManager.ActorManagerData actors, private IReadOnlyList<IReadOnlyList<(string Name, ObjectKind Kind, uint Id)>> CreateModelObjects(ActorManager.ActorManagerData actors,
DataManager gameData, ClientLanguage language) DataManager gameData, ClientLanguage language)
{ {
var modelSheet = gameData.GetExcelSheet<ModelChara>(language)!; var modelSheet = gameData.GetExcelSheet<ModelChara>(language)!;
var ret = new List<ConcurrentBag<(string Name, ObjectKind Kind)>>((int)modelSheet.RowCount); var ret = new List<ConcurrentBag<(string Name, ObjectKind Kind, uint Id)>>((int)modelSheet.RowCount);
for (var i = -1; i < modelSheet.Last().RowId; ++i) for (var i = -1; i < modelSheet.Last().RowId; ++i)
ret.Add(new ConcurrentBag<(string Name, ObjectKind Kind)>()); ret.Add(new ConcurrentBag<(string Name, ObjectKind Kind, uint Id)>());
void AddChara(int modelChara, ObjectKind kind, uint dataId) void AddChara(int modelChara, ObjectKind kind, uint dataId, uint displayId)
{ {
if (modelChara == 0 || modelChara >= ret.Count) if (modelChara >= ret.Count)
return; return;
if (actors.TryGetName(kind, dataId, out var name)) if (actors.TryGetName(kind, dataId, out var name))
ret[modelChara].Add((name, kind)); ret[modelChara].Add((name, kind, displayId));
} }
var oTask = Task.Run(() => var oTask = Task.Run(() =>
{ {
foreach (var ornament in gameData.GetExcelSheet<Ornament>(language)!) foreach (var ornament in gameData.GetExcelSheet<Ornament>(language)!)
AddChara(ornament.Model, (ObjectKind)15, ornament.RowId); AddChara(ornament.Model, ObjectKind.Ornament, ornament.RowId, ornament.RowId);
}); });
var mTask = Task.Run(() => var mTask = Task.Run(() =>
{ {
foreach (var mount in gameData.GetExcelSheet<Mount>(language)!) foreach (var mount in gameData.GetExcelSheet<Mount>(language)!)
AddChara((int)mount.ModelChara.Row, ObjectKind.MountType, mount.RowId); AddChara((int)mount.ModelChara.Row, ObjectKind.MountType, mount.RowId, mount.RowId);
}); });
var cTask = Task.Run(() => var cTask = Task.Run(() =>
{ {
foreach (var companion in gameData.GetExcelSheet<Companion>(language)!) foreach (var companion in gameData.GetExcelSheet<Companion>(language)!)
AddChara((int)companion.Model.Row, ObjectKind.Companion, companion.RowId); AddChara((int)companion.Model.Row, ObjectKind.Companion, companion.RowId, companion.RowId);
}); });
var eTask = Task.Run(() => var eTask = Task.Run(() =>
{ {
foreach (var eNpc in gameData.GetExcelSheet<ENpcBase>(language)!) foreach (var eNpc in gameData.GetExcelSheet<ENpcBase>(language)!)
AddChara((int)eNpc.ModelChara.Row, ObjectKind.EventNpc, eNpc.RowId); AddChara((int)eNpc.ModelChara.Row, ObjectKind.EventNpc, eNpc.RowId, eNpc.RowId);
}); });
var options = new ParallelOptions() var options = new ParallelOptions()
@ -296,14 +302,14 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier
Parallel.ForEach(gameData.GetExcelSheet<BNpcBase>(language)!.Where(b => b.RowId < BnpcNames.Count), options, bNpc => Parallel.ForEach(gameData.GetExcelSheet<BNpcBase>(language)!.Where(b => b.RowId < BnpcNames.Count), options, bNpc =>
{ {
foreach (var name in BnpcNames[(int)bNpc.RowId]) foreach (var name in BnpcNames[(int)bNpc.RowId])
AddChara((int)bNpc.ModelChara.Row, ObjectKind.BattleNpc, name); AddChara((int)bNpc.ModelChara.Row, ObjectKind.BattleNpc, name, bNpc.RowId);
}); });
Task.WaitAll(oTask, mTask, cTask, eTask); Task.WaitAll(oTask, mTask, cTask, eTask);
return ret.Select(s => s.Count > 0 return ret.Select(s => !s.IsEmpty
? s.ToArray() ? s.ToArray()
: Array.Empty<(string Name, ObjectKind Kind)>()).ToArray(); : Array.Empty<(string Name, ObjectKind Kind, uint Id)>()).ToArray();
} }
public static unsafe ulong KeyFromCharacterBase(CharacterBase* drawObject) public static unsafe ulong KeyFromCharacterBase(CharacterBase* drawObject)

View file

@ -6,7 +6,7 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>; using PseudoEquipItem = System.ValueTuple<string, ulong, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Data; namespace Penumbra.GameData.Data;

View file

@ -204,6 +204,14 @@ public static class EquipSlotExtensions
public static readonly EquipSlot[] EquipmentSlots = Enum.GetValues<EquipSlot>().Where(e => e.IsEquipment()).ToArray(); public static readonly EquipSlot[] EquipmentSlots = Enum.GetValues<EquipSlot>().Where(e => e.IsEquipment()).ToArray();
public static readonly EquipSlot[] AccessorySlots = Enum.GetValues<EquipSlot>().Where(e => e.IsAccessory()).ToArray(); public static readonly EquipSlot[] AccessorySlots = Enum.GetValues<EquipSlot>().Where(e => e.IsAccessory()).ToArray();
public static readonly EquipSlot[] EqdpSlots = EquipmentSlots.Concat(AccessorySlots).ToArray(); public static readonly EquipSlot[] EqdpSlots = EquipmentSlots.Concat(AccessorySlots).ToArray();
public static readonly EquipSlot[] WeaponSlots =
{
EquipSlot.MainHand,
EquipSlot.OffHand,
};
public static readonly EquipSlot[] FullSlots = WeaponSlots.Concat(EqdpSlots).ToArray();
} }
public static partial class Names public static partial class Names

View file

@ -2,8 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Dalamud; using Dalamud;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Plugin; using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
@ -63,6 +63,14 @@ public interface IObjectIdentifier : IDisposable
/// <inheritdoc cref="Identify(SetId, WeaponType, ushort, EquipSlot)"/> /// <inheritdoc cref="Identify(SetId, WeaponType, ushort, EquipSlot)"/>
public IEnumerable<EquipItem> Identify(SetId setId, ushort variant, EquipSlot slot) public IEnumerable<EquipItem> Identify(SetId setId, ushort variant, EquipSlot slot)
=> Identify(setId, 0, variant, slot); => Identify(setId, 0, variant, slot);
/// <summary> Obtain a list of BNPC Name Ids associated with a BNPC Id. </summary>
public IReadOnlyList<uint> GetBnpcNames(uint bNpcId);
/// <summary> Obtain a list of Names and Object Kinds associated with a ModelChara ID. </summary>
public IReadOnlyList<(string Name, ObjectKind Kind, uint Id)> ModelCharaNames(uint modelId);
public int NumModelChara { get; }
} }
public interface IGamePathParser public interface IGamePathParser

View file

@ -1,4 +1,6 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Penumbra.String.Functions; using Penumbra.String.Functions;
@ -6,12 +8,28 @@ using Penumbra.String.Functions;
namespace Penumbra.GameData.Structs; namespace Penumbra.GameData.Structs;
[StructLayout(LayoutKind.Sequential, Size = Size)] [StructLayout(LayoutKind.Sequential, Size = Size)]
public unsafe struct CustomizeData : IEquatable< CustomizeData > public unsafe struct CustomizeData : IEquatable<CustomizeData>, IReadOnlyCollection<byte>
{ {
public const int Size = 26; public const int Size = 26;
public fixed byte Data[Size]; public fixed byte Data[Size];
public int Count
=> Size;
public IEnumerator<byte> GetEnumerator()
{
for (var i = 0; i < Size; ++i)
yield return At(i);
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
private unsafe byte At(int index)
=> Data[index];
public void Read(void* source) public void Read(void* source)
{ {
fixed (byte* ptr = Data) fixed (byte* ptr = Data)
@ -78,21 +96,18 @@ public unsafe struct CustomizeData : IEquatable< CustomizeData >
{ {
var sb = new StringBuilder(Size * 3); var sb = new StringBuilder(Size * 3);
for (var i = 0; i < Size - 1; ++i) for (var i = 0; i < Size - 1; ++i)
{
sb.Append($"{Data[i]:X2} "); sb.Append($"{Data[i]:X2} ");
}
sb.Append($"{Data[Size - 1]:X2}"); sb.Append($"{Data[Size - 1]:X2}");
return sb.ToString(); return sb.ToString();
} }
public bool LoadBase64(string base64) public bool LoadBase64(string base64)
{ {
var buffer = stackalloc byte[Size]; var buffer = stackalloc byte[Size];
var span = new Span<byte>(buffer, Size); var span = new Span<byte>(buffer, Size);
if (!Convert.TryFromBase64String(base64, span, out var written) || written != Size) if (!Convert.TryFromBase64String(base64, span, out var written) || written != Size)
{
return false; return false;
}
Read(buffer); Read(buffer);
return true; return true;

View file

@ -2,7 +2,7 @@
using Dalamud.Utility; using Dalamud.Utility;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>; using PseudoEquipItem = System.ValueTuple<string, ulong, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Structs; namespace Penumbra.GameData.Structs;
@ -10,13 +10,16 @@ namespace Penumbra.GameData.Structs;
public readonly struct EquipItem public readonly struct EquipItem
{ {
public readonly string Name; public readonly string Name;
public readonly uint Id; public readonly ulong Id;
public readonly ushort IconId; public readonly ushort IconId;
public readonly SetId ModelId; public readonly SetId ModelId;
public readonly WeaponType WeaponType; public readonly WeaponType WeaponType;
public readonly byte Variant; public readonly byte Variant;
public readonly FullEquipType Type; public readonly FullEquipType Type;
public uint ItemId
=> (uint)Id;
public bool Valid public bool Valid
=> Type != FullEquipType.Unknown; => Type != FullEquipType.Unknown;
@ -35,7 +38,7 @@ public readonly struct EquipItem
public EquipItem() public EquipItem()
=> Name = string.Empty; => Name = string.Empty;
public EquipItem(string name, uint id, ushort iconId, SetId modelId, WeaponType weaponType, byte variant, FullEquipType type) public EquipItem(string name, ulong id, ushort iconId, SetId modelId, WeaponType weaponType, byte variant, FullEquipType type)
{ {
Name = string.Intern(name); Name = string.Intern(name);
Id = id; Id = id;
@ -53,7 +56,7 @@ public readonly struct EquipItem
=> new(it.Item1, it.Item2, it.Item3, it.Item4, it.Item5, it.Item6, (FullEquipType)it.Item7); => new(it.Item1, it.Item2, it.Item3, it.Item4, it.Item5, it.Item6, (FullEquipType)it.Item7);
public static explicit operator PseudoEquipItem(EquipItem it) public static explicit operator PseudoEquipItem(EquipItem it)
=> (it.Name, it.Id, it.IconId, (ushort)it.ModelId, (ushort)it.WeaponType, it.Variant, (byte)it.Type); => (it.Name, it.ItemId, it.IconId, (ushort)it.ModelId, (ushort)it.WeaponType, it.Variant, (byte)it.Type);
public static EquipItem FromArmor(Item item) public static EquipItem FromArmor(Item item)
{ {
@ -90,4 +93,28 @@ public readonly struct EquipItem
var variant = (byte)(item.ModelSub >> 32); var variant = (byte)(item.ModelSub >> 32);
return new EquipItem(name, id, icon, model, weapon, variant, type); return new EquipItem(name, id, icon, model, weapon, variant, type);
} }
public static EquipItem FromIds(uint itemId, ushort iconId, SetId modelId, WeaponType type, byte variant,
FullEquipType equipType = FullEquipType.Unknown, string? name = null)
{
name ??= $"Unknown ({modelId.Value}-{(type.Value != 0 ? $"{type.Value}-" : string.Empty)}{variant})";
var fullId = itemId == 0
? modelId.Value | ((ulong)type.Value << 16) | ((ulong)variant << 32) | ((ulong)equipType << 40) | (1ul << 48)
: itemId;
return new EquipItem(name, fullId, iconId, modelId, type, variant, equipType);
}
public static EquipItem FromId(ulong id)
{
var setId = (SetId)id;
var type = (WeaponType)(id >> 16);
var variant = (byte)(id >> 32);
var equipType = (FullEquipType)(id >> 40);
return new EquipItem($"Unknown ({setId.Value}-{(type.Value != 0 ? $"{type.Value}-" : string.Empty)}{variant})", id, 0, setId, type,
variant, equipType);
}
public override string ToString()
=> Name;
} }

View file

@ -96,7 +96,7 @@ public sealed partial class IndividualCollections
identifiers = new[] identifiers = new[]
{ {
manager.CreateRetainer(retainerName, 0), manager.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both),
}; };
break; break;
case IdentifierType.Owned: case IdentifierType.Owned:
@ -131,7 +131,7 @@ public sealed partial class IndividualCollections
ObjectKind.EventNpc => manager.Data.ENpcs, ObjectKind.EventNpc => manager.Data.ENpcs,
ObjectKind.Companion => manager.Data.Companions, ObjectKind.Companion => manager.Data.Companions,
ObjectKind.MountType => manager.Data.Mounts, ObjectKind.MountType => manager.Data.Mounts,
(ObjectKind)15 => manager.Data.Ornaments, ObjectKind.Ornament => manager.Data.Ornaments,
_ => throw new NotImplementedException(), _ => throw new NotImplementedException(),
}; };
return table.Where(kvp => kvp.Value == name) return table.Where(kvp => kvp.Value == name)

View file

@ -122,14 +122,14 @@ public unsafe class MetaState : IDisposable
_gameEventManager.CharacterBaseCreated -= OnCharacterBaseCreated; _gameEventManager.CharacterBaseCreated -= OnCharacterBaseCreated;
} }
private void OnCreatingCharacterBase(uint modelCharaId, nint customize, nint equipData) private void OnCreatingCharacterBase(nint modelCharaId, nint customize, nint equipData)
{ {
_lastCreatedCollection = _collectionResolver.IdentifyLastGameObjectCollection(true); _lastCreatedCollection = _collectionResolver.IdentifyLastGameObjectCollection(true);
if (_lastCreatedCollection.Valid && _lastCreatedCollection.AssociatedGameObject != nint.Zero) if (_lastCreatedCollection.Valid && _lastCreatedCollection.AssociatedGameObject != nint.Zero)
_communicator.CreatingCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject, _communicator.CreatingCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject,
_lastCreatedCollection.ModCollection.Name, (nint)(&modelCharaId), customize, equipData); _lastCreatedCollection.ModCollection.Name, modelCharaId, customize, equipData);
var decal = new DecalReverter(_config, _characterUtility, _resources, _lastCreatedCollection, UsesDecal(modelCharaId, customize)); var decal = new DecalReverter(_config, _characterUtility, _resources, _lastCreatedCollection, UsesDecal(*(uint*)modelCharaId, customize));
var cmp = _lastCreatedCollection.ModCollection.TemporarilySetCmpFile(_characterUtility); var cmp = _lastCreatedCollection.ModCollection.TemporarilySetCmpFile(_characterUtility);
_characterBaseCreateMetaChanges.Dispose(); // Should always be empty. _characterBaseCreateMetaChanges.Dispose(); // Should always be empty.
_characterBaseCreateMetaChanges = new DisposableContainer(decal, cmp); _characterBaseCreateMetaChanges = new DisposableContainer(decal, cmp);

View file

@ -2,7 +2,6 @@ using Dalamud.Hooking;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using Penumbra.GameData; using Penumbra.GameData;
using System; using System;
using System.Diagnostics;
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
@ -154,7 +153,7 @@ public unsafe class GameEventManager : IDisposable
{ {
try try
{ {
((CreatingCharacterBaseEvent)subscriber).Invoke(a, b, c); ((CreatingCharacterBaseEvent)subscriber).Invoke((nint) (&a), b, c);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -181,7 +180,7 @@ public unsafe class GameEventManager : IDisposable
return ret; return ret;
} }
public delegate void CreatingCharacterBaseEvent(uint modelCharaId, nint customize, nint equipment); public delegate void CreatingCharacterBaseEvent(nint modelCharaId, nint customize, nint equipment);
public delegate void CharacterBaseCreatedEvent(uint modelCharaId, nint customize, nint equipment, nint drawObject); public delegate void CharacterBaseCreatedEvent(uint modelCharaId, nint customize, nint equipment, nint drawObject);
#endregion #endregion