88using Lumina . Excel . GeneratedSheets ;
99using Penumbra . GameData . Enums ;
1010using Penumbra . GameData . Structs ;
11+ using PseudoEquipItem = System . ValueTuple < string , uint , ushort , ushort , ushort , byte , byte > ;
1112
1213namespace Penumbra . GameData . Data ;
1314
1415public 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}
0 commit comments