Make equipitems sharable again.

This commit is contained in:
Ottermandias 2023-06-13 21:04:19 +02:00
parent 323b4d6f21
commit 8436455936
9 changed files with 146 additions and 52 deletions

View file

@ -6,10 +6,11 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Data;
internal sealed class EquipmentIdentificationList : KeyList<EquipItem>
internal sealed class EquipmentIdentificationList : KeyList<PseudoEquipItem>
{
private const string Tag = "EquipmentIdentification";
@ -20,11 +21,11 @@ internal sealed class EquipmentIdentificationList : KeyList<EquipItem>
public IEnumerable<EquipItem> Between(SetId modelId, EquipSlot slot = EquipSlot.Unknown, byte variant = 0)
{
if (slot == EquipSlot.Unknown)
return Between(ToKey(modelId, 0, 0), ToKey(modelId, (EquipSlot)0xFF, 0xFF));
return Between(ToKey(modelId, 0, 0), ToKey(modelId, (EquipSlot)0xFF, 0xFF)).Select(e => (EquipItem)e);
if (variant == 0)
return Between(ToKey(modelId, slot, 0), ToKey(modelId, slot, 0xFF));
return Between(ToKey(modelId, slot, 0), ToKey(modelId, slot, 0xFF)).Select(e => (EquipItem)e);
return Between(ToKey(modelId, slot, variant), ToKey(modelId, slot, variant));
return Between(ToKey(modelId, slot, variant), ToKey(modelId, slot, variant)).Select(e => (EquipItem)e);
}
public void Dispose(DalamudPluginInterface pi, ClientLanguage language)
@ -34,9 +35,9 @@ internal sealed class EquipmentIdentificationList : KeyList<EquipItem>
=> ((ulong)modelId << 32) | ((ulong)slot << 16) | variant;
public static ulong ToKey(EquipItem i)
=> ToKey(i.ModelId, i.Slot, i.Variant);
=> ToKey(i.ModelId, i.Type.ToSlot(), i.Variant);
protected override IEnumerable<ulong> ToKeys(EquipItem i)
protected override IEnumerable<ulong> ToKeys(PseudoEquipItem i)
{
yield return ToKey(i);
}
@ -44,12 +45,12 @@ internal sealed class EquipmentIdentificationList : KeyList<EquipItem>
protected override bool ValidKey(ulong key)
=> key != 0;
protected override int ValueKeySelector(EquipItem data)
=> (int)data.Id;
protected override int ValueKeySelector(PseudoEquipItem data)
=> (int)data.Item2;
private static IEnumerable<EquipItem> CreateEquipmentList(DataManager gameData, ClientLanguage language)
private static IEnumerable<PseudoEquipItem> CreateEquipmentList(DataManager gameData, ClientLanguage language)
{
var items = gameData.GetExcelSheet<Item>(language)!;
return items.Where(i => ((EquipSlot)i.EquipSlotCategory.Row).IsEquipmentPiece()).Select(EquipItem.FromArmor);
return items.Where(i => ((EquipSlot)i.EquipSlotCategory.Row).IsEquipmentPiece()).Select(i => (PseudoEquipItem)EquipItem.FromArmor(i));
}
}

View file

