11package gregtech .api .capability .impl ;
22
3- import it .unimi .dsi .fastutil .objects .Object2IntMap ;
4-
53import net .minecraft .item .ItemStack ;
64import net .minecraftforge .items .IItemHandler ;
75import net .minecraftforge .items .IItemHandlerModifiable ;
108import it .unimi .dsi .fastutil .ints .Int2ObjectOpenHashMap ;
119import it .unimi .dsi .fastutil .objects .Object2IntArrayMap ;
1210import it .unimi .dsi .fastutil .objects .Object2IntMap ;
11+ import it .unimi .dsi .fastutil .objects .ObjectIterator ;
1312import org .jetbrains .annotations .NotNull ;
1413
1514import java .util .*;
@@ -22,19 +21,24 @@ public class ItemHandlerList extends AbstractList<IItemHandler> implements IItem
2221 private final Int2ObjectMap <IItemHandler > handlerBySlotIndex = new Int2ObjectOpenHashMap <>();
2322 private final Object2IntMap <IItemHandler > baseIndexOffset = new Object2IntArrayMap <>();
2423
25- private final List < IItemHandler > handlerList = new ArrayList <>();
24+ public ItemHandlerList () {}
2625
27- public ItemHandlerList (List <? extends IItemHandler > itemHandlerList ) {
26+ public ItemHandlerList (Collection <? extends IItemHandler > itemHandlerList ) {
2827 addAll (itemHandlerList );
2928 }
3029
30+ public ItemHandlerList (ItemHandlerList parent , IItemHandler ... additional ) {
31+ addAll (parent .getBackingHandlers ());
32+ Collections .addAll (this , additional );
33+ }
34+
3135 public int getIndexOffset (IItemHandler handler ) {
3236 return baseIndexOffset .getOrDefault (handler , -1 );
3337 }
3438
3539 @ Override
3640 public int getSlots () {
37- return size ();
41+ return handlerBySlotIndex . size ();
3842 }
3943
4044 @ Override
@@ -81,14 +85,19 @@ public ItemStack extractItem(int slot, int amount, boolean simulate) {
8185 return itemHandler .extractItem (slot - baseIndexOffset .getInt (itemHandler ), amount , simulate );
8286 }
8387
88+ private boolean invalidSlot (int slot ) {
89+ if (handlerBySlotIndex .isEmpty ()) return false ;
90+ return slot < 0 || slot >= handlerBySlotIndex .size ();
91+ }
92+
8493 @ NotNull
8594 public Collection <IItemHandler > getBackingHandlers () {
86- return Collections .unmodifiableCollection (handlerList );
95+ return Collections .unmodifiableCollection (baseIndexOffset . keySet () );
8796 }
8897
8998 @ Override
9099 public int size () {
91- return handlerList .size ();
100+ return baseIndexOffset .size ();
92101 }
93102
94103 @ Override
@@ -99,12 +108,18 @@ public boolean add(IItemHandler handler) {
99108 }
100109
101110 @ Override
102- public void add (int index , IItemHandler element ) {
103- // Objects.checkIndex(index, size() );
104- if (handlerList . contains (element )) {
111+ public void add (int unused , IItemHandler element ) {
112+ Objects .requireNonNull ( element );
113+ if (baseIndexOffset . containsKey (element )) {
105114 throw new IllegalArgumentException ("Attempted to add item handler " + element + " twice" );
106115 }
107- handlerList .add (index , element );
116+ if (element instanceof ItemHandlerList list ) {
117+ // possible infinite recursion
118+ // throw instead?
119+ addAll (list );
120+ return ;
121+ }
122+
108123 int offset = handlerBySlotIndex .size ();
109124 baseIndexOffset .put (element , offset );
110125 for (int slotIndex = 0 ; slotIndex < element .getSlots (); slotIndex ++) {
@@ -114,33 +129,48 @@ public void add(int index, IItemHandler element) {
114129
115130 @ Override
116131 public IItemHandler get (int index ) {
117- return handlerList .get (index );
132+ 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
118136 }
119137
120138 @ Override
121139 public IItemHandler remove (int index ) {
122- // Objects.checkIndex(index, size());
123- var handler2 = get (index );
124- int offset2 = baseIndexOffset .getInt (handler2 );
125-
126- for (int i = index ; i < size (); i ++) {
127- int offset = baseIndexOffset .removeInt (get (i ));
128- for (int j = 0 ; j < get (i ).getSlots (); j ++) {
129- handlerBySlotIndex .remove (offset + j );
130- }
140+ if (invalidIndex (index )) {
141+ throw new IndexOutOfBoundsException ();
131142 }
132143
133- var removed = handlerList .remove (index );
134- for (var handler : handlerList ) {
135- if (baseIndexOffset .containsKey (handler ))
136- continue ;
144+ IItemHandler handler = get (index );
137145
138- int offset = handlerBySlotIndex .size ();
139- baseIndexOffset .put (handler , offset );
140- for (int i = 0 ; i < handler .getSlots (); i ++) {
141- handlerBySlotIndex .put (offset + i , handler );
146+ // remove handler
147+ int lower = baseIndexOffset .removeInt (handler );
148+
149+ // remove slot indices
150+ int upper = lower + handler .getSlots ();
151+ for (int i = lower ; i < upper ; i ++) {
152+ handlerBySlotIndex .remove (i );
153+ }
154+
155+ // update slot indices ahead of the removed handler
156+ for (int slot = upper ; slot < getSlots () + handler .getSlots (); slot ++) {
157+ IItemHandler remove = handlerBySlotIndex .remove (slot );
158+ handlerBySlotIndex .put (slot - upper , remove );
159+ }
160+
161+ // update handlers ahead of the removed handler
162+ for (IItemHandler h : baseIndexOffset .keySet ()) {
163+ int offset = baseIndexOffset .getInt (h );
164+ if (offset > lower ) {
165+ baseIndexOffset .put (h , offset - handler .getSlots ());
142166 }
143167 }
144- return removed ;
168+
169+ return handler ;
170+ }
171+
172+ public boolean invalidIndex (int index ) {
173+ if (baseIndexOffset .isEmpty ()) return false ;
174+ return index < 0 || index >= baseIndexOffset .size ();
145175 }
146176}
0 commit comments