Package logisticspipes.logistics

Source Code of logisticspipes.logistics.LogisticsManager

/**
* Copyright (c) Krapht, 2011
*
* "LogisticsPipes" is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/

package logisticspipes.logistics;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import logisticspipes.interfaces.routing.ICraftItems;
import logisticspipes.interfaces.routing.IFilter;
import logisticspipes.interfaces.routing.IProvideItems;
import logisticspipes.items.LogisticsFluidContainer;
import logisticspipes.logisticspipes.IRoutedItem;
import logisticspipes.logisticspipes.IRoutedItem.TransportMode;
import logisticspipes.modules.abstractmodules.LogisticsModule;
import logisticspipes.pipefxhandlers.Particles;
import logisticspipes.pipes.PipeItemsCraftingLogistics;
import logisticspipes.pipes.PipeItemsProviderLogistics;
import logisticspipes.pipes.PipeItemsRequestLogistics;
import logisticspipes.pipes.PipeLogisticsChassi;
import logisticspipes.pipes.basic.CoreRoutedPipe;
import logisticspipes.proxy.SimpleServiceLocator;
import logisticspipes.routing.ExitRoute;
import logisticspipes.routing.IRouter;
import logisticspipes.routing.PipeRoutingConnectionType;
import logisticspipes.routing.ServerRouter;
import logisticspipes.utils.SinkReply;
import logisticspipes.utils.SinkReply.FixedPriority;
import logisticspipes.utils.item.ItemIdentifier;
import logisticspipes.utils.item.ItemIdentifierStack;
import logisticspipes.utils.tuples.Pair;
import logisticspipes.utils.tuples.Triplet;

public class LogisticsManager implements ILogisticsManager {

  /**
   * Method used to check if a given stack has a destination.
   *
   * @return Triplet of destinationSimpleID, sinkreply, relays; null if nothing found
   * @param stack The stack to check if it has destination.
   * @param allowDefault Boolean, if true then a default route will be considered a valid destination.
   * @param sourceRouter The UUID of the router pipe that wants to send the stack.
   * @param excludeSource Boolean, true means it will not consider the pipe itself as a valid destination.
   */
  @Override
  public Triplet<Integer, SinkReply, List<IFilter>> hasDestination(ItemIdentifier stack, boolean allowDefault, int sourceID, List<Integer> routerIDsToExclude) {
    IRouter sourceRouter = SimpleServiceLocator.routerManager.getRouter(sourceID);
    if (sourceRouter == null) return null;
    BitSet routersIndex = ServerRouter.getRoutersInterestedIn(stack);
    List<ExitRoute> validDestinations = new ArrayList<ExitRoute>(); // get the routing table
    for (int i = routersIndex.nextSetBit(0); i >= 0; i = routersIndex.nextSetBit(i+1)) {
      IRouter r = SimpleServiceLocator.routerManager.getRouterUnsafe(i,false);
      List<ExitRoute> exits = sourceRouter.getDistanceTo(r);
      if (exits!=null) {
        for(ExitRoute e:exits) {
          if(e.containsFlag(PipeRoutingConnectionType.canRouteTo))
            validDestinations.add(e);
        }
      }
    }
    Collections.sort(validDestinations);
    Triplet<Integer, SinkReply, List<IFilter>> search = getBestReply(stack, sourceRouter, validDestinations, true, routerIDsToExclude, null, allowDefault);

    if (search.getValue2() == null) return null;

    if (!allowDefault && search.getValue2().isDefault) return null;

    return search;
  }

  /**
   * Method used to check if a given stack has a passive sink destination at a priority.
   *
   * @return Triplet of destinationSimpleID, sinkreply, relays; null if nothing found
   * @param stack The stack to check if it has destination.
   * @param sourceRouter The UUID of the router pipe that wants to send the stack.
   * @param excludeSource Boolean, true means it will not consider the pipe itself as a valid destination.
   * @param priority The priority that the stack must have.
   */
  @Override
  public Triplet<Integer, SinkReply, List<IFilter>> hasDestinationWithMinPriority(ItemIdentifier stack, int sourceRouter, boolean excludeSource, FixedPriority priority) {
    if (!SimpleServiceLocator.routerManager.isRouter(sourceRouter)) return null;
    Triplet<Integer, SinkReply, List<IFilter>> search = getBestReply(stack, SimpleServiceLocator.routerManager.getRouter(sourceRouter), SimpleServiceLocator.routerManager.getRouter(sourceRouter).getIRoutersByCost(), excludeSource, new ArrayList<Integer>(), null, true);
    if (search.getValue2() == null) return null;
    if (search.getValue2().fixedPriority.ordinal() < priority.ordinal()) return null;
    return search;
  }


  private Triplet<Integer, SinkReply, List<IFilter>> getBestReply(ItemIdentifier stack, IRouter sourceRouter, List<ExitRoute> validDestinations, boolean excludeSource, List<Integer> jamList, Triplet<Integer, SinkReply, List<IFilter>> result, boolean allowDefault) {
    if(result == null) {
      result = new Triplet<Integer, SinkReply, List<IFilter>>(null, null, null);
    }
   
outer:
    for (ExitRoute candidateRouter : validDestinations){
      if (excludeSource) {
        if(candidateRouter.destination.getId().equals(sourceRouter.getId())) continue;
      }
      if(jamList.contains(candidateRouter.destination.getSimpleID())) continue;

      if(!candidateRouter.containsFlag(PipeRoutingConnectionType.canRouteTo)) continue;

      for(IFilter filter:candidateRouter.filters) {
        if(filter.blockRouting() || (filter.isBlocked() == filter.isFilteredItem(stack))) continue outer;
      }

      SinkReply reply = canSink(candidateRouter.destination,sourceRouter,excludeSource,stack,result.getValue2(), false,allowDefault);
         
      if (reply == null) continue;
      if (result.getValue1() == null){
        result.setValue1(candidateRouter.destination.getSimpleID());
        result.setValue2(reply);
        List<IFilter> list = new LinkedList<IFilter>();
        result.setValue3(list);
        continue;
      }

      if (reply.fixedPriority.ordinal() > result.getValue2().fixedPriority.ordinal()) {
        result.setValue1(candidateRouter.destination.getSimpleID());
        result.setValue2(reply);
        List<IFilter> list = new LinkedList<IFilter>();
        result.setValue3(list);
        continue;
      }

      if (reply.fixedPriority == result.getValue2().fixedPriority && reply.customPriority >  result.getValue2().customPriority) {
        result.setValue1(candidateRouter.destination.getSimpleID());
        result.setValue2(reply);
        List<IFilter> list = new LinkedList<IFilter>();
        result.setValue3(list);
        continue;
      }
    }
    if(result.getValue1() != null) {
      CoreRoutedPipe pipe = SimpleServiceLocator.routerManager.getRouterUnsafe(result.getValue1(),false).getPipe();
      pipe.useEnergy(result.getValue2().energyUse);
      pipe.spawnParticle(Particles.BlueParticle, 10);
    }
    return result;
  }
 
  public static SinkReply canSink(IRouter destination, IRouter sourceRouter, boolean excludeSource,ItemIdentifier stack,SinkReply result, boolean activeRequest, boolean allowDefault) {

    SinkReply reply = null;
    LogisticsModule module = destination.getLogisticsModule();
    CoreRoutedPipe crp = destination.getPipe();
    if (module == null) return null;
    if (!(module.recievePassive() || activeRequest))
      return null;
    if (crp == null || !crp.isEnabled()) return null;
    if (excludeSource && sourceRouter !=null) {
      if(destination.getPipe().sharesInventoryWith(sourceRouter.getPipe())) return null;
    }
    if (result== null) {
      reply = module.sinksItem(stack, -1, 0, allowDefault,true);
    } else {
      reply = module.sinksItem(stack, result.fixedPriority.ordinal(), result.customPriority, allowDefault,true);
    }
    return reply;
  }
 
  /**
   * Will assign a destination for a IRoutedItem based on a best sink reply recieved from other pipes.
   * @param item The item that needs to be routed.
   * @param sourceRouterID The SimpleID of the pipe that is sending the item. (the routedItem will cache the UUID, and that the SimpleID belongs to the UUID will be checked when appropriate)
   * @param excludeSource Boolean, true means that it wont set the source as the destination.
   * @return IRoutedItem with a newly assigned destination
   */
  @Override
  public IRoutedItem assignDestinationFor(IRoutedItem item, int sourceRouterID, boolean excludeSource) {

    //Assert: only called server side.
   
    //If we for some reason can't get the router we can't do anything either
    IRouter sourceRouter = SimpleServiceLocator.routerManager.getRouterUnsafe(sourceRouterID,false);
    if (sourceRouter == null) return item;

    //Wipe current destination
    item.clearDestination();

    BitSet routersIndex = ServerRouter.getRoutersInterestedIn(item.getItemIdentifierStack().getItem());
    List<ExitRoute> validDestinations = new ArrayList<ExitRoute>(); // get the routing table
    for (int i = routersIndex.nextSetBit(0); i >= 0; i = routersIndex.nextSetBit(i+1)) {
      IRouter r = SimpleServiceLocator.routerManager.getRouterUnsafe(i,false);
      List<ExitRoute> exits = sourceRouter.getDistanceTo(r);
      if (exits!=null) {
        for(ExitRoute e:exits) {
          if(e.containsFlag(PipeRoutingConnectionType.canRouteTo))
            validDestinations.add(e);
        }
      }
    }
    Collections.sort(validDestinations);
    if(item.getItemIdentifierStack() != null && item.getItemIdentifierStack().makeNormalStack().getItem() instanceof LogisticsFluidContainer) {
      Pair<Integer, Integer> bestReply = SimpleServiceLocator.logisticsFluidManager.getBestReply(SimpleServiceLocator.logisticsFluidManager.getFluidFromContainer(item.getItemIdentifierStack()), sourceRouter, item.getJamList());
      if (bestReply.getValue1() != null && bestReply.getValue1() != 0){
        item.setDestination(bestReply.getValue1());
      }
      return item;
    } else {
      Triplet<Integer, SinkReply, List<IFilter>> bestReply = getBestReply(item.getItemIdentifierStack().getItem(), sourceRouter, validDestinations, excludeSource, item.getJamList(), null, true)
      if (bestReply.getValue1() != null && bestReply.getValue1() != 0){
        item.setDestination(bestReply.getValue1());
        if (bestReply.getValue2().isPassive){
          if (bestReply.getValue2().isDefault){
            item.setTransportMode(TransportMode.Default);
          } else {
            item.setTransportMode(TransportMode.Passive);
          }
        } else {
          item.setTransportMode(TransportMode.Active);
        }
      }
      return item;
    }
  }

  /**
   * If there is a better router name available, it will return it.  Else, it will return the UUID as a string.
   * @param r The IRouter that you want the name for.
   * @return String with value of a better name if available, else just the UUID as a string.
   */
  @Override
  public String getBetterRouterName(IRouter r){

    if (r.getPipe() instanceof PipeItemsCraftingLogistics){
      PipeItemsCraftingLogistics pipe = (PipeItemsCraftingLogistics) r.getPipe();
      if (pipe.getCraftedItems() != null){
        List<ItemIdentifierStack> items = pipe.getCraftedItems();
        if(items.size()==1)
          return ("Crafter<" + items.get(0).getFriendlyName() + ">");
        return ("Crafter< MULTIPLE ITEMS >");
      }
    }

    if (r.getPipe() instanceof PipeItemsProviderLogistics){
      return ("Provider");
    }

    if (r.getPipe() instanceof PipeLogisticsChassi) {
      return "Chassis";
    }
    if (r.getPipe() instanceof PipeItemsRequestLogistics) {
      return "Request";
    }

    return r.getId().toString();

  }

  /**
   * @param validDestinations a list of ExitRoute of valid destinations.
   * @return HashMap with ItemIdentifier and Integer item count of available items.
   */
  @Override
  public HashMap<ItemIdentifier, Integer> getAvailableItems(List<ExitRoute> validDestinations) {
    //TODO: Replace this entire function wiht a fetch from the pre-built arrays (path incoming later)
    List<Map<ItemIdentifier, Integer>> items = new ArrayList<Map<ItemIdentifier, Integer>>(ServerRouter.getBiggestSimpleID());
    for(int i = 0; i < ServerRouter.getBiggestSimpleID(); i++)
      items.add(new HashMap<ItemIdentifier, Integer>());
    BitSet used = new BitSet(ServerRouter.getBiggestSimpleID());
outer:
    for(ExitRoute r: validDestinations){
      if(r == null) continue;
      if(!r.containsFlag(PipeRoutingConnectionType.canRequestFrom)) continue;
      if (!(r.destination.getPipe() instanceof IProvideItems)) continue;
      for(IFilter filter:r.filters) {
        if(filter.blockProvider()) continue outer;
      }
      IProvideItems provider = (IProvideItems) r.destination.getPipe();
      provider.getAllItems(items.get(r.destination.getSimpleID()), r.filters);
      used.set(r.destination.getSimpleID(), true);
    }
    //TODO: Fix this doubly nested list
    HashMap<ItemIdentifier, Integer> allAvailableItems = new HashMap<ItemIdentifier, Integer>();
    for(Map<ItemIdentifier, Integer> allItems:items) {
      for (Entry<ItemIdentifier, Integer> item : allItems.entrySet()){
        Integer currentItem=allAvailableItems.get(item.getKey());
        if (currentItem==null){
          allAvailableItems.put(item.getKey(), item.getValue());
        } else {
          allAvailableItems.put(item.getKey(), currentItem + item.getValue());
        }
      }
    }
    return allAvailableItems;
  }

  /**
   * @param validDestinations a List of ExitRoute of valid destinations.
   * @return LinkedList with ItemIdentifier
   */
  @Override
  public LinkedList<ItemIdentifier> getCraftableItems(List<ExitRoute> validDestinations) {
    LinkedList<ItemIdentifier> craftableItems = new LinkedList<ItemIdentifier>();
    BitSet used = new BitSet(ServerRouter.getBiggestSimpleID());
outer:
    for (ExitRoute r : validDestinations){
      if(r == null) continue;
      if(!r.containsFlag(PipeRoutingConnectionType.canRequestFrom)) continue;
      if(used.get(r.destination.getSimpleID())) continue;
      if (!(r.destination.getPipe() instanceof ICraftItems)) continue;
      for(IFilter filter:r.filters) {
        if(filter.blockCrafting()) continue outer;
      }
      ICraftItems crafter = (ICraftItems) r.destination.getPipe();
      List<ItemIdentifierStack> craftedItems = crafter.getCraftedItems();
      if(craftedItems != null) {
outer2:
        for(ItemIdentifierStack craftedItem:craftedItems) {
          if (craftedItem != null && !craftableItems.contains(craftedItem.getItem())) {
            for(IFilter filter:r.filters) {
              if(filter.isBlocked() == filter.isFilteredItem(craftedItem.getItem())) continue outer2;
            }
            craftableItems.add(craftedItem.getItem());
          }
        }
      }
      used.set(r.destination.getSimpleID(), true);
    }
    return craftableItems;
  }

  @Override
  public int getAmountFor(ItemIdentifier itemType, List<ExitRoute> validDestinations) {
    // TODO: Replace this entire function wiht a fetch from the pre-built arrays (path incoming later)
    List<Map<ItemIdentifier, Integer>> items = new ArrayList<Map<ItemIdentifier, Integer>>(ServerRouter.getBiggestSimpleID());
    for(int i = 0; i < ServerRouter.getBiggestSimpleID(); i++)
      items.add(new HashMap<ItemIdentifier, Integer>());
    BitSet used = new BitSet(ServerRouter.getBiggestSimpleID());
    outer:
    for(ExitRoute r: validDestinations) {
      if(r == null) continue;
      if(!r.containsFlag(PipeRoutingConnectionType.canRequestFrom)) continue;
      if(!(r.destination.getPipe() instanceof IProvideItems)) continue;
      for(IFilter filter: r.filters) {
        if(filter.blockProvider()) continue outer;
      }
      IProvideItems provider = (IProvideItems)r.destination.getPipe();
      provider.getAllItems(items.get(r.destination.getSimpleID()), r.filters);
      used.set(r.destination.getSimpleID(), true);
    }
    // TODO: Fix this doubly nested list
    int amount = 0;
    for(Map<ItemIdentifier, Integer> allItems: items) {
      for(Entry<ItemIdentifier, Integer> item: allItems.entrySet()) {
        if(item.getKey().equals(itemType)) {
          amount += item.getValue();
        }
      }
    }
    return amount;
  }
}
TOP

Related Classes of logisticspipes.logistics.LogisticsManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.