Package de.kumpelblase2.remoteentities.api.pathfinding

Source Code of de.kumpelblase2.remoteentities.api.pathfinding.Pathfinder

package de.kumpelblase2.remoteentities.api.pathfinding;

import java.util.*;
import net.minecraft.server.v1_7_R1.EntityLiving;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;
import de.kumpelblase2.remoteentities.api.RemoteEntity;
import de.kumpelblase2.remoteentities.api.events.RemoteAsyncPathFindEvent;
import de.kumpelblase2.remoteentities.api.events.RemotePathCancelEvent;
import de.kumpelblase2.remoteentities.api.pathfinding.checkers.*;
import de.kumpelblase2.remoteentities.utilities.NMSUtil;
import de.kumpelblase2.remoteentities.utilities.WorldUtilities;

public class Pathfinder
{
  private final TreeSet<BlockNode> m_openList;
  private final Set<BlockNode> m_closedList;
  private final List<MoveChecker> m_checkers;
  private HeuristicType m_heuristicType = HeuristicType.MANHATTAN;
  private final RemoteEntity m_entity;
  private Path m_currentPath;
  public static int MAX_CHECK_TIMEOUT = 10000;
  private int m_checked = 0;
  private Path m_lastPath;
  private boolean m_isFindingAsync = false;
  public static final Set<Material> transparentMaterial = new HashSet<Material>();
  public static final Set<Material> liquidMaterial = new HashSet<Material>();

  static
  {
    Material[] array = new Material[] {
      Material.AIR, Material.ACTIVATOR_RAIL, Material.BROWN_MUSHROOM, Material.CARROT, Material.CROPS, Material.DETECTOR_RAIL, Material.DIODE, Material.DIODE_BLOCK_OFF,
      Material.DIODE_BLOCK_ON, Material.FENCE_GATE, Material.GRASS, Material.LADDER, Material.LEVER, Material.LONG_GRASS, Material.MELON_STEM, Material.NETHER_WARTS,
      Material.PAINTING, Material.PORTAL, Material.POTATO, Material.PUMPKIN_STEM, Material.RAILS, Material.REDSTONE, Material.RED_ROSE, Material.REDSTONE_COMPARATOR,
      Material.REDSTONE_COMPARATOR_OFF, Material.REDSTONE_COMPARATOR_ON, Material.REDSTONE_WIRE, Material.REDSTONE_TORCH_OFF, Material.REDSTONE_TORCH_ON, Material.SAPLING,
      Material.SIGN_POST, Material.SKULL, Material.SNOW, Material.TORCH, Material.TRIPWIRE, Material.WALL_SIGN, Material.WOOD_BUTTON, Material.STONE_BUTTON, Material.STONE_PLATE,
      Material.WOOD_PLATE, Material.YELLOW_FLOWER
    };
    transparentMaterial.addAll(Arrays.asList(array));

    array = new Material[] { Material.WATER, Material.STATIONARY_WATER, Material.LAVA, Material.STATIONARY_LAVA, Material.LADDER };
    liquidMaterial.addAll(Arrays.asList(array));
  }

  public Pathfinder(RemoteEntity inEntity)
  {
    this.m_openList = new TreeSet<BlockNode>(new NodeComparator());
    this.m_closedList = new HashSet<BlockNode>();
    this.m_checkers = new ArrayList<MoveChecker>();
    this.m_entity = inEntity;
  }

  public Pathfinder(RemoteEntity inEntity, boolean inAsyncFinding)
  {
    this(inEntity);
    this.m_isFindingAsync = inAsyncFinding;
  }

  public PathResult find(Location inStart, Location inEnd)
  {
    this.m_closedList.clear();
    this.m_openList.clear();
    this.m_checked = 0;
    BlockNode start = new BlockNode(this, inStart);
    BlockNode end = new BlockNode(this, inEnd);
    if(start.equals(end))
    {
      this.m_lastPath = new Path(end);
      return PathResult.SUCCESS;
    }


    start.calculateGScore();
    start.calculateHScore(end);
    this.m_openList.add(start);
    BlockNode next = null;
    while(!this.m_closedList.contains(end))
    {
      if(this.m_openList.size() <= 0)
        return PathResult.NO_PATH;

      next = this.m_openList.first();
      this.m_openList.remove(next);
      this.m_closedList.add(next);

      if(end.equals(next))
        break;

      Set<BlockNode> newNodes = this.getNearNodes(next, end);
      if(this.m_checked >= MAX_CHECK_TIMEOUT)
        return PathResult.MAX_ITERATION;

      for(BlockNode n : newNodes)
      {
        n.setParent(next);
        if(!this.m_openList.add(n))
        {
          BlockNode old = this.getFromOpenList(n.toString());
          if(old.getGScore() > n.getGScore())
          {
            old.setParent(next);
            old.calculateGScore();
          }
        }
      }
    }

    ArrayList<BlockNode> inOrder = new ArrayList<BlockNode>();
    inOrder.add(next);
    while((next = next.getParent()) != null)
    {
      inOrder.add(next);
    }

    Collections.reverse(inOrder);
    this.m_lastPath = new Path(inOrder);
    return PathResult.SUCCESS;
  }

