CavePVP-Stuff/cSpigot-master/spigot-server-Patches/0105-Async-path-searches.patch
2023-05-01 19:59:40 +01:00

1615 lines
63 KiB
Diff

From 1c0aa00f7386228c8dc1695964edf10261ea6e47 Mon Sep 17 00:00:00 2001
From: Poweruser_rs <poweruser.rs@hotmail.com>
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<UUID, SearchCacheEntry> searchCache;
+ private HashMap<PositionPathSearchType, SearchCacheEntryPosition> 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<UUID, SearchCacheEntry>();
+ this.positionSearchCache = new HashMap<PositionPathSearchType, SearchCacheEntryPosition>();
+ 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<Entry<UUID, SearchCacheEntry>> iter = this.searchCache.entrySet().iterator();
+ while(iter.hasNext()) {
+ Entry<UUID, SearchCacheEntry> entry = iter.next();
+ if(entry.getValue().hasExpired()) {
+ iter.remove();
+ }
+ }
+ }
+ synchronized(this.positionSearchCache) {
+ Iterator<Entry<PositionPathSearchType, SearchCacheEntryPosition>> iter2 = this.positionSearchCache.entrySet().iterator();
+ while(iter2.hasNext()) {
+ Entry<PositionPathSearchType, SearchCacheEntryPosition> 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<PathSearchJob, PathSearchJob> filter;
+ private HashSet<Integer> activeSearchHashes;
+ private static PathSearchThrottlerThread instance;
+
+ public PathSearchThrottlerThread(int poolSize) {
+ super(poolSize, poolSize, 1L, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), new NamePriorityThreadFactory(Thread.MIN_PRIORITY, "mSpigot_PathFinder"));
+ instance = this;
+ adjustPoolSize(poolSize);
+ this.filter = new LinkedHashMap<PathSearchJob, PathSearchJob>();
+ this.activeSearchHashes = new HashSet<Integer>();
+ }
+
+ 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<Entry<PathSearchJob, PathSearchJob>> 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<PathSearchJob> task = (FutureTask<PathSearchJob>) 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<PathSearchJob> {
+
+ 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