Search in sources :

Example 1 with TransitResponse

use of mekanism.common.lib.inventory.TransitRequest.TransitResponse in project Mekanism by mekanism.

the class TileEntityLogisticalSorter method onUpdateServer.

@Override
protected void onUpdateServer() {
    super.onUpdateServer();
    delayTicks = Math.max(0, delayTicks - 1);
    if (delayTicks == 6) {
        setActive(false);
    }
    if (MekanismUtils.canFunction(this) && delayTicks == 0) {
        Direction direction = getDirection();
        TileEntity back = WorldUtils.getTileEntity(getLevel(), worldPosition.relative(direction.getOpposite()));
        TileEntity front = WorldUtils.getTileEntity(getLevel(), worldPosition.relative(direction));
        // If there is no tile to pull from or the push to, skip doing any checks
        if (InventoryUtils.isItemHandler(back, direction) && front != null) {
            boolean sentItems = false;
            for (SorterFilter<?> filter : filters) {
                TransitRequest request = filter.mapInventory(back, direction, singleItem);
                if (request.isEmpty()) {
                    continue;
                }
                int min = singleItem ? 1 : filter.sizeMode ? filter.min : 0;
                TransitResponse response = emitItemToTransporter(front, request, filter.color, min);
                if (!response.isEmpty()) {
                    response.useAll();
                    WorldUtils.saveChunk(back);
                    setActive(true);
                    sentItems = true;
                    break;
                }
            }
            if (!sentItems && autoEject) {
                TransitRequest request = TransitRequest.definedItem(back, direction, singleItem ? 1 : 64, strictFinder);
                TransitResponse response = emitItemToTransporter(front, request, color, 0);
                if (!response.isEmpty()) {
                    response.useAll();
                    WorldUtils.saveChunk(back);
                    setActive(true);
                }
            }
        }
        delayTicks = 10;
    }
}
Also used : TileEntity(net.minecraft.tileentity.TileEntity) TransitResponse(mekanism.common.lib.inventory.TransitRequest.TransitResponse) Direction(net.minecraft.util.Direction) TransitRequest(mekanism.common.lib.inventory.TransitRequest)

Example 2 with TransitResponse

use of mekanism.common.lib.inventory.TransitRequest.TransitResponse in project Mekanism by mekanism.

the class TileEntityBin method onUpdateServer.

@Override
protected void onUpdateServer() {
    super.onUpdateServer();
    addTicks = Math.max(0, addTicks - 1);
    removeTicks = Math.max(0, removeTicks - 1);
    delayTicks = Math.max(0, delayTicks - 1);
    if (delayTicks == 0) {
        if (getActive()) {
            TileEntity tile = WorldUtils.getTileEntity(getLevel(), getBlockPos().below());
            TileTransitRequest request = new TileTransitRequest(this, Direction.DOWN);
            request.addItem(binSlot.getBottomStack(), 0);
            TransitResponse response;
            if (tile instanceof TileEntityLogisticalTransporterBase) {
                response = ((TileEntityLogisticalTransporterBase) tile).getTransmitter().insert(this, request, null, true, 0);
            } else {
                response = request.addToInventory(tile, Direction.DOWN, 0, false);
            }
            if (!response.isEmpty() && tier != BinTier.CREATIVE) {
                int sendingAmount = response.getSendingAmount();
                MekanismUtils.logMismatchedStackSize(binSlot.shrinkStack(sendingAmount, Action.EXECUTE), sendingAmount);
            }
            delayTicks = 10;
        }
    } else {
        delayTicks--;
    }
}
Also used : TileEntity(net.minecraft.tileentity.TileEntity) TransitResponse(mekanism.common.lib.inventory.TransitRequest.TransitResponse) TileTransitRequest(mekanism.common.lib.inventory.TileTransitRequest) TileEntityLogisticalTransporterBase(mekanism.common.tile.transmitter.TileEntityLogisticalTransporterBase)

Example 3 with TransitResponse

use of mekanism.common.lib.inventory.TransitRequest.TransitResponse in project Mekanism by mekanism.

the class LogisticalTransporterBase method tick.

