Skip to content

Commit 8436455

Browse files
committed
Make equipitems sharable again.
1 parent 323b4d6 commit 8436455

File tree

9 files changed

+146
-52
lines changed

9 files changed

+146
-52
lines changed

Penumbra.GameData/Data/EquipmentIdentificationList.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
using Lumina.Excel.GeneratedSheets;
77
using Penumbra.GameData.Enums;
88
using Penumbra.GameData.Structs;
9+
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>;
910

1011
namespace Penumbra.GameData.Data;
1112

12-
internal sealed class EquipmentIdentificationList : KeyList<EquipItem>
13+
internal sealed class EquipmentIdentificationList : KeyList<PseudoEquipItem>
1314
{
1415
private const string Tag = "EquipmentIdentification";
1516

@@ -20,11 +21,11 @@ public EquipmentIdentificationList(DalamudPluginInterface pi, ClientLanguage lan
2021
public IEnumerable<EquipItem> Between(SetId modelId, EquipSlot slot = EquipSlot.Unknown, byte variant = 0)
2122
{
2223
if (slot == EquipSlot.Unknown)
23-
return Between(ToKey(modelId, 0, 0), ToKey(modelId, (EquipSlot)0xFF, 0xFF));
24+
return Between(ToKey(modelId, 0, 0), ToKey(modelId, (EquipSlot)0xFF, 0xFF)).Select(e => (EquipItem)e);
2425
if (variant == 0)
25-
return Between(ToKey(modelId, slot, 0), ToKey(modelId, slot, 0xFF));
26+
return Between(ToKey(modelId, slot, 0), ToKey(modelId, slot, 0xFF)).Select(e => (EquipItem)e);
2627

27-
return Between(ToKey(modelId, slot, variant), ToKey(modelId, slot, variant));
28+
return Between(ToKey(modelId, slot, variant), ToKey(modelId, slot, variant)).Select(e => (EquipItem)e);
2829
}
2930

3031
public void Dispose(DalamudPluginInterface pi, ClientLanguage language)
@@ -34,22 +35,22 @@ public static ulong ToKey(SetId modelId, EquipSlot slot, byte variant)
3435
=> ((ulong)modelId << 32) | ((ulong)slot << 16) | variant;
3536

3637
public static ulong ToKey(EquipItem i)
37-
=> ToKey(i.ModelId, i.Slot, i.Variant);
38+
=> ToKey(i.ModelId, i.Type.ToSlot(), i.Variant);
3839

39-
protected override IEnumerable<ulong> ToKeys(EquipItem i)
40+
protected override IEnumerable<ulong> ToKeys(PseudoEquipItem i)
4041
{
4142
yield return ToKey(i);
4243
}
4344

4445
protected override bool ValidKey(ulong key)
4546
=> key != 0;
4647

47-
protected override int ValueKeySelector(EquipItem data)
48-
=> (int)data.Id;
48+
protected override int ValueKeySelector(PseudoEquipItem data)
49+
=> (int)data.Item2;
4950

50-
private static IEnumerable<EquipItem> CreateEquipmentList(DataManager gameData, ClientLanguage language)
51+
private static IEnumerable<PseudoEquipItem> CreateEquipmentList(DataManager gameData, ClientLanguage language)
5152
{
5253
var items = gameData.GetExcelSheet<Item>(language)!;
53-
return items.Where(i => ((EquipSlot)i.EquipSlotCategory.Row).IsEquipmentPiece()).Select(EquipItem.FromArmor);
54+
return items.Where(i => ((EquipSlot)i.EquipSlotCategory.Row).IsEquipmentPiece()).Select(i => (PseudoEquipItem)EquipItem.FromArmor(i));
5455
}
5556
}

Penumbra.GameData/Data/GamePaths.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Text.RegularExpressions;
2-
using Lumina.Excel.GeneratedSheets;
32
using Penumbra.GameData.Enums;
43
using Penumbra.GameData.Structs;
54

@@ -18,7 +17,6 @@ public static GenderRace ParseRaceCode(string path)
1817
: GenderRace.Unknown;
1918
}
2019