@ -1,5 +1,4 @@
using System.Text.RegularExpressions;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -18,7 +17,6 @@ public static partial class GamePaths
: GenderRace.Unknown;
}
public static partial class Monster
{
public static partial class Imc

View file

@ -8,14 +8,17 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Data;
public sealed class ItemData : DataSharer, IReadOnlyDictionary<FullEquipType, IReadOnlyList<EquipItem>>
{
private readonly IReadOnlyList<IReadOnlyList<EquipItem>> _items;
private readonly IReadOnlyDictionary<uint, PseudoEquipItem> _mainItems;
private readonly IReadOnlyDictionary<uint, PseudoEquipItem> _offItems;
private readonly IReadOnlyList<IReadOnlyList<PseudoEquipItem>> _byType;
private static IReadOnlyList<IReadOnlyList<EquipItem>> CreateItems(DataManager dataManager, ClientLanguage language)
private static IReadOnlyList<IReadOnlyList<PseudoEquipItem>> CreateItems(DataManager dataManager, ClientLanguage language)
{
var tmp = Enum.GetValues<FullEquipType>().Select(_ => new List<EquipItem>(1024)).ToArray();
@ -28,7 +31,7 @@ public sealed class ItemData : DataSharer, IReadOnlyDictionary<FullEquipType, IR
if (item.ModelMain != 0)
tmp[(int)type].Add(EquipItem.FromMainhand(item));
if (item.ModelSub != 0)
tmp[(int)type].Add(EquipItem.FromOffhand(item));
tmp[(int)type.Offhand()].Add(EquipItem.FromOffhand(item));
}
else if (type != FullEquipType.Unknown)
{
@ -36,56 +39,141 @@ public sealed class ItemData : DataSharer, IReadOnlyDictionary<FullEquipType, IR
}
}
var ret = new IReadOnlyList<EquipItem>[tmp.Length];
ret[0] = Array.Empty<EquipItem>();
var ret = new IReadOnlyList<PseudoEquipItem>[tmp.Length];
ret[0] = Array.Empty<PseudoEquipItem>();
for (var i = 1; i < tmp.Length; ++i)
ret[i] = tmp[i].OrderBy(item => item.Name).ToArray();
ret[i] = tmp[i].OrderBy(item => item.Name).Select(s => (PseudoEquipItem)s).ToArray();
return ret;
}
private static IReadOnlyDictionary<uint, PseudoEquipItem> CreateMainItems(IReadOnlyList<IReadOnlyList<PseudoEquipItem>> items)
{
var dict = new Dictionary<uint, PseudoEquipItem>(1024 * 4);
foreach (var type in Enum.GetValues<FullEquipType>().Where(v => !FullEquipTypeExtensions.OffhandTypes.Contains(v)))
{
var list = items[(int)type];
foreach (var item in list)
dict.TryAdd(item.Item2, item);
}
dict.TrimExcess();
return dict;
}
private static IReadOnlyDictionary<uint, PseudoEquipItem> CreateOffItems(IReadOnlyList<IReadOnlyList<PseudoEquipItem>> items)
{
var dict = new Dictionary<uint, PseudoEquipItem>(128);
foreach (var type in FullEquipTypeExtensions.OffhandTypes)
{
var list = items[(int)type];
foreach (var item in list)
dict.TryAdd(item.Item2, item);
}
dict.TrimExcess();
return dict;
}
public ItemData(DalamudPluginInterface pluginInterface, DataManager dataManager, ClientLanguage language)
: base(pluginInterface, language, 1)
{
_items = TryCatchData("ItemList", () => CreateItems(dataManager, language));
_byType = TryCatchData("ItemList", () => CreateItems(dataManager, language));
_mainItems = TryCatchData("ItemDictMain", () => CreateMainItems(_byType));
_offItems = TryCatchData("ItemDictOff", () => CreateOffItems(_byType));
}
protected override void DisposeInternal()
=> DisposeTag("ItemList");
{
DisposeTag("ItemList");
DisposeTag("ItemDictMain");
DisposeTag("ItemDictOff");
}
public IEnumerator<KeyValuePair<FullEquipType, IReadOnlyList<EquipItem>>> GetEnumerator()
{
for (var i = 1; i < _items.Count; ++i)
yield return new KeyValuePair<FullEquipType, IReadOnlyList<EquipItem>>((FullEquipType)i, _items[i]);
for (var i = 1; i < _byType.Count; ++i)
yield return new KeyValuePair<FullEquipType, IReadOnlyList<EquipItem>>((FullEquipType)i, new EquipItemList(_byType[i]));
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public int Count
=> _items.Count - 1;
=> _byType.Count - 1;
public bool ContainsKey(FullEquipType key)
=> (int)key < _items.Count && key != FullEquipType.Unknown;
=> (int)key < _byType.Count && key != FullEquipType.Unknown;
public bool TryGetValue(FullEquipType key, out IReadOnlyList<EquipItem> value)
{
if (ContainsKey(key))
{
value = _items[(int)key];
value = new EquipItemList(_byType[(int)key]);
return true;
}
value = _items[0];
value = Array.Empty<EquipItem>();
return false;
}
public IReadOnlyList<EquipItem> this[FullEquipType key]
=> TryGetValue(key, out var ret) ? ret : throw new IndexOutOfRangeException();
public bool ContainsKey(uint key, bool main = true)
=> main ? _mainItems.ContainsKey(key) : _offItems.ContainsKey(key);
public bool TryGetValue(uint key, out EquipItem value)
{
if (_mainItems.TryGetValue(key, out var v))
{
value = v;
return true;
}
value = default;
return false;
}
public IEnumerable<(uint, EquipItem)> AllItems(bool main)
=> (main ? _mainItems : _offItems).Select(i => (i.Key, (EquipItem)i.Value));
public bool TryGetValue(uint key, bool main, out EquipItem value)
{
var dict = main ? _mainItems : _offItems;
if (dict.TryGetValue(key, out var v))
{
value = v;
return true;
}
value = default;
return false;
}
public IEnumerable<FullEquipType> Keys
=> Enum.GetValues<FullEquipType>().Skip(1);
public IEnumerable<IReadOnlyList<EquipItem>> Values
=> _items.Skip(1);
=> _byType.Skip(1).Select(l => (IReadOnlyList<EquipItem>)new EquipItemList(l));
private readonly struct EquipItemList : IReadOnlyList<EquipItem>
{
private readonly IReadOnlyList<PseudoEquipItem> _items;
public EquipItemList(IReadOnlyList<PseudoEquipItem> items)
=> _items = items;
public IEnumerator<EquipItem> GetEnumerator()
=> _items.Select(i => (EquipItem)i).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public int Count
=> _items.Count;
public EquipItem this[int index]
=> _items[index];
}
}