public void tick() {
    if (isRemote()) {
        for (TransporterStack stack : transit.values()) {
            stack.progress = Math.min(100, stack.progress + tier.getSpeed());
        }
    } else if (getTransmitterNetwork() != null) {
        // Pull items into the transporter
        if (delay > 0) {
            // If a delay has been imposed, wait a bit
            delay--;
        } else {
            // Reset delay to 3 ticks; if nothing is available to insert OR inserted, we'll try again in 3 ticks
            delay = 3;
            // Attempt to pull
            for (Direction side : getConnections(ConnectionType.PULL)) {
                TileEntity tile = WorldUtils.getTileEntity(getTileWorld(), getTilePos().relative(side));
                if (tile != null) {
                    TransitRequest request = TransitRequest.anyItem(tile, side.getOpposite(), tier.getPullAmount());
                    // There's a stack available to insert into the network...
                    if (!request.isEmpty()) {
                        TransitResponse response = insert(tile, request, getColor(), true, 0);
                        if (response.isEmpty()) {
                            // Insert failed; increment the backoff and calculate delay. Note that we cap retries
                            // at a max of 40 ticks (2 seconds), which would be 4 consecutive retries
                            delayCount++;
                            delay = Math.min(40, (int) Math.exp(delayCount));
                        } else {
                            // If the insert succeeded, remove the inserted count and try again for another 10 ticks
                            response.useAll();
                            delay = 10;
                        }
                    }
                }
            }
        }
        if (!transit.isEmpty()) {
            InventoryNetwork network = getTransmitterNetwork();
            // Update stack positions
            IntSet deletes = new IntOpenHashSet();
            // collection to occur actually causing the tick time to go up slightly.
            for (Int2ObjectMap.Entry<TransporterStack> entry : transit.int2ObjectEntrySet()) {
                int stackId = entry.getIntKey();
                TransporterStack stack = entry.getValue();
                if (!stack.initiatedPath) {
                    if (stack.itemStack.isEmpty() || !recalculate(stackId, stack, null)) {
                        deletes.add(stackId);
                        continue;
                    }
                }
                int prevProgress = stack.progress;
                stack.progress += tier.getSpeed();
                if (stack.progress >= 100) {
                    BlockPos prevSet = null;
                    if (stack.hasPath()) {
                        int currentIndex = stack.getPath().indexOf(getTilePos());
                        if (currentIndex == 0) {
                            // Necessary for transition reasons, not sure why
                            deletes.add(stackId);
                            continue;
                        }
                        BlockPos next = stack.getPath().get(currentIndex - 1);
                        if (next != null) {
                            if (!stack.isFinal(this)) {
                                LogisticalTransporterBase transmitter = network.getTransmitter(next);
                                if (stack.canInsertToTransporter(transmitter, stack.getSide(this), this)) {
                                    transmitter.entityEntering(stack, stack.progress % 100);
                                    deletes.add(stackId);
                                    continue;
                                }
                                prevSet = next;
                            } else if (stack.getPathType() != Path.NONE) {
                                TileEntity tile = WorldUtils.getTileEntity(getTileWorld(), next);
                                if (tile != null) {
                                    TransitResponse response = TransitRequest.simple(stack.itemStack).addToInventory(tile, stack.getSide(this), 0, stack.getPathType() == Path.HOME);
                                    if (!response.isEmpty()) {
                                        // We were able to add at least part of the stack to the inventory
                                        ItemStack rejected = response.getRejected();
                                        if (rejected.isEmpty()) {
                                            // Nothing was rejected (it was all accepted); remove the stack from the prediction
                                            // tracker and schedule this stack for deletion. Continue the loop thereafter
                                            TransporterManager.remove(getTileWorld(), stack);
                                            deletes.add(stackId);
                                            continue;
                                        }
                                        // Some portion of the stack got rejected; save the remainder and
                                        // let the recalculate below sort out what to do next
                                        stack.itemStack = rejected;
                                    }
                                    // else the entire stack got rejected (Note: we don't need to update the stack to point to itself)
                                    prevSet = next;
                                }
                            }
                        }
                    }
                    if (!recalculate(stackId, stack, prevSet)) {
                        deletes.add(stackId);
                    } else if (prevSet == null) {
                        stack.progress = 50;
                    } else {
                        stack.progress = 0;
                    }
                } else if (prevProgress < 50 && stack.progress >= 50) {
                    boolean tryRecalculate;
                    if (stack.isFinal(this)) {
                        Path pathType = stack.getPathType();
                        if (pathType == Path.DEST || pathType == Path.HOME) {
                            Direction side = stack.getSide(this);
                            ConnectionType connectionType = getConnectionType(side);
                            tryRecalculate = connectionType != ConnectionType.NORMAL && connectionType != ConnectionType.PUSH || !TransporterUtils.canInsert(WorldUtils.getTileEntity(getTileWorld(), stack.getDest()), stack.color, stack.itemStack, side, pathType == Path.HOME);
                        } else {
                            tryRecalculate = pathType == Path.NONE;
                        }
                    } else {
                        LogisticalTransporterBase nextTransmitter = network.getTransmitter(stack.getNext(this));
                        if (nextTransmitter == null && stack.getPathType() == Path.NONE && stack.getPath().size() == 2) {
                            // If there is no next transmitter, and it was an idle path, assume that we are idling
                            // in a single length transmitter, in which case we only recalculate it at 50 if it won't
                            // be able to go into that connection type
                            ConnectionType connectionType = getConnectionType(stack.getSide(this));
                            tryRecalculate = connectionType != ConnectionType.NORMAL && connectionType != ConnectionType.PUSH;
                        } else {
                            tryRecalculate = !stack.canInsertToTransporter(nextTransmitter, stack.getSide(this), this);
                        }
                    }
                    if (tryRecalculate && !recalculate(stackId, stack, null)) {
                        deletes.add(stackId);
                    }
                }
            }
            if (!deletes.isEmpty() || !needsSync.isEmpty()) {
                // Notify clients, so that we send the information before we start clearing our lists
                Mekanism.packetHandler.sendToAllTracking(new PacketTransporterUpdate(this, needsSync, deletes), getTransmitterTile());
                // Now remove any entries from transit that have been deleted
                deletes.forEach((IntConsumer) (this::deleteStack));
                // Clear the pending sync packets
                needsSync.clear();
                // Finally, mark chunk for save
                WorldUtils.saveChunk(getTransmitterTile());
            }
        }
    }
}
Also used : Path(mekanism.common.content.transporter.TransporterStack.Path) ConnectionType(mekanism.common.lib.transmitter.ConnectionType) IntSet(it.unimi.dsi.fastutil.ints.IntSet) Direction(net.minecraft.util.Direction) TransitRequest(mekanism.common.lib.inventory.TransitRequest) InventoryNetwork(mekanism.common.content.network.InventoryNetwork) IntConsumer(java.util.function.IntConsumer) TileEntity(net.minecraft.tileentity.TileEntity) IntOpenHashSet(it.unimi.dsi.fastutil.ints.IntOpenHashSet) TransporterStack(mekanism.common.content.transporter.TransporterStack) PacketTransporterUpdate(mekanism.common.network.to_client.PacketTransporterUpdate) TransitResponse(mekanism.common.lib.inventory.TransitRequest.TransitResponse) BlockPos(net.minecraft.util.math.BlockPos) ItemStack(net.minecraft.item.ItemStack)

