use of logisticspipes.routing.ExitRoute in project LogisticsPipes by RS485.
the class DebugController method handledPipe.
public void handledPipe(boolean flag) {
for (int i = 0; i < closedSet.size(); i++) {
EnumSet<PipeRoutingConnectionType> set = closedSet.get(i);
if (set != null) {
IRouter router = SimpleServiceLocator.routerManager.getRouter(i);
if (router != null) {
MainProxy.sendPacketToPlayer(PacketHandler.getPacket(RoutingUpdateDebugClosedSet.class).setPos(router.getLPPosition()).setSet(set), (EntityPlayer) sender);
}
}
}
for (int i = 0; i < filterList.size(); i++) {
EnumMap<PipeRoutingConnectionType, List<List<IFilter>>> filters = filterList.get(i);
if (filters != null) {
IRouter router = SimpleServiceLocator.routerManager.getRouter(i);
if (router != null) {
MainProxy.sendPacketToPlayer(PacketHandler.getPacket(RoutingUpdateDebugFilters.class).setPos(router.getLPPosition()).setFilters(filters), (EntityPlayer) sender);
}
}
}
ExitRoute[] e = candidatesCost.toArray(new ExitRoute[] {});
if (flag) {
LinkedList<ExitRoute> list = new LinkedList<>();
list.add(nextNode);
list.addAll(Arrays.asList(e));
e = list.toArray(new ExitRoute[] {});
}
MainProxy.sendPacketToPlayer(PacketHandler.getPacket(RoutingUpdateDebugCanidateList.class).setMsg(e), (EntityPlayer) sender);
if (prevNode == null || prevNode.debug.isTraced) {
//Display Information On Client Side
wait("Continue with next pipe?", false);
}
pipeHandled = true;
}
use of logisticspipes.routing.ExitRoute in project LogisticsPipes by RS485.
the class PathFinder method getConnectedRoutingPipes.
private HashMap<CoreRoutedPipe, ExitRoute> getConnectedRoutingPipes(IPipeInformationProvider startPipe, EnumSet<PipeRoutingConnectionType> connectionFlags, ForgeDirection side) {
HashMap<CoreRoutedPipe, ExitRoute> foundPipes = new HashMap<>();
boolean root = setVisited.size() == 0;
//Reset visited count at top level
if (setVisited.size() == 1) {
pipesVisited = 0;
}
//Break recursion if we have visited a set number of pipes, to prevent client hang if pipes are weirdly configured
if (++pipesVisited > maxVisited) {
return foundPipes;
}
//Break recursion after certain amount of nodes visited
if (setVisited.size() > maxLength) {
return foundPipes;
}
if (!startPipe.isRouterInitialized()) {
return foundPipes;
}
//Break recursion if we end up on a routing pipe, unless its the first one. Will break if matches the first call
if (startPipe.isRoutingPipe() && setVisited.size() != 0) {
CoreRoutedPipe rp = startPipe.getRoutingPipe();
if (rp.stillNeedReplace()) {
return foundPipes;
}
double size = 0;
for (Double dis : distances.values()) {
size += dis;
}
if (!rp.getUpgradeManager().hasPowerPassUpgrade()) {
connectionFlags.remove(PipeRoutingConnectionType.canPowerSubSystemFrom);
}
foundPipes.put(rp, new ExitRoute(null, rp.getRouter(), ForgeDirection.UNKNOWN, side.getOpposite(), Math.max(1, size), connectionFlags, distances.size()));
return foundPipes;
}
//Visited is checked after, so we can reach the same target twice to allow to keep the shortest path
setVisited.add(new DoubleCoordinates(startPipe));
distances.put(new DoubleCoordinates(startPipe), startPipe.getDistance());
// first check specialPipeConnections (tesseracts, teleports, other connectors)
List<ConnectionInformation> pipez = SimpleServiceLocator.specialpipeconnection.getConnectedPipes(startPipe, connectionFlags, side);
for (ConnectionInformation specialConnection : pipez) {
if (setVisited.contains(new DoubleCoordinates(specialConnection.getConnectedPipe()))) {
//Don't go where we have been before
continue;
}
distances.put(new DoubleCoordinates(startPipe).center(), specialConnection.getDistance());
HashMap<CoreRoutedPipe, ExitRoute> result = getConnectedRoutingPipes(specialConnection.getConnectedPipe(), specialConnection.getConnectionFlags(), specialConnection.getInsertOrientation());
distances.remove(new DoubleCoordinates(startPipe).center());
for (Entry<CoreRoutedPipe, ExitRoute> pipe : result.entrySet()) {
pipe.getValue().exitOrientation = specialConnection.getExitOrientation();
ExitRoute foundPipe = foundPipes.get(pipe.getKey());
if (foundPipe == null || (pipe.getValue().distanceToDestination < foundPipe.distanceToDestination)) {
// New path OR If new path is better, replace old path
foundPipes.put(pipe.getKey(), pipe.getValue());
}
}
}
ArrayDeque<Pair<TileEntity, ForgeDirection>> connections = new ArrayDeque<>();
//Recurse in all directions
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) {
if (root && !ForgeDirection.UNKNOWN.equals(side) && !direction.equals(side)) {
continue;
}
// tile may be up to 1 second old, but any neighbour pipe change will cause an immidiate update here, so we know that if it has changed, it isn't a pipe that has done so.
TileEntity tile = startPipe.getNextConnectedTile(direction);
if (tile == null) {
continue;
}
if (OrientationsUtil.isSide(direction)) {
if (root && tile instanceof ILogisticsPowerProvider) {
if (powerNodes == null) {
powerNodes = new ArrayList<>();
}
//If we are a FireWall pipe add our filter to the pipes
if (startPipe.isFirewallPipe()) {
powerNodes.add(new Pair<>((ILogisticsPowerProvider) tile, new OneList<>(startPipe.getFirewallFilter())));
} else {
powerNodes.add(new Pair<>((ILogisticsPowerProvider) tile, Collections.unmodifiableList(new ArrayList<>(0))));
}
}
if (root && tile instanceof ISubSystemPowerProvider) {
if (subPowerProvider == null) {
subPowerProvider = new ArrayList<>();
}
//If we are a FireWall pipe add our filter to the pipes
if (startPipe.isFirewallPipe()) {
subPowerProvider.add(new Pair<>((ISubSystemPowerProvider) tile, new OneList<>(startPipe.getFirewallFilter())));
} else {
subPowerProvider.add(new Pair<>((ISubSystemPowerProvider) tile, Collections.unmodifiableList(new ArrayList<>(0))));
}
}
}
connections.add(new Pair<>(tile, direction));
}
while (!connections.isEmpty()) {
Pair<TileEntity, ForgeDirection> pair = connections.pollFirst();
TileEntity tile = pair.getValue1();
ForgeDirection direction = pair.getValue2();
EnumSet<PipeRoutingConnectionType> nextConnectionFlags = EnumSet.copyOf(connectionFlags);
boolean isDirectConnection = false;
int resistance = 0;
if (root) {
Collection<TileEntity> list = SimpleServiceLocator.specialtileconnection.getConnectedPipes(tile);
if (!list.isEmpty()) {
connections.addAll(list.stream().map(pipe -> new Pair<>(pipe, direction)).collect(Collectors.toList()));
listTileEntity(tile);
continue;
}
if (!startPipe.getRoutingPipe().getUpgradeManager().hasPowerPassUpgrade()) {
nextConnectionFlags.remove(PipeRoutingConnectionType.canPowerSubSystemFrom);
}
}
if (tile instanceof IInventory && startPipe.isRoutingPipe() && startPipe.getRoutingPipe() instanceof IDirectRoutingConnection && startPipe.canConnect(tile, direction, false)) {
if (SimpleServiceLocator.connectionManager.hasDirectConnection(startPipe.getRoutingPipe().getRouter())) {
CoreRoutedPipe CRP = SimpleServiceLocator.connectionManager.getConnectedPipe(startPipe.getRoutingPipe().getRouter());
if (CRP != null) {
tile = CRP.container;
isDirectConnection = true;
resistance = ((IDirectRoutingConnection) startPipe.getRoutingPipe()).getConnectionResistance();
}
}
}
if (tile == null) {
continue;
}
IPipeInformationProvider currentPipe = SimpleServiceLocator.pipeInformationManager.getInformationProviderFor(tile);
if (currentPipe != null && currentPipe.isRouterInitialized() && (isDirectConnection || SimpleServiceLocator.pipeInformationManager.canConnect(startPipe, currentPipe, direction, true))) {
listTileEntity(tile);
// DON'T USE THIS ANYMORE CAN CAUSE TROUBLE WITH MULTIBLOCKS
tile = null;
if (currentPipe.isMultiBlock()) {
currentPipe.getPartsOfPipe().forEach(this::listTileEntity);
}
if (setVisited.contains(new DoubleCoordinates(currentPipe))) {
//Don't go where we have been before
continue;
}
if (side != pair.getValue2() && !root) {
//Only straight connections for subsystem power
nextConnectionFlags.remove(PipeRoutingConnectionType.canPowerSubSystemFrom);
}
if (isDirectConnection) {
//ISC doesn't pass power
nextConnectionFlags.remove(PipeRoutingConnectionType.canPowerFrom);
nextConnectionFlags.remove(PipeRoutingConnectionType.canPowerSubSystemFrom);
}
//Iron, obsidean and liquid pipes will separate networks
if (currentPipe.divideNetwork()) {
continue;
}
if (currentPipe.powerOnly()) {
nextConnectionFlags.remove(PipeRoutingConnectionType.canRouteTo);
nextConnectionFlags.remove(PipeRoutingConnectionType.canRequestFrom);
}
if (startPipe.isOnewayPipe()) {
if (!startPipe.isOutputOpen(direction)) {
nextConnectionFlags.remove(PipeRoutingConnectionType.canRouteTo);
}
}
if (currentPipe.isOnewayPipe()) {
nextConnectionFlags.remove(PipeRoutingConnectionType.canPowerSubSystemFrom);
if (!currentPipe.isOutputOpen(direction.getOpposite())) {
nextConnectionFlags.remove(PipeRoutingConnectionType.canRequestFrom);
nextConnectionFlags.remove(PipeRoutingConnectionType.canPowerFrom);
}
}
if (nextConnectionFlags.isEmpty()) {
//don't bother going somewhere we can't do anything with
continue;
}
int beforeRecurseCount = foundPipes.size();
HashMap<CoreRoutedPipe, ExitRoute> result = null;
if (currentPipe instanceof IRouteProvider) {
List<RouteInfo> list = ((IRouteProvider) currentPipe).getConnectedPipes(direction.getOpposite());
if (list != null) {
result = new HashMap<>();
DoubleCoordinates pos = new DoubleCoordinates(currentPipe);
for (RouteInfo info : list) {
if (info.getPipe() == startPipe)
continue;
if (setVisited.contains(new DoubleCoordinates(info.getPipe()))) {
//Don't go where we have been before
continue;
}
distances.put(pos, currentPipe.getDistance() + info.getLength());
result.putAll(getConnectedRoutingPipes(info.getPipe(), nextConnectionFlags, direction));
distances.remove(pos);
}
}
}
if (result == null) {
result = getConnectedRoutingPipes(currentPipe, nextConnectionFlags, direction);
}
for (Entry<CoreRoutedPipe, ExitRoute> pipeEntry : result.entrySet()) {
//Update Result with the direction we took
pipeEntry.getValue().exitOrientation = direction;
ExitRoute foundPipe = foundPipes.get(pipeEntry.getKey());
if (foundPipe == null) {
// New path
foundPipes.put(pipeEntry.getKey(), pipeEntry.getValue());
//Add resistance
pipeEntry.getValue().distanceToDestination += resistance;
} else if (pipeEntry.getValue().distanceToDestination + resistance < foundPipe.distanceToDestination) {
//If new path is better, replace old path, otherwise do nothing
foundPipes.put(pipeEntry.getKey(), pipeEntry.getValue());
//Add resistance
pipeEntry.getValue().distanceToDestination += resistance;
}
}
if (foundPipes.size() > beforeRecurseCount && pathPainter != null) {
pathPainter.addLaser(startPipe.getWorld(), new LaserData(startPipe.getX(), startPipe.getY(), startPipe.getZ(), direction, connectionFlags));
}
}
}
setVisited.remove(new DoubleCoordinates(startPipe));
distances.remove(new DoubleCoordinates(startPipe));
if (startPipe.isRoutingPipe()) {
// ie, has the recursion returned to the pipe it started from?
for (ExitRoute e : foundPipes.values()) {
e.root = (startPipe.getRoutingPipe()).getRouter();
}
}
//If we are a FireWall pipe add our filter to the pipes
if (startPipe.isFirewallPipe() && root) {
for (ExitRoute e : foundPipes.values()) {
e.filters = new OneList<>(startPipe.getFirewallFilter());
}
}
return foundPipes;
}
use of logisticspipes.routing.ExitRoute in project LogisticsPipes by RS485.
the class RequestTreeNode method checkCrafting.
private boolean checkCrafting() {
// get all the routers
BitSet routersIndex = ServerRouter.getRoutersInterestedIn(getRequestType());
// get the routing table
List<ExitRoute> validSources = new ArrayList<>();
for (int i = routersIndex.nextSetBit(0); i >= 0; i = routersIndex.nextSetBit(i + 1)) {
IRouter r = SimpleServiceLocator.routerManager.getRouterUnsafe(i, false);
if (!r.isValidCache()) {
//Skip Routers without a valid pipe
continue;
}
List<ExitRoute> e = getRequestType().getRouter().getDistanceTo(r);
if (e != null) {
validSources.addAll(e);
}
}
// distance doesn't matter, because ingredients have to be delivered to the crafter, and we can't tell how long that will take.
workWeightedSorter wSorter = new workWeightedSorter(0);
Collections.sort(validSources, wSorter);
List<Pair<ICraftingTemplate, List<IFilter>>> allCraftersForItem = RequestTreeNode.getCrafters(getRequestType(), validSources);
// if you have a crafter which can make the top treeNode.getStack().getItem()
Iterator<Pair<ICraftingTemplate, List<IFilter>>> iterAllCrafters = allCraftersForItem.iterator();
//a queue to store the crafters, sorted by todo; we will fill up from least-most in a balanced way.
PriorityQueue<CraftingSorterNode> craftersSamePriority = new PriorityQueue<>(5);
ArrayList<CraftingSorterNode> craftersToBalance = new ArrayList<>();
//TODO ^ Make this a generic list
boolean done = false;
Pair<ICraftingTemplate, List<IFilter>> lastCrafter = null;
int currentPriority = 0;
outer: while (!done) {
/// First: Create a list of all crafters with the same priority (craftersSamePriority).
if (iterAllCrafters.hasNext()) {
if (lastCrafter == null) {
lastCrafter = iterAllCrafters.next();
}
} else if (lastCrafter == null) {
done = true;
}
int itemsNeeded = getMissingAmount();
if (lastCrafter != null && (craftersSamePriority.isEmpty() || (currentPriority == lastCrafter.getValue1().getPriority()))) {
currentPriority = lastCrafter.getValue1().getPriority();
Pair<ICraftingTemplate, List<IFilter>> crafter = lastCrafter;
lastCrafter = null;
ICraftingTemplate template = crafter.getValue1();
if (isCrafterUsed(template)) {
continue;
}
if (!template.canCraft(getRequestType())) {
// we this is crafting something else
continue;
}
for (IFilter filter : crafter.getValue2()) {
// is this filtered for some reason.
if (filter.isBlocked() == filter.isFilteredItem(template.getResultItem()) || filter.blockCrafting()) {
continue outer;
}
}
CraftingSorterNode cn = new CraftingSorterNode(crafter, itemsNeeded, root, this);
// if(cn.getWorkSetsAvailableForCrafting()>0)
craftersSamePriority.add(cn);
continue;
}
if (craftersToBalance.isEmpty() && (craftersSamePriority == null || craftersSamePriority.isEmpty())) {
//nothing at this priority was available for crafting
continue;
}
if (craftersSamePriority.size() == 1) {
// then no need to balance.
craftersToBalance.add(craftersSamePriority.poll());
// automatically capped at the real amount of extra work.
craftersToBalance.get(0).addToWorkRequest(itemsNeeded);
} else {
// or the amount of work they have is equal to the next-least busy crafter. then pull the next crafter and repeat.
if (!craftersSamePriority.isEmpty()) {
craftersToBalance.add(craftersSamePriority.poll());
}
// while we crafters that can work and we have work to do.
while (!craftersToBalance.isEmpty() && itemsNeeded > 0) {
// typically pulls 1 at a time, but may pull multiple, if they have the exact same todo.
while (!craftersSamePriority.isEmpty() && craftersSamePriority.peek().currentToDo() <= craftersToBalance.get(0).currentToDo()) {
craftersToBalance.add(craftersSamePriority.poll());
}
// find the most we can add this iteration
int cap;
if (!craftersSamePriority.isEmpty()) {
cap = craftersSamePriority.peek().currentToDo();
} else {
cap = Integer.MAX_VALUE;
}
//split the work between N crafters, up to "cap" (at which point we would be dividing the work between N+1 crafters.
int floor = craftersToBalance.get(0).currentToDo();
cap = Math.min(cap, floor + (itemsNeeded + craftersToBalance.size() - 1) / craftersToBalance.size());
for (CraftingSorterNode crafter : craftersToBalance) {
int request = Math.min(itemsNeeded, cap - floor);
if (request > 0) {
int craftingDone = crafter.addToWorkRequest(request);
// ignored under-crafting
itemsNeeded -= craftingDone;
}
}
}
// all craftersToBalance exhausted, or work completed.
}
// end of else more than 1 crafter at this priority
// commit this work set.
Iterator<CraftingSorterNode> iter = craftersToBalance.iterator();
while (iter.hasNext()) {
CraftingSorterNode c = iter.next();
if (c.stacksOfWorkRequested > 0 && !c.addWorkPromisesToTree()) {
// then it ran out of resources
iter.remove();
}
}
itemsNeeded = getMissingAmount();
if (itemsNeeded <= 0) {
// we have everything we need for this crafting request
break outer;
}
// don't clear, because we might have under-requested, and need to consider these again
if (!craftersToBalance.isEmpty()) {
done = false;
//craftersSamePriority.clear(); // we've extracted all we can from these priority crafters, and we still have more to do, back to the top to get the next priority level.
}
}
//LogisticsPipes.log.info("done");
return isDone();
}
use of logisticspipes.routing.ExitRoute in project LogisticsPipes by RS485.
the class RequestTreeNode method getProviders.
private static List<Pair<IProvide, List<IFilter>>> getProviders(IRouter destination, IResource item) {
// get all the routers
BitSet routersIndex = ServerRouter.getRoutersInterestedIn(item);
// get the routing table
List<ExitRoute> validSources = new ArrayList<>();
for (int i = routersIndex.nextSetBit(0); i >= 0; i = routersIndex.nextSetBit(i + 1)) {
IRouter r = SimpleServiceLocator.routerManager.getRouterUnsafe(i, false);
if (!r.isValidCache()) {
//Skip Routers without a valid pipe
continue;
}
List<ExitRoute> e = destination.getDistanceTo(r);
if (e != null) {
validSources.addAll(e);
}
}
// closer providers are good
Collections.sort(validSources, new workWeightedSorter(1.0));
List<Pair<IProvide, List<IFilter>>> providers = new LinkedList<>();
validSources.stream().filter(r -> r.containsFlag(PipeRoutingConnectionType.canRequestFrom)).forEach(r -> {
CoreRoutedPipe pipe = r.destination.getPipe();
if (pipe instanceof IProvide) {
List<IFilter> list = new LinkedList<>();
list.addAll(r.filters);
providers.add(new Pair<>((IProvide) pipe, list));
}
});
return providers;
}
use of logisticspipes.routing.ExitRoute in project LogisticsPipes by RS485.
the class EntrencsTransport method resolveDestination.
@Override
public ForgeDirection resolveDestination(LPTravelingItemServer data) {
if (data.getDestination() < 0 || data.getArrived()) {
if (pipe.getLocalFreqUUID() != null) {
if (pipe.useEnergy(5)) {
for (ExitRoute router : pipe.getRouter().getIRoutersByCost()) {
if (!router.containsFlag(PipeRoutingConnectionType.canRouteTo)) {
continue;
}
CoreRoutedPipe lPipe = router.destination.getPipe();
if (lPipe instanceof PipeItemsSystemDestinationLogistics) {
PipeItemsSystemDestinationLogistics dPipe = (PipeItemsSystemDestinationLogistics) lPipe;
if (dPipe.getTargetUUID() != null) {
if (dPipe.getTargetUUID().equals(pipe.getLocalFreqUUID())) {
data.setDestination(dPipe.getRouter().getSimpleID());
data.setArrived(false);
}
}
}
}
}
}
}
return super.resolveDestination(data);
}
Aggregations