21-
2220
public static partial class Monster
2321
{
2422
public static partial class Imc

Penumbra.GameData/Data/ItemData.cs

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
using Lumina.Excel.GeneratedSheets;
99
using Penumbra.GameData.Enums;
1010
using Penumbra.GameData.Structs;
11+
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>;
1112

1213
namespace Penumbra.GameData.Data;
1314

1415
public sealed class ItemData : DataSharer, IReadOnlyDictionary<FullEquipType, IReadOnlyList<EquipItem>>
1516
{
16-
private readonly IReadOnlyList<IReadOnlyList<EquipItem>> _items;
17+
private readonly IReadOnlyDictionary<uint, PseudoEquipItem> _mainItems;
18+
private readonly IReadOnlyDictionary<uint, PseudoEquipItem> _offItems;
19+
private readonly IReadOnlyList<IReadOnlyList<PseudoEquipItem>> _byType;
1720

18-
private static IReadOnlyList<IReadOnlyList<EquipItem>> CreateItems(DataManager dataManager, ClientLanguage language)
21+
private static IReadOnlyList<IReadOnlyList<PseudoEquipItem>> CreateItems(DataManager dataManager, ClientLanguage language)
1922
{
2023
var tmp = Enum.GetValues<FullEquipType>().Select(_ => new List<EquipItem>(1024)).ToArray();
2124

@@ -28,64 +31,149 @@ private static IReadOnlyList<IReadOnlyList<EquipItem>> CreateItems(DataManager d
2831
if (item.ModelMain != 0)
2932
tmp[(int)type].Add(EquipItem.FromMainhand(item));
3033
if (item.ModelSub != 0)
31-
tmp[(int)type].Add(EquipItem.FromOffhand(item));
34+
tmp[(int)type.Offhand()].Add(EquipItem.FromOffhand(item));
3235
}
3336
else if (type != FullEquipType.Unknown)
3437
{
3538
tmp[(int)type].Add(EquipItem.FromArmor(item));
3639
}
3740
}
3841

39-
var ret = new IReadOnlyList<EquipItem>[tmp.Length];
40-
ret[0] = Array.Empty<EquipItem>();
42+
var ret = new IReadOnlyList<PseudoEquipItem>[tmp.Length];
43+
ret[0] = Array.Empty<PseudoEquipItem>();
4144
for (var i = 1; i < tmp.Length; ++i)
42-
ret[i] = tmp[i].OrderBy(item => item.Name).ToArray();
45+
ret[i] = tmp[i].OrderBy(item => item.Name).Select(s => (PseudoEquipItem)s).ToArray();
4346

4447
return ret;
4548
}
4649

50+
private static IReadOnlyDictionary<uint, PseudoEquipItem> CreateMainItems(IReadOnlyList<IReadOnlyList<PseudoEquipItem>> items)
51+
{
52+
var dict = new Dictionary<uint, PseudoEquipItem>(1024 * 4);
53+
foreach (var type in Enum.GetValues<FullEquipType>().Where(v => !FullEquipTypeExtensions.OffhandTypes.Contains(v)))
54+
{
55+
var list = items[(int)type];
56+
foreach (var item in list)
57+
dict.TryAdd(item.Item2, item);
58+
}
59+
60+
dict.TrimExcess();
61+
return dict;
62+
}
63+
64+
private static IReadOnlyDictionary<uint, PseudoEquipItem> CreateOffItems(IReadOnlyList<IReadOnlyList<PseudoEquipItem>> items)
65+
{
66+
var dict = new Dictionary<uint, PseudoEquipItem>(128);
67+
foreach (var type in FullEquipTypeExtensions.OffhandTypes)
68+
{
69+
var list = items[(int)type];
70+
foreach (var item in list)
71+
dict.TryAdd(item.Item2, item);
72+
}
73+
74+
dict.TrimExcess();
75+
return dict;
76+
}
77+
4778
public ItemData(DalamudPluginInterface pluginInterface, DataManager dataManager, ClientLanguage language)
4879
: base(pluginInterface, language, 1)
4980
{
50-
_items = TryCatchData("ItemList", () => CreateItems(dataManager, language));
81+
_byType = TryCatchData("ItemList", () => CreateItems(dataManager, language));
82+
_mainItems = TryCatchData("ItemDictMain", () => CreateMainItems(_byType));
83+
_offItems = TryCatchData("ItemDictOff", () => CreateOffItems(_byType));
5184
}
5285

5386
protected override void DisposeInternal()
54-
=> DisposeTag("ItemList");
87+
{
88+
DisposeTag("ItemList");
89+
DisposeTag("ItemDictMain");
90+
DisposeTag("ItemDictOff");
91+
}
5592

5693
public IEnumerator<KeyValuePair<FullEquipType, IReadOnlyList<EquipItem>>> GetEnumerator()
5794
{
58-
for (var i = 1; i < _items.Count; ++i)
59-
yield return new KeyValuePair<FullEquipType, IReadOnlyList<EquipItem>>((FullEquipType)i, _items[i]);
95+
for (var i = 1; i < _byType.Count; ++i)
96+
yield return new KeyValuePair<FullEquipType, IReadOnlyList<EquipItem>>((FullEquipType)i, new EquipItemList(_byType[i]));
6097
}
6198

6299
IEnumerator IEnumerable.GetEnumerator()
63100
=> GetEnumerator();
64101

65102
public int Count
66-
=> _items.Count - 1;
103+
=> _byType.Count - 1;
67104

68105
public bool ContainsKey(FullEquipType key)
69-
=> (int)key < _items.Count && key != FullEquipType.Unknown;
106+
=> (int)key < _byType.Count && key != FullEquipType.Unknown;
70107

71108
public bool TryGetValue(FullEquipType key, out IReadOnlyList<EquipItem> value)
72109
{
73110
if (ContainsKey(key))
74111
{
75-
value = _items[(int)key];
112+
value = new EquipItemList(_byType[(int)key]);
76113
return true;
77114
}
78115

79-
value = _items[0];
116+
value = Array.Empty<EquipItem>();
80117
return false;
81118
}
82119

83120
public IReadOnlyList<EquipItem> this[FullEquipType key]
84121
=> TryGetValue(key, out var ret) ? ret : throw new IndexOutOfRangeException();
85122

123+
public bool ContainsKey(uint key, bool main = true)
124+
=> main ? _mainItems.ContainsKey(key) : _offItems.ContainsKey(key);
125+
126+
public bool TryGetValue(uint key, out EquipItem value)
127+
{
128+
if (_mainItems.TryGetValue(key, out var v))
129+
{
130+
value = v;
131+
return true;
132+
}
133+
134+
value = default;
135+
return false;
136+
}
137+
138+
public IEnumerable<(uint, EquipItem)> AllItems(bool main)
139+
=> (main ? _mainItems : _offItems).Select(i => (i.Key, (EquipItem)i.Value));
140+
141+
public bool TryGetValue(uint key, bool main, out EquipItem value)
142+
{
143+
var dict = main ? _mainItems : _offItems;
144+
if (dict.TryGetValue(key, out var v))
145+
{
146+
value = v;
147+
return true;
148+
}
149+
150+
value = default;
151+
return false;
152+
}
153+
86154
public IEnumerable<FullEquipType> Keys
87155
=> Enum.GetValues<FullEquipType>().Skip(1);
88156

89157
public IEnumerable<IReadOnlyList<EquipItem>> Values
90-
=> _items.Skip(1);
158+
=> _byType.Skip(1).Select(l => (IReadOnlyList<EquipItem>)new EquipItemList(l));
159+
160+
private readonly struct EquipItemList : IReadOnlyList<EquipItem>
161+
{
162+
private readonly IReadOnlyList<PseudoEquipItem> _items;
163+
164+
public EquipItemList(IReadOnlyList<PseudoEquipItem> items)
165+
=> _items = items;
166+
167+
public IEnumerator<EquipItem> GetEnumerator()
168+
=> _items.Select(i => (EquipItem)i).GetEnumerator();
169+
170+
IEnumerator IEnumerable.GetEnumerator()
171+
=> GetEnumerator();
172+
173+
public int Count
174+
=> _items.Count;
175+
176+
public EquipItem this[int index]
177+
=> _items[index];
178+
}
91179
}

