77import java .util .Collection ;
88import java .util .Map ;
99import java .util .Map .Entry ;
10+ import java .util .function .BiFunction ;
1011import java .util .function .Function ;
1112import java .util .function .ToIntFunction ;
1213import mekanism .api .Action ;
2122import mekanism .common .capabilities .holder .slot .InventorySlotHelper ;
2223import mekanism .common .capabilities .item .CursedTransporterItemHandler ;
2324import mekanism .common .content .network .transmitter .LogisticalTransporterBase ;
25+ import mekanism .common .content .network .transmitter .LogisticalTransporterBase .PathCalculator ;
2426import mekanism .common .content .qio .QIOFrequency ;
2527import mekanism .common .content .qio .QIOFrequency .QIOItemTypeData ;
2628import mekanism .common .content .qio .filter .QIOFilter ;
2729import mekanism .common .content .qio .filter .QIOItemStackFilter ;
2830import mekanism .common .content .qio .filter .QIOModIDFilter ;
2931import mekanism .common .content .qio .filter .QIOTagFilter ;
3032import mekanism .common .content .transporter .TransporterManager ;
33+ import mekanism .common .content .transporter .TransporterStack ;
3134import mekanism .common .integration .computer .ComputerException ;
3235import mekanism .common .integration .computer .annotation .ComputerMethod ;
3336import mekanism .common .inventory .container .MekanismContainer ;
6164
6265public class TileEntityQIOExporter extends TileEntityQIOFilterHandler implements IAdvancedTransportEjector {
6366
67+ private static final EfficientEjector <Object2LongMap .Entry <HashedItem >> FILTER_EJECTOR = new EfficientEjector <>(Entry ::getKey , e -> MathUtils .clampToInt (e .getLongValue ()),
68+ (exporter , freq ) -> exporter .getFilterEjectMap (freq ).object2LongEntrySet ());
69+ private static final EfficientEjector <Map .Entry <HashedItem , QIOItemTypeData >> FILTERLESS_EJECTOR =
70+ new EfficientEjector <>(Entry ::getKey , e -> MathUtils .clampToInt (e .getValue ().getCount ()), (exporter , freq ) -> freq .getItemDataMap ().entrySet ());
6471 private static final int MAX_DELAY = MekanismUtils .TICKS_PER_HALF_SECOND ;
6572
6673 @ Nullable
@@ -71,11 +78,6 @@ public class TileEntityQIOExporter extends TileEntityQIOFilterHandler implements
7178 @ Nullable
7279 private SidedBlockPos rrTarget ;
7380
74- private final EfficientEjector <Object2LongMap .Entry <HashedItem >> filterEjector = new EfficientEjector <>(Entry ::getKey , e -> MathUtils .clampToInt (e .getLongValue ()),
75- freq -> getFilterEjectMap (freq ).object2LongEntrySet ());
76- private final EfficientEjector <Map .Entry <HashedItem , QIOItemTypeData >> filterlessEjector =
77- new EfficientEjector <>(Entry ::getKey , e -> MathUtils .clampToInt (e .getValue ().getCount ()), freq -> freq .getItemDataMap ().entrySet ());
78-
7981 public TileEntityQIOExporter (BlockPos pos , BlockState state ) {
8082 super (MekanismBlocks .QIO_EXPORTER , pos , state );
8183 }
@@ -122,15 +124,14 @@ private void tryEject(QIOFrequency freq) {
122124 backInventory = Capabilities .ITEM .createCache ((ServerLevel ) level , worldPosition .relative (direction .getOpposite ()), direction );
123125 }
124126 IItemHandler backHandler = backInventory .getCapability ();
125- //TODO - 1.20.4: Optimize exporting into transporters, maybe by checking if it is a cursed transporter handler??
126127 if (backHandler == null ) {
127128 return ;
128129 }
129130 EfficientEjector <?> ejector ;
130131 if (getFilterManager ().hasEnabledFilters ()) {
131- ejector = filterEjector ;
132+ ejector = FILTER_EJECTOR ;
132133 } else if (exportWithoutFilter ) {
133- ejector = filterlessEjector ;
134+ ejector = FILTERLESS_EJECTOR ;
134135 } else {
135136 return ;
136137 }
@@ -307,42 +308,39 @@ void setRoundRobin(boolean value) throws ComputerException {
307308 *
308309 * @author aidancbrady
309310 */
310- private final class EfficientEjector <T > {
311+ private record EfficientEjector <T >(Function <T , HashedItem > typeSupplier , ToIntFunction <T > countSupplier ,
312+ BiFunction <TileEntityQIOExporter , QIOFrequency , Collection <T >> ejectMapCalculator ) {
311313
312314 private static final double MAX_EJECT_ATTEMPTS = 100 ;
313315
314- private final Function <QIOFrequency , Collection <T >> ejectMapCalculator ;
315- private final Function <T , HashedItem > typeSupplier ;
316- private final ToIntFunction <T > countSupplier ;
317-
318- private EfficientEjector (Function <T , HashedItem > typeSupplier , ToIntFunction <T > countSupplier , Function <QIOFrequency , Collection <T >> ejectMapCalculator ) {
319- this .typeSupplier = typeSupplier ;
320- this .countSupplier = countSupplier ;
321- this .ejectMapCalculator = ejectMapCalculator ;
322- }
323-
324316 private void eject (TileEntityQIOExporter exporter , QIOFrequency freq , IItemHandler inventory ) {
325317 int slots = inventory .getSlots ();
326318 if (slots == 0 ) {
327319 //If the inventory has no slots just exit early and don't even bother calculating the eject map
328320 return ;
329321 }
330- Collection <T > ejectMap = ejectMapCalculator .apply (freq );
322+ Collection <T > ejectMap = ejectMapCalculator .apply (exporter , freq );
331323 if (ejectMap .isEmpty ()) {
332324 return ;
333325 }
334326 LogisticalTransporterBase transporter = null ;
327+ PathCalculator <TileEntityQIOExporter > pathCalculator = null ;
335328 if (inventory instanceof CursedTransporterItemHandler cursed ) {
336329 transporter = cursed .getTransporter ();
337330 if (!transporter .hasTransmitterNetwork ()) {//Probably will never happen, but if we don't have a network just skip doing anything
338331 return ;
339332 }
333+ Direction from = exporter .getDirection ();
334+ if (!transporter .canReceiveFrom (from ) || !transporter .canConnectMutual (from , exporter )) {
335+ //Skip if the transporter can't receive from this position or connect to it
336+ return ;
337+ }
338+ pathCalculator = exporter .getRoundRobin () ? TransporterStack ::recalculateRRPath : TransporterStack ::recalculatePath ;
340339 }
341- BlockPos exportPos = exporter .getBlockPos ();
342- RandomSource random = getLevel ().getRandom ();
340+ RandomSource random = exporter .getLevel ().getRandom ();
343341 double ejectChance = Math .min (1 , MAX_EJECT_ATTEMPTS / ejectMap .size ());
344342 boolean randomizeEject = ejectChance < 1 ;
345- int maxTypes = getMaxTransitTypes (), maxCount = getMaxTransitCount ();
343+ int maxTypes = exporter . getMaxTransitTypes (), maxCount = exporter . getMaxTransitCount ();
346344 Object2IntMap <HashedItem > removed = new Object2IntOpenHashMap <>();
347345 int amountRemoved = 0 ;
348346 for (T obj : ejectMap ) {
@@ -380,7 +378,8 @@ private void eject(TileEntityQIOExporter exporter, QIOFrequency freq, IItemHandl
380378 //TODO: Technically if we still have more of the same item input, we want to allow trying to insert it into different transport
381379 // destinations, which this doesn't do as it only checks once, rather than trying to check again if we still have some that we
382380 // are able to insert
383- TransitResponse response = transporter .insertMaybeRR (exporter , exportPos , request , transporter .getColor (), true , 1 );
381+ //Note: We don't use transporter#insertMaybeRR so that we only have to validate the transporter once
382+ TransitResponse response = transporter .insertUnchecked (exporter , request , transporter .getColor (), true , 1 , pathCalculator );
384383 toUse = response .getSendingAmount ();
385384 }
386385 if (toUse > 0 ) {
0 commit comments