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;
}
}
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--;
}
}
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());
}
}
}
}
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;
}
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;
}
Aggregations