Penumbra.GameData/Data/WeaponIdentificationList.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
using Lumina.Excel.GeneratedSheets;
77
using Penumbra.GameData.Enums;
88
using Penumbra.GameData.Structs;
9+
using PseudoEquipItem = System.ValueTuple<string, uint, ushort, ushort, ushort, byte, byte>;
910

1011
namespace Penumbra.GameData.Data;
1112

12-
internal sealed class WeaponIdentificationList : KeyList<EquipItem>
13+
internal sealed class WeaponIdentificationList : KeyList<PseudoEquipItem>
1314
{
1415
private const string Tag = "WeaponIdentification";
1516
private const int Version = 1;
@@ -19,16 +20,16 @@ public WeaponIdentificationList(DalamudPluginInterface pi, ClientLanguage langua
1920
{ }
2021

2122
public IEnumerable<EquipItem> Between(SetId modelId)
22-
=> Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF));
23+
=> Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF)).Select(e => (EquipItem)e);
2324

2425
public IEnumerable<EquipItem> Between(SetId modelId, WeaponType type, byte variant = 0)
2526
{
2627
if (type == 0)
27-
return Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF));
28+
return Between(ToKey(modelId, 0, 0), ToKey(modelId, 0xFFFF, 0xFF)).Select(e => (EquipItem)e);
2829
if (variant == 0)
29-
return Between(ToKey(modelId, type, 0), ToKey(modelId, type, 0xFF));
30+
return Between(ToKey(modelId, type, 0), ToKey(modelId, type, 0xFF)).Select(e => (EquipItem)e);
3031