View file

@ -6,10 +6,11 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>;
namespace Penumbra.GameData.Data;
internal sealed class WeaponIdentificationList : KeyList<EquipItem>
internal sealed class WeaponIdentificationList : KeyList<PseudoEquipItem>
{
private const string Tag = "WeaponIdentification";
private const int Version = 1;
@ -19,16 +20,16 @@ internal sealed class WeaponIdentificationList : KeyList<EquipItem>
{ }
public IEnumerable<EquipItem> Between(SetId modelId)
=> Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF));
=> Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF)).Select(e => (EquipItem)e);
public IEnumerable<EquipItem> Between(SetId modelId, WeaponType type, byte variant = 0)
{
if (type == 0)
return Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF));
return Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF)).Select(e => (EquipItem)e);
if (variant == 0)
return Between(ToKey(modelId, type, 0), ToKey(modelId, type, 0xFF));
return Between(ToKey(modelId, type, 0), ToKey(modelId, type, 0xFF)).Select(e => (EquipItem)e);
return Between(ToKey(modelId, type, variant), ToKey(modelId, type, variant));
return Between(ToKey(modelId, type, variant), ToKey(modelId, type, variant)).Select(e => (EquipItem)e);
}
public void Dispose(DalamudPluginInterface pi, ClientLanguage language)
@ -40,7 +41,7 @@ internal sealed class WeaponIdentificationList : KeyList<EquipItem>
public static ulong ToKey(EquipItem i)
=> ToKey(i.ModelId, i.WeaponType, i.Variant);
protected override IEnumerable<ulong> ToKeys(EquipItem data)
protected override IEnumerable<ulong> ToKeys(PseudoEquipItem data)
{
yield return ToKey(data);
}
@ -48,20 +49,20 @@ internal sealed class WeaponIdentificationList : KeyList<EquipItem>
protected override bool ValidKey(ulong key)
=> key != 0;
protected override int ValueKeySelector(EquipItem data)
=> (int)data.Id;
protected override int ValueKeySelector(PseudoEquipItem data)
=> (int)data.Item2;
private static IEnumerable<EquipItem> CreateWeaponList(DataManager gameData, ClientLanguage language)
private static IEnumerable<PseudoEquipItem> CreateWeaponList(DataManager gameData, ClientLanguage language)
=> gameData.GetExcelSheet<Item>(language)!.SelectMany(ToEquipItems);
private static IEnumerable<EquipItem> ToEquipItems(Item item)
private static IEnumerable<PseudoEquipItem> ToEquipItems(Item item)
{
if ((EquipSlot)item.EquipSlotCategory.Row is not (EquipSlot.MainHand or EquipSlot.OffHand or EquipSlot.BothHand))
yield break;
if (item.ModelMain != 0)
yield return EquipItem.FromMainhand(item);
yield return (PseudoEquipItem)EquipItem.FromMainhand(item);
if (item.ModelSub != 0)
yield return EquipItem.FromOffhand(item);
yield return (PseudoEquipItem)EquipItem.FromOffhand(item);
}
}