From 1c0aa00f7386228c8dc1695964edf10261ea6e47 Mon Sep 17 00:00:00 2001 From: Poweruser_rs Date: Sun, 28 Feb 2016 22:55:26 +0100 Subject: [PATCH] Async path searches diff --git a/src/main/java/net/frozenorb/ThreadingManager.java b/src/main/java/net/frozenorb/ThreadingManager.java index f56e68e1b..ed1dfbbc2 100644 --- a/src/main/java/net/frozenorb/ThreadingManager.java +++ b/src/main/java/net/frozenorb/ThreadingManager.java @@ -9,6 +9,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import net.frozenorb.pathsearch.PathSearchThrottlerThread; +import net.frozenorb.pathsearch.jobs.PathSearchJob; import net.minecraft.server.NBTCompressedStreamTools; import net.minecraft.server.NBTTagCompound; @@ -20,12 +22,15 @@ public class ThreadingManager { private final Logger log = LogManager.getLogger(); private ExecutorService nbtFileService = Executors.newSingleThreadExecutor(new NamePriorityThreadFactory(Thread.NORM_PRIORITY - 2, "mSpigot_NBTFileSaver")); private static ThreadingManager instance; + private PathSearchThrottlerThread pathSearchThrottler; public ThreadingManager() { instance = this; + this.pathSearchThrottler = new PathSearchThrottlerThread(2); } public void shutdown() { + this.pathSearchThrottler.shutdown(); this.nbtFileService.shutdown(); while(!this.nbtFileService.isTerminated()) { try { @@ -72,4 +77,8 @@ public class ThreadingManager { this.file = null; } } + + public static boolean queuePathSearch(PathSearchJob pathSearchJob) { + return instance.pathSearchThrottler.queuePathSearch(pathSearchJob); + } } diff --git a/src/main/java/net/frozenorb/WeakChunkCache.java b/src/main/java/net/frozenorb/WeakChunkCache.java new file mode 100644 index 000000000..4b0c8fd4f --- /dev/null +++ b/src/main/java/net/frozenorb/WeakChunkCache.java @@ -0,0 +1,113 @@ +package net.frozenorb; + +import net.minecraft.server.Block; +import net.minecraft.server.Blocks; +import net.minecraft.server.Chunk; +import net.minecraft.server.IBlockAccess; +import net.minecraft.server.TileEntity; +import net.minecraft.server.World; + +public class WeakChunkCache implements IBlockAccess { + private int lowerChunkX; + private int lowerChunkZ; + private Chunk[][] chunks; + private boolean ownArray = false; + + public WeakChunkCache(Chunk[][] chunks, int lowerChunkX, int lowerChunkZ) { + this.chunks = chunks; + this.lowerChunkX = lowerChunkX; + this.lowerChunkZ = lowerChunkZ; + } + + public WeakChunkCache(World world, int chunkX, int chunkZ, int chunkRadius) { + this(world, chunkX - chunkRadius, chunkZ - chunkRadius, chunkX + chunkRadius, chunkZ + chunkRadius); + } + + public WeakChunkCache(World world, int lowerChunkX, int lowerChunkZ, int upperChunkX, int upperChunkZ) { + this.lowerChunkX = lowerChunkX; + this.lowerChunkZ = lowerChunkZ; + + this.chunks = new Chunk[upperChunkX - this.lowerChunkX + 1][upperChunkZ - this.lowerChunkZ + 1]; + this.ownArray = true; + + for (int chunkX = this.lowerChunkX; chunkX <= upperChunkX; ++chunkX) { + for (int chunkZ = this.lowerChunkZ; chunkZ <= upperChunkZ; ++chunkZ) { + this.chunks[chunkX - this.lowerChunkX][chunkZ - this.lowerChunkZ] = world.getChunkIfLoaded(chunkX, chunkZ); + } + } + } + + public WeakChunkCache(World world, int lowerBlockX, int lowerBlockY, int lowerBlockZ, int upperBlockX, int upperBlockY, int upperBlockZ, int blockRadius) { + this(world, (lowerBlockX - blockRadius) >> 4, + (lowerBlockZ - blockRadius) >> 4, + (upperBlockX + blockRadius) >> 4, + (upperBlockZ + blockRadius) >> 4); + } + + public Block getType(int x, int y, int z) { + Block block = Blocks.AIR; + + if (y >= 0 && y < 256) { + int indexX = (x >> 4) - this.lowerChunkX; + int indexZ = (z >> 4) - this.lowerChunkZ; + + if (indexX >= 0 && indexX < this.chunks.length && indexZ >= 0 && indexZ < this.chunks[indexX].length) { + Chunk chunk = this.chunks[indexX][indexZ]; + + if (chunk != null) { + block = chunk.getType(x & 15, y, z & 15); + } + } + } + + return block; + } + + public TileEntity getTileEntity(int x, int y, int z) { + int indexX = (x >> 4) - this.lowerChunkX; + int indexZ = (z >> 4) - this.lowerChunkZ; + + Chunk chunk = this.chunks[indexX][indexZ]; + if(chunk != null) { + return chunk.e(x & 15, y, z & 15); + } + return null; + } + + public int getData(int x, int y, int z) { + if (y >= 0 && y < 256) { + int indexX = (x >> 4) - this.lowerChunkX; + int indexZ = (z >> 4) - this.lowerChunkZ; + if (indexX >= 0 && indexX < this.chunks.length && indexZ >= 0 && indexZ < this.chunks[indexX].length) { + Chunk chunk = this.chunks[indexX][indexZ]; + if(chunk != null) { + return chunk.getData(x & 15, y, z & 15); + } + } + } + return 0; + } + + public int getBlockPower(int i, int j, int k, int l) { + return this.getType(i, j, k).c(this, i, j, k, l); + } + + public boolean isLoaded(int x, int y, int z) { + int indexX = (x >> 4) - this.lowerChunkX; + int indexZ = (z >> 4) - this.lowerChunkZ; + if (indexX >= 0 && indexX < this.chunks.length && indexZ >= 0 && indexZ < this.chunks[indexX].length) { + return this.chunks[indexX][indexZ] != null; + } + return false; + } + + public void clear() { + if(this.ownArray) { + for(int i = 0; i < this.chunks.length; i++) { + for(int j = 0; j < this.chunks[i].length; j++) { + this.chunks[i][j] = null; + } + } + } + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/AsyncNavigation.java b/src/main/java/net/frozenorb/pathsearch/AsyncNavigation.java new file mode 100644 index 000000000..d4c6b1014 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/AsyncNavigation.java @@ -0,0 +1,203 @@ +package net.frozenorb.pathsearch; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.UUID; + +import org.bukkit.util.BlockVector; + +import net.frozenorb.ThreadingManager; +import net.frozenorb.pathsearch.cache.SearchCacheEntry; +import net.frozenorb.pathsearch.cache.SearchCacheEntryEntity; +import net.frozenorb.pathsearch.cache.SearchCacheEntryPosition; +import net.frozenorb.pathsearch.jobs.PathSearchJob; +import net.frozenorb.pathsearch.jobs.PathSearchJobEntity; +import net.frozenorb.pathsearch.jobs.PathSearchJobNavigationEntity; +import net.frozenorb.pathsearch.jobs.PathSearchJobNavigationPosition; +import net.frozenorb.pathsearch.jobs.PathSearchJobPosition; +import net.frozenorb.pathsearch.jobs.PathSearchQueuingManager; +import net.minecraft.server.Entity; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.MathHelper; +import net.minecraft.server.Navigation; +import net.minecraft.server.PathEntity; +import net.minecraft.server.World; + +public class AsyncNavigation extends Navigation { + + private HashMap searchCache; + private HashMap positionSearchCache; + private static double minimumDistanceForOffloadingSquared = 0.0D; + private int cleanUpDelay = 0; + private PathSearchQueuingManager queuingManager; + + public AsyncNavigation(EntityInsentient entityinsentient, World world) { + super(entityinsentient, world); + this.searchCache = new HashMap(); + this.positionSearchCache = new HashMap(); + this.queuingManager = new PathSearchQueuingManager(); + } + + private BlockVector createBlockVectorForPosition(int x, int y, int z) { + return new BlockVector(x, y, z); + } + + private void issueSearch(Entity target, float range, boolean j, boolean k, boolean l, boolean m) { + this.queuingManager.queueSearch(new PathSearchJobNavigationEntity(this.a, target, range, j, k, l, m)); + } + + private void issueSearch(PositionPathSearchType type, int x, int y, int z, float range, boolean j, boolean k, boolean l, boolean m) { + this.queuingManager.queueSearch(new PathSearchJobNavigationPosition(type, this.a, x, y, z, range, j, k, l, m)); + } + + @Override + public void cancelSearch(PathSearchJob pathSearch) { + this.queuingManager.checkLastSearchResult(pathSearch); + pathSearch.cleanup(); + } + + @Override + public void setSearchResult(PathSearchJobNavigationEntity pathSearch) { + this.queuingManager.checkLastSearchResult(pathSearch); + SearchCacheEntry entry = pathSearch.getCacheEntryValue(); + if(entry != null && entry.didSearchSucceed()) { + synchronized(this.searchCache) { + UUID key = pathSearch.getCacheEntryKey(); + this.searchCache.put(key, entry); + } + } + } + + @Override + public void setSearchResult(PathSearchJobNavigationPosition pathSearch) { + this.queuingManager.checkLastSearchResult(pathSearch); + SearchCacheEntryPosition entry = pathSearch.getCacheEntryValue(); + if(entry != null && entry.didSearchSucceed()) { + synchronized(this.positionSearchCache) { + PositionPathSearchType key = pathSearch.getCacheEntryKey(); + this.positionSearchCache.put(key, entry); + } + } + } + + @Override + public PathEntity a(double d0, double d1, double d2) { + return this.a(PositionPathSearchType.ANYOTHER, d0, d1, d2); + } + + @Override + public boolean a(PositionPathSearchType type, double d0, double d1, double d2, double d3) { + PathEntity pathentity = this.a(type, (double) MathHelper.floor(d0), (double) ((int) d1), (double) MathHelper.floor(d2)); + + return this.a(pathentity, d3); + } + + public void cleanUpExpiredSearches() { + if(++this.cleanUpDelay > 100) { + this.cleanUpDelay = 0; + synchronized(this.searchCache) { + Iterator> iter = this.searchCache.entrySet().iterator(); + while(iter.hasNext()) { + Entry entry = iter.next(); + if(entry.getValue().hasExpired()) { + iter.remove(); + } + } + } + synchronized(this.positionSearchCache) { + Iterator> iter2 = this.positionSearchCache.entrySet().iterator(); + while(iter2.hasNext()) { + Entry entry = iter2.next(); + if(entry.getValue().hasExpired()) { + iter2.remove(); + } + } + } + } + } + + @Override + public PathEntity a(Entity entity) { + if(!this.offloadSearches() || this.a.f(entity) < minimumDistanceForOffloadingSquared) { + return super.a(entity); + } + if(!this.l()) { + return null; + } + SearchCacheEntry entry = null; + UUID id = entity.getUniqueID(); + synchronized(this.searchCache) { + if(this.searchCache.containsKey(id)) { + entry = this.searchCache.get(id); + } + } + PathEntity resultPath = null; + if(entry != null) { + resultPath = entry.getAdjustedPathEntity(); + if(!entry.isStillValid()) { + this.issueSearch(entity, this.d(), this.j, this.k, this.l, this.m); + } + } + if(entry == null && !this.queuingManager.hasAsyncSearchIssued()) { + resultPath = super.a(entity); + if(resultPath != null) { + entry = new SearchCacheEntryEntity(this.a, entity, resultPath); + synchronized(this.searchCache) { + SearchCacheEntry oldEntry = this.searchCache.put(id, entry); + if(oldEntry != null) { + oldEntry.cleanup(); + } + } + } + } + return resultPath; + } + + @Override + public PathEntity a(PositionPathSearchType type, double d0, double d1, double d2) { + if(!this.offloadSearches() || this.a.e(d0, d1, d2) < minimumDistanceForOffloadingSquared) { + return super.a(d0, d1, d2); + } + if(!this.l()) { + return null; + } + + int x = MathHelper.floor(d0); + int y = (int) d1; + int z = MathHelper.floor(d2); + + SearchCacheEntryPosition entry = null; + synchronized(this.positionSearchCache) { + if(this.positionSearchCache.containsKey(type)) { + entry = this.positionSearchCache.get(type); + } + } + + PathEntity resultPath = null; + if(entry != null) { + resultPath = entry.getAdjustedPathEntity(); + if(!entry.isStillValid()) { + this.issueSearch(type, x, y, z, this.d(), this.j, this.k, this.l, this.m); + } + } + if(entry == null && !this.queuingManager.hasAsyncSearchIssued()) { + resultPath = super.a(d0, d1, d2); + if(resultPath != null) { + entry = new SearchCacheEntryPosition(this.a, x, y, z, resultPath); + synchronized(this.positionSearchCache) { + SearchCacheEntry oldEntry = this.positionSearchCache.put(type, entry); + if(oldEntry != null) { + oldEntry.cleanup(); + } + } + } + } + return resultPath; + } + + private boolean offloadSearches() { + return true; + //return Migot.getConfig().isPathSearchOffloadedFor(this.b); + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/AsyncPathfinder.java b/src/main/java/net/frozenorb/pathsearch/AsyncPathfinder.java new file mode 100644 index 000000000..4a6b9e471 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/AsyncPathfinder.java @@ -0,0 +1,21 @@ +package net.frozenorb.pathsearch; + +import net.minecraft.server.Entity; +import net.minecraft.server.IBlockAccess; +import net.minecraft.server.PathPoint; +import net.minecraft.server.Pathfinder; + +public class AsyncPathfinder extends Pathfinder { + + private IBlockAccess iblockaccess; + + public AsyncPathfinder(IBlockAccess iblockaccess, boolean flag, boolean flag1, boolean flag2, boolean flag3) { + super(iblockaccess, flag, flag1, flag2, flag3); + this.iblockaccess = iblockaccess; + } + + @Override + public int a(Entity entity, int i, int j, int k, PathPoint pathpoint) { + return this.a(this.iblockaccess, entity, i, j, k, pathpoint); + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/PathSearchThrottlerThread.java b/src/main/java/net/frozenorb/pathsearch/PathSearchThrottlerThread.java new file mode 100644 index 000000000..53f011b14 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/PathSearchThrottlerThread.java @@ -0,0 +1,105 @@ +package net.frozenorb.pathsearch; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import net.frozenorb.NamePriorityThreadFactory; +import net.frozenorb.pathsearch.jobs.PathSearchJob; + +public class PathSearchThrottlerThread extends ThreadPoolExecutor { + + private int queueLimit; + private LinkedHashMap filter; + private HashSet activeSearchHashes; + private static PathSearchThrottlerThread instance; + + public PathSearchThrottlerThread(int poolSize) { + super(poolSize, poolSize, 1L, TimeUnit.MINUTES, new LinkedBlockingQueue(), new NamePriorityThreadFactory(Thread.MIN_PRIORITY, "mSpigot_PathFinder")); + instance = this; + adjustPoolSize(poolSize); + this.filter = new LinkedHashMap(); + this.activeSearchHashes = new HashSet(); + } + + public boolean queuePathSearch(PathSearchJob newJob) { + boolean jobHasBeenQueued = false; + if(newJob != null) { + synchronized(this.filter) { + if(this.filter.containsKey(newJob) || this.filter.size() < 1000) { + jobHasBeenQueued = true; + PathSearchJob previousJob = this.filter.put(newJob, newJob); + if(previousJob != null) { + previousJob.cancel(); + } + } + } + if(!jobHasBeenQueued) { + newJob.cancel(); + } + } + PathSearchJob jobToExecute = null; + synchronized(this.filter) { + Iterator> iter = this.filter.entrySet().iterator(); + while(iter.hasNext() && this.getQueue().size() < this.queueLimit) { + jobToExecute = iter.next().getValue(); + if(!this.activeSearchHashes.contains(jobToExecute.getSearchHash())) { + iter.remove(); + if(jobToExecute != null) { + this.activeSearchHashes.add(jobToExecute.getSearchHash()); + this.submit(jobToExecute); + } + if(newJob != null) { + break; + } + } + } + } + return jobHasBeenQueued; + } + + @Override + public void shutdown() { + this.getQueue().clear(); + super.shutdown(); + } + + @Override + protected void afterExecute(Runnable runnable, Throwable throwable) { + super.afterExecute(runnable, throwable); + if(runnable instanceof FutureTask) { + FutureTask task = (FutureTask) runnable; + PathSearchJob job = null; + try { + job = task.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + if(job != null) { + synchronized(this.filter) { + this.activeSearchHashes.remove(job.getSearchHash()); + } + } + } + this.queuePathSearch(null); + } + + public static void adjustPoolSize(int size) { + if(instance != null) { + if(size > instance.getMaximumPoolSize()) { + instance.setMaximumPoolSize(size); + instance.setCorePoolSize(size); + } else if(size < instance.getMaximumPoolSize()) { + instance.setCorePoolSize(size); + instance.setMaximumPoolSize(size); + } + instance.queueLimit = size * 8; + } + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/PositionPathSearchType.java b/src/main/java/net/frozenorb/pathsearch/PositionPathSearchType.java new file mode 100644 index 000000000..d7c9a1e9b --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/PositionPathSearchType.java @@ -0,0 +1,16 @@ +package net.frozenorb.pathsearch; + +public enum PositionPathSearchType { + ANYOTHER, + AVOIDPLAYER, + FLEESUN, + JUMPONBLOCK, + MOVEINDOORS, + MOVETHROUGHVILLAGE, + MOVETOWARDSRESTRICTION, + MOVETOWARDSTARGET, + PANIC, + PLAY, + RANDOMSTROLL, + TAME; +} diff --git a/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntry.java b/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntry.java new file mode 100644 index 000000000..7d5e62a02 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntry.java @@ -0,0 +1,81 @@ +package net.frozenorb.pathsearch.cache; + +import net.minecraft.server.Entity; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PathEntity; +import net.minecraft.server.PathPoint; + +import org.bukkit.util.BlockVector; + +public class SearchCacheEntry { + protected long tick; + protected BlockVector positionStart; + protected BlockVector positionTarget; + protected EntityInsentient entity; + private PathEntity path; + + public SearchCacheEntry(EntityInsentient entity, PathEntity path) { + this.entity = entity; + this.positionStart = this.getEntityPosition(this.entity); + this.path = path; + this.tick = this.getCurrentTick(); + } + + protected int getCurrentTick() { + return MinecraftServer.getServer().al(); + } + + protected BlockVector getEntityPosition(Entity entity) { + return new BlockVector(entity.locX, entity.locY, entity.locZ); + } + + protected BlockVector getTargetPosition(int x, int y, int z) { + return new BlockVector(x, y, z); + } + + public boolean isStillValid() { + return false; + } + + public PathEntity getPathEntity() { + return this.path; + } + + public boolean hasExpired() { + return !this.entity.isAlive() || (this.getCurrentTick() - this.tick) > 200; + } + + public boolean didSearchSucceed() { + return this.path != null; + } + + public boolean shouldBeRefreshed() { + return (this.getCurrentTick() - this.tick) > 5; + } + + public PathEntity getAdjustedPathEntity() { + if(this.path != null && (this.path.e() < this.path.d() - 1)) { + PathPoint pathpoint = this.path.a(this.path.e()); + double currentDist = this.entity.e(pathpoint.a, pathpoint.b, pathpoint.c); + while(this.path.e() < this.path.d() - 1) { + pathpoint = this.path.a(this.path.e() + 1); + double nextDist = this.entity.e(pathpoint.a, pathpoint.b, pathpoint.c); + if(nextDist < currentDist) { + currentDist = nextDist; + this.path.a(); + } else { + break; + } + } + } + return this.path; + } + + public void cleanup() { + this.positionStart = null; + this.positionTarget = null; + this.entity = null; + this.path = null; + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntryEntity.java b/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntryEntity.java new file mode 100644 index 000000000..d0f98af71 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntryEntity.java @@ -0,0 +1,37 @@ +package net.frozenorb.pathsearch.cache; + +import org.bukkit.util.BlockVector; + +import net.minecraft.server.Entity; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.PathEntity; + +public class SearchCacheEntryEntity extends SearchCacheEntry { + + private Entity target; + + public SearchCacheEntryEntity(EntityInsentient entity, Entity target, PathEntity path) { + super(entity, path); + this.target = target; + this.positionTarget = this.getEntityPosition(this.target); + } + + @Override + public boolean isStillValid() { + if(this.getCurrentTick() - this.tick > 20) { + return false; + } + BlockVector bvStart = this.getEntityPosition(this.entity); + BlockVector bvTarget = this.getEntityPosition(this.target); + if(!bvStart.equals(this.positionStart) || !bvTarget.equals(this.positionTarget)) { + return false; + } + return true; + } + + @Override + public void cleanup() { + super.cleanup(); + this.target = null; + } +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntryPosition.java b/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntryPosition.java new file mode 100644 index 000000000..c3c314956 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/cache/SearchCacheEntryPosition.java @@ -0,0 +1,31 @@ +package net.frozenorb.pathsearch.cache; + +import net.minecraft.server.Entity; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.PathEntity; + +import org.bukkit.util.BlockVector; + +public class SearchCacheEntryPosition extends SearchCacheEntry { + + public SearchCacheEntryPosition(EntityInsentient entity, int x, int y, int z, PathEntity path) { + super(entity, path); + this.positionTarget = this.getTargetPosition(x, y, z); + } + + @Override + public boolean isStillValid() { + if(this.getCurrentTick() - this.tick > 20) { + return false; + } + BlockVector bvStart = this.getEntityPosition(this.entity); + if(!bvStart.equals(this.positionStart)) { + return false; + } + return true; + } + + public boolean targetEquals(BlockVector bv) { + return this.positionTarget.equals(bv); + } +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJob.java b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJob.java new file mode 100644 index 000000000..bc33d1555 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJob.java @@ -0,0 +1,75 @@ +package net.frozenorb.pathsearch.jobs; + +import java.util.UUID; +import java.util.concurrent.Callable; + +import net.frozenorb.WeakChunkCache; +import net.frozenorb.pathsearch.cache.SearchCacheEntry; +import net.minecraft.server.ChunkCache; +import net.minecraft.server.EntityCreature; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.MathHelper; +import net.minecraft.server.PathEntity; +import net.minecraft.server.World; + +public abstract class PathSearchJob implements Callable { + + protected EntityInsentient entity; + protected WeakChunkCache chunkCache; + protected boolean issued; + protected float range; + protected boolean b1, b2, b3, b4; + protected PathEntity pathEntity; + protected int hash; + + public PathSearchJob(EntityInsentient entity, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + this.entity = entity; + this.range = range; + this.b1 = b1; + this.b2 = b2; + this.b3 = b3; + this.b4 = b4; + this.issued = false; + this.hash = entity.getUniqueID().hashCode(); + this.createChunkCache(); + } + + private void createChunkCache() { + int x = MathHelper.floor(this.entity.locX); + int y = MathHelper.floor(this.entity.locY); + int z = MathHelper.floor(this.entity.locZ); + int radius = (int) (this.range + 8.0F); + int xMinor = x - radius; + int yMinor = y - radius; + int zMinor = z - radius; + int xMajor = x + radius; + int yMajor = y + radius; + int zMajor = z + radius; + this.chunkCache = new WeakChunkCache(this.entity.world, xMinor, yMinor, zMinor, xMajor, yMajor, zMajor, 0); + } + + public void cleanup() { + this.entity = null; + this.chunkCache = null; + this.pathEntity = null; + } + + public int getSearchHash() { + return this.hash; + } + + @Override + public int hashCode() { + return this.hash; + } + + public abstract Object getCacheEntryKey(); + + public abstract SearchCacheEntry getCacheEntryValue(); + + public abstract void cancel(); + + protected boolean isEntityStillValid() { + return this.entity != null && this.entity.valid && this.entity.isAlive(); + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobEntity.java b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobEntity.java new file mode 100644 index 000000000..e834c0d89 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobEntity.java @@ -0,0 +1,62 @@ +package net.frozenorb.pathsearch.jobs; + +import java.util.UUID; + +import net.frozenorb.pathsearch.AsyncPathfinder; +import net.frozenorb.pathsearch.cache.SearchCacheEntry; +import net.frozenorb.pathsearch.cache.SearchCacheEntryEntity; +import net.minecraft.server.Entity; +import net.minecraft.server.EntityCreature; +import net.minecraft.server.PathEntity; + +public class PathSearchJobEntity extends PathSearchJob { + + private Entity target; + + public PathSearchJobEntity(EntityCreature entity, Entity target, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + super(entity, range, b1, b2, b3, b4); + this.target = target; + } + + @Override + public PathSearchJob call() throws Exception { + if(!this.isEntityStillValid()) { + this.cancel(); + } else if(!this.issued) { + this.issued = true; + this.pathEntity = (new AsyncPathfinder(this.chunkCache, this.b1, this.b2, this.b3, this.b4)).a(entity, this.target, this.range); + ((EntityCreature) this.entity).setSearchResult(this, this.target, this.pathEntity); + this.cleanup(); + } + return this; + } + + @Override + public void cleanup() { + super.cleanup(); + this.target = null; + } + + @Override + public Object getCacheEntryKey() { + return this.entity.getUniqueID(); + } + + @Override + public SearchCacheEntry getCacheEntryValue() { + return new SearchCacheEntryEntity(this.entity, this.target, this.pathEntity); + } + + @Override + public void cancel() { + ((EntityCreature) this.entity).cancelSearch(this); + } + + @Override + public boolean equals(Object o) { + if(o == null || !(o instanceof PathSearchJobEntity)) { + return false; + } + return this.getSearchHash() == ((PathSearchJobEntity)o).getSearchHash(); + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobNavigationEntity.java b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobNavigationEntity.java new file mode 100644 index 000000000..7b6b7ea25 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobNavigationEntity.java @@ -0,0 +1,63 @@ +package net.frozenorb.pathsearch.jobs; + +import java.util.UUID; + +import net.frozenorb.pathsearch.AsyncPathfinder; +import net.frozenorb.pathsearch.cache.SearchCacheEntry; +import net.frozenorb.pathsearch.cache.SearchCacheEntryEntity; + +import net.minecraft.server.ChunkCache; +import net.minecraft.server.Entity; +import net.minecraft.server.EntityCreature; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.PathEntity; + +public class PathSearchJobNavigationEntity extends PathSearchJob { + + private Entity target; + + public PathSearchJobNavigationEntity(EntityInsentient entity, Entity target, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + super(entity, range, b1, b2, b3, b4); + this.target = target; + } + + @Override + public PathSearchJob call() throws Exception { + if(!this.isEntityStillValid()) { + this.cancel(); + } else if(!this.issued) { + this.issued = true; + this.pathEntity = (new AsyncPathfinder(this.chunkCache, this.b1, this.b2, this.b3, this.b4)).a(entity, this.target, this.range); + this.entity.getNavigation().setSearchResult(this); + this.cleanup(); + } + return this; + } + + @Override + public void cleanup() { + super.cleanup(); + this.target = null; + } + + public UUID getCacheEntryKey() { + return this.target.getUniqueID(); + } + + public SearchCacheEntry getCacheEntryValue() { + return new SearchCacheEntryEntity(this.entity, this.target, this.pathEntity); + } + + @Override + public void cancel() { + this.entity.getNavigation().cancelSearch(this); + } + + @Override + public boolean equals(Object o) { + if(o == null || !(o instanceof PathSearchJobNavigationEntity)) { + return false; + } + return this.getSearchHash() == ((PathSearchJobNavigationEntity)o).getSearchHash(); + } +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobNavigationPosition.java b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobNavigationPosition.java new file mode 100644 index 000000000..7d37724a7 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobNavigationPosition.java @@ -0,0 +1,68 @@ +package net.frozenorb.pathsearch.jobs; + +import net.frozenorb.pathsearch.AsyncPathfinder; +import net.frozenorb.pathsearch.PositionPathSearchType; +import net.frozenorb.pathsearch.cache.SearchCacheEntryPosition; +import net.minecraft.server.ChunkCache; +import net.minecraft.server.EntityCreature; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.PathEntity; + +public class PathSearchJobNavigationPosition extends PathSearchJob { + + private int x, y, z; + private PositionPathSearchType type; + + public PathSearchJobNavigationPosition(PositionPathSearchType type, EntityInsentient entity, int x, int y, int z, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + super(entity, range, b1, b2, b3, b4); + this.type = type; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public PathSearchJob call() throws Exception { + if(!this.isEntityStillValid()) { + this.cancel(); + } else if(!this.issued) { + this.issued = true; + this.pathEntity = (new AsyncPathfinder(this.chunkCache, this.b1, this.b2, this.b3, this.b4)).a(entity, this.x, this.y, this.z, this.range); + this.entity.getNavigation().setSearchResult(this); + this.cleanup(); + } + return this; + } + + public PositionPathSearchType getCacheEntryKey() { + return this.type; + } + + public SearchCacheEntryPosition getCacheEntryValue() { + return new SearchCacheEntryPosition(this.entity, this.x, this.y, this.z, this.pathEntity); + } + + @Override + public int hashCode() { + return this.type.hashCode() ^ + (this.getSearchHash() << 4); + } + + @Override + public boolean equals(Object o) { + if(o == null || !(o instanceof PathSearchJobNavigationPosition)) { + return false; + } + PathSearchJobNavigationPosition other = (PathSearchJobNavigationPosition) o; + + return this.type.equals( + other.type) && + this.getSearchHash() == + other.getSearchHash(); + } + + @Override + public void cancel() { + this.entity.getNavigation().cancelSearch(this); + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobPosition.java b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobPosition.java new file mode 100644 index 000000000..f7106eaa3 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchJobPosition.java @@ -0,0 +1,68 @@ +package net.frozenorb.pathsearch.jobs; + +import net.frozenorb.pathsearch.AsyncPathfinder; +import net.frozenorb.pathsearch.PositionPathSearchType; +import net.frozenorb.pathsearch.cache.SearchCacheEntry; +import net.frozenorb.pathsearch.cache.SearchCacheEntryPosition; +import net.minecraft.server.EntityCreature; +import net.minecraft.server.PathEntity; +import net.minecraft.server.Pathfinder; + +public class PathSearchJobPosition extends PathSearchJob { + + private int x, y, z; + private PositionPathSearchType type; + + public PathSearchJobPosition(EntityCreature entity, int x, int y, int z, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + super(entity, range, b1, b2, b3, b4); + this.type = PositionPathSearchType.ANYOTHER; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public PathSearchJob call() throws Exception { + if(!this.isEntityStillValid()) { + this.cancel(); + } else if(!this.issued) { + this.issued = true; + this.pathEntity = (new AsyncPathfinder(this.chunkCache, this.b1, this.b2, this.b3, this.b4)).a(entity, this.x, this.y, this.z, this.range); + ((EntityCreature)this.entity).setSearchResult(this, this.pathEntity); + this.cleanup(); + } + return this; + } + + @Override + public Object getCacheEntryKey() { + return this.type; + } + + @Override + public SearchCacheEntry getCacheEntryValue() { + return new SearchCacheEntryPosition(this.entity, this.x, this.y, this.z, this.pathEntity); + } + + @Override + public int hashCode() { + return this.type.hashCode() ^ (this.getSearchHash() << 4); + } + + @Override + public boolean equals(Object o) { + if(o == null || !(o instanceof PathSearchJobPosition)) { + return false; + } + PathSearchJobPosition other = (PathSearchJobPosition) o; + + return this.type.equals( + other.type) && + this.getSearchHash() == other.getSearchHash(); + } + + @Override + public void cancel() { + ((EntityCreature) this.entity).cancelSearch(this); + } +} diff --git a/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchQueuingManager.java b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchQueuingManager.java new file mode 100644 index 000000000..cd6828655 --- /dev/null +++ b/src/main/java/net/frozenorb/pathsearch/jobs/PathSearchQueuingManager.java @@ -0,0 +1,28 @@ +package net.frozenorb.pathsearch.jobs; + +import net.frozenorb.ThreadingManager; + +public class PathSearchQueuingManager { + + private PathSearchJob lastQueuedJob; + + public PathSearchQueuingManager() { + this.lastQueuedJob = null; + } + + public synchronized boolean hasAsyncSearchIssued() { + return this.lastQueuedJob != null; + } + + public synchronized void queueSearch(PathSearchJob job) { + if(ThreadingManager.queuePathSearch(job)) { + this.lastQueuedJob = job; + } + } + + public synchronized void checkLastSearchResult(PathSearchJob pathSearch) { + if(this.lastQueuedJob == pathSearch) { + this.lastQueuedJob = null; + } + } +} diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index 204e4f8c4..c31c59294 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -920,9 +920,15 @@ public abstract class Entity { } public boolean P() { - return this.world.a(this.boundingBox.grow(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.LAVA); + // Poweruser start + return this.P(this.world); } + public boolean P(IBlockAccess iblockaccess) { + return this.world.a(this.boundingBox.grow(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.LAVA, iblockaccess); + } + // Poweruser end + public void a(float f, float f1, float f2) { float f3 = f * f + f1 * f1; diff --git a/src/main/java/net/minecraft/server/EntityCreature.java b/src/main/java/net/minecraft/server/EntityCreature.java index 6960b0580..3810671e6 100644 --- a/src/main/java/net/minecraft/server/EntityCreature.java +++ b/src/main/java/net/minecraft/server/EntityCreature.java @@ -8,6 +8,13 @@ import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.EntityUnleashEvent; // CraftBukkit end +// Poweruser start +import net.frozenorb.pathsearch.jobs.PathSearchJob; +import net.frozenorb.pathsearch.jobs.PathSearchJobEntity; +import net.frozenorb.pathsearch.jobs.PathSearchJobPosition; +import net.frozenorb.pathsearch.jobs.PathSearchQueuingManager; +// Poweruser end + public abstract class EntityCreature extends EntityInsentient { public static final UUID h = UUID.fromString("E199AD21-BA8A-4C53-8D13-6182D5C69D3A"); @@ -21,6 +28,41 @@ public abstract class EntityCreature extends EntityInsentient { private PathfinderGoal bs = new PathfinderGoalMoveTowardsRestriction(this, 1.0D); private boolean bt; + // Poweruser start + private PathSearchQueuingManager queuingManager = new PathSearchQueuingManager(); + private boolean searchIssued = false; + private PathEntity returnedPathEntity; + + public boolean isSearchingForAPath() { + return this.queuingManager.hasAsyncSearchIssued(); + } + + public void cancelSearch(PathSearchJob pathSearch) { + this.queuingManager.checkLastSearchResult(pathSearch); + pathSearch.cleanup(); + } + + private void issueSearch(int x, int y, int z, float range) { + this.queuingManager.queueSearch(new PathSearchJobPosition(this, x, y, z, range, true, false, false, true)); + } + + private void issueSearch(Entity target, float range) { + this.queuingManager.queueSearch(new PathSearchJobEntity(this, target, range, true, false, false, true)); + } + + public void setSearchResult(PathSearchJobEntity pathSearchJobEntity, Entity target, PathEntity pathentity) { + this.queuingManager.checkLastSearchResult(pathSearchJobEntity); + if(this.target != null && this.target.equals(target)) { + this.returnedPathEntity = pathentity; + } + } + + public void setSearchResult(PathSearchJobPosition pathSearchJobPosition, PathEntity pathentity) { + this.queuingManager.checkLastSearchResult(pathSearchJobPosition); + this.returnedPathEntity = pathentity; + } + // Poweruser end + public EntityCreature(World world) { super(world); } @@ -58,7 +100,8 @@ public abstract class EntityCreature extends EntityInsentient { // CraftBukkit end if (this.target != null) { - this.pathEntity = this.world.findPath(this, this.target, f11, true, false, false, true); + //this.pathEntity = this.world.findPath(this, this.target, f11, true, false, false, true); + this.issueSearch(this.target, f11); // Poweruser } } else if (this.target.isAlive()) { float f1 = this.target.e((Entity) this); @@ -86,8 +129,17 @@ public abstract class EntityCreature extends EntityInsentient { } this.world.methodProfiler.b(); + + // Poweruser start + if(this.returnedPathEntity != null) { + this.pathEntity = this.returnedPathEntity; + this.returnedPathEntity = null; + } + // Poweruser end + if (!this.bn && this.target != null && (this.pathEntity == null || this.random.nextInt(20) == 0)) { - this.pathEntity = this.world.findPath(this, this.target, f11, true, false, false, true); + //this.pathEntity = this.world.findPath(this, this.target, f11, true, false, false, true); + this.issueSearch(this.target, f11); // Poweruser } else if (!this.bn && (this.pathEntity == null && this.random.nextInt(180) == 0 || this.random.nextInt(120) == 0 || this.bo > 0) && this.aU < 100) { this.bQ(); } @@ -190,7 +242,8 @@ public abstract class EntityCreature extends EntityInsentient { } if (flag) { - this.pathEntity = this.world.a(this, i, j, k, 10.0F, true, false, false, true); + //this.pathEntity = this.world.a(this, i, j, k, 10.0F, true, false, false, true); + this.issueSearch(i, j, k, 10.0F); // Poweruser } this.world.methodProfiler.b(); diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java index ccc86bbeb..2cb337986 100644 --- a/src/main/java/net/minecraft/server/EntityInsentient.java +++ b/src/main/java/net/minecraft/server/EntityInsentient.java @@ -11,6 +11,10 @@ import org.bukkit.event.entity.EntityUnleashEvent; import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason; // CraftBukkit end +// Poweruser start +import net.frozenorb.pathsearch.AsyncNavigation; +// Poweruser end + public abstract class EntityInsentient extends EntityLiving { public int a_; @@ -43,7 +47,7 @@ public abstract class EntityInsentient extends EntityLiving { this.moveController = new ControllerMove(this); this.bm = new ControllerJump(this); this.bn = new EntityAIBodyControl(this); - this.navigation = new Navigation(this, world); + this.navigation = new AsyncNavigation(this, world); // Poweruser this.bq = new EntitySenses(this); for (int i = 0; i < this.dropChances.length; ++i) { @@ -417,6 +421,7 @@ public abstract class EntityInsentient extends EntityLiving { protected void bn() { ++this.aU; + this.navigation.cleanUpExpiredSearches(); // Poweruser this.world.methodProfiler.a("checkDespawn"); this.w(); this.world.methodProfiler.b(); diff --git a/src/main/java/net/minecraft/server/EntitySilverfish.java b/src/main/java/net/minecraft/server/EntitySilverfish.java index ac5714f02..0881e251e 100644 --- a/src/main/java/net/minecraft/server/EntitySilverfish.java +++ b/src/main/java/net/minecraft/server/EntitySilverfish.java @@ -120,7 +120,7 @@ public class EntitySilverfish extends EntityMonster { } } - if (this.target == null && !this.bS()) { + if (this.target == null && !this.bS() && !this.isSearchingForAPath()) { // Poweruser i = MathHelper.floor(this.locX); j = MathHelper.floor(this.locY + 0.5D); k = MathHelper.floor(this.locZ); @@ -141,7 +141,7 @@ public class EntitySilverfish extends EntityMonster { } else { this.bQ(); } - } else if (this.target != null && !this.bS()) { + } else if (this.target != null && !this.bS() && !this.isSearchingForAPath()) { // Poweruser this.target = null; } } diff --git a/src/main/java/net/minecraft/server/EntityWolf.java b/src/main/java/net/minecraft/server/EntityWolf.java index 8f1ebf2eb..aed649652 100644 --- a/src/main/java/net/minecraft/server/EntityWolf.java +++ b/src/main/java/net/minecraft/server/EntityWolf.java @@ -110,7 +110,7 @@ public class EntityWolf extends EntityTameableAnimal { public void e() { super.e(); - if (!this.world.isStatic && this.bs && !this.bt && !this.bS() && this.onGround) { + if (!this.world.isStatic && this.bs && !this.bt && !this.bS() && this.onGround && !this.isSearchingForAPath()) { // Poweruser this.bt = true; this.bu = 0.0F; this.bv = 0.0F; diff --git a/src/main/java/net/minecraft/server/Navigation.java b/src/main/java/net/minecraft/server/Navigation.java index 7002621b1..e5cd99c26 100644 --- a/src/main/java/net/minecraft/server/Navigation.java +++ b/src/main/java/net/minecraft/server/Navigation.java @@ -1,9 +1,16 @@ package net.minecraft.server; +// Poweruser start +import net.frozenorb.pathsearch.PositionPathSearchType; +import net.frozenorb.pathsearch.jobs.PathSearchJob; +import net.frozenorb.pathsearch.jobs.PathSearchJobNavigationEntity; +import net.frozenorb.pathsearch.jobs.PathSearchJobNavigationPosition; +//Poweruser end + public class Navigation { - private EntityInsentient a; - private World b; + protected EntityInsentient a; // Poweruser - private -> protected + protected World b; // Poweruser - private -> protected private PathEntity c; private double d; private AttributeInstance e; @@ -11,10 +18,28 @@ public class Navigation { private int g; private int h; private Vec3D i = Vec3D.a(0.0D, 0.0D, 0.0D); - private boolean j = true; - private boolean k; - private boolean l; - private boolean m; + protected boolean j = true; // Poweruser - private -> protected + protected boolean k; // Poweruser - private -> protected + protected boolean l; // Poweruser - private -> protected + protected boolean m; // Poweruser - private -> protected + + // Poweruser start + public void setSearchResult(PathSearchJobNavigationEntity pathSearch) { } + + public void setSearchResult(PathSearchJobNavigationPosition pathSearch) { } + + public PathEntity a(PositionPathSearchType type, double d0, double d1, double d2) { + return this.a(d0, d1, d2); + } + + public boolean a(PositionPathSearchType type, double d0, double d1, double d2, double d3) { + return this.a(d0, d1, d2, d3); + } + + public void cleanUpExpiredSearches() { } + + public void cancelSearch(PathSearchJob pathSearch) { } + // Poweruser end public Navigation(EntityInsentient entityinsentient, World world) { this.a = entityinsentient; @@ -205,7 +230,7 @@ public class Navigation { } } - private boolean l() { + protected boolean l() { // Poweruser - private -> protected return this.a.onGround || this.m && this.m() || this.a.am() && this.a instanceof EntityZombie && this.a.vehicle instanceof EntityChicken; } diff --git a/src/main/java/net/minecraft/server/Pathfinder.java b/src/main/java/net/minecraft/server/Pathfinder.java index de9593976..2181fdad3 100644 --- a/src/main/java/net/minecraft/server/Pathfinder.java +++ b/src/main/java/net/minecraft/server/Pathfinder.java @@ -200,12 +200,22 @@ public class Pathfinder { } public static int a(Entity entity, int i, int j, int k, PathPoint pathpoint, boolean flag, boolean flag1, boolean flag2) { + // Poweruser start + return a(entity.world, entity, i, j, k, pathpoint, flag, flag1, flag2); + } + + public int a(IBlockAccess blockaccess, Entity entity, int i, int j, int k, PathPoint pathpoint) { + return a(blockaccess, entity, i, j, k, pathpoint, this.g, this.f, this.e); + } + + public static int a(IBlockAccess blockaccess, Entity entity, int i, int j, int k, PathPoint pathpoint, boolean flag, boolean flag1, boolean flag2) { + // Poweruser end boolean flag3 = false; for (int l = i; l < i + pathpoint.a; ++l) { for (int i1 = j; i1 < j + pathpoint.b; ++i1) { for (int j1 = k; j1 < k + pathpoint.c; ++j1) { - Block block = entity.world.getType(l, i1, j1); + Block block = blockaccess.getType(l, i1, j1); // Poweruser - entity.world -> blockaccess if (block.getMaterial() != Material.AIR) { if (block == Blocks.TRAP_DOOR) { @@ -224,12 +234,12 @@ public class Pathfinder { int k1 = block.b(); - if (entity.world.getType(l, i1, j1).b() == 9) { + if (k1 == 9) { // Poweruser int l1 = MathHelper.floor(entity.locX); int i2 = MathHelper.floor(entity.locY); int j2 = MathHelper.floor(entity.locZ); - if (entity.world.getType(l1, i2, j2).b() != 9 && entity.world.getType(l1, i2 - 1, j2).b() != 9) { + if (blockaccess.getType(l1, i2, j2).b() != 9 && blockaccess.getType(l1, i2 - 1, j2).b() != 9) { // Poweruser - entity.world -> blockaccess return -3; } } else if (!block.b(entity.world, l, i1, j1) && (!flag1 || block != Blocks.WOODEN_DOOR)) { @@ -247,7 +257,7 @@ public class Pathfinder { return 0; } - if (!entity.P()) { + if (!entity.P(blockaccess)) { // Poweruser return -2; } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalAvoidPlayer.java b/src/main/java/net/minecraft/server/PathfinderGoalAvoidPlayer.java index e964925af..b27b2113c 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalAvoidPlayer.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalAvoidPlayer.java @@ -51,7 +51,7 @@ public class PathfinderGoalAvoidPlayer extends PathfinderGoal { } else if (this.e.e(vec3d.a, vec3d.b, vec3d.c) < this.e.f((Entity) this.b)) { return false; } else { - this.g = this.h.a(vec3d.a, vec3d.b, vec3d.c); + this.g = this.h.a(net.frozenorb.pathsearch.PositionPathSearchType.AVOIDPLAYER, vec3d.a, vec3d.b, vec3d.c); // Poweruser return this.g == null ? false : this.g.b(vec3d); } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalFleeSun.java b/src/main/java/net/minecraft/server/PathfinderGoalFleeSun.java index 846214a4d..36de3b98e 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalFleeSun.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalFleeSun.java @@ -44,7 +44,7 @@ public class PathfinderGoalFleeSun extends PathfinderGoal { } public void c() { - this.a.getNavigation().a(this.b, this.c, this.d, this.e); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.FLEESUN, this.b, this.c, this.d, this.e); // Poweruser } private Vec3D f() { diff --git a/src/main/java/net/minecraft/server/PathfinderGoalJumpOnBlock.java b/src/main/java/net/minecraft/server/PathfinderGoalJumpOnBlock.java index e28f3f20e..23aa1a389 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalJumpOnBlock.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalJumpOnBlock.java @@ -26,7 +26,7 @@ public class PathfinderGoalJumpOnBlock extends PathfinderGoal { } public void c() { - this.a.getNavigation().a((double) ((float) this.f) + 0.5D, (double) (this.g + 1), (double) ((float) this.h) + 0.5D, this.b); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.JUMPONBLOCK, (double) ((float) this.f) + 0.5D, (double) (this.g + 1), (double) ((float) this.h) + 0.5D, this.b); // Poweruser this.c = 0; this.d = 0; this.e = this.a.aI().nextInt(this.a.aI().nextInt(1200) + 1200) + 1200; diff --git a/src/main/java/net/minecraft/server/PathfinderGoalMoveIndoors.java b/src/main/java/net/minecraft/server/PathfinderGoalMoveIndoors.java index 06f2765d6..d2d90addd 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalMoveIndoors.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalMoveIndoors.java @@ -47,10 +47,10 @@ public class PathfinderGoalMoveIndoors extends PathfinderGoal { Vec3D vec3d = RandomPositionGenerator.a(this.a, 14, 3, Vec3D.a((double) this.b.getIndoorsX() + 0.5D, (double) this.b.getIndoorsY(), (double) this.b.getIndoorsZ() + 0.5D)); if (vec3d != null) { - this.a.getNavigation().a(vec3d.a, vec3d.b, vec3d.c, 1.0D); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.MOVEINDOORS, vec3d.a, vec3d.b, vec3d.c, 1.0D); // Poweruser } } else { - this.a.getNavigation().a((double) this.b.getIndoorsX() + 0.5D, (double) this.b.getIndoorsY(), (double) this.b.getIndoorsZ() + 0.5D, 1.0D); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.MOVEINDOORS, (double) this.b.getIndoorsX() + 0.5D, (double) this.b.getIndoorsY(), (double) this.b.getIndoorsZ() + 0.5D, 1.0D); // Poweruser } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalMoveThroughVillage.java b/src/main/java/net/minecraft/server/PathfinderGoalMoveThroughVillage.java index f4ec2d44d..aa579a5ab 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalMoveThroughVillage.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalMoveThroughVillage.java @@ -37,7 +37,7 @@ public class PathfinderGoalMoveThroughVillage extends PathfinderGoal { boolean flag = this.a.getNavigation().c(); this.a.getNavigation().b(false); - this.c = this.a.getNavigation().a((double) this.d.locX, (double) this.d.locY, (double) this.d.locZ); + this.c = this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.MOVETHROUGHVILLAGE, (double) this.d.locX, (double) this.d.locY, (double) this.d.locZ); // Poweruser this.a.getNavigation().b(flag); if (this.c != null) { return true; @@ -48,7 +48,7 @@ public class PathfinderGoalMoveThroughVillage extends PathfinderGoal { return false; } else { this.a.getNavigation().b(false); - this.c = this.a.getNavigation().a(vec3d.a, vec3d.b, vec3d.c); + this.c = this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.MOVETHROUGHVILLAGE, vec3d.a, vec3d.b, vec3d.c); // Poweruser this.a.getNavigation().b(flag); return this.c != null; } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsRestriction.java b/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsRestriction.java index 69a940e5d..4dcf7c22c 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsRestriction.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsRestriction.java @@ -37,6 +37,6 @@ public class PathfinderGoalMoveTowardsRestriction extends PathfinderGoal { } public void c() { - this.a.getNavigation().a(this.b, this.c, this.d, this.e); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.MOVETOWARDSRESTRICTION, this.b, this.c, this.d, this.e); // Poweruser } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsTarget.java b/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsTarget.java index 28c6252c8..c75bc76ca 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsTarget.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalMoveTowardsTarget.java @@ -46,6 +46,6 @@ public class PathfinderGoalMoveTowardsTarget extends PathfinderGoal { } public void c() { - this.a.getNavigation().a(this.c, this.d, this.e, this.f); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.MOVETOWARDSTARGET, this.c, this.d, this.e, this.f); // Poweruser } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalPanic.java b/src/main/java/net/minecraft/server/PathfinderGoalPanic.java index 1b8608d0b..599d8673c 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalPanic.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalPanic.java @@ -32,7 +32,7 @@ public class PathfinderGoalPanic extends PathfinderGoal { } public void c() { - this.a.getNavigation().a(this.c, this.d, this.e, this.b); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.PANIC, this.c, this.d, this.e, this.b); // Poweruser } public boolean b() { diff --git a/src/main/java/net/minecraft/server/PathfinderGoalPlay.java b/src/main/java/net/minecraft/server/PathfinderGoalPlay.java index 8fba19a7f..53d191dc2 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalPlay.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalPlay.java @@ -81,7 +81,7 @@ public class PathfinderGoalPlay extends PathfinderGoal { return; } - this.a.getNavigation().a(vec3d.a, vec3d.b, vec3d.c, this.c); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.PLAY, vec3d.a, vec3d.b, vec3d.c, this.c); // Poweruser } } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalRandomStroll.java b/src/main/java/net/minecraft/server/PathfinderGoalRandomStroll.java index 396997afe..c0c7580d4 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalRandomStroll.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalRandomStroll.java @@ -38,6 +38,6 @@ public class PathfinderGoalRandomStroll extends PathfinderGoal { } public void c() { - this.a.getNavigation().a(this.b, this.c, this.d, this.e); + this.a.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.RANDOMSTROLL, this.b, this.c, this.d, this.e); // Poweruser } } diff --git a/src/main/java/net/minecraft/server/PathfinderGoalTame.java b/src/main/java/net/minecraft/server/PathfinderGoalTame.java index a13c63825..fa98af65b 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalTame.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalTame.java @@ -32,7 +32,7 @@ public class PathfinderGoalTame extends PathfinderGoal { } public void c() { - this.entity.getNavigation().a(this.c, this.d, this.e, this.b); + this.entity.getNavigation().a(net.frozenorb.pathsearch.PositionPathSearchType.TAME, this.c, this.d, this.e, this.b); // Poweruser } public boolean b() { diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 16eb99ccb..aa89f7b12 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -39,6 +39,7 @@ import org.bukkit.event.weather.ThunderChangeEvent; // Poweruser start import net.frozenorb.LightingUpdater; +import net.frozenorb.WeakChunkCache; // Poweruser end public abstract class World implements IBlockAccess { @@ -1908,6 +1909,12 @@ public abstract class World implements IBlockAccess { } public boolean a(AxisAlignedBB axisalignedbb, Material material) { + // Poweruser start + return this.a(axisalignedbb, material, this); + } + + public boolean a(AxisAlignedBB axisalignedbb, Material material, IBlockAccess iblockaccess) { + // Poweruser end int i = MathHelper.floor(axisalignedbb.a); int j = MathHelper.floor(axisalignedbb.d + 1.0D); int k = MathHelper.floor(axisalignedbb.b); @@ -1918,7 +1925,7 @@ public abstract class World implements IBlockAccess { for (int k1 = i; k1 < j; ++k1) { for (int l1 = k; l1 < l; ++l1) { for (int i2 = i1; i2 < j1; ++i2) { - if (this.getType(k1, l1, i2).getMaterial() == material) { + if (iblockaccess.getType(k1, l1, i2).getMaterial() == material) { // Poweruser return true; } } @@ -2816,7 +2823,7 @@ public abstract class World implements IBlockAccess { int l1 = i + l; int i2 = j + l; int j2 = k + l; - ChunkCache chunkcache = new ChunkCache(this, i1, j1, k1, l1, i2, j2, 0); + WeakChunkCache chunkcache = new WeakChunkCache(this, i1, j1, k1, l1, i2, j2, 0); // Poweruser PathEntity pathentity = (new Pathfinder(chunkcache, flag, flag1, flag2, flag3)).a(entity, entity1, f); this.methodProfiler.b(); @@ -2835,7 +2842,7 @@ public abstract class World implements IBlockAccess { int k2 = l + k1; int l2 = i1 + k1; int i3 = j1 + k1; - ChunkCache chunkcache = new ChunkCache(this, l1, i2, j2, k2, l2, i3, 0); + WeakChunkCache chunkcache = new WeakChunkCache(this, l1, i2, j2, k2, l2, i3, 0); // Poweruser PathEntity pathentity = (new Pathfinder(chunkcache, flag, flag1, flag2, flag3)).a(entity, i, j, k, f); this.methodProfiler.b(); -- 2.13.3