Example 4 with TransitResponse

use of mekanism.common.lib.inventory.TransitRequest.TransitResponse in project Mekanism by mekanism.

the class InventoryNetwork method calculateAcceptors.

public List<AcceptorData> calculateAcceptors(TransitRequest request, TransporterStack stack, Long2ObjectMap<IChunk> chunkMap) {
    List<AcceptorData> toReturn = new ArrayList<>();
    for (Map.Entry<BlockPos, Map<Direction, LazyOptional<IItemHandler>>> entry : acceptorCache.getAcceptorEntrySet()) {
        BlockPos pos = entry.getKey();
        if (!pos.equals(stack.homeLocation)) {
            TileEntity acceptor = WorldUtils.getTileEntity(getWorld(), chunkMap, pos);
            if (acceptor == null) {
                continue;
            }
            Map<TransitResponse, AcceptorData> dataMap = new HashMap<>();
            Coord4D position = new Coord4D(pos, getWorld());
            for (Map.Entry<Direction, LazyOptional<IItemHandler>> acceptorEntry : entry.getValue().entrySet()) {
                Optional<IItemHandler> handler = acceptorEntry.getValue().resolve();
                if (handler.isPresent()) {
                    Direction side = acceptorEntry.getKey();
                    // actually need to even query the TE
                    if (acceptor instanceof ISideConfiguration) {
                        // If the acceptor in question implements the mekanism interface, check that the color matches and bail fast if it doesn't
                        ISideConfiguration config = (ISideConfiguration) acceptor;
                        if (config.getEjector().hasStrictInput()) {
                            EnumColor configColor = config.getEjector().getInputColor(RelativeSide.fromDirections(config.getDirection(), side));
                            if (configColor != null && configColor != stack.color) {
                                continue;
                            }
                        }
                    }
                    TransitResponse response = TransporterManager.getPredictedInsert(position, side, handler.get(), request);
                    if (!response.isEmpty()) {
                        Direction opposite = side.getOpposite();
                        // If the response isn't empty, check if we already have acceptor data for
                        // a matching response at the destination
                        AcceptorData data = dataMap.get(response);
                        if (data == null) {
                            // If we don't, add a new acceptor data for the response and position with side
                            data = new AcceptorData(pos, response, opposite);
                            dataMap.put(response, data);
                            toReturn.add(data);
                        // Note: In theory this shouldn't cause any issues if some exposed slots overlap but are for
                        // different acceptor data/sides as our predicted insert takes into account all en-route
                        // items to the destination, and only checks about the side if none are actually able to be
                        // inserted in the first place
                        } else {
                            // If we do, add our side as one of the sides it can accept things from for that response
                            // This equates to the destination being the same
                            data.sides.add(opposite);
                        }
                    }
                }
            }
        }
    }
    return toReturn;
}
Also used : IItemHandler(net.minecraftforge.items.IItemHandler) HashMap(java.util.HashMap) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ArrayList(java.util.ArrayList) Direction(net.minecraft.util.Direction) TileEntity(net.minecraft.tileentity.TileEntity) EnumColor(mekanism.api.text.EnumColor) LazyOptional(net.minecraftforge.common.util.LazyOptional) TransitResponse(mekanism.common.lib.inventory.TransitRequest.TransitResponse) Coord4D(mekanism.api.Coord4D) BlockPos(net.minecraft.util.math.BlockPos) HashMap(java.util.HashMap) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) Map(java.util.Map) Long2ObjectMap(it.unimi.dsi.fastutil.longs.Long2ObjectMap) ISideConfiguration(mekanism.common.tile.interfaces.ISideConfiguration)

