Package com.bergerkiller.bukkit.tc.pathfinding

Source Code of com.bergerkiller.bukkit.tc.pathfinding.PathProvider$PathFindOperation

package com.bergerkiller.bukkit.tc.pathfinding;

import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.logging.Level;

import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.plugin.java.JavaPlugin;

import com.bergerkiller.bukkit.common.BlockLocation;
import com.bergerkiller.bukkit.common.Task;
import com.bergerkiller.bukkit.common.utils.FaceUtil;
import com.bergerkiller.bukkit.tc.TrainCarts;
import com.bergerkiller.bukkit.tc.Util;
import com.bergerkiller.bukkit.tc.events.SignActionEvent;
import com.bergerkiller.bukkit.tc.rails.type.RailType;
import com.bergerkiller.bukkit.tc.signactions.SignActionMode;
import com.bergerkiller.bukkit.tc.utils.TrackIterator;

public class PathProvider extends Task {
  public static boolean DEBUG_MODE = false;
  private static final int STEP_COUNT = 100; // Steps performed per timing check
  private static final int MAX_PROCESSING_PER_TICK = 30; // Maximum processing time in Ms per tick
  private static PathProvider task;
  private Set<PathNode> pendingNodes = new LinkedHashSet<PathNode>();
  private Queue<PathFindOperation> pendingOperations = new LinkedList<PathFindOperation>();

  private PathProvider(JavaPlugin plugin) {
    super(plugin);
  }

  public static void init() {
    task = new PathProvider(TrainCarts.plugin);
    task.start(1, 1);
  }

  public static void deinit() {
    if (task == null) {
      return;
    }
    task.stop();
    task = null;
  }

  /**
   * Tells this Path Provider to start calculating all neighboring paths from the node specified
   *
   * @param startNode to schedule
   */
  public static void schedule(PathNode startNode) {
    if (task != null) {
      task.pendingNodes.add(startNode);
    }
  }

  /**
   * Tells this Path Provider to start finding the next node(s) from the start point specified
   *
   * @param startNode from which to seek and to which connections should be made
   * @param startBlock from which to start searching
   * @param startDirection towards which direction to start searching
   */
  public static void schedule(PathNode startNode, Block startBlock, BlockFace startDirection) {
    if (task != null) {
      task.pendingOperations.offer(new PathFindOperation(startNode, startBlock, startDirection));
    }
  }

  /**
   * Checks whether this Path Provider is currently busy processing path finding
   *
   * @return True if processing is being performed, False if not
   */
  public static boolean isProcessing() {
    return task != null && (!task.pendingOperations.isEmpty() || !task.pendingNodes.isEmpty());
  }

  @Override
  public Task stop() {
    addPendingNodes();
    if (!this.pendingOperations.isEmpty()) {
      TrainCarts.plugin.log(Level.INFO, "Performing " + this.pendingOperations.size() + " pending path finding operations (can take a while)...");
      while (!this.pendingOperations.isEmpty()) {
        PathFindOperation operation = this.pendingOperations.poll();
        while (operation.next());
      }
    }
    return super.stop();
  }

  @Override
  public void run() {
    if (this.pendingOperations.isEmpty()) {
      addPendingNodes();
    }
    if (this.pendingOperations.isEmpty()) {
      return;
    }
    int i;
    boolean done;
    final long startTime = System.currentTimeMillis();
    while (!this.pendingOperations.isEmpty()) {
      PathFindOperation operation = this.pendingOperations.peek();
      done = false;
      if (DEBUG_MODE) {
        System.out.println("DISCOVERING EVERYTHING FROM " + operation.startNode.getDisplayName() +
            " INTO " + operation.startDir);
      }
      // Perform the operations in steps
      // Not per step, because System.currentTimeMillis is not entirely cheap!
      do {
        for (i = 0; i < STEP_COUNT && !done; i++) {
          done = operation.next();
        }
      } while (!done && (System.currentTimeMillis() - startTime) <= MAX_PROCESSING_PER_TICK);
      if (done) {
        this.pendingOperations.poll();
      } else {
        break; // Ran out of time
      }
    }
  }

  private void addPendingNodes() {
    if (!this.pendingNodes.isEmpty()) {
      for (PathNode node : this.pendingNodes) {
        Block startRail = node.location.getBlock();
        RailType startType = RailType.getType(startRail);
        if (startType == RailType.NONE) {
          // Track type can not be identified
          continue;
        }
        if (node.containsSwitcher()) {
          if (DEBUG_MODE) {
            System.out.println("NODE " + node.getDisplayName() + " CONTAINS A SWITCHER");
          }
          // Check north-east-south-west for possible routes
          for (BlockFace dir : FaceUtil.AXIS) {
            scheduleNode(node, startType.findMinecartPos(startRail).getRelative(dir), dir);
          }
        } else {
          // Only check available routes
          for (BlockFace dir : startType.getPossibleDirections(startRail)) {
            scheduleNode(node, startType.getNextPos(startRail, dir), dir);
          }
        }
      }
      this.pendingNodes.clear();
    }
  }

  private void scheduleNode(PathNode node, Block startBlock, BlockFace direction) {
    for (RailType nextType : RailType.values()) {
      Block startRail = nextType.findRail(startBlock);
      if (startRail != null) {
        schedule(node, startRail, direction);
        return;
      }
    }
  }

  private static class PathFindOperation {
    private final TrackIterator iter;
    private final BlockFace startDir;
    private final PathNode startNode;

    public PathFindOperation(PathNode startNode, Block startBlock, BlockFace startFace) {
      this.iter = new TrackIterator(startBlock, startFace);
      this.startDir = startFace;
      this.startNode = startNode;
    }

    /**
     * Performs the next finding run
     *
     * @return True if this task is finished, False if not
     */
    public boolean next() {
      if (!iter.hasNext()) {
        return true;
      }
      Block nextRail = iter.next();
      BlockLocation newNodeLocation;
      String newNodeName;
      boolean hasFinished = false;
      for (Block signblock : Util.getSignsFromRails(nextRail)) {
        SignActionEvent event = new SignActionEvent(signblock);
        if (event.getMode() != SignActionMode.NONE) {
          if (event.isType("tag", "switcher")){
            newNodeLocation = new BlockLocation(nextRail);
            newNodeName = newNodeLocation.toString();
          } else if (event.isType("destination")) {
            newNodeLocation = new BlockLocation(nextRail);
            newNodeName = event.getLine(2);
          } else if (event.isType("blocker") && event.isWatchedDirection(iter.currentDirection()) && event.isPowerAlwaysOn()) {
            hasFinished = true;
            break;
          } else {
            continue;
          }
          if (!newNodeName.isEmpty() && !startNode.containsName(newNodeName)) {
            //finished, we found our first target - create connection
            PathNode to = PathNode.getOrCreate(newNodeName, newNodeLocation);
            this.startNode.addNeighbour(to, iter.getDistance() + 1, this.startDir);
            hasFinished = true;
            if (DEBUG_MODE) {
              System.out.println("MADE CONNECTION FROM " + startNode.getDisplayName() + " TO " + newNodeName);
            }
          }
        }
      }
      return hasFinished;
    }
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.tc.pathfinding.PathProvider$PathFindOperation

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.