  public void findAsync(final Location inStart, final Location inEnd, final PathfinderCallback inCallback)
  {
    Bukkit.getScheduler().runTaskAsynchronously(this.m_entity.getManager().getPlugin(), new Runnable()
    {
      @Override
      public void run()
      {
        PathResult result = find(inStart, inEnd);
        inCallback.onPathfindEnd(Pathfinder.this, result);
      }
    });
  }

  public boolean moveTo(Location inTo)
  {
    if(!this.m_entity.isSpawned())
      return false;

    PathResult result = this.find(this.m_entity.getBukkitEntity().getLocation(), inTo);
    if(result != PathResult.SUCCESS)
      return false;

    RemoteAsyncPathFindEvent event = new RemoteAsyncPathFindEvent(this.m_entity, this.getLastPath());
    Bukkit.getPluginManager().callEvent(event);
    this.m_currentPath = event.getPath();
    NMSUtil.getNavigation(this.m_entity.getHandle()).a(this.m_currentPath.toNMSPath(), this.m_entity.getSpeed());
    return true;
  }

  public boolean moveTo(Location inTo, float inSpeed)
  {
    if(!this.m_entity.isSpawned())
      return false;

    PathResult result = this.find(this.m_entity.getBukkitEntity().getLocation(), inTo);
    if(result != PathResult.SUCCESS)
      return false;

    RemoteAsyncPathFindEvent event = new RemoteAsyncPathFindEvent(this.m_entity, this.getLastPath());
    Bukkit.getPluginManager().callEvent(event);
    this.m_currentPath = event.getPath();
    NMSUtil.getNavigation(this.m_entity.getHandle()).a(this.m_currentPath.toNMSPath(), inSpeed);
    return true;
  }

  public boolean moveToAsync(Location inTo)
  {
    if(!this.m_entity.isSpawned())
      return false;

    this.findAsync(this.m_entity.getBukkitEntity().getLocation(), inTo, new PathfinderCallback()
    {
      @Override
      public void onPathfindEnd(Pathfinder inFinder, PathResult inResult)
      {
        if(inResult == PathResult.SUCCESS)
        {
          RemoteAsyncPathFindEvent event = new RemoteAsyncPathFindEvent(Pathfinder.this.m_entity, inFinder.getLastPath(), true);
          Bukkit.getPluginManager().callEvent(event);
          if(event.isCancelled())
            return;

          Pathfinder.this.m_currentPath = event.getPath();
          NMSUtil.getNavigation(Pathfinder.this.m_entity.getHandle()).a(Pathfinder.this.m_currentPath.toNMSPath(), Pathfinder.this.m_entity.getSpeed());
        }
      }
    });
    return true;
  }

  public boolean moveToAsync(Location inTo, final float inSpeed)
  {
    if(!this.m_entity.isSpawned())
      return false;

    this.findAsync(this.m_entity.getBukkitEntity().getLocation(), inTo, new PathfinderCallback()
    {
      @Override
      public void onPathfindEnd(Pathfinder inFinder, PathResult inResult)
      {
        if(inResult == PathResult.SUCCESS)
        {
          RemoteAsyncPathFindEvent event = new RemoteAsyncPathFindEvent(Pathfinder.this.m_entity, inFinder.getLastPath(), true);
          Bukkit.getPluginManager().callEvent(event);
          if(event.isCancelled())
            return;

          Pathfinder.this.m_currentPath = event.getPath();
          Pathfinder.this.m_currentPath.setCustomSpeed(inSpeed);
          NMSUtil.getNavigation(Pathfinder.this.m_entity.getHandle()).a(Pathfinder.this.m_currentPath.toNMSPath(), inSpeed);
        }
      }
    });
    return true;
  }

  protected Set<BlockNode> getNearNodes(BlockNode inCurrent, BlockNode inEnd)
  {
    Set<BlockNode> nodes = new HashSet<BlockNode>(26);
    for(int x = -1; x <= 1; x++)
    {
      for(int y = -1; y <= 1; y++)
      {
        for(int z = -1 ; z <= 1; z++)
        {
          if(x == 0 && y == 0 && z == 0)
            continue;

          BlockNode node = new BlockNode(this, inCurrent.getLocation().add(x, y, z));
          if(!this.m_closedList.contains(node) && this.canWalk(inCurrent.getLocation(), node.getLocation()))
          {
            this.m_checked++;
            node.setParent(inCurrent);
            node.calculateGScore();
            node.calculateHScore(inEnd);
            nodes.add(node);
          }
        }
      }
    }
    return nodes;
  }