Example 5 with TransitResponse

use of mekanism.common.lib.inventory.TransitRequest.TransitResponse in project Mekanism by mekanism.

the class TransporterPathfinder method getPath.

@Nullable
private static Destination getPath(InventoryNetwork network, AcceptorData data, LogisticalTransporterBase start, TransporterStack stack, int min, Long2ObjectMap<IChunk> chunkMap) {
    TransitResponse response = data.getResponse();
    if (response.getSendingAmount() >= min) {
        BlockPos dest = data.getLocation();
        CachedPath test = PathfinderCache.getCache(start, dest, data.getSides());
        if (test != null && checkPath(network, test.getPath(), stack)) {
            return new Destination(test.getPath(), false, response, test.getCost());
        }
        Pathfinder p = new Pathfinder(new DestChecker() {

            @Override
            public boolean isValid(TransporterStack stack, Direction side, TileEntity tile) {
                return TransporterUtils.canInsert(tile, stack.color, response.getStack(), side, false);
            }
        }, network, start.getTileWorld(), dest, start.getTilePos(), stack);
        p.find(chunkMap);
        List<BlockPos> path = p.getPath();
        if (path.size() >= 2) {
            PathfinderCache.addCachedPath(start, new PathData(start.getTilePos(), dest, p.getSide()), path, p.finalScore);
            return new Destination(path, false, response, p.finalScore);
        }
    }
    return null;
}
Also used : TileEntity(net.minecraft.tileentity.TileEntity) CachedPath(mekanism.common.content.transporter.PathfinderCache.CachedPath) DestChecker(mekanism.common.content.transporter.TransporterPathfinder.Pathfinder.DestChecker) TransitResponse(mekanism.common.lib.inventory.TransitRequest.TransitResponse) PathData(mekanism.common.content.transporter.PathfinderCache.PathData) SidedBlockPos(mekanism.common.lib.SidedBlockPos) BlockPos(net.minecraft.util.math.BlockPos) Direction(net.minecraft.util.Direction) Nullable(javax.annotation.Nullable)

Aggregations

TransitResponse (mekanism.common.lib.inventory.TransitRequest.TransitResponse)7 TileEntity (net.minecraft.tileentity.TileEntity)7 Direction (net.minecraft.util.Direction)6 TransitRequest (mekanism.common.lib.inventory.TransitRequest)3 TileEntityLogisticalTransporterBase (mekanism.common.tile.transmitter.TileEntityLogisticalTransporterBase)3 BlockPos (net.minecraft.util.math.BlockPos)3 IntOpenHashSet (it.unimi.dsi.fastutil.ints.IntOpenHashSet)1 IntSet (it.unimi.dsi.fastutil.ints.IntSet)1 Long2ObjectMap (it.unimi.dsi.fastutil.longs.Long2ObjectMap)1 Object2ObjectOpenHashMap (it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 IntConsumer (java.util.function.IntConsumer)1 Nullable (javax.annotation.Nullable)1 Coord4D (mekanism.api.Coord4D)1 FloatingLong (mekanism.api.math.FloatingLong)1 EnumColor (mekanism.api.text.EnumColor)1 InventoryNetwork (mekanism.common.content.network.InventoryNetwork)1 CachedPath (mekanism.common.content.transporter.PathfinderCache.CachedPath)1