diff --git a/TacoSpigot-API/pom.xml b/TacoSpigot-API/pom.xml index 288ce92..b0219e6 100644 --- a/TacoSpigot-API/pom.xml +++ b/TacoSpigot-API/pom.xml @@ -78,7 +78,7 @@ com.google.code.gson gson - 2.2.4 + 2.9.0 org.avaje @@ -102,7 +102,7 @@ org.projectlombok lombok - 1.18.20 + 1.18.22 provided @@ -136,8 +136,6 @@ 3.1 - - eclipse true diff --git a/TacoSpigot-API/src/main/java/net/techcable/tacospigot/event/entity/ChunkSnapshot.java b/TacoSpigot-API/src/main/java/net/techcable/tacospigot/event/entity/ChunkSnapshot.java new file mode 100644 index 0000000..4d947dc --- /dev/null +++ b/TacoSpigot-API/src/main/java/net/techcable/tacospigot/event/entity/ChunkSnapshot.java @@ -0,0 +1,5 @@ +package net.techcable.tacospigot.event.entity; + +public interface ChunkSnapshot { + +} diff --git a/TacoSpigot-API/src/main/java/org/bukkit/Chunk.java b/TacoSpigot-API/src/main/java/org/bukkit/Chunk.java index 0510151..436a518 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/Chunk.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/Chunk.java @@ -121,4 +121,8 @@ public interface Chunk { * @return true if the chunk has unloaded successfully, otherwise false */ boolean unload(); + + net.techcable.tacospigot.event.entity.ChunkSnapshot takeSnapshot(); + + void restoreSnapshot(net.techcable.tacospigot.event.entity.ChunkSnapshot snapshot); } diff --git a/TacoSpigot-API/src/main/java/org/bukkit/World.java b/TacoSpigot-API/src/main/java/org/bukkit/World.java index 325d65a..a12daa1 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/World.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/World.java @@ -494,6 +494,23 @@ public interface World extends PluginMessageRecipient, Metadatable { */ public boolean setSpawnLocation(int x, int y, int z); + /** + * Sets the spawn location of the world + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + * @return True if it was successfully set. + */ + public boolean setSpawnLocation(double x, double y, double z, float yaw, float pitch); + /** + * Sets the spawn location of the world + * + * @param location Location of the spawn + * @return True if it was successfully set. + */ + public boolean setSpawnLocation(Location location); + /** * Gets the relative in-game time of this world. *

diff --git a/TacoSpigot-Server/pom.xml b/TacoSpigot-Server/pom.xml index 614566c..d771e17 100644 --- a/TacoSpigot-Server/pom.xml +++ b/TacoSpigot-Server/pom.xml @@ -29,6 +29,12 @@ + + org.projectlombok + lombok + 1.18.22 + provided + io.netty netty-all @@ -105,18 +111,23 @@ mockito-core 1.10.19 + + it.unimi.dsi + fastutil + 8.1.0 + + + net.jafama + jafama + 2.3.2 + compile + org.hamcrest hamcrest-library 1.3 test - - org.projectlombok - lombok - 1.18.20 - provided - com.velocitypowered velocity-native @@ -228,31 +239,29 @@ - - net.md-5 - specialsource-maven-plugin - 1.2.1 - - - package - - remap - - - ${project.basedir}/deprecation-mappings.csrg - ${project.basedir}/deprecation-mappings.at - - - - + org.apache.maven.plugins maven-compiler-plugin 3.8.1 - - eclipse true diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/ChunkSectionSnapshot.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/ChunkSectionSnapshot.java new file mode 100644 index 0000000..56a367b --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/ChunkSectionSnapshot.java @@ -0,0 +1,49 @@ +package com.elevatemc.spigot.chunk; + + +import net.minecraft.server.NibbleArray; + +public class ChunkSectionSnapshot { + + private final int nonEmptyBlockCount; + private final int tickingBlockCount; + private final char[] blockIds; + private final NibbleArray emittedLight; + private final NibbleArray skyLight; + + public ChunkSectionSnapshot( + int nonEmptyBlockCount, + int tickingBlockCount, + char[] blockIds, + NibbleArray emittedLight, + NibbleArray skyLight + ) { + this.nonEmptyBlockCount = nonEmptyBlockCount; + this.tickingBlockCount = tickingBlockCount; + this.blockIds = blockIds; + this.emittedLight = emittedLight; + this.skyLight = skyLight; + } + + public final int getNonEmptyBlockCount() { + return nonEmptyBlockCount; + } + + public final int getTickingBlockCount() { + return tickingBlockCount; + } + + public final char[] getBlockIds() { + return blockIds; + } + + public final NibbleArray getEmittedLight() { + return emittedLight; + } + + public final NibbleArray getSkyLight() { + return skyLight; + } + +} + diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/CraftChunkSnapshot.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/CraftChunkSnapshot.java new file mode 100644 index 0000000..7793bf1 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/CraftChunkSnapshot.java @@ -0,0 +1,22 @@ +package com.elevatemc.spigot.chunk; + +import net.minecraft.server.NBTTagCompound; +import net.techcable.tacospigot.event.entity.ChunkSnapshot; + +import java.util.ArrayList; +import java.util.List; + +public class CraftChunkSnapshot implements ChunkSnapshot { + + private final ChunkSectionSnapshot[] sections = new ChunkSectionSnapshot[16]; + private final List tileEntities = new ArrayList<>(); + + public ChunkSectionSnapshot[] getSections() { + return this.sections; + } + + public List getTileEntities() { + return this.tileEntities; + } +} + diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/WeakChunkCache.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/WeakChunkCache.java new file mode 100644 index 0000000..9a8ae28 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/chunk/WeakChunkCache.java @@ -0,0 +1,119 @@ +package com.elevatemc.spigot.chunk; + +import net.minecraft.server.*; + +public class WeakChunkCache implements IBlockAccess { + + private final int lowerChunkX; + private final int lowerChunkZ; + private final 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 IBlockData getData(BlockPosition blockPosition) { + if (blockPosition.getY() >= 0 && blockPosition.getY() < 256) { + int indexX = (blockPosition.getX() >> 4) - this.lowerChunkX; + int indexZ = (blockPosition.getZ() >> 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.getBlockData(blockPosition); + } + } + } + return null; + } + + 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; + } + } + } + } + + @Override + public TileEntity getTileEntity(BlockPosition blockPosition) { + int indexX = (blockPosition.getX() >> 4) - this.lowerChunkX; + int indexZ = (blockPosition.getZ() >> 4) - this.lowerChunkZ; + + Chunk chunk = this.chunks[indexX][indexZ]; + if (chunk != null) { + return chunk.i(blockPosition); + } + + return null; + } + + @Override + public IBlockData getType(BlockPosition blockPosition) { + Block block = Blocks.AIR; + + if (blockPosition.getY() >= 0 && blockPosition.getY() < 256) { + int indexX = (blockPosition.getX() >> 4) - this.lowerChunkX; + int indexZ = (blockPosition.getZ() >> 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(blockPosition); + } + } + } + + return block.getBlockData(); + } + + @Override + public boolean isEmpty(BlockPosition blockPosition) { + return getType(blockPosition) != Blocks.AIR.getBlockData(); + } + + @Override + public int getBlockPower(BlockPosition blockposition, EnumDirection enumdirection) { + IBlockData iblockdata = this.getType(blockposition); + return iblockdata.getBlock().b(this, blockposition, iblockdata, enumdirection); + } + +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/command/TicksPerSecondCommand.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/command/TicksPerSecondCommand.java index b3f50ed..59b0576 100644 --- a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/command/TicksPerSecondCommand.java +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/command/TicksPerSecondCommand.java @@ -16,6 +16,7 @@ import java.lang.management.ManagementFactory; import java.math.RoundingMode; import java.text.DecimalFormat; + public class TicksPerSecondCommand extends Command { public TicksPerSecondCommand() { diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigot.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigot.java index 555ec1f..8d799b7 100644 --- a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigot.java +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigot.java @@ -2,18 +2,26 @@ package com.elevatemc.spigot; import com.elevatemc.spigot.command.KnockbackCommand; import com.elevatemc.spigot.command.TicksPerSecondCommand; +import com.elevatemc.spigot.handler.MovementHandler; +import com.elevatemc.spigot.handler.PacketHandler; import com.elevatemc.spigot.util.YamlConfig; import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import com.elevatemc.spigot.knockback.KnockbackHandler; import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class eSpigot { + + private final Set packetHandlers = new HashSet<>(); + private final Set movementHandlers = new HashSet<>(); public static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); @@ -45,6 +53,25 @@ public class eSpigot { EXECUTOR_SERVICE.scheduleAtFixedRate(() -> MinecraftServer.getServer().aq().processFastPackets(), 5L, 5L, TimeUnit.MILLISECONDS); } + public void addPacketHandler(PacketHandler handler) { + Bukkit.getLogger().info("Adding packet handler: " + handler.getClass().getPackage().getName() + "." + handler.getClass().getSimpleName()); + this.packetHandlers.add(handler); + } + + public void addMovementHandler(MovementHandler handler) { + Bukkit.getLogger().info("Adding movement handler: " + handler.getClass().getPackage().getName() + "." + handler.getClass().getSimpleName()); + this.movementHandlers.add(handler); + } + + public Set getMovementHandlers() { + return this.movementHandlers; + } + + public Set getPacketHandlers() { + return this.packetHandlers; + } + + public YamlConfig getConfig() { return config; } diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/BlockDropItemsEvent.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/BlockDropItemsEvent.java new file mode 100644 index 0000000..feb3c76 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/BlockDropItemsEvent.java @@ -0,0 +1,56 @@ +package com.elevatemc.spigot.event; + +import org.bukkit.block.Block; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import java.util.List; + +public class BlockDropItemsEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private Block block; + private Player player; + private List toDrop; + private boolean cancelled = false; + + public BlockDropItemsEvent(Block block, Player player, List toDrop) { + this.block = block; + this.player = player; + this.toDrop = toDrop; + } + + public Block getBlock() { + return this.block; + } + + public Player getPlayer() { + return this.player; + } + + public List getToDrop() { + return this.toDrop; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/PlayerHealthChangeEvent.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/PlayerHealthChangeEvent.java new file mode 100644 index 0000000..39faa33 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/PlayerHealthChangeEvent.java @@ -0,0 +1,38 @@ +package com.elevatemc.spigot.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerHealthChangeEvent extends PlayerEvent { + + private static final HandlerList handlers = new HandlerList(); + + private final double previousHealth; + private final double newHealth; + + public PlayerHealthChangeEvent(Player who, double previousHealth, double newHealth) { + super(who); + + this.previousHealth = previousHealth; + this.newHealth = newHealth; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + public double getPreviousHealth() { + return previousHealth; + } + + public double getNewHealth() { + return newHealth; + } +} + diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/PlayerPearlRefundEvent.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/PlayerPearlRefundEvent.java new file mode 100644 index 0000000..d11afc0 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/event/PlayerPearlRefundEvent.java @@ -0,0 +1,22 @@ +package com.elevatemc.spigot.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerPearlRefundEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); + + public PlayerPearlRefundEvent(final Player player) { + super(player); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/handler/MovementHandler.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/handler/MovementHandler.java new file mode 100644 index 0000000..f0c7374 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/handler/MovementHandler.java @@ -0,0 +1,13 @@ +package com.elevatemc.spigot.handler; + +import net.minecraft.server.PacketPlayInFlying; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface MovementHandler { + + void handleUpdateLocation(Player player, Location to, Location from, PacketPlayInFlying packet); + + void handleUpdateRotation(Player player, Location to, Location from, PacketPlayInFlying packet); + +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/handler/PacketHandler.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/handler/PacketHandler.java new file mode 100644 index 0000000..4775d68 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/handler/PacketHandler.java @@ -0,0 +1,17 @@ +package com.elevatemc.spigot.handler; + +import net.minecraft.server.Packet; +import net.minecraft.server.PlayerConnection; + +public interface PacketHandler { + + default void handleReceivedPacket(PlayerConnection connection, Packet packet) {} + + default void handleSentPacket(PlayerConnection connection, Packet packet) {} + + default boolean handleSentPacketCancellable(PlayerConnection connection, Packet packet) { + return true; + } + +} + diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncNavigation.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncNavigation.java new file mode 100644 index 0000000..08c28af --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncNavigation.java @@ -0,0 +1,200 @@ +package com.elevatemc.spigot.pathsearch; + +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntry; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntryEntity; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntryPosition; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJob; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobNavigationEntity; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobNavigationPosition; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchQueuingManager; +import net.minecraft.server.*; +import org.bukkit.util.BlockVector; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +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.b, target, range, j, k, l, m)); + } + + private void issueSearch(PositionPathSearchType type, BlockPosition blockPosition, float range, boolean j, boolean k, boolean l, boolean m) { + this.queuingManager.queueSearch(new PathSearchJobNavigationPosition(type, this.b, blockPosition, 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(BlockPosition blockPosition) { + return this.a(PositionPathSearchType.ANYOTHER, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); + } + + @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); + } + + @Override + public PathEntity a(Entity entity) { + if (!this.offloadSearches() || this.b.h(entity) < minimumDistanceForOffloadingSquared) { + return super.a(entity); + } + + if (!this.b()) { + 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.i(), this.a.getB(), this.a.getC(), this.a.getD(), this.a.getE()); + } + } + if (entry == null && !this.queuingManager.hasAsyncSearchIssued()) { + resultPath = super.a(entity); + if (resultPath != null) { + entry = new SearchCacheEntryEntity(this.b, 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.b.e(d0, d1, d2) < minimumDistanceForOffloadingSquared) { + return super.a(d0, d1, d2); + } + + if (!this.b()) { + 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, new BlockPosition(x, y, z), this.i(), this.a.getB(), this.a.getC(), this.a.getD(), this.a.getE()); + } + } + + if (entry == null && !this.queuingManager.hasAsyncSearchIssued()) { + resultPath = super.a(d0, d1, d2); + if (resultPath != null) { + entry = new SearchCacheEntryPosition(this.b, x, y, z, resultPath); + synchronized (this.positionSearchCache) { + SearchCacheEntry oldEntry = this.positionSearchCache.put(type, entry); + if (oldEntry != null) { + oldEntry.cleanup(); + } + } + } + } + return resultPath; + } + + @Override + public void cleanUpExpiredSearches() { + if (++this.cleanUpDelay > 100) { + this.cleanUpDelay = 0; + synchronized (this.searchCache) { + Iterator> iter = this.searchCache.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + if (entry.getValue().hasExpired()) { + iter.remove(); + } + } + } + synchronized (this.positionSearchCache) { + Iterator> iter2 = this.positionSearchCache.entrySet().iterator(); + while (iter2.hasNext()) { + Map.Entry entry = iter2.next(); + if (entry.getValue().hasExpired()) { + iter2.remove(); + } + } + } + } + } + + private boolean offloadSearches() { + return true; + } + +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncPathfinder.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncPathfinder.java new file mode 100644 index 0000000..c857ab1 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncPathfinder.java @@ -0,0 +1,25 @@ +package com.elevatemc.spigot.pathsearch; + +import net.minecraft.server.*; + +public class AsyncPathfinder extends Pathfinder { + + private IBlockAccess iblockaccess; + + public AsyncPathfinder(IBlockAccess iblockaccess) { + super(new AsyncPathfinderNormal(iblockaccess)); + + this.iblockaccess = iblockaccess; + } + + @Override + public PathEntity a(IBlockAccess var1, Entity var2, Entity var3, float var4) { + return super.a(iblockaccess, var2, var3, var4); + } + + @Override + public PathEntity a(IBlockAccess var1, Entity var2, BlockPosition var3, float var4) { + return super.a(iblockaccess, var2, var3, var4); + } + +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncPathfinderNormal.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncPathfinderNormal.java new file mode 100644 index 0000000..b14acbf --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/AsyncPathfinderNormal.java @@ -0,0 +1,20 @@ +package com.elevatemc.spigot.pathsearch; + +import net.minecraft.server.Entity; +import net.minecraft.server.IBlockAccess; +import net.minecraft.server.PathfinderNormal; + +public class AsyncPathfinderNormal extends PathfinderNormal { + + private IBlockAccess iblockaccess; + + public AsyncPathfinderNormal(IBlockAccess iblockaccess) { + this.iblockaccess = iblockaccess; + } + + @Override + public void a(IBlockAccess iblockaccess, Entity entity) { + super.a(this.iblockaccess, entity); + } + +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/PathSearchThrottlerThread.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/PathSearchThrottlerThread.java new file mode 100644 index 0000000..ad2cb8c --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/PathSearchThrottlerThread.java @@ -0,0 +1,101 @@ +package com.elevatemc.spigot.pathsearch; + +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJob; +import com.elevatemc.spigot.threading.NamePriorityThreadFactory; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.*; + +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, "eSpigot_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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/PositionPathSearchType.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/PositionPathSearchType.java new file mode 100644 index 0000000..e78c211 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/PositionPathSearchType.java @@ -0,0 +1,18 @@ +package com.elevatemc.spigot.pathsearch; + + +public enum PositionPathSearchType { + + ANYOTHER, + AVOIDPLAYER, + FLEESUN, + JUMPONBLOCK, + MOVEINDOORS, + MOVETHROUGHVILLAGE, + MOVETOWARDSRESTRICTION, + MOVETOWARDSTARGET, + PANIC, + PLAY, + RANDOMSTROLL, + TAME; +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntry.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntry.java new file mode 100644 index 0000000..4843ca5 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntry.java @@ -0,0 +1,78 @@ +package com.elevatemc.spigot.pathsearch.cache; + +import net.minecraft.server.*; +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.currentTick; + } + + 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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntryEntity.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntryEntity.java new file mode 100644 index 0000000..5fe8ff4 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntryEntity.java @@ -0,0 +1,38 @@ +package com.elevatemc.spigot.pathsearch.cache; + +import net.minecraft.server.Entity; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.PathEntity; +import org.bukkit.util.BlockVector; + +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); + + return bvStart.equals(this.positionStart) && bvTarget.equals(this.positionTarget); + } + + @Override + public void cleanup() { + super.cleanup(); + + this.target = null; + } + +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntryPosition.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntryPosition.java new file mode 100644 index 0000000..33bdbfe --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/cache/SearchCacheEntryPosition.java @@ -0,0 +1,29 @@ +package com.elevatemc.spigot.pathsearch.cache; + +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); + return bvStart.equals(this.positionStart); + } + + public boolean targetEquals(BlockVector bv) { + return this.positionTarget.equals(bv); + } + +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJob.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJob.java new file mode 100644 index 0000000..6139949 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJob.java @@ -0,0 +1,73 @@ +package com.elevatemc.spigot.pathsearch.jobs; + +import com.elevatemc.spigot.chunk.WeakChunkCache; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntry; +import net.minecraft.server.EntityInsentient; +import net.minecraft.server.MathHelper; +import net.minecraft.server.PathEntity; + +import java.util.concurrent.Callable; + +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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobEntity.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobEntity.java new file mode 100644 index 0000000..5e1e62d --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobEntity.java @@ -0,0 +1,61 @@ +package com.elevatemc.spigot.pathsearch.jobs; + +import com.elevatemc.spigot.pathsearch.AsyncPathfinder; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntry; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntryEntity; +import net.minecraft.server.Entity; +import net.minecraft.server.EntityCreature; + +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)).a(this.chunkCache, 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 instanceof PathSearchJobEntity)) { + return false; + } + + return this.getSearchHash() == ((PathSearchJobEntity)o).getSearchHash(); + } +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobNavigationEntity.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobNavigationEntity.java new file mode 100644 index 0000000..9df435a --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobNavigationEntity.java @@ -0,0 +1,62 @@ +package com.elevatemc.spigot.pathsearch.jobs; + +import com.elevatemc.spigot.pathsearch.AsyncPathfinder; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntry; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntryEntity; +import net.minecraft.server.Entity; +import net.minecraft.server.EntityInsentient; + +import java.util.UUID; + +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)).a(this.chunkCache, 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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobNavigationPosition.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobNavigationPosition.java new file mode 100644 index 0000000..4a0adb7 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobNavigationPosition.java @@ -0,0 +1,65 @@ +package com.elevatemc.spigot.pathsearch.jobs; + +import com.elevatemc.spigot.pathsearch.AsyncPathfinder; +import com.elevatemc.spigot.pathsearch.PositionPathSearchType; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntryPosition; +import net.minecraft.server.BlockPosition; +import net.minecraft.server.EntityInsentient; + +public class PathSearchJobNavigationPosition extends PathSearchJob { + + private BlockPosition blockPosition; + private PositionPathSearchType type; + + public PathSearchJobNavigationPosition(PositionPathSearchType type, EntityInsentient entity, BlockPosition blockPosition, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + super(entity, range, b1, b2, b3, b4); + + this.type = type; + this.blockPosition = blockPosition; + } + + @Override + public PathSearchJob call() throws Exception { + if(!this.isEntityStillValid()) { + this.cancel(); + } else if(!this.issued) { + this.issued = true; + this.pathEntity = (new AsyncPathfinder(this.chunkCache)).a(this.chunkCache, entity, blockPosition, range); + this.entity.getNavigation().setSearchResult(this); + this.cleanup(); + } + return this; + } + + public PositionPathSearchType getCacheEntryKey() { + return this.type; + } + + public SearchCacheEntryPosition getCacheEntryValue() { + return new SearchCacheEntryPosition(this.entity, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), 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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobPosition.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobPosition.java new file mode 100644 index 0000000..5b75bd7 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchJobPosition.java @@ -0,0 +1,66 @@ +package com.elevatemc.spigot.pathsearch.jobs; + +import com.elevatemc.spigot.pathsearch.AsyncPathfinder; +import com.elevatemc.spigot.pathsearch.PositionPathSearchType; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntry; +import com.elevatemc.spigot.pathsearch.cache.SearchCacheEntryPosition; +import net.minecraft.server.BlockPosition; +import net.minecraft.server.EntityCreature; + +public class PathSearchJobPosition extends PathSearchJob { + + private BlockPosition blockPosition; + private PositionPathSearchType type; + + public PathSearchJobPosition(EntityCreature entity, BlockPosition blockPosition, float range, boolean b1, boolean b2, boolean b3, boolean b4) { + super(entity, range, b1, b2, b3, b4); + + this.type = PositionPathSearchType.ANYOTHER; + this.blockPosition = blockPosition; + } + + @Override + public PathSearchJob call() throws Exception { + if(!this.isEntityStillValid()) { + this.cancel(); + } else if(!this.issued) { + this.issued = true; + this.pathEntity = (new AsyncPathfinder(this.chunkCache)).a(this.chunkCache, entity, blockPosition, 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.blockPosition.getX(), this.blockPosition.getY(), this.blockPosition.getZ(), 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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchQueuingManager.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchQueuingManager.java new file mode 100644 index 0000000..ec2fe4d --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/pathsearch/jobs/PathSearchQueuingManager.java @@ -0,0 +1,30 @@ +package com.elevatemc.spigot.pathsearch.jobs; + + +import com.elevatemc.spigot.threading.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/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/NamePriorityThreadFactory.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/NamePriorityThreadFactory.java new file mode 100644 index 0000000..0e4044c --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/NamePriorityThreadFactory.java @@ -0,0 +1,85 @@ +package com.elevatemc.spigot.threading; + +import net.jafama.FastMath; + +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +public class NamePriorityThreadFactory implements ThreadFactory { + + private final int priority; + private int idCounter = 0; + private String name = "gSpigotThread"; + private boolean isDaemon = false; + private Queue> createdThreadList; + + public NamePriorityThreadFactory(int priority) { + this.priority = FastMath.min(FastMath.max(priority, Thread.MIN_PRIORITY), Thread.MAX_PRIORITY); + } + + public NamePriorityThreadFactory(int priority, String name) { + this(priority); + this.name = name; + } + + public NamePriorityThreadFactory(String name) { + this(Thread.NORM_PRIORITY); + this.name = name; + } + + public NamePriorityThreadFactory setDaemon(boolean daemon) { + this.isDaemon = daemon; + return this; + } + + public NamePriorityThreadFactory setLogThreads(boolean log) { + if (log) { + if (this.createdThreadList == null) { + this.createdThreadList = new ConcurrentLinkedQueue>(); + } + } else { + this.createdThreadList = null; + } + return this; + } + + @Override + public Thread newThread(Runnable runnable) { + Thread thread = Executors.defaultThreadFactory().newThread(runnable); + thread.setPriority(this.priority); + thread.setName(this.name + "-" + idCounter); + thread.setDaemon(this.isDaemon); + if (this.createdThreadList != null) { + this.createdThreadList.add(new WeakReference<>(thread)); + } + idCounter++; + return thread; + } + + public int getActiveCount() { + if (this.createdThreadList != null) { + Iterator> iter = this.createdThreadList.iterator(); + int count = 0; + while (iter.hasNext()) { + WeakReference ref = iter.next(); + Thread t = ref.get(); + if (t == null) { + iter.remove(); + } else if (t.isAlive()) { + count++; + } + } + return count; + } + return -1; + } + + public Queue> getThreadList() { + return this.createdThreadList; + } + +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/ThreadingManager.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/ThreadingManager.java new file mode 100644 index 0000000..6452f04 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/ThreadingManager.java @@ -0,0 +1,281 @@ +package com.elevatemc.spigot.threading; + +import com.elevatemc.spigot.pathsearch.PathSearchThrottlerThread; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJob; +import net.minecraft.server.NBTCompressedStreamTools; +import net.minecraft.server.NBTTagCompound; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.ref.WeakReference; +import java.util.ArrayDeque; +import java.util.Iterator; +import java.util.Queue; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class ThreadingManager { + + private static ThreadingManager instance; + + private final Logger log = LogManager.getLogger(); + private PathSearchThrottlerThread pathSearchThrottler; + private ScheduledExecutorService timerService = Executors.newScheduledThreadPool(1, new NamePriorityThreadFactory(Thread.NORM_PRIORITY + 2, "eSpigot_TimerService")); + private TickCounter tickCounter = new TickCounter(); + private NamePriorityThreadFactory cachedThreadPoolFactory; + private ExecutorService cachedThreadPool; + + private ScheduledFuture tickTimerTask; + private TickTimer tickTimerObject; + private static int timerDelay = 45; + + private TaskQueueWorker nbtFiles; + private TaskQueueWorker headConversions; + + public ThreadingManager() { + instance = this; + this.pathSearchThrottler = new PathSearchThrottlerThread(2); + this.timerService.scheduleAtFixedRate(this.tickCounter, 1, 1000, TimeUnit.MILLISECONDS); + this.tickTimerObject = new TickTimer(); + this.cachedThreadPoolFactory = new NamePriorityThreadFactory(Thread.currentThread().getPriority() - 1, "eSpigot_Async-Executor").setLogThreads(true).setDaemon(true); + this.cachedThreadPool = Executors.newCachedThreadPool(this.cachedThreadPoolFactory); + this.nbtFiles = this.createTaskQueueWorker(); + this.headConversions = this.createTaskQueueWorker(); + } + + public void shutdown() { + this.pathSearchThrottler.shutdown(); + this.timerService.shutdown(); + this.cachedThreadPool.shutdown(); + while((this.nbtFiles.isActive()) && !this.cachedThreadPool.isTerminated()) { + try { + this.cachedThreadPool.awaitTermination(10, TimeUnit.SECONDS); + log.warn("gSpigot is still waiting for NBT files to be written to disk. " + this.nbtFiles.getTaskCount() + " to go..."); + } catch(InterruptedException e) {} + } + if(!this.cachedThreadPool.isTerminated()) { + this.cachedThreadPool.shutdownNow(); + try { + this.cachedThreadPool.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if(this.cachedThreadPoolFactory.getActiveCount() > 0) { + log.warn("gSpigot is still waiting for " + this.cachedThreadPoolFactory.getActiveCount() + " async threads to finish."); + Queue> queue = this.cachedThreadPoolFactory.getThreadList(); + Iterator> iter = null; + if(queue != null) { + System.out.println("== List of async threads that did not terminate on their own == "); + iter = queue.iterator(); + } + while(iter != null && iter.hasNext()) { + WeakReference ref = iter.next(); + Thread t = ref.get(); + if(t == null) { + iter.remove(); + } else if (t.isAlive()) { + StackTraceElement[] e = t.getStackTrace(); + System.out.println(t.getName() + " - " + t.getState().toString()); + for(StackTraceElement et: e) { + System.out.println(et.toString()); + } + System.out.println("========================== "); + } + } + } + } + } + + public static void saveNBTFileStatic(NBTTagCompound compound, File file) { + instance.saveNBTFile(compound, file); + } + + public void saveNBTFile(NBTTagCompound compound, File file) { + this.nbtFiles.queueTask(new NBTFileSaver(compound, file)); + } + + private class NBTFileSaver implements Runnable { + + private NBTTagCompound compound; + private File file; + + public NBTFileSaver(NBTTagCompound compound, File file) { + this.compound = compound; + this.file = file; + } + + public void run() { + FileOutputStream fileoutputstream = null; + try { + fileoutputstream = new FileOutputStream(this.file); + NBTCompressedStreamTools.a(this.compound, fileoutputstream); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if(fileoutputstream != null) { + try { + fileoutputstream.close(); + } catch (IOException e) {} + } + } + this.compound = null; + this.file = null; + } + } + + public static boolean queuePathSearch(PathSearchJob pathSearchJob) { + return instance.pathSearchThrottler.queuePathSearch(pathSearchJob); + } + + public class TickCounter implements Runnable { + + private ArrayDeque ticksPerSecond; + private AtomicInteger ticksCounter; + + public TickCounter() { + this.ticksPerSecond = new ArrayDeque<>(); + this.ticksCounter = new AtomicInteger(0); + } + + @Override + public void run() { + int lastCount = this.ticksCounter.getAndSet(0); + synchronized(this.ticksPerSecond) { + this.ticksPerSecond.addLast(lastCount); + if(this.ticksPerSecond.size() > 30) { + this.ticksPerSecond.removeFirst(); + } + } + } + + public void increaseTickCounter() { + this.ticksCounter.incrementAndGet(); + } + + public Integer[] getTicksPerSecond() { + synchronized(this.ticksPerSecond) { + return this.ticksPerSecond.toArray(new Integer[0]); + } + } + } + + public static TickCounter getTickCounter() { + return instance.tickCounter; + } + + public static void startTickTimerTask() { + instance.tickTimerTask = instance.timerService.schedule(instance.tickTimerObject, timerDelay, TimeUnit.MILLISECONDS); + } + + public static void cancelTimerTask(float tickTime) { + if(checkTickTime(tickTime) && instance.tickTimerTask.cancel(false)) { + instance.tickTimerObject.tickFinishedEarly(); + } + } + + private static boolean checkTickTime(float tickTime) { + if(tickTime > 45.0F) { + if(timerDelay > 40) { + timerDelay--; + } + } else { + if(timerDelay < 45) { + timerDelay++; + } + return tickTime < 40.0F; + } + return false; + } + + private class TickTimer implements Callable { + public Object call() { + this.tickIsGoingToFinishLate(); + return null; + } + + public void tickIsGoingToFinishLate() { + } + + public void tickFinishedEarly() { + } + } + + public static void execute(Runnable runnable) { + instance.cachedThreadPool.execute(runnable); + } + + public static Future submit(Runnable runnable) { + return instance.cachedThreadPool.submit(runnable); + } + + public static Future submit(Callable callable) { + return instance.cachedThreadPool.submit(callable); + } + + public static void queueHeadConversion(Runnable runnable) { + instance.headConversions.queueTask(runnable); + } + + public static TaskQueueWorker createTaskQueue() { + return instance.createTaskQueueWorker(); + } + + public TaskQueueWorker createTaskQueueWorker() { + return new TaskQueueWorker(this.cachedThreadPool); + } + + public class TaskQueueWorker implements Runnable { + private ConcurrentLinkedDeque taskQueue = new ConcurrentLinkedDeque<>(); + private ExecutorService service; + private volatile boolean isActive = false; + + public TaskQueueWorker(ExecutorService service) { + this.service = service; + } + + @Override + public void run() { + Runnable task = null; + while(this.isActive = ((task = this.taskQueue.pollFirst()) != null)) { + try { + task.run(); + } catch (Exception e) { + log.error("Thread " + Thread.currentThread().getName() + " encountered an exception: " + e.getMessage(), e); + } + } + } + + public void queueTask(Runnable runnable) { + this.taskQueue.addLast(runnable); + if(!this.isActive) { + this.isActive = true; + this.service.execute(this); + } + } + + public boolean isActive() { + if(!this.isActive && !this.taskQueue.isEmpty()) { + this.isActive = true; + this.service.execute(this); + } + return this.isActive; + } + + public int getTaskCount() { + int count = this.taskQueue.size(); + if(this.isActive) { + count++; + } + return count; + } + } + + public static Executor getCommonThreadPool() { + return instance.cachedThreadPool; + } + +} diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/util/Cuboid.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/util/Cuboid.java new file mode 100644 index 0000000..8acaef7 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/util/Cuboid.java @@ -0,0 +1,211 @@ +package com.elevatemc.spigot.util; + +import net.jafama.FastMath; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.entity.Entity; + +import java.util.*; +public class Cuboid implements Iterable, Cloneable, ConfigurationSerializable { + + protected String worldName; + public int lowerX; + public int lowerY; + public int lowerZ; + public int upperX; + public int upperY; + public int upperZ; + + public Cuboid(Location loc1, Location loc2) { + if (loc1.getWorld() != loc2.getWorld()) { + throw new IllegalArgumentException("Locations must be on the same world"); + } + + this.worldName = loc1.getWorld().getName(); + this.lowerX = FastMath.min(loc1.getBlockX(), loc2.getBlockX()); + this.lowerY = FastMath.min(loc1.getBlockY(), loc2.getBlockY()); + this.lowerZ = FastMath.min(loc1.getBlockZ(), loc2.getBlockZ()); + this.upperX = FastMath.max(loc1.getBlockX(), loc2.getBlockX()); + this.upperY = FastMath.max(loc1.getBlockY(), loc2.getBlockY()); + this.upperZ = FastMath.max(loc1.getBlockZ(), loc2.getBlockZ()); + } + + public Cuboid(Cuboid cuboid) { + this.worldName = cuboid.worldName; + this.lowerX = cuboid.lowerX; + this.lowerY = cuboid.lowerY; + this.lowerZ = cuboid.lowerZ; + this.upperX = cuboid.upperX; + this.upperY = cuboid.upperY; + this.upperZ = cuboid.upperZ; + } + + public Cuboid(Map map) { + this.worldName = (String) map.get("worldName"); + this.lowerX = (int) map.get("x1"); + this.lowerY = (int) map.get("y1"); + this.lowerZ = (int) map.get("z1"); + this.upperX = (int) map.get("x2"); + this.upperY = (int) map.get("y2"); + this.upperZ = (int) map.get("z2"); + } + + public World getWorld() { + World world = Bukkit.getWorld(this.worldName); + if (world == null) { + throw new IllegalStateException("World '" + this.worldName + "' is not loaded"); + } + return world; + } + + public Location getLowerNE() { + return new Location(this.getWorld(), this.lowerX, this.lowerY, this.lowerZ); + } + + public Location getUpperSW() { + return new Location(this.getWorld(), this.upperX, this.upperY, this.upperZ); + } + + public Location getCenter() { + return new Location( + this.getWorld(), + this.lowerX + (((this.upperX + 1) - this.lowerX) / 2.0), + this.lowerY + (((this.upperY + 1) - this.lowerY) / 2.0), + this.lowerZ + (((this.upperZ + 1) - this.lowerZ) / 2.0) + ); + } + + public int getSizeX() { + return this.upperX - this.lowerX + 1; + } + + public int getSizeY() { + return this.upperY - this.lowerY + 1; + } + + public int getSizeZ() { + return this.upperZ - this.lowerZ + 1; + } + + public int getVolume() { + return this.getSizeX() * this.getSizeY() * this.getSizeZ(); + } + + public List getChunks() { + List results = new ArrayList<>(); + World world = this.getWorld(); + + final int x1 = this.lowerX & -0x10; + final int x2 = this.upperX & -0x10; + final int z1 = this.lowerZ & -0x10; + final int z2 = this.upperZ & -0x10; + + int x3 = x1; + while (x3 <= x2) { + int z3 = z1; + while (z3 <= z2) { + results.add(world.getChunkAt(x3 >> 4, z3 << 4)); + z3 += 16; + } + + x3 += 16; + } + + return results; + } + + public List getBlocks() { + List copy = new ArrayList<>(); + + for (Block block : this) { + copy.add(block); + } + + return copy; + } + + public boolean contains(int x, int y, int z) { + return x >= lowerX && x <= upperX && y >= lowerY && y <= upperY && z >= lowerZ && z <= upperZ; + } + + public boolean contains(Location location) { + return worldName.equals(location.getWorld().getName()) && contains(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + public boolean contains(Block block) { + return contains(block.getLocation()); + } + + public boolean contains(Entity entity) { + return contains(entity.getLocation()); + } + + @Override + public Iterator iterator() { + return new CuboidIterator(this.getWorld(), this.lowerX, this.lowerY, this.lowerZ, this.upperX, this.upperY, this.upperZ); + } + + @Override + public Map serialize() { + Map map = new HashMap<>(); + map.put("worldName", this.worldName); + map.put("x1", this.lowerX); + map.put("y1", this.lowerY); + map.put("z1", this.lowerZ); + map.put("x2", this.upperX); + map.put("y2", this.upperY); + map.put("z2", this.upperZ); + return map; + } + + static class CuboidIterator implements Iterator { + private final World world; + + private final int baseX; + private final int baseY; + private final int baseZ; + + private int x = 0; + private int y = 0; + private int z = 0; + + private final int sizeX; + private final int sizeY; + private final int sizeZ; + + public CuboidIterator(World world, int x1, int y1, int z1, int x2, int y2, int z2) { + this.world = world; + this.baseX = FastMath.min(x1, x2); + this.baseY = FastMath.min(y1, y2); + this.baseZ = FastMath.min(z1, z2); + this.sizeX = FastMath.abs(x2 - x1) + 1; + this.sizeY = FastMath.abs(y2 - y1) + 1; + this.sizeZ = FastMath.abs(z2 - z1) + 1; + } + + @Override + public boolean hasNext() { + return this.x < this.sizeX && this.y < this.sizeY && this.z < this.sizeZ; + } + + @Override + public Block next() { + Block block = this.world.getBlockAt(this.baseX + this.x, this.baseY + this.y, this.baseZ + this.z); + if (++this.x >= this.sizeX) { + this.x = 0; + + if (++this.y >= this.sizeY) { + this.y = 0; + ++this.z; + } + } + return block; + } + } + +} + diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/Block.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/Block.java index 2817389..4e1c6a0 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/Block.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Block.java @@ -1,11 +1,18 @@ package net.minecraft.server; +import com.elevatemc.spigot.event.BlockDropItemsEvent; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.entity.CraftItem; + +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; public class Block { + public List droppedItemsCatcher; + private static final MinecraftKey a = new MinecraftKey("air"); public static final RegistryBlocks REGISTRY = new RegistryBlocks(Block.a); public static final RegistryID d = new RegistryID(); @@ -342,7 +349,30 @@ public class Block { } public final void b(World world, BlockPosition blockposition, IBlockData iblockdata, int i) { - this.dropNaturally(world, blockposition, iblockdata, 1.0F, i); + if (this == Blocks.AIR) return; + if (this.droppedItemsCatcher == null) { + + this.droppedItemsCatcher = new ArrayList<>(1); + this.dropNaturally(world, blockposition, iblockdata, 1.0F, i); + + BlockDropItemsEvent dropItemsEvent = new BlockDropItemsEvent(world.getWorld().getBlockAt( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ()), null, this.droppedItemsCatcher); + + Bukkit.getPluginManager().callEvent(dropItemsEvent); + + if (!dropItemsEvent.isCancelled() && dropItemsEvent.getToDrop() != null) { + for (final org.bukkit.entity.Item item : dropItemsEvent.getToDrop()) { + + world.addEntity(((CraftItem) item).getHandle()); + } + } + + this.droppedItemsCatcher = null; + } else { + this.dropNaturally(world, blockposition, iblockdata, 1.0F, i); + } } public void dropNaturally(World world, BlockPosition blockposition, IBlockData iblockdata, float f, int i) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/Chunk.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/Chunk.java index 1157d4e..aa099d6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/Chunk.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Chunk.java @@ -42,7 +42,7 @@ public class Chunk { private boolean done; private boolean lit; private boolean p; - private boolean q; + public boolean q; private boolean r; private long lastSaved; private int t; @@ -828,7 +828,7 @@ public class Chunk { return j >= this.heightMap[k << 4 | i]; } - private TileEntity i(BlockPosition blockposition) { + public TileEntity i(BlockPosition blockposition) { Block block = this.getType(blockposition); return !block.isTileEntity() ? null : ((IContainer) block).a(this.world, this.c(blockposition)); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkSection.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkSection.java index 907c57b..6a14609 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkSection.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkSection.java @@ -1,5 +1,7 @@ package net.minecraft.server; +import com.elevatemc.spigot.chunk.ChunkSectionSnapshot; + public class ChunkSection { private int yPos; @@ -8,7 +10,7 @@ public class ChunkSection { private char[] blockIds; private NibbleArray emittedLight; private NibbleArray skyLight; - boolean isDirty; // PaperSpigot + public boolean isDirty; public ChunkSection(int i, boolean flag) { this.yPos = i; @@ -58,7 +60,6 @@ public class ChunkSection { } this.blockIds[j << 8 | k << 4 | i] = (char) Block.d.b(iblockdata); - isDirty = true; // PaperSpigot } public Block b(int i, int j, int k) { @@ -85,7 +86,6 @@ public class ChunkSection { public void a(int i, int j, int k, int l) { this.skyLight.a(i, j, k, l); - isDirty = true; // PaperSpigot } public int d(int i, int j, int k) { @@ -94,7 +94,6 @@ public class ChunkSection { public void b(int i, int j, int k, int l) { this.emittedLight.a(i, j, k, l); - isDirty = true; // PaperSpigot } public int e(int i, int j, int k) { @@ -145,4 +144,23 @@ public class ChunkSection { public void b(NibbleArray nibblearray) { this.skyLight = nibblearray; } + + public ChunkSectionSnapshot createSnapshot() { + return new ChunkSectionSnapshot( + nonEmptyBlockCount, + tickingBlockCount, + blockIds.clone(), + new NibbleArray(), + new NibbleArray() + ); + } + + public void restoreSnapshot(ChunkSectionSnapshot snap) { + nonEmptyBlockCount = snap.getNonEmptyBlockCount(); + tickingBlockCount = snap.getTickingBlockCount(); + blockIds = snap.getBlockIds().clone(); + isDirty = true; + } + + } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/Entity.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/Entity.java index 99303c3..68bf2e6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/Entity.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Entity.java @@ -85,7 +85,7 @@ public abstract class Entity implements ICommandListener { public float M; public float N; public float fallDistance; - private int h; + public int h; //Last ground Y public double P; public double Q; public double R; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityCreature.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityCreature.java index 5ea36f7..9835c96 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityCreature.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityCreature.java @@ -3,6 +3,10 @@ package net.minecraft.server; import java.util.UUID; // CraftBukkit start +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJob; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobEntity; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobPosition; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchQueuingManager; import org.bukkit.event.entity.EntityUnleashEvent; // CraftBukkit end @@ -15,6 +19,41 @@ public abstract class EntityCreature extends EntityInsentient { private PathfinderGoal c; private boolean bm; + // ImHacking 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(BlockPosition blockPosition, float range) { + this.queuingManager.queueSearch(new PathSearchJobPosition(this, blockPosition, 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.goalTarget != null && this.goalTarget.equals(target)) { + this.returnedPathEntity = pathentity; + } + } + + public void setSearchResult(PathSearchJobPosition pathSearchJobPosition, PathEntity pathentity) { + this.queuingManager.checkLastSearchResult(pathSearchJobPosition); + this.returnedPathEntity = pathentity; + } + // ImHacking end + public EntityCreature(World world) { super(world); this.a = BlockPosition.ZERO; @@ -31,7 +70,7 @@ public abstract class EntityCreature extends EntityInsentient { } public boolean cf() { - return !this.navigation.m(); + return !this.getNavigation().m(); } public boolean cg() { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderPearl.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderPearl.java index 319c0bc..682b889 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderPearl.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderPearl.java @@ -1,15 +1,37 @@ package net.minecraft.server; // CraftBukkit start +import com.elevatemc.spigot.event.PlayerPearlRefundEvent; +import com.google.common.collect.Sets; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.Gate; +import org.bukkit.material.Openable; +import org.bukkit.util.BlockIterator; +import org.bukkit.util.Vector; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; // CraftBukkit end public class EntityEnderPearl extends EntityProjectile { private EntityLiving c; + private Location teleportLocation; + + private static final Set PROHIBITED_PEARL_BLOCKS = Sets.newHashSet(Block.getById(85), Block.getById(107)); + public static List pearlAbleType = Arrays.asList("STEP", "STAIR"); + public static List forwardTypes = Collections.singletonList(org.bukkit.Material.ENDER_PORTAL_FRAME); + public EntityEnderPearl(World world) { super(world); this.loadChunks = world.paperSpigotConfig.loadUnloadedEnderPearls; // PaperSpigot @@ -21,80 +43,177 @@ public class EntityEnderPearl extends EntityProjectile { this.loadChunks = world.paperSpigotConfig.loadUnloadedEnderPearls; // PaperSpigot } - protected void a(MovingObjectPosition movingobjectposition) { - EntityLiving entityliving = this.getShooter(); + @Override + protected void a(final MovingObjectPosition objectPosition) { + final EntityLiving entityliving = this.getShooter(); + BlockPosition position = objectPosition.a(); + if(position == null) { + position = new BlockPosition(this); + } + Block block = this.world.getType(position).getBlock(); - if (movingobjectposition.entity != null) { - if (movingobjectposition.entity == this.c) { - return; + if (block == Blocks.TRIPWIRE) { + return; + } else if (block == Blocks.FENCE_GATE) { + BlockIterator bi = null; + + try { + Vector l = new Vector(this.locX, this.locY, this.locZ); + Vector l2 = new Vector(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ); + Vector dir = new Vector(l2.getX() - l.getX(), l2.getY() - l.getY(), l2.getZ() - l.getZ()).normalize(); + bi = new BlockIterator(this.world.getWorld(), l, dir, 0, 1); + } catch (IllegalStateException ex) { + // ignore } - movingobjectposition.entity.damageEntity(DamageSource.projectile(this, entityliving), 0.0F); + if (bi != null) { + boolean open = true; + boolean hasSolidBlock = false; + + while (bi.hasNext()) { + org.bukkit.block.Block b = bi.next(); + + if (b.getType().isSolid() && b.getType().isOccluding()) { + hasSolidBlock = true; + } + + if (b.getState().getData() instanceof Gate && !((Gate) b.getState().getData()).isOpen()) { + open = false; + break; + } + } + + if (open && !hasSolidBlock) { + return; + } + } + } + if (objectPosition.entity != null) { + if (objectPosition.entity == this.c) { + return; + } + objectPosition.entity.damageEntity(DamageSource.projectile(this, entityliving), 0.0f); } - // PaperSpigot start - Remove entities in unloaded chunks - if (this.inUnloadedChunk && world.paperSpigotConfig.removeUnloadedEnderPearls) { + if (this.inUnloadedChunk && this.world.paperSpigotConfig.removeUnloadedEnderPearls) { this.die(); } - // PaperSpigot end for (int i = 0; i < 32; ++i) { - this.world.addParticle(EnumParticle.PORTAL, this.locX, this.locY + this.random.nextDouble() * 2.0D, this.locZ, this.random.nextGaussian(), 0.0D, this.random.nextGaussian(), new int[0]); + this.world.addParticle(EnumParticle.PORTAL, this.locX, this.locY + this.random.nextDouble() * 2.0, this.locZ, this.random.nextGaussian(), + 0.0, this.random.nextGaussian()); } - if (!this.world.isClientSide) { if (entityliving instanceof EntityPlayer) { - EntityPlayer entityplayer = (EntityPlayer) entityliving; + final EntityPlayer entityplayer = (EntityPlayer)entityliving; if (entityplayer.playerConnection.a().g() && entityplayer.world == this.world && !entityplayer.isSleeping()) { - // CraftBukkit start - Fire PlayerTeleportEvent - org.bukkit.craftbukkit.entity.CraftPlayer player = entityplayer.getBukkitEntity(); - org.bukkit.Location location = getBukkitEntity().getLocation(); - location.setPitch(player.getLocation().getPitch()); - location.setYaw(player.getLocation().getYaw()); + if (teleportLocation != null) { + CraftPlayer player = entityplayer.getBukkitEntity(); + Location previousLocation = player.getLocation(); - PlayerTeleportEvent teleEvent = new PlayerTeleportEvent(player, player.getLocation(), location, PlayerTeleportEvent.TeleportCause.ENDER_PEARL); - Bukkit.getPluginManager().callEvent(teleEvent); + teleportLocation.setYaw(previousLocation.getYaw()); + teleportLocation.setPitch(previousLocation.getPitch()); - if (!teleEvent.isCancelled() && !entityplayer.playerConnection.isDisconnected()) { - if (this.random.nextFloat() < 0.05F && this.world.getGameRules().getBoolean("doMobSpawning")) { - EntityEndermite entityendermite = new EntityEndermite(this.world); + // Fix an issue with the pearl actually not teleporting you into the exact Y it will + // randomly/based of the pitch the Y would change, the closer to the thrower/thrown from + // will cause it to be higher, unless directly down + teleportLocation.setY((int) teleportLocation.getY()); - entityendermite.a(true); - entityendermite.setPositionRotation(entityliving.locX, entityliving.locY, entityliving.locZ, entityliving.yaw, entityliving.pitch); - this.world.addEntity(entityendermite); + PlayerTeleportEvent teleEvent = new PlayerTeleportEvent(player, player.getLocation(), + teleportLocation, PlayerTeleportEvent.TeleportCause.ENDER_PEARL); + + Bukkit.getPluginManager().callEvent(teleEvent); + if (!teleEvent.isCancelled() && !entityplayer.playerConnection.isDisconnected()) { + if (entityliving.au()) { + this.getShooter().mount(null); + } + + entityplayer.playerConnection.teleport(teleEvent.getTo()); + entityliving.fallDistance = 0.0F; + ((Entity)entityliving).h = -1; + CraftEventFactory.entityDamage = this; + entityliving.damageEntity(DamageSource.FALL, 5.0F); + CraftEventFactory.entityDamage = null; } - - if (entityliving.au()) { - entityliving.mount((Entity) null); - } - - entityplayer.playerConnection.teleport(teleEvent.getTo()); - entityliving.fallDistance = 0.0F; - CraftEventFactory.entityDamage = this; - entityliving.damageEntity(DamageSource.FALL, 5.0F); - CraftEventFactory.entityDamage = null; + } else { + //ImHacking Add Player Pearl Refund + Bukkit.getPluginManager().callEvent(new PlayerPearlRefundEvent(entityplayer.getBukkitEntity())); + // ImHacking (Give back the pearl since the teleport location was not made correctly) + player.getInventory().addItem(new ItemStack(org.bukkit.Material.ENDER_PEARL)); } - // CraftBukkit end } } else if (entityliving != null) { entityliving.enderTeleportTo(this.locX, this.locY, this.locZ); - entityliving.fallDistance = 0.0F; + entityliving.fallDistance = 0.0f; + ((Entity)entityliving).h = -1; } - this.die(); } - } + @Override public void t_() { - EntityLiving entityliving = this.getShooter(); + final EntityLiving shooter = this.getShooter(); - if (entityliving != null && entityliving instanceof EntityHuman && !entityliving.isAlive()) { + // ImHacking Start - Prevent Pearling into blocks + // (This is a simple check to make sure + // that people can't make an impossible pearl through block + if (shooter != null && !shooter.isAlive()) { this.die(); } else { - super.t_(); - } + AxisAlignedBB boundingBox = AxisAlignedBB.a(this.locX - 0.3D, this.locY - 0.05D, this.locZ - 0.3D, this.locX + 0.3D, this.locY + 0.5D, this.locZ + 0.3D); + if (!this.world.boundingBoxContainsMaterials(this.getBoundingBox().grow(0.25D, + 0D, 0.25D), PROHIBITED_PEARL_BLOCKS) && this.world.getCubes(this, boundingBox).isEmpty()) { + this.teleportLocation = getBukkitEntity().getLocation(); + } + org.bukkit.block.Block block = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)); + org.bukkit.Material typeHere = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), + MathHelper.floor(this.locY), MathHelper.floor(this.locZ)).getType(); + + if (pearlAbleType.stream().anyMatch(it -> typeHere.name().contains(it))) { + this.teleportLocation = getBukkitEntity().getLocation(); + } + + if (shooter != null && forwardTypes.stream().anyMatch(it -> + block.getRelative(getDirection((EntityPlayer) shooter)).getType() == it)) { + this.teleportLocation = getBukkitEntity().getLocation(); + } + + if (typeHere == org.bukkit.Material.FENCE_GATE) { + if (((Openable) block.getState().getData()).isOpen()) { + this.teleportLocation = getBukkitEntity().getLocation(); + } + } + + if (shooter != null) { + final org.bukkit.block.Block newTrap = block.getRelative(getDirection((EntityPlayer) shooter)).getRelative(BlockFace.DOWN); + + if (newTrap.getType() == org.bukkit.Material.COBBLE_WALL || newTrap.getType() == Material.FENCE) { + this.teleportLocation = newTrap.getLocation(); + } + } + + } + super.t_(); + // ImHacking End + } + + public static BlockFace getDirection(EntityPlayer entityPlayer) { + float yaw = entityPlayer.getBukkitEntity().getLocation().getYaw(); + if (yaw < 0) { + yaw += 360; + } + if (yaw >= 315 || yaw < 45) { + return BlockFace.SOUTH; + } else if (yaw < 135) { + return BlockFace.WEST; + } else if (yaw < 225) { + return BlockFace.NORTH; + } else if (yaw < 315) { + return BlockFace.EAST; + } + return BlockFace.NORTH; } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHorse.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHorse.java index 53aaa65..9ae99f3 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHorse.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHorse.java @@ -749,7 +749,7 @@ public class EntityHorse extends EntityAnimal implements IInventoryListener { EntityHorse entityhorse = this.a(this, 16.0D); if (entityhorse != null && this.h((Entity) entityhorse) > 4.0D) { - this.navigation.a((Entity) entityhorse); + this.getNavigation().a(entityhorse); } } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHuman.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHuman.java index fac3c8e..5accac6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHuman.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityHuman.java @@ -1,11 +1,14 @@ package net.minecraft.server; +import com.elevatemc.spigot.event.PlayerHealthChangeEvent; import com.google.common.base.Charsets; import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.elevatemc.spigot.eSpigot; +import org.bukkit.Bukkit; import org.bukkit.craftbukkit.entity.CraftHumanEntity; import org.bukkit.craftbukkit.entity.CraftItem; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityCombustByEntityEvent; @@ -1756,8 +1759,13 @@ public abstract class EntityHuman extends EntityLiving { if (f < 0.0F) { f = 0.0F; } - + float previous = getAbsorptionHearts(); // ImHacking this.getDataWatcher().watch(17, Float.valueOf(f)); + // ImHacking Start - Player Health Change Event + if (previous != f) { + Bukkit.getPluginManager().callEvent(new PlayerHealthChangeEvent(((CraftPlayer) getBukkitEntity()), previous, getHealth())); + } + // ImHacking End } public boolean a(ChestLock chestlock) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityInsentient.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityInsentient.java index b82b984..fa26a31 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityInsentient.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityInsentient.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.UUID; // CraftBukkit start +import com.elevatemc.spigot.pathsearch.AsyncNavigation; import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.entity.CraftLivingEntity; import org.bukkit.event.entity.EntityTargetLivingEntityEvent; @@ -21,10 +22,10 @@ public abstract class EntityInsentient extends EntityLiving { protected ControllerMove moveController; protected ControllerJump g; private EntityAIBodyControl b; - protected NavigationAbstract navigation; + private Navigation navigation; public PathfinderGoalSelector goalSelector; public PathfinderGoalSelector targetSelector; - private EntityLiving goalTarget; + public EntityLiving goalTarget; private EntitySenses bk; private ItemStack[] equipment = new ItemStack[5]; public float[] dropChances = new float[5]; @@ -43,7 +44,7 @@ public abstract class EntityInsentient extends EntityLiving { this.moveController = new ControllerMove(this); this.g = new ControllerJump(this); this.b = new EntityAIBodyControl(this); - this.navigation = this.b(world); + this.navigation = new AsyncNavigation(this, world); // ImHacking this.bk = new EntitySenses(this); for (int i = 0; i < this.dropChances.length; ++i) { @@ -76,7 +77,7 @@ public abstract class EntityInsentient extends EntityLiving { return this.g; } - public NavigationAbstract getNavigation() { + public Navigation getNavigation() { return this.navigation; } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityLiving.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityLiving.java index fe77482..32b1df1 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityLiving.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityLiving.java @@ -67,6 +67,8 @@ public abstract class EntityLiving extends Entity { protected boolean aP; protected int ticksFarFromPlayer; protected float aR; + + public int lastGroundY; //lastGroundY protected float aS; protected float aT; protected float aU; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityProjectile.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityProjectile.java index e7cca3c..5eab0d0 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityProjectile.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityProjectile.java @@ -1,5 +1,7 @@ package net.minecraft.server; +import org.bukkit.craftbukkit.entity.CraftPlayer; + import java.util.List; import java.util.UUID; @@ -13,6 +15,10 @@ public abstract class EntityProjectile extends Entity implements IProjectile { public int shake; public EntityLiving shooter; public String shooterName; + + //ImHacking - Start + public CraftPlayer player; + //ImHacking - End private int i; private int ar; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityRabbit.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityRabbit.java index bb47e09..68845e0 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityRabbit.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityRabbit.java @@ -27,7 +27,7 @@ public class EntityRabbit extends EntityAnimal { // CraftBukkit start - code from constructor public void initializePathFinderGoals(){ - this.navigation.a(2.5F); + this.getNavigation().a(2.5F); this.goalSelector.a(1, new PathfinderGoalFloat(this)); this.goalSelector.a(1, new EntityRabbit.PathfinderGoalRabbitPanic(this, 1.33D)); this.goalSelector.a(2, new PathfinderGoalTempt(this, 1.0D, Items.CARROT, false)); @@ -123,7 +123,7 @@ public class EntityRabbit extends EntityAnimal { if (!entityrabbit_controllerjumprabbit.c()) { if (this.moveController.a() && this.bs == 0) { - PathEntity pathentity = this.navigation.j(); + PathEntity pathentity = this.getNavigation().j(); Vec3D vec3d = new Vec3D(this.moveController.d(), this.moveController.e(), this.moveController.f()); if (pathentity != null && pathentity.e() < pathentity.d()) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityWolf.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityWolf.java index 469c87a..89b5953 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityWolf.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityWolf.java @@ -272,8 +272,8 @@ public class EntityWolf extends EntityTameableAnimal { if (this.e((EntityLiving) entityhuman) && !this.world.isClientSide && !this.d(itemstack)) { this.bm.setSitting(!this.isSitting()); this.aY = false; - this.navigation.n(); - this.setGoalTarget((EntityLiving) null, TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason + this.getNavigation().n(); + this.setGoalTarget(null, TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason } } else if (itemstack != null && itemstack.getItem() == Items.BONE && !this.isAngry()) { if (!entityhuman.abilities.canInstantlyBuild) { @@ -288,8 +288,8 @@ public class EntityWolf extends EntityTameableAnimal { // CraftBukkit - added event call and isCancelled check. if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { this.setTamed(true); - this.navigation.n(); - this.setGoalTarget((EntityLiving) null, TargetReason.FORGOT_TARGET, true); + this.getNavigation().n(); + this.setGoalTarget(null, TargetReason.FORGOT_TARGET, true); this.bm.setSitting(true); this.setHealth(this.getMaxHealth()); // CraftBukkit - 20.0 -> getMaxHealth() this.setOwnerUUID(entityhuman.getUniqueID().toString()); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/Navigation.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/Navigation.java new file mode 100644 index 0000000..ae463ea --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Navigation.java @@ -0,0 +1,239 @@ +package net.minecraft.server; + +import com.elevatemc.spigot.pathsearch.PositionPathSearchType; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJob; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobNavigationEntity; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobNavigationPosition; +import net.jafama.FastMath; + +import java.util.Iterator; + +public class Navigation extends NavigationAbstract { + + protected PathfinderNormal a; + private boolean f; + + public Navigation(EntityInsentient var1, World var2) { + super(var1, var2); + } + + // ImHacking 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) { + } + // ImHacking end + + protected Pathfinder a() { + this.a = new PathfinderNormal(); + this.a.a(true); + return new Pathfinder(this.a); + } + + protected boolean b() { + return this.b.onGround || this.h() && this.o() || this.b.au() && this.b instanceof EntityZombie && this.b.vehicle instanceof EntityChicken; + } + + protected Vec3D c() { + return new Vec3D(this.b.locX, (double) this.p(), this.b.locZ); + } + + private int p() { + if (this.b.V() && this.h()) { + int var1 = (int) this.b.getBoundingBox().b; + Block var2 = this.c.getType(new BlockPosition(MathHelper.floor(this.b.locX), var1, MathHelper.floor(this.b.locZ))).getBlock(); + int var3 = 0; + + do { + if (var2 != Blocks.FLOWING_WATER && var2 != Blocks.WATER) { + return var1; + } + + ++var1; + var2 = this.c.getType(new BlockPosition(MathHelper.floor(this.b.locX), var1, MathHelper.floor(this.b.locZ))).getBlock(); + ++var3; + } while (var3 <= 16); + + return (int) this.b.getBoundingBox().b; + } else { + return (int) (this.b.getBoundingBox().b + 0.5D); + } + } + + protected void d() { + super.d(); + if (this.f) { + if (this.c.i(new BlockPosition(MathHelper.floor(this.b.locX), (int) (this.b.getBoundingBox().b + 0.5D), MathHelper.floor(this.b.locZ)))) { + return; + } + + for (int var1 = 0; var1 < this.d.d(); ++var1) { + PathPoint var2 = this.d.a(var1); + if (this.c.i(new BlockPosition(var2.a, var2.b, var2.c))) { + this.d.b(var1 - 1); + return; + } + } + } + + } + + protected boolean a(Vec3D var1, Vec3D var2, int var3, int var4, int var5) { + int var6 = MathHelper.floor(var1.a); + int var7 = MathHelper.floor(var1.c); + double var8 = var2.a - var1.a; + double var10 = var2.c - var1.c; + double var12 = var8 * var8 + var10 * var10; + if (var12 < 1.0E-8D) { + return false; + } else { + double var14 = 1.0D / FastMath.sqrt(var12); + var8 *= var14; + var10 *= var14; + var3 += 2; + var5 += 2; + if (!this.a(var6, (int) var1.b, var7, var3, var4, var5, var1, var8, var10)) { + return false; + } else { + var3 -= 2; + var5 -= 2; + double var16 = 1.0D / FastMath.abs(var8); + double var18 = 1.0D / FastMath.abs(var10); + double var20 = (double) (var6 * 1) - var1.a; + double var22 = (double) (var7 * 1) - var1.c; + if (var8 >= 0.0D) { + ++var20; + } + + if (var10 >= 0.0D) { + ++var22; + } + + var20 /= var8; + var22 /= var10; + int var24 = var8 < 0.0D ? -1 : 1; + int var25 = var10 < 0.0D ? -1 : 1; + int var26 = MathHelper.floor(var2.a); + int var27 = MathHelper.floor(var2.c); + int var28 = var26 - var6; + int var29 = var27 - var7; + + do { + if (var28 * var24 <= 0 && var29 * var25 <= 0) { + return true; + } + + if (var20 < var22) { + var20 += var16; + var6 += var24; + var28 = var26 - var6; + } else { + var22 += var18; + var7 += var25; + var29 = var27 - var7; + } + } while (this.a(var6, (int) var1.b, var7, var3, var4, var5, var1, var8, var10)); + + return false; + } + } + } + + private boolean a(int var1, int var2, int var3, int var4, int var5, int var6, Vec3D var7, double var8, double var10) { + int var12 = var1 - var4 / 2; + int var13 = var3 - var6 / 2; + if (!this.b(var12, var2, var13, var4, var5, var6, var7, var8, var10)) { + return false; + } else { + for (int var14 = var12; var14 < var12 + var4; ++var14) { + for (int var15 = var13; var15 < var13 + var6; ++var15) { + double var16 = (double) var14 + 0.5D - var7.a; + double var18 = (double) var15 + 0.5D - var7.c; + if (!(var16 * var8 + var18 * var10 < 0.0D)) { + Block var20 = this.c.getType(new BlockPosition(var14, var2 - 1, var15)).getBlock(); + Material var21 = var20.getMaterial(); + if (var21 == Material.AIR) { + return false; + } + + if (var21 == Material.WATER && !this.b.V()) { + return false; + } + + if (var21 == Material.LAVA) { + return false; + } + } + } + } + + return true; + } + } + + private boolean b(int var1, int var2, int var3, int var4, int var5, int var6, Vec3D var7, double var8, double var10) { + Iterator var12 = BlockPosition.a(new BlockPosition(var1, var2, var3), new BlockPosition(var1 + var4 - 1, var2 + var5 - 1, var3 + var6 - 1)).iterator(); + + while (var12.hasNext()) { + BlockPosition var13 = (BlockPosition) var12.next(); + double var14 = (double) var13.getX() + 0.5D - var7.a; + double var16 = (double) var13.getZ() + 0.5D - var7.c; + if (!(var14 * var8 + var16 * var10 < 0.0D)) { + Block var18 = this.c.getType(var13).getBlock(); + if (!var18.b(this.c, var13)) { + return false; + } + } + } + + return true; + } + + public void a(boolean var1) { + this.a.c(var1); + } + + public boolean e() { + return this.a.e(); + } + + public void b(boolean var1) { + this.a.b(var1); + } + + public void c(boolean var1) { + this.a.a(var1); + } + + public boolean g() { + return this.a.b(); + } + + public void d(boolean var1) { + this.a.d(var1); + } + + public boolean h() { + return this.a.d(); + } + + public void e(boolean var1) { + this.f = var1; + } + +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/NavigationAbstract.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/NavigationAbstract.java index 8ebe584..82ea88b 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/NavigationAbstract.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/NavigationAbstract.java @@ -1,5 +1,10 @@ package net.minecraft.server; +import com.elevatemc.spigot.pathsearch.PositionPathSearchType; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJob; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobNavigationEntity; +import com.elevatemc.spigot.pathsearch.jobs.PathSearchJobNavigationPosition; + import java.util.Iterator; import java.util.List; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/NetworkManager.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/NetworkManager.java index 6c2e06f..014c0e6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/NetworkManager.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/NetworkManager.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import com.elevatemc.spigot.eSpigot; import com.elevatemc.spigot.util.CryptException; import com.google.common.collect.Queues; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -190,8 +191,17 @@ public class NetworkManager extends SimpleChannelInboundHandler { if (this.channel.isOpen()) { try { packet.a(this.m); + + + if (this.m instanceof PlayerConnection) { + try { + eSpigot.getInstance().getPacketHandlers().forEach(packetHandler -> packetHandler.handleReceivedPacket((PlayerConnection) this.m, packet)); + } catch (Exception e) { + e.printStackTrace(); + } + } } catch (CancelledPacketHandleException cancelledpackethandleexception) { - } + }; } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInUseEntity.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInUseEntity.java new file mode 100644 index 0000000..3553ae2 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInUseEntity.java @@ -0,0 +1,58 @@ +package net.minecraft.server; + +import java.io.IOException; + +public class PacketPlayInUseEntity implements Packet { + + public int a; + public EnumEntityUseAction action; + public Vec3D c; + + public PacketPlayInUseEntity() { + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = packetdataserializer.e(); + this.action = packetdataserializer.a(EnumEntityUseAction.class); + if (this.action == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT_AT) { + this.c = new Vec3D( packetdataserializer.readFloat(), packetdataserializer.readFloat(), packetdataserializer.readFloat()); + } + + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.b(this.a); + packetdataserializer.a(this.action); + if (this.action == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT_AT) { + packetdataserializer.writeFloat((float)this.c.a); + packetdataserializer.writeFloat((float)this.c.b); + packetdataserializer.writeFloat((float)this.c.c); + } + + } + + public void a(PacketListenerPlayIn packetlistenerplayin) { + packetlistenerplayin.a(this); + } + + public Entity a(World world) { + return world.a(this.a); + } + + public EnumEntityUseAction a() { + return this.action; + } + + public Vec3D b() { + return this.c; + } + + public enum EnumEntityUseAction { + INTERACT, + ATTACK, + INTERACT_AT; + + private EnumEntityUseAction() { + } + } +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutAttachEntity.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutAttachEntity.java new file mode 100644 index 0000000..73b0d3f --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutAttachEntity.java @@ -0,0 +1,46 @@ +package net.minecraft.server; + +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; + +@Getter +@Setter +public class PacketPlayOutAttachEntity implements Packet { + + public int a; + public int b; + public int c; + + public PacketPlayOutAttachEntity() {} + + public PacketPlayOutAttachEntity(int entity, int vehicle) { + a = 0; + b = entity; + c = vehicle; + } + + public PacketPlayOutAttachEntity(int i, Entity entity, Entity entity1) { + this.a = i; + this.b = entity.getId(); + this.c = entity1 != null ? entity1.getId() : -1; + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.b = packetdataserializer.readInt(); + this.c = packetdataserializer.readInt(); + this.a = packetdataserializer.readUnsignedByte(); + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.writeInt(this.b); + packetdataserializer.writeInt(this.c); + packetdataserializer.writeByte(this.a); + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java new file mode 100644 index 0000000..2377f35 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java @@ -0,0 +1,43 @@ +package net.minecraft.server; + + +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; +import java.util.List; + +@Getter +@Setter +public class PacketPlayOutEntityMetadata implements Packet { + + public int a; + public List b; + + public PacketPlayOutEntityMetadata() {} + + public PacketPlayOutEntityMetadata(int i, DataWatcher datawatcher, boolean flag) { + this.a = i; + if (flag) { + this.b = datawatcher.c(); + } else { + this.b = datawatcher.b(); + } + + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = packetdataserializer.e(); + this.b = DataWatcher.b(packetdataserializer); + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.b(this.a); + DataWatcher.a(this.b, packetdataserializer); + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java new file mode 100644 index 0000000..70306a3 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutPlayerInfo.java @@ -0,0 +1,312 @@ +package net.minecraft.server; + +import com.google.common.base.Objects; +import com.google.common.collect.Lists; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +@Getter @Setter +public class PacketPlayOutPlayerInfo implements Packet { + + public PacketPlayOutPlayerInfo.EnumPlayerInfoAction a; + public List b = Lists.newArrayList(); + + public PacketPlayOutPlayerInfo() { + } + + public PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction packetplayoutplayerinfo_enumplayerinfoaction, EntityPlayer... aentityplayer) { + this.a = packetplayoutplayerinfo_enumplayerinfoaction; + EntityPlayer[] aentityplayer1 = aentityplayer; + int i = aentityplayer.length; + + for (int j = 0; j < i; ++j) { + EntityPlayer entityplayer = aentityplayer1[j]; + + this.b.add(new PacketPlayOutPlayerInfo.PlayerInfoData(entityplayer.getProfile(), + entityplayer.ping, entityplayer.playerInteractManager.getGameMode(), entityplayer.getPlayerListName())); + } + + } + + public PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction packetplayoutplayerinfo_enumplayerinfoaction, List b) { + this.a = packetplayoutplayerinfo_enumplayerinfoaction; + this.b = b; + } + public static PacketPlayOutPlayerInfo addPlayer(EntityPlayer player) { + PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(); + packet.a = EnumPlayerInfoAction.ADD_PLAYER; + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = + new PacketPlayOutPlayerInfo.PlayerInfoData(player.getProfile(), player.ping, + player.playerInteractManager.getGameMode(), player.getPlayerListName()); + packet.b.add(playerInfoData); + return packet; + } + + public static PacketPlayOutPlayerInfo updatePing(EntityPlayer player) { + PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(); + packet.a = EnumPlayerInfoAction.UPDATE_LATENCY; + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = + new PacketPlayOutPlayerInfo.PlayerInfoData(player.getProfile(), player.ping, + player.playerInteractManager.getGameMode(), player.getPlayerListName()); + packet.b.add(playerInfoData); + return packet; + } + + public static PacketPlayOutPlayerInfo updateGamemode(EntityPlayer player) { + PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(); + packet.a = EnumPlayerInfoAction.UPDATE_GAME_MODE; + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = + new PacketPlayOutPlayerInfo.PlayerInfoData(player.getProfile(), player.ping, + player.playerInteractManager.getGameMode(), player.getPlayerListName()); + packet.b.add(playerInfoData); + return packet; + } + + public static PacketPlayOutPlayerInfo updateDisplayName(EntityPlayer player) { + PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(); + packet.a = EnumPlayerInfoAction.UPDATE_DISPLAY_NAME; + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = + new PacketPlayOutPlayerInfo.PlayerInfoData(player.getProfile(), player.ping, + player.playerInteractManager.getGameMode(), player.getPlayerListName()); + packet.b.add(playerInfoData); + return packet; + } + + public static PacketPlayOutPlayerInfo removePlayer(EntityPlayer player) { + PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(); + packet.a = EnumPlayerInfoAction.REMOVE_PLAYER; + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = + new PacketPlayOutPlayerInfo.PlayerInfoData(player.getProfile(), player.ping, + player.playerInteractManager.getGameMode(), player.getPlayerListName()); + packet.b.add(playerInfoData); + return packet; + } + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = packetdataserializer.a(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class); + int i = packetdataserializer.e(); + + for (int j = 0; j < i; ++j) { + GameProfile gameprofile = null; + int k = 0; + WorldSettings.EnumGamemode worldsettings_enumgamemode = null; + IChatBaseComponent ichatbasecomponent = null; + + switch (PacketPlayOutPlayerInfo.SyntheticClass_1.a[this.a.ordinal()]) { + case 1: + gameprofile = new GameProfile(packetdataserializer.g(), packetdataserializer.c(16)); + int l = packetdataserializer.e(); + + for (int i1 = 0; i1 < l; ++i1) { + String s = packetdataserializer.c(32767); + String s1 = packetdataserializer.c(32767); + + if (packetdataserializer.readBoolean()) { + gameprofile.getProperties().put(s, new Property(s, s1, packetdataserializer.c(32767))); + } else { + gameprofile.getProperties().put(s, new Property(s, s1)); + } + } + + worldsettings_enumgamemode = WorldSettings.EnumGamemode.getById(packetdataserializer.e()); + k = packetdataserializer.e(); + if (packetdataserializer.readBoolean()) { + ichatbasecomponent = packetdataserializer.d(); + } + break; + + case 2: + gameprofile = new GameProfile(packetdataserializer.g(), null); + worldsettings_enumgamemode = WorldSettings.EnumGamemode.getById(packetdataserializer.e()); + break; + + case 3: + gameprofile = new GameProfile(packetdataserializer.g(), null); + k = packetdataserializer.e(); + break; + + case 4: + gameprofile = new GameProfile(packetdataserializer.g(), null); + if (packetdataserializer.readBoolean()) { + ichatbasecomponent = packetdataserializer.d(); + } + break; + + case 5: + gameprofile = new GameProfile(packetdataserializer.g(), null); + } + + this.b.add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameprofile, k, worldsettings_enumgamemode, ichatbasecomponent)); + } + + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.a((Enum) this.a); + packetdataserializer.b(this.b.size()); + Iterator iterator = this.b.iterator(); + + while (iterator.hasNext()) { + PacketPlayOutPlayerInfo.PlayerInfoData packetplayoutplayerinfo_playerinfodata = (PacketPlayOutPlayerInfo.PlayerInfoData) iterator.next(); + + switch (PacketPlayOutPlayerInfo.SyntheticClass_1.a[this.a.ordinal()]) { + case 1: + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.a().getId()); + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.a().getName()); + packetdataserializer.b(packetplayoutplayerinfo_playerinfodata.a().getProperties().size()); + Iterator iterator1 = packetplayoutplayerinfo_playerinfodata.a().getProperties().values().iterator(); + + while (iterator1.hasNext()) { + Property property = (Property) iterator1.next(); + + packetdataserializer.a(property.getName()); + packetdataserializer.a(property.getValue()); + if (property.hasSignature()) { + packetdataserializer.writeBoolean(true); + packetdataserializer.a(property.getSignature()); + } else { + packetdataserializer.writeBoolean(false); + } + } + + packetdataserializer.b(packetplayoutplayerinfo_playerinfodata.c().getId()); + packetdataserializer.b(packetplayoutplayerinfo_playerinfodata.b()); + if (packetplayoutplayerinfo_playerinfodata.d() == null) { + packetdataserializer.writeBoolean(false); + } else { + packetdataserializer.writeBoolean(true); + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.d()); + } + break; + + case 2: + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.a().getId()); + packetdataserializer.b(packetplayoutplayerinfo_playerinfodata.c().getId()); + break; + + case 3: + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.a().getId()); + packetdataserializer.b(packetplayoutplayerinfo_playerinfodata.b()); + break; + + case 4: + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.a().getId()); + if (packetplayoutplayerinfo_playerinfodata.d() == null) { + packetdataserializer.writeBoolean(false); + } else { + packetdataserializer.writeBoolean(true); + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.d()); + } + break; + + case 5: + packetdataserializer.a(packetplayoutplayerinfo_playerinfodata.a().getId()); + } + } + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + + public String toString() { + return Objects.toStringHelper(this).add("action", this.a).add("entries", this.b).toString(); + } + + + static class SyntheticClass_1 { + + static final int[] a = new int[PacketPlayOutPlayerInfo.EnumPlayerInfoAction.values().length]; + + static { + try { + PacketPlayOutPlayerInfo.SyntheticClass_1.a[PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER.ordinal()] = 1; + } catch (NoSuchFieldError ignored) { + ; + } + + try { + PacketPlayOutPlayerInfo.SyntheticClass_1.a[PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE.ordinal()] = 2; + } catch (NoSuchFieldError ignored) { + ; + } + + try { + PacketPlayOutPlayerInfo.SyntheticClass_1.a[PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_LATENCY.ordinal()] = 3; + } catch (NoSuchFieldError ignored) { + ; + } + + try { + PacketPlayOutPlayerInfo.SyntheticClass_1.a[PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_DISPLAY_NAME.ordinal()] = 4; + } catch (NoSuchFieldError ignored) { + ; + } + + try { + PacketPlayOutPlayerInfo.SyntheticClass_1.a[PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER.ordinal()] = 5; + } catch (NoSuchFieldError ignored) { + ; + } + + } + } + + public static class PlayerInfoData { + + private final int b; + private final WorldSettings.EnumGamemode c; + private final GameProfile d; + private final IChatBaseComponent e; + + public PlayerInfoData(GameProfile gameprofile, int i, WorldSettings.EnumGamemode worldsettings_enumgamemode, IChatBaseComponent ichatbasecomponent) { + this.d = gameprofile; + this.b = i; + this.c = worldsettings_enumgamemode; + this.e = ichatbasecomponent; + } + + public GameProfile a() { + return this.d; + } + + public int b() { + return this.b; + } + + public WorldSettings.EnumGamemode c() { + return this.c; + } + + public IChatBaseComponent d() { + return this.e; + } + + public String toString() { + return Objects.toStringHelper(this) + .add("latency", this.b) + .add("gameMode", this.c) + .add("profile", this.d) + .add("displayName", this.e == null ? null : IChatBaseComponent.ChatSerializer.a(this.e)).toString(); + } + } + + public enum EnumPlayerInfoAction { + + ADD_PLAYER, UPDATE_GAME_MODE, UPDATE_LATENCY, UPDATE_DISPLAY_NAME, REMOVE_PLAYER; + + EnumPlayerInfoAction() { + } + } + + // ImHacking start + public GameProfile getPlayer() { + return this.b.get(this.b.size() - 1).d; + } + // ImHacking end +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutScoreboardTeam.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutScoreboardTeam.java new file mode 100644 index 0000000..dfce289 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutScoreboardTeam.java @@ -0,0 +1,119 @@ +package net.minecraft.server; + +import com.google.common.collect.Lists; +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; + +@Getter +@Setter +public class PacketPlayOutScoreboardTeam implements Packet { + + public String a = ""; + public String b = ""; + public String c = ""; + public String d = ""; + public String e; + public int f; + public Collection g; + public int h; + public int i; + + public PacketPlayOutScoreboardTeam() { + this.e = ScoreboardTeamBase.EnumNameTagVisibility.ALWAYS.e; + this.f = -1; + this.g = Lists.newArrayList(); + } + + public PacketPlayOutScoreboardTeam(ScoreboardTeam scoreboardteam, int i) { + this.e = ScoreboardTeamBase.EnumNameTagVisibility.ALWAYS.e; + this.f = -1; + this.g = Lists.newArrayList(); + this.a = scoreboardteam.getName(); + this.h = i; + + if (i == 0 || i == 2) { + this.b = scoreboardteam.getDisplayName(); + this.c = scoreboardteam.getPrefix(); + this.d = scoreboardteam.getSuffix(); + this.i = scoreboardteam.packOptionData(); + this.e = scoreboardteam.getNameTagVisibility().e; + this.f = scoreboardteam.l().b(); + } + + if (i == 0) { + this.g.addAll(scoreboardteam.getPlayerNameSet()); + } + + } + + public PacketPlayOutScoreboardTeam(ScoreboardTeam scoreboardteam, Collection collection, int i) { + this.e = ScoreboardTeamBase.EnumNameTagVisibility.ALWAYS.e; + this.f = -1; + this.g = Lists.newArrayList(); + if (i != 3 && i != 4) { + throw new IllegalArgumentException("Method must be join or leave for player constructor"); + } else if (collection != null && !collection.isEmpty()) { + this.h = i; + this.a = scoreboardteam.getName(); + this.g.addAll(collection); + } else { + throw new IllegalArgumentException("Players cannot be null/empty"); + } + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = packetdataserializer.c(16); + this.h = packetdataserializer.readByte(); + if (this.h == 0 || this.h == 2) { + this.b = packetdataserializer.c(32); + this.c = packetdataserializer.c(16); + this.d = packetdataserializer.c(16); + this.i = packetdataserializer.readByte(); + this.e = packetdataserializer.c(32); + this.f = packetdataserializer.readByte(); + } + + if (this.h == 0 || this.h == 3 || this.h == 4) { + int i = packetdataserializer.e(); + + for (int j = 0; j < i; ++j) { + this.g.add(packetdataserializer.c(40)); + } + } + + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.a(this.a); + packetdataserializer.writeByte(this.h); + + if (this.h == 0 || this.h == 2) { + packetdataserializer.a(this.b); + packetdataserializer.a(this.c); + packetdataserializer.a(this.d); + packetdataserializer.writeByte(this.i); + packetdataserializer.a(this.e); + packetdataserializer.writeByte(this.f); + } + + if (this.h == 0 || this.h == 3 || this.h == 4) { + packetdataserializer.b(this.g.size()); + Iterator iterator = this.g.iterator(); + + while (iterator.hasNext()) { + String s = (String) iterator.next(); + + packetdataserializer.a(s); + } + } + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntity.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntity.java new file mode 100644 index 0000000..b21e8f4 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntity.java @@ -0,0 +1,168 @@ +package net.minecraft.server; + +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; + +@Getter +@Setter +public class PacketPlayOutSpawnEntity implements Packet { + + public int a; + public int b; + public int c; + public int d; + private int e; + private int f; + private int g; + private int h; + private int i; + private int j; + private int k; + + public PacketPlayOutSpawnEntity() {} + + public PacketPlayOutSpawnEntity(Entity entity, int i) { + this(entity, i, 0); + } + + public PacketPlayOutSpawnEntity(Entity entity, int i, int j) { + this.a = entity.getId(); + this.b = MathHelper.floor(entity.locX * 32.0D); + this.c = MathHelper.floor(entity.locY * 32.0D); + this.d = MathHelper.floor(entity.locZ * 32.0D); + this.h = MathHelper.d(entity.pitch * 256.0F / 360.0F); + this.i = MathHelper.d(entity.yaw * 256.0F / 360.0F); + this.j = i; + this.k = j; + if (j > 0) { + double d0 = entity.motX; + double d1 = entity.motY; + double d2 = entity.motZ; + double d3 = 3.9D; + + if (d0 < -d3) { + d0 = -d3; + } + + if (d1 < -d3) { + d1 = -d3; + } + + if (d2 < -d3) { + d2 = -d3; + } + + if (d0 > d3) { + d0 = d3; + } + + if (d1 > d3) { + d1 = d3; + } + + if (d2 > d3) { + d2 = d3; + } + + this.e = (int) (d0 * 8000.0D); + this.f = (int) (d1 * 8000.0D); + this.g = (int) (d2 * 8000.0D); + } + + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = packetdataserializer.e(); + this.j = packetdataserializer.readByte(); + this.b = packetdataserializer.readInt(); + this.c = packetdataserializer.readInt(); + this.d = packetdataserializer.readInt(); + this.h = packetdataserializer.readByte(); + this.i = packetdataserializer.readByte(); + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.b(this.a); + packetdataserializer.writeByte(this.j); + switch (this.k) { + case 0: { + this.d -= 32; + this.i = 128; + break; + } + case 1: { + this.b += 32; + this.i = 64; + break; + } + case 2: { + this.d += 32; + this.i = 0; + break; + } + case 3: { + this.b -= 32; + this.i = 192; + break; + } + } + packetdataserializer.writeInt(this.b); + packetdataserializer.writeInt(this.c); + packetdataserializer.writeInt(this.d); + packetdataserializer.writeByte(this.h); + packetdataserializer.writeByte(this.i); + packetdataserializer.writeInt(this.k); + if (this.k > 0) { + packetdataserializer.writeShort(this.e); + packetdataserializer.writeShort(this.f); + packetdataserializer.writeShort(this.g); + } + } + + public void b_old(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.b(this.a); + packetdataserializer.writeByte(this.j); + packetdataserializer.writeInt(this.b); + packetdataserializer.writeInt(this.c); + packetdataserializer.writeInt(this.d); + packetdataserializer.writeByte(this.h); + packetdataserializer.writeByte(this.i); + packetdataserializer.writeInt(this.k); + if (this.k > 0) { + packetdataserializer.writeShort(this.e); + packetdataserializer.writeShort(this.f); + packetdataserializer.writeShort(this.g); + } + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + + public void a(int i) { + this.b = i; + } + + public void b(int i) { + this.c = i; + } + + public void c(int i) { + this.d = i; + } + + public void d(int i) { + this.e = i; + } + + public void e(int i) { + this.f = i; + } + + public void f(int i) { + this.g = i; + } + +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntityLiving.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntityLiving.java new file mode 100644 index 0000000..e733385 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntityLiving.java @@ -0,0 +1,107 @@ +package net.minecraft.server; + +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; +import java.util.List; + +@Getter +@Setter +public class PacketPlayOutSpawnEntityLiving implements Packet { + + public int id; + public int type; + public int x; + public int y; + public int z; + public int motionX; + public int motionY; + public int motionZ; + public byte yaw; + public byte pitch; + public byte headYaw; + public DataWatcher l; + public List m; + + public PacketPlayOutSpawnEntityLiving() {} + + public PacketPlayOutSpawnEntityLiving(EntityLiving entityliving) { + this.id = entityliving.getId(); + this.type = (byte) EntityTypes.a(entityliving); + this.x = MathHelper.floor(entityliving.locX * 32.0D); + this.y = MathHelper.floor(entityliving.locY * 32.0D); + this.z = MathHelper.floor(entityliving.locZ * 32.0D); + this.yaw = (byte) ((int) (entityliving.yaw * 256.0F / 360.0F)); + this.pitch = (byte) ((int) (entityliving.pitch * 256.0F / 360.0F)); + this.headYaw = (byte) ((int) (entityliving.aK * 256.0F / 360.0F)); + double d0 = 3.9D; + double d1 = entityliving.motX; + double d2 = entityliving.motY; + double d3 = entityliving.motZ; + + if (d1 < -d0) { + d1 = -d0; + } + + if (d2 < -d0) { + d2 = -d0; + } + + if (d3 < -d0) { + d3 = -d0; + } + + if (d1 > d0) { + d1 = d0; + } + + if (d2 > d0) { + d2 = d0; + } + + if (d3 > d0) { + d3 = d0; + } + + this.motionX = (int) (d1 * 8000.0D); + this.motionY = (int) (d2 * 8000.0D); + this.motionZ = (int) (d3 * 8000.0D); + this.l = entityliving.getDataWatcher(); + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.id = packetdataserializer.e(); + this.type = packetdataserializer.readByte() & 255; + this.x = packetdataserializer.readInt(); + this.y = packetdataserializer.readInt(); + this.z = packetdataserializer.readInt(); + this.yaw = packetdataserializer.readByte(); + this.pitch = packetdataserializer.readByte(); + this.headYaw = packetdataserializer.readByte(); + this.motionX = packetdataserializer.readShort(); + this.motionY = packetdataserializer.readShort(); + this.motionZ = packetdataserializer.readShort(); + this.m = DataWatcher.b(packetdataserializer); + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.b(this.id); + packetdataserializer.writeByte(this.type & 255); + packetdataserializer.writeInt(this.x); + packetdataserializer.writeInt(this.y); + packetdataserializer.writeInt(this.z); + packetdataserializer.writeByte(this.yaw); + packetdataserializer.writeByte(this.pitch); + packetdataserializer.writeByte(this.headYaw); + packetdataserializer.writeShort(this.motionX); + packetdataserializer.writeShort(this.motionY); + packetdataserializer.writeShort(this.motionZ); + this.l.a(packetdataserializer); + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntityWeather.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntityWeather.java new file mode 100644 index 0000000..96a86f0 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutSpawnEntityWeather.java @@ -0,0 +1,51 @@ +package net.minecraft.server; + +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; + +@Getter +@Setter +public class PacketPlayOutSpawnEntityWeather implements Packet { + + private int a; + private int b; + private int c; + private int d; + private int e; + + public PacketPlayOutSpawnEntityWeather() {} + + public PacketPlayOutSpawnEntityWeather(Entity entity) { + this.a = entity.getId(); + this.b = MathHelper.floor(entity.locX * 32.0D); + this.c = MathHelper.floor(entity.locY * 32.0D); + this.d = MathHelper.floor(entity.locZ * 32.0D); + if (entity instanceof EntityLightning) { + this.e = 1; + } + + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = packetdataserializer.e(); + this.e = packetdataserializer.readByte(); + this.b = packetdataserializer.readInt(); + this.c = packetdataserializer.readInt(); + this.d = packetdataserializer.readInt(); + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.b(this.a); + packetdataserializer.writeByte(this.e); + packetdataserializer.writeInt(this.b); + packetdataserializer.writeInt(this.c); + packetdataserializer.writeInt(this.d); + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutWorldParticles.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutWorldParticles.java new file mode 100644 index 0000000..44e240c --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutWorldParticles.java @@ -0,0 +1,87 @@ +package net.minecraft.server; + +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; + +@Getter +@Setter +public class PacketPlayOutWorldParticles implements Packet { + + public EnumParticle a; + public float b; + public float c; + public float d; + public float e; + public float f; + public float g; + public float h; + public int i; + public boolean j; + public int[] k; + + public PacketPlayOutWorldParticles() {} + + public PacketPlayOutWorldParticles(EnumParticle enumparticle, boolean flag, float f, float f1, float f2, float f3, float f4, float f5, float f6, int i, int... aint) { + this.a = enumparticle; + this.j = flag; + this.b = f; + this.c = f1; + this.d = f2; + this.e = f3; + this.f = f4; + this.g = f5; + this.h = f6; + this.i = i; + this.k = aint; + } + + public void a(PacketDataSerializer packetdataserializer) throws IOException { + this.a = EnumParticle.a(packetdataserializer.readInt()); + if (this.a == null) { + this.a = EnumParticle.BARRIER; + } + + this.j = packetdataserializer.readBoolean(); + this.b = packetdataserializer.readFloat(); + this.c = packetdataserializer.readFloat(); + this.d = packetdataserializer.readFloat(); + this.e = packetdataserializer.readFloat(); + this.f = packetdataserializer.readFloat(); + this.g = packetdataserializer.readFloat(); + this.h = packetdataserializer.readFloat(); + this.i = packetdataserializer.readInt(); + int i = this.a.d(); + + this.k = new int[i]; + + for (int j = 0; j < i; ++j) { + this.k[j] = packetdataserializer.e(); + } + + } + + public void b(PacketDataSerializer packetdataserializer) throws IOException { + packetdataserializer.writeInt(this.a.c()); + packetdataserializer.writeBoolean(this.j); + packetdataserializer.writeFloat(this.b); + packetdataserializer.writeFloat(this.c); + packetdataserializer.writeFloat(this.d); + packetdataserializer.writeFloat(this.e); + packetdataserializer.writeFloat(this.f); + packetdataserializer.writeFloat(this.g); + packetdataserializer.writeFloat(this.h); + packetdataserializer.writeInt(this.i); + + int i = this.a.d(); + for (int j = 0; j < i; ++j) { + packetdataserializer.b(this.k[j]); + } + } + + public void a(PacketListenerPlayOut packetlistenerplayout) { + packetlistenerplayout.a(this); + } + +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PathfinderNormal.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PathfinderNormal.java index 629aa16..f67cde4 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PathfinderNormal.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PathfinderNormal.java @@ -216,4 +216,20 @@ public class PathfinderNormal extends PathfinderAbstract { public boolean e() { return this.h; } + + public boolean getB() { + return this.f; + } + + public boolean getC() { + return this.g; + } + + public boolean getD() { + return this.i; + } + + public boolean getE() { + return this.h; + } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerChunkMap.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerChunkMap.java index 38586aa..2ee5cb7 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -348,7 +348,13 @@ public class PlayerChunkMap { public static int getFurthestViewableBlock(int i) { return i * 16 - 16; } + public void resend(int chunkX, int chunkZ) { + PlayerChunk chunk = this.a(chunkX, chunkZ, false); + if (chunk != null) { + chunk.resend(); + } + } class PlayerChunk { private final List b = Lists.newArrayList(); @@ -372,7 +378,13 @@ public class PlayerChunkMap { this.location = new ChunkCoordIntPair(i, j); PlayerChunkMap.this.a().chunkProviderServer.getChunkAt(i, j, loadedRunnable); // CraftBukkit } - + public void resend() { + if (this.dirtyCount == 0) { + PlayerChunkMap.this.e.add(this); + } + this.dirtyCount = 64; + this.f = 0xFFFF; + } public void a(final EntityPlayer entityplayer) { // CraftBukkit - added final to argument if (this.b.contains(entityplayer)) { PlayerChunkMap.a.debug("Failed to add player. {} already is in chunk {}, {}", new Object[] { entityplayer, Integer.valueOf(this.location.x), Integer.valueOf(this.location.z)}); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerConnection.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerConnection.java index 923f0c8..9cf80da 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerConnection.java @@ -1,5 +1,8 @@ package net.minecraft.server; +import com.elevatemc.spigot.eSpigot; +import com.elevatemc.spigot.handler.MovementHandler; +import com.elevatemc.spigot.handler.PacketHandler; import com.google.common.collect.Lists; import com.google.common.primitives.Doubles; import com.google.common.primitives.Floats; @@ -263,6 +266,26 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList double delta = Math.pow(this.lastPosX - to.getX(), 2) + Math.pow(this.lastPosY - to.getY(), 2) + Math.pow(this.lastPosZ - to.getZ(), 2); float deltaAngle = Math.abs(this.lastYaw - to.getYaw()) + Math.abs(this.lastPitch - to.getPitch()); + if (packetplayinflying.hasPos && delta > 0.0D && this.checkMovement && !this.player.dead) { + for (MovementHandler handler : eSpigot.getInstance().getMovementHandlers()) { + try { + handler.handleUpdateLocation(player, to, from, packetplayinflying); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + if (packetplayinflying.hasLook && deltaAngle > 0.0F && this.checkMovement && !this.player.dead) { + for (MovementHandler handler : eSpigot.getInstance().getMovementHandlers()) { + try { + handler.handleUpdateRotation(player, to, from, packetplayinflying); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + if ((delta > 1f / 256 || deltaAngle > 10f) && (this.checkMovement && !this.player.dead)) { this.lastPosX = to.getX(); this.lastPosY = to.getY(); @@ -920,7 +943,12 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList // CraftBukkit end try { - this.networkManager.handle(packet); + // Loop through normal handlers + for (PacketHandler handler : eSpigot.getInstance().getPacketHandlers()) { + handler.handleSentPacket(this, packet); + } + + this.networkManager.a((EnumProtocol) packet); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.a(throwable, "Sending packet"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Packet being sent"); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerList.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerList.java index 165a088..f89e840 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerList.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerList.java @@ -890,10 +890,11 @@ public abstract class PlayerList { } public void tick() { - if (++this.u > 600) { - this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_LATENCY, this.players)); + // ImHacking - Useless feature. + /*if (++this.u > 600) { + this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_LATENCY, (EntityPlayer) this.players)); this.u = 0; - } + }*/ } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntity.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntity.java index fdcbf44..0fddbde 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntity.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntity.java @@ -17,7 +17,7 @@ public abstract class TileEntity { private static Map> f = Maps.newHashMap(); private static Map, String> g = Maps.newHashMap(); protected World world; - protected BlockPosition position; + public BlockPosition position; protected boolean d; private int h; protected Block e; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/World.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/World.java index baf34c4..194a70d 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/World.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/World.java @@ -5,6 +5,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; @@ -2042,6 +2043,30 @@ public abstract class World implements IBlockAccess { return false; } + // ImHacking start + public boolean boundingBoxContainsMaterials(AxisAlignedBB boundingBox, Set matching) { + int i = MathHelper.floor(boundingBox.a); + int j = MathHelper.floor(boundingBox.d + 1.0D); + int k = MathHelper.floor(boundingBox.b); + int l = MathHelper.floor(boundingBox.e + 1.0D); + int i1 = MathHelper.floor(boundingBox.c); + int j1 = MathHelper.floor(boundingBox.f + 1.0D); + BlockPosition.MutableBlockPosition blockPosition = new BlockPosition.MutableBlockPosition(); + + for (int k1 = i; k1 < j; ++k1) { + for (int l1 = k; l1 < l; ++l1) { + for (int i2 = i1; i2 < j1; ++i2) { + if (matching.contains(this.getType(blockPosition.c(k1, l1, i2)).getBlock())) { + return true; + } + } + } + } + + return false; + } + // ImHacking end + public boolean b(AxisAlignedBB axisalignedbb, Material material) { int i = MathHelper.floor(axisalignedbb.a); int j = MathHelper.floor(axisalignedbb.d + 1.0D); @@ -3171,11 +3196,11 @@ public abstract class World implements IBlockAccess { return blockposition; } - public void B(BlockPosition blockposition) { - this.worldData.setSpawn(blockposition); + this.worldData.setSpawn(new Location(getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ())); } + public boolean a(EntityHuman entityhuman, BlockPosition blockposition) { return true; } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldData.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldData.java index 3a7b22b..c4f3e89 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldData.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldData.java @@ -3,6 +3,7 @@ package net.minecraft.server; import java.util.concurrent.Callable; // CraftBukkit start import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.event.weather.ThunderChangeEvent; import org.bukkit.event.weather.WeatherChangeEvent; // CraftBukkit end @@ -13,9 +14,11 @@ public class WorldData { private long b; private WorldType c; private String d; - private int e; - private int f; - private int g; + private double e; + private double f; + private double g; + private float yaw; + private float pitch; private long h; private long i; private long j; @@ -108,6 +111,15 @@ public class WorldData { this.e = nbttagcompound.getInt("SpawnX"); this.f = nbttagcompound.getInt("SpawnY"); this.g = nbttagcompound.getInt("SpawnZ"); + // ImHacking Start - Add yaw and pitch to spawns + if (nbttagcompound.hasKey("SpawnYaw")) { + this.yaw = nbttagcompound.getFloat("SpawnYaw"); + } + + if (nbttagcompound.hasKey("SpawnPitch")) { + this.pitch = nbttagcompound.getFloat("SpawnPitch"); + } + // ImHacking End this.h = nbttagcompound.getLong("Time"); if (nbttagcompound.hasKeyOfType("DayTime", 99)) { this.i = nbttagcompound.getLong("DayTime"); @@ -292,9 +304,13 @@ public class WorldData { nbttagcompound.setString("generatorOptions", this.d); nbttagcompound.setInt("GameType", this.u.getId()); nbttagcompound.setBoolean("MapFeatures", this.v); - nbttagcompound.setInt("SpawnX", this.e); - nbttagcompound.setInt("SpawnY", this.f); - nbttagcompound.setInt("SpawnZ", this.g); + nbttagcompound.setDouble("SpawnX", this.e); + nbttagcompound.setDouble("SpawnY", this.f); + nbttagcompound.setDouble("SpawnZ", this.g); + // ImHacking Start + nbttagcompound.setFloat("SpawnYaw", this.yaw); + nbttagcompound.setFloat("SpawnPitch", this.pitch); + // ImHacking End nbttagcompound.setLong("Time", this.h); nbttagcompound.setLong("DayTime", this.i); nbttagcompound.setLong("SizeOnDisk", this.k); @@ -334,15 +350,15 @@ public class WorldData { return this.b; } - public int c() { + public double c() { return this.e; } - public int d() { + public double d() { return this.f; } - public int e() { + public double e() { return this.g; } @@ -366,11 +382,15 @@ public class WorldData { this.i = i; } - public void setSpawn(BlockPosition blockposition) { - this.e = blockposition.getX(); - this.f = blockposition.getY(); - this.g = blockposition.getZ(); + // ImHacking Start - Add yaw and pitch to spawns + public void setSpawn(Location location) { + this.e = location.getX(); + this.f = location.getY(); + this.g = location.getZ(); + this.yaw = location.getYaw(); + this.pitch = location.getPitch(); } + // ImHacking End public String getName() { return this.n; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldProvider.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldProvider.java new file mode 100644 index 0000000..2ad4c4e --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldProvider.java @@ -0,0 +1,139 @@ +package net.minecraft.server; + +public abstract class WorldProvider { + + public static final float[] a = new float[]{1.0F, 0.75F, 0.5F, 0.25F, 0.0F, 0.25F, 0.5F, 0.75F}; + + protected World b; + private WorldType type; + private String i; + protected WorldChunkManager c; + protected boolean d; + public boolean e; + protected final float[] f = new float[16]; + protected int dimension; + private final float[] j = new float[4]; + + public WorldProvider() { + } + + public final void a(World var1) { + this.b = var1; + this.type = var1.getWorldData().getType(); + this.i = var1.getWorldData().getGeneratorOptions(); + this.b(); + this.a(); + } + + protected void a() { + float var1 = 0.0F; + + for(int var2 = 0; var2 <= 15; ++var2) { + float var3 = 1.0F - (float)var2 / 15.0F; + this.f[var2] = (1.0F - var3) / (var3 * 3.0F + 1.0F) * (1.0F - var1) + var1; + } + + } + + protected void b() { + WorldType var1 = this.b.getWorldData().getType(); + if (var1 == WorldType.FLAT) { + WorldGenFlatInfo var2 = WorldGenFlatInfo.a(this.b.getWorldData().getGeneratorOptions()); + this.c = new WorldChunkManagerHell(BiomeBase.getBiome(var2.a(), BiomeBase.ad), 0.5F); + } else if (var1 == WorldType.DEBUG_ALL_BLOCK_STATES) { + this.c = new WorldChunkManagerHell(BiomeBase.PLAINS, 0.0F); + } else { + this.c = new WorldChunkManager(this.b); + } + + } + + public IChunkProvider getChunkProvider() { + if (this.type == WorldType.FLAT) { + return new ChunkProviderFlat(this.b, this.b.getSeed(), this.b.getWorldData().shouldGenerateMapFeatures(), this.i); + } else if (this.type == WorldType.DEBUG_ALL_BLOCK_STATES) { + return new ChunkProviderDebug(this.b); + } else { + return this.type == WorldType.CUSTOMIZED ? new ChunkProviderGenerate(this.b, this.b.getSeed(), this.b.getWorldData().shouldGenerateMapFeatures(), this.i) : new ChunkProviderGenerate(this.b, this.b.getSeed(), this.b.getWorldData().shouldGenerateMapFeatures(), this.i); + } + } + + public boolean canSpawn(int var1, int var2) { + return this.b.c(new BlockPosition(var1, 0, var2)) == Blocks.GRASS; + } + + public float a(long var1, float var3) { + int var4 = (int)(var1 % 24000L); + float var5 = ((float)var4 + var3) / 24000.0F - 0.25F; + if (var5 < 0.0F) { + ++var5; + } + + if (var5 > 1.0F) { + --var5; + } + + float var6 = var5; + var5 = 1.0F - (float)((Math.cos((double)var5 * 3.141592653589793D) + 1.0D) / 2.0D); + var5 = var6 + (var5 - var6) / 3.0F; + return var5; + } + + public int a(long var1) { + return (int)(var1 / 24000L % 8L + 8L) % 8; + } + + public boolean d() { + return true; + } + + public boolean e() { + return true; + } + + public static WorldProvider byDimension(int var0) { + if (var0 == -1) { + return new WorldProviderHell(); + } else if (var0 == 0) { + return new WorldProviderNormal(); + } else { + return var0 == 1 ? new WorldProviderTheEnd() : null; + } + } + + public BlockPosition h() { + return null; + } + + public int getSeaLevel() { + return this.type == WorldType.FLAT ? 4 : this.b.F() + 1; + } + + public abstract String getName(); + + public abstract String getSuffix(); + + public WorldChunkManager m() { + return this.c; + } + + public boolean n() { + return this.d; + } + + public boolean o() { + return this.e; + } + + public float[] p() { + return this.f; + } + + public int getDimension() { + return this.dimension; + } + + public WorldBorder getWorldBorder() { + return new WorldBorder(); + } +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java index 6fdb189..e7ad12f 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java @@ -17,6 +17,7 @@ import org.apache.logging.log4j.Logger; import java.util.*; import java.util.logging.Level; +import org.bukkit.Location; import org.bukkit.WeatherType; import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.util.LongHash; @@ -33,8 +34,7 @@ public class WorldServer extends World implements IAsyncTaskHandler { private final MinecraftServer server; public EntityTracker tracker; private final PlayerChunkMap manager; - // private final Set L = Sets.newHashSet(); // PAIL: Rename nextTickListHash - private final HashTreeSet M = new HashTreeSet(); // CraftBukkit - HashTreeSet // PAIL: Rename nextTickList + private final HashTreeSet M = new HashTreeSet<>(); // CraftBukkit - HashTreeSet // PAIL: Rename nextTickList private final Map entitiesByUUID = Maps.newHashMap(); public ChunkProviderServer chunkProviderServer; public boolean savingDisabled; @@ -876,9 +876,11 @@ public class WorldServer extends World implements IAsyncTaskHandler { private void b(WorldSettings worldsettings) { if (!this.worldProvider.e()) { - this.worldData.setSpawn(BlockPosition.ZERO.up(this.worldProvider.getSeaLevel())); + BlockPosition position = BlockPosition.ZERO.up(this.worldProvider.getSeaLevel()); + this.worldData.setSpawn(new Location(getWorld(), position.getX(), position.getY(), position.getZ())); } else if (this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) { - this.worldData.setSpawn(BlockPosition.ZERO.up()); + BlockPosition position = BlockPosition.ZERO.up(); + this.worldData.setSpawn(new Location(getWorld(), position.getX(), position.getY(), position.getZ())); } else { this.isLoading = true; WorldChunkManager worldchunkmanager = this.worldProvider.m(); @@ -898,7 +900,7 @@ public class WorldServer extends World implements IAsyncTaskHandler { if (spawn.getWorld() != ((WorldServer) this).getWorld()) { throw new IllegalStateException("Cannot set spawn point for " + this.worldData.getName() + " to be in another world (" + spawn.getWorld().getName() + ")"); } else { - this.worldData.setSpawn(new BlockPosition(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ())); + this.worldData.setSpawn(spawn); this.isLoading = false; return; } @@ -924,7 +926,7 @@ public class WorldServer extends World implements IAsyncTaskHandler { } } - this.worldData.setSpawn(new BlockPosition(i, j, k)); + this.worldData.setSpawn(new Location(getWorld(), i, j, k)); this.isLoading = false; if (worldsettings.c()) { this.l(); @@ -937,8 +939,8 @@ public class WorldServer extends World implements IAsyncTaskHandler { WorldGenBonusChest worldgenbonuschest = new WorldGenBonusChest(WorldServer.U, 10); for (int i = 0; i < 10; ++i) { - int j = this.worldData.c() + this.random.nextInt(6) - this.random.nextInt(6); - int k = this.worldData.e() + this.random.nextInt(6) - this.random.nextInt(6); + int j = (int) this.worldData.c() + this.random.nextInt(6) - this.random.nextInt(6); + int k = (int) this.worldData.e() + this.random.nextInt(6) - this.random.nextInt(6); BlockPosition blockposition = this.r(new BlockPosition(j, 0, k)).up(); if (worldgenbonuschest.generate(this, this.random, blockposition)) { diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index 9fea55b..888a520 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -1,7 +1,9 @@ package org.bukkit.craftbukkit; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Map; import net.minecraft.server.*; @@ -10,8 +12,10 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; import org.bukkit.entity.Entity; import org.bukkit.ChunkSnapshot; +import org.bukkit.entity.HumanEntity; public class CraftChunk implements Chunk { private WeakReference weakChunk; @@ -24,7 +28,7 @@ public class CraftChunk implements Chunk { public CraftChunk(net.minecraft.server.Chunk chunk) { if (!(chunk instanceof EmptyChunk)) { - this.weakChunk = new WeakReference(chunk); + this.weakChunk = new WeakReference<>(chunk); } worldServer = (WorldServer) getHandle().world; @@ -310,4 +314,78 @@ public class CraftChunk implements Chunk { static { Arrays.fill(emptySkyLight, (byte) 0xFF); } + + + @Override + public net.techcable.tacospigot.event.entity.ChunkSnapshot takeSnapshot() { + net.minecraft.server.Chunk handle = getHandle(); + com.elevatemc.spigot.chunk.CraftChunkSnapshot snap = new com.elevatemc.spigot.chunk.CraftChunkSnapshot(); + + // save chunk sections to snapshot + for (int i = 0; i < 16; i++) { + if (handle.getSections()[i] != null) { + snap.getSections()[i] = handle.getSections()[i].createSnapshot(); + } + } + + // save tile entities to snapshot + for (Map.Entry entry : handle.tileEntities.entrySet()) { + NBTTagCompound nbt = new NBTTagCompound(); + entry.getValue().b(nbt); // writeToNBT + snap.getTileEntities().add(nbt); + } + return snap; + } + + @Override + public void restoreSnapshot(net.techcable.tacospigot.event.entity.ChunkSnapshot snapshot) { + com.elevatemc.spigot.chunk.CraftChunkSnapshot snap = (com.elevatemc.spigot.chunk.CraftChunkSnapshot) snapshot; + net.minecraft.server.Chunk handle = getHandle(); + + // add chunk sections from snapshot + for (int i = 0; i < 16; i++) { + if (snap.getSections()[i] == null) { + handle.getSections()[i] = null; + } else { + handle.getSections()[i] = new ChunkSection(i << 4, !worldServer.worldProvider.e); + handle.getSections()[i].restoreSnapshot(snap.getSections()[i]); + } + } + + // clear tile entities currently in the chunk + for (TileEntity tileEntity : handle.tileEntities.values()) { + if (tileEntity instanceof IInventory) { + for (HumanEntity h : new ArrayList<> (((IInventory) tileEntity).getViewers())) { + if (h instanceof CraftHumanEntity) { + ((CraftHumanEntity) h).getHandle().closeInventory(); + } + } + } + worldServer.a(tileEntity); + } + handle.tileEntities.clear(); + + // add tile entities from snapshot + for (NBTTagCompound nbt : snap.getTileEntities()) { + // deserialize nbt to new tile entity instance + TileEntity tileEntity = TileEntity.c(nbt); + // TODO: might have to fix this + // move the tile entity into this chunk's space + tileEntity.position = new BlockPosition( + (tileEntity.position.getX() & 15) | handle.locX << 4, + tileEntity.position.getY(), + (tileEntity.position.getZ() & 15) | handle.locX << 4 + ); + + // add it + handle.a(tileEntity); + } + + handle.q = true; // needs saving flag + worldServer.getPlayerChunkMap().resend(x, z); + } + + static { + Arrays.fill(emptySkyLight, (byte) 0xFF); + } } diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 958fe4f..e0fe200 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -106,11 +106,35 @@ public class CraftWorld implements World { BlockPosition spawn = world.getSpawn(); return new Location(this, spawn.getX(), spawn.getY(), spawn.getZ()); } + @Override + public boolean setSpawnLocation(Location location) { + Location previousLocation = getSpawnLocation(); + world.worldData.setSpawn(location); + // Notify anyone who's listening. + SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); + server.getPluginManager().callEvent(event); + + return true; + } public boolean setSpawnLocation(int x, int y, int z) { try { Location previousLocation = getSpawnLocation(); - world.worldData.setSpawn(new BlockPosition(x, y, z)); + world.worldData.setSpawn(new Location(this, x, y, z)); + + // Notify anyone who's listening. + SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); + server.getPluginManager().callEvent(event); + + return true; + } catch (Exception e) { + return false; + } + } + public boolean setSpawnLocation(double x, double y, double z, float yaw, float pitch) { + try { + Location previousLocation = getSpawnLocation(); + world.worldData.setSpawn(new Location(this, x, y, z, yaw, pitch)); // Notify anyone who's listening. SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index d2a2bcb..3f1b541 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.entity; +import com.elevatemc.spigot.event.PlayerHealthChangeEvent; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.mojang.authlib.GameProfile; @@ -1382,7 +1383,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } public void setRealHealth(double health) { + double previous = this.health; // ImHacking; + this.health = health; + + // ImHacking Start - Player Health Change Event + if (previous != health) { + Bukkit.getPluginManager().callEvent(new PlayerHealthChangeEvent(this, previous, getHealth())); + } + // ImHacking End } public void updateScaledHealth() {