  protected BlockNode getFromOpenList(String inHash)
  {
    for(BlockNode n : this.m_openList)
    {
      if(n.toString().equals(inHash))
        return n;
    }
    return null;
  }

  public HeuristicType getHeuristicType()
  {
    return this.m_heuristicType;
  }

  public void setHeuristicType(HeuristicType inType)
  {
    this.m_heuristicType = inType;
  }

  public boolean canWalk(Location inFrom, Location inTo)
  {
    MoveData data = new MoveData(this, inFrom, inTo);
    for(MoveChecker checker : this.m_checkers)
    {
      checker.checkMove(data);
    }
    return data.isValid();
  }

  public void addChecker(MoveChecker inChecker)
  {
    this.m_checkers.add(inChecker);
  }

  public void addChecker(MoveChecker inChecker, int inPriority)
  {
    this.m_checkers.add(inPriority, inChecker);
  }

  public boolean hasChecker(Class<? extends MoveChecker> inType)
  {
    return this.getChecker(inType) != null;
  }

  @SuppressWarnings("unchecked")
  public <T extends MoveChecker> T getChecker(Class<T> inType)
  {
    for(MoveChecker c : this.m_checkers)
    {
      if(c.getClass().isAssignableFrom(inType))
        return (T)c;
    }

    return null;
  }

  public void removeChecker(Class<? extends MoveChecker> inType)
  {
    Iterator<MoveChecker> it = this.m_checkers.iterator();
    while(it.hasNext())
    {
      if(it.next().getClass().isAssignableFrom(inType))
        it.remove();
    }
  }

  public boolean hasPath()
  {
    return this.m_currentPath != null && !this.m_currentPath.isDone();
  }

  public Path getCurrentPath()
  {
    return this.m_currentPath;
  }

  public void setPath(Path inPath)
  {
    this.m_currentPath = inPath;
  }

  public RemoteEntity getEntity()
  {
    return this.m_entity;
  }

  public void update()
  {
    if(!this.hasPath() || !this.getEntity().isSpawned())
      return;

    EntityLiving entity = this.getEntity().getHandle();
    if(!NMSUtil.getNavigation(this.m_entity.getHandle()).g() || NMSUtil.getControllerMove(this.m_entity.getHandle()).a())
      return;

    BlockNode next = this.m_currentPath.next();
    if(next == null)
    {
      this.cancelPath(CancelReason.END);
      return;
    }

    double yDist = next.getY() - entity.locY;
    if(yDist > 0)
      NMSUtil.getNavigation(entity).a();

    Vector moveVec = WorldUtilities.addEntityWidth(this.m_entity, next);
    NMSUtil.getControllerMove(entity).a(moveVec.getX(), moveVec.getY(), moveVec.getZ(), (this.m_currentPath.hasCustomSpeed() ? this.m_currentPath.getCustomSpeed() : this.m_entity.getSpeed()));

    if(this.m_currentPath.isDone())
      this.cancelPath(CancelReason.END);
  }

  public void cancelPath()
  {
    this.cancelPath(CancelReason.PLUGIN);
  }

  public void cancelPath(CancelReason inReason)
  {
    RemotePathCancelEvent event = new RemotePathCancelEvent(this.m_entity, inReason);
    Bukkit.getPluginManager().callEvent(event);
    this.m_currentPath = null;
  }

  public Path getLastPath()
  {
    return this.m_lastPath;
  }

  public boolean isFindingAsync()
  {
    return this.m_isFindingAsync;
  }

  public void setFindingAsync(boolean inFindingAsync)
  {
    this.m_isFindingAsync = inFindingAsync;
  }

  public static Pathfinder getDefaultPathfinder(RemoteEntity inEntity)
  {
    Pathfinder p = new Pathfinder(inEntity);

    p.addChecker(new AirChecker());
    p.addChecker(new JumpChecker());
    p.addChecker(new JumpDownChecker());
    p.addChecker(new WallChecker());
    p.addChecker(new DoorOpenChecker());

    return p;
  }

  public static boolean isTransparent(Block inBlock)
  {
    return isTransparent(inBlock.getType());
  }

  public static boolean isTransparent(Material inType)
  {
    return transparentMaterial.contains(inType);
  }

  public static boolean isLiquid(Block inBlock)
  {
    return isLiquid(inBlock.getType());
  }

  public static boolean isLiquid(Material inMaterial)
  {
    return liquidMaterial.contains(inMaterial);
  }
}
TOP

Related Classes of de.kumpelblase2.remoteentities.api.pathfinding.Pathfinder

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.