88import it .unimi .dsi .fastutil .ints .Int2ObjectOpenHashMap ;
99import it .unimi .dsi .fastutil .objects .Object2IntArrayMap ;
1010import it .unimi .dsi .fastutil .objects .Object2IntMap ;
11- import it .unimi .dsi .fastutil .objects .ObjectIterator ;
1211import org .jetbrains .annotations .NotNull ;
1312
1413import java .util .*;
1817 */
1918public class ItemHandlerList extends AbstractList <IItemHandler > implements IItemHandlerModifiable {
2019
21- private final Int2ObjectMap <IItemHandler > handlerBySlotIndex = new Int2ObjectOpenHashMap <>();
22- private final Object2IntMap <IItemHandler > baseIndexOffset = new Object2IntArrayMap <>();
20+ protected final Int2ObjectMap <IItemHandler > handlerBySlotIndex = new Int2ObjectOpenHashMap <>();
21+ protected final Object2IntMap <IItemHandler > baseIndexOffset = new Object2IntArrayMap <>();
2322
24- public ItemHandlerList () {}
23+ // this is only used for get()
24+ protected IItemHandler [] handlers = new IItemHandler [0 ];
2525
2626 public ItemHandlerList (Collection <? extends IItemHandler > itemHandlerList ) {
2727 addAll (itemHandlerList );
28+ baseIndexOffset .defaultReturnValue (-1 );
29+ }
30+
31+ public ItemHandlerList () {
32+ this (Collections .emptyList ());
2833 }
2934
3035 public ItemHandlerList (ItemHandlerList parent , IItemHandler ... additional ) {
31- addAll (parent . getBackingHandlers () );
36+ this (parent );
3237 Collections .addAll (this , additional );
3338 }
3439
40+ /**
41+ * @param handler the handler to get the slot offset of
42+ * @return the slot offset
43+ * @throws IllegalArgumentException if the handler is not in this list
44+ */
3545 public int getIndexOffset (IItemHandler handler ) {
36- return baseIndexOffset .getOrDefault (handler , -1 );
46+ int offset = baseIndexOffset .get (handler );
47+ if (offset == -1 ) throw new IllegalArgumentException ();
48+ return offset ;
49+ }
50+
51+ @ NotNull
52+ protected IItemHandler getHandlerBySlot (int slot ) {
53+ if (invalidSlot (slot )) throw new IndexOutOfBoundsException ();
54+ return handlerBySlotIndex .get (slot );
55+ }
56+
57+ protected int getInternalSlot (int slot ) {
58+ return slot - getIndexOffset (getHandlerBySlot (slot ));
3759 }
3860
3961 @ Override
@@ -44,11 +66,12 @@ public int getSlots() {
4466 @ Override
4567 public void setStackInSlot (int slot , @ NotNull ItemStack stack ) {
4668 if (invalidSlot (slot )) return ;
47- IItemHandler itemHandler = handlerBySlotIndex . get (slot );
48- int actualSlot = slot - baseIndexOffset . get ( itemHandler );
69+ IItemHandler itemHandler = getHandlerBySlot (slot );
70+ int actualSlot = getInternalSlot ( slot );
4971 if (itemHandler instanceof IItemHandlerModifiable modifiable ) {
5072 modifiable .setStackInSlot (actualSlot , stack );
5173 } else {
74+ // should this no-op instead?
5275 itemHandler .extractItem (actualSlot , Integer .MAX_VALUE , false );
5376 itemHandler .insertItem (actualSlot , stack , false );
5477 }
@@ -58,36 +81,27 @@ public void setStackInSlot(int slot, @NotNull ItemStack stack) {
5881 @ Override
5982 public ItemStack getStackInSlot (int slot ) {
6083 if (invalidSlot (slot )) return ItemStack .EMPTY ;
61- IItemHandler itemHandler = handlerBySlotIndex .get (slot );
62- return itemHandler .getStackInSlot (slot - baseIndexOffset .getInt (itemHandler ));
84+ return getHandlerBySlot (slot ).getStackInSlot (getInternalSlot (slot ));
6385 }
6486
6587 @ Override
6688 public int getSlotLimit (int slot ) {
6789 if (invalidSlot (slot )) return 0 ;
68- IItemHandler itemHandler = handlerBySlotIndex .get (slot );
69- return itemHandler .getSlotLimit (slot - baseIndexOffset .getInt (itemHandler ));
90+ return getHandlerBySlot (slot ).getSlotLimit (getInternalSlot (slot ));
7091 }
7192
7293 @ NotNull
7394 @ Override
7495 public ItemStack insertItem (int slot , @ NotNull ItemStack stack , boolean simulate ) {
7596 if (invalidSlot (slot )) return stack ;
76- IItemHandler itemHandler = handlerBySlotIndex .get (slot );
77- return itemHandler .insertItem (slot - baseIndexOffset .getInt (itemHandler ), stack , simulate );
97+ return getHandlerBySlot (slot ).insertItem (getInternalSlot (slot ), stack , simulate );
7898 }
7999
80100 @ NotNull
81101 @ Override
82102 public ItemStack extractItem (int slot , int amount , boolean simulate ) {
83103 if (invalidSlot (slot )) return ItemStack .EMPTY ;
84- IItemHandler itemHandler = handlerBySlotIndex .get (slot );
85- return itemHandler .extractItem (slot - baseIndexOffset .getInt (itemHandler ), amount , simulate );
86- }
87-
88- private boolean invalidSlot (int slot ) {
89- if (handlerBySlotIndex .isEmpty ()) return false ;
90- return slot < 0 || slot >= handlerBySlotIndex .size ();
104+ return getHandlerBySlot (slot ).extractItem (getInternalSlot (slot ), amount , simulate );
91105 }
92106
93107 @ NotNull
@@ -103,7 +117,13 @@ public int size() {
103117 @ Override
104118 public boolean add (IItemHandler handler ) {
105119 int s = size ();
106- add (s , handler );
120+ if (handler instanceof ItemHandlerList list ) {
121+ // possible infinite recursion
122+ // throw instead?
123+ addAll (s , list );
124+ } else {
125+ add (s , handler );
126+ }
107127 return s != size ();
108128 }
109129
@@ -113,12 +133,6 @@ public void add(int unused, IItemHandler element) {
113133 if (baseIndexOffset .containsKey (element )) {
114134 throw new IllegalArgumentException ("Attempted to add item handler " + element + " twice" );
115135 }
116- if (element instanceof ItemHandlerList list ) {
117- // possible infinite recursion
118- // throw instead?
119- addAll (list );
120- return ;
121- }
122136
123137 int offset = handlerBySlotIndex .size ();
124138 baseIndexOffset .put (element , offset );
@@ -127,12 +141,16 @@ public void add(int unused, IItemHandler element) {
127141 }
128142 }
129143
144+ @ Override
145+ public @ NotNull Iterator <IItemHandler > iterator () {
146+ return baseIndexOffset .keySet ().iterator ();
147+ }
148+
130149 @ Override
131150 public IItemHandler get (int index ) {
132151 if (invalidIndex (index )) throw new IndexOutOfBoundsException ();
133- ObjectIterator <IItemHandler > itr = baseIndexOffset .keySet ().iterator ();
134- itr .skip (index ); // skip n-1 elements
135- return itr .next (); // get nth element
152+ updateHandlerArray ();
153+ return handlers [index ];
136154 }
137155
138156 @ Override
@@ -169,8 +187,53 @@ public IItemHandler remove(int index) {
169187 return handler ;
170188 }
171189
172- public boolean invalidIndex (int index ) {
190+ private boolean invalidSlot (int slot ) {
191+ if (handlerBySlotIndex .isEmpty ()) return false ;
192+ return slot < 0 || slot >= handlerBySlotIndex .size ();
193+ }
194+
195+ private boolean invalidIndex (int index ) {
173196 if (baseIndexOffset .isEmpty ()) return false ;
174197 return index < 0 || index >= baseIndexOffset .size ();
175198 }
199+
200+ private void updateHandlerArray () {
201+ if (handlers .length != size ()) {
202+ handlers = new IItemHandler [size ()];
203+ int i = 0 ;
204+ for (IItemHandler h : baseIndexOffset .keySet ()) {
205+ handlers [i ++] = h ;
206+ }
207+ }
208+ }
209+
210+ public ItemHandlerList toImmutable () {
211+ return new Immutable (this );
212+ }
213+
214+ private static class Immutable extends ItemHandlerList {
215+
216+ private Immutable (ItemHandlerList list ) {
217+ this .handlers = list .handlers ;
218+ this .baseIndexOffset .putAll (list .baseIndexOffset );
219+ this .handlerBySlotIndex .putAll (list .handlerBySlotIndex );
220+ }
221+
222+ @ Override
223+ public void add (int unused , IItemHandler element ) {
224+ // no op?
225+ throw new UnsupportedOperationException ();
226+ }
227+
228+ @ Override
229+ public IItemHandler remove (int index ) {
230+ // no op?
231+ throw new UnsupportedOperationException ();
232+ }
233+
234+ @ Override
235+ public IItemHandler get (int index ) {
236+ return handlers [index ];
237+ }
238+ }
176239}
0 commit comments