31-
return Between(ToKey(modelId, type, variant), ToKey(modelId, type, variant));
32+
return Between(ToKey(modelId, type, variant), ToKey(modelId, type, variant)).Select(e => (EquipItem)e);
3233
}
3334

3435
public void Dispose(DalamudPluginInterface pi, ClientLanguage language)
@@ -40,28 +41,28 @@ public static ulong ToKey(SetId modelId, WeaponType type, byte variant)
4041
public static ulong ToKey(EquipItem i)
4142
=> ToKey(i.ModelId, i.WeaponType, i.Variant);
4243

43-
protected override IEnumerable<ulong> ToKeys(EquipItem data)
44+
protected override IEnumerable<ulong> ToKeys(PseudoEquipItem data)
4445
{
4546
yield return ToKey(data);
4647
}
4748

4849
protected override bool ValidKey(ulong key)
4950
=> key != 0;
5051

51-
protected override int ValueKeySelector(EquipItem data)
52-
=> (int)data.Id;
52+
protected override int ValueKeySelector(PseudoEquipItem data)
53+
=> (int)data.Item2;
5354

54-
private static IEnumerable<EquipItem> CreateWeaponList(DataManager gameData, ClientLanguage language)
55+
private static IEnumerable<PseudoEquipItem> CreateWeaponList(DataManager gameData, ClientLanguage language)
5556
=> gameData.GetExcelSheet<Item>(language)!.SelectMany(ToEquipItems);
5657

57-
private static IEnumerable<EquipItem> ToEquipItems(Item item)
58+
private static IEnumerable<PseudoEquipItem> ToEquipItems(Item item)
5859
{
5960
if ((EquipSlot)item.EquipSlotCategory.Row is not (EquipSlot.MainHand or EquipSlot.OffHand or EquipSlot.BothHand))
6061
yield break;
6162

6263
if (item.ModelMain != 0)
63-
yield return EquipItem.FromMainhand(item);
64+
yield return (PseudoEquipItem)EquipItem.FromMainhand(item);
6465
if (item.ModelSub != 0)
65-
yield return EquipItem.FromOffhand(item);
66+
yield return (PseudoEquipItem)EquipItem.FromOffhand(item);
6667
}
6768
}

Penumbra.GameData/Enums/FullEquipType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,4 +403,7 @@ public static readonly IReadOnlyList<FullEquipType> EquipmentTypes
403403

404404
public static readonly IReadOnlyList<FullEquipType> AccessoryTypes
405405
= Enum.GetValues<FullEquipType>().Where(v => v.IsAccessory()).ToArray();
406+
407+
public static readonly IReadOnlyList<FullEquipType> OffhandTypes
408+
= Enum.GetValues<FullEquipType>().Where(v => v.OffhandTypeSuffix().Length > 0).ToArray();
406409
}

0 commit comments

Comments
 (0)