diff --git a/TacoSpigot-API/pom.xml b/TacoSpigot-API/pom.xml index b0219e6..a5cd46c 100644 --- a/TacoSpigot-API/pom.xml +++ b/TacoSpigot-API/pom.xml @@ -89,7 +89,7 @@ org.yaml snakeyaml - 1.15 + 1.30 compile diff --git a/TacoSpigot-API/src/main/java/org/bukkit/Bukkit.java b/TacoSpigot-API/src/main/java/org/bukkit/Bukkit.java index 8fbc828..9b47a61 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/Bukkit.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/Bukkit.java @@ -1166,4 +1166,10 @@ public final class Bukkit { { return server.spigot(); } + + // KigPaper start + public static String getPermissionMessage() { + return server.getPermissionMessage(); + } + // KigPaper end } diff --git a/TacoSpigot-API/src/main/java/org/bukkit/Server.java b/TacoSpigot-API/src/main/java/org/bukkit/Server.java index 1b62463..29b3d88 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/Server.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/Server.java @@ -1007,4 +1007,11 @@ public interface Server extends PluginMessageRecipient { } Spigot spigot(); + + // KigPaper start + /** + * @return the server's no permission message + */ + String getPermissionMessage(); + // KigPaper end } diff --git a/TacoSpigot-API/src/main/java/org/bukkit/Sound.java b/TacoSpigot-API/src/main/java/org/bukkit/Sound.java index 0913530..77dbecf 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/Sound.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/Sound.java @@ -208,4 +208,17 @@ public enum Sound { VILLAGER_IDLE, VILLAGER_NO, VILLAGER_YES, + // KigPaper start - Guardian sounds + GUARDIAN_IDLE, + GUARDIAN_IDLE_LAND, + GUARDIAN_IDLE_ELDER, + GUARDIAN_HIT, + GUARDIAN_HIT_LAND, + GUARDIAN_HIT_ELDER, + GUARDIAN_DEATH, + GUARDIAN_DEATH_LAND, + GUARDIAN_DEATH_ELDER, + GUARDIAN_FLOP, + GUARDIAN_CURSE + // KigPaper end } diff --git a/TacoSpigot-API/src/main/java/org/bukkit/command/Command.java b/TacoSpigot-API/src/main/java/org/bukkit/command/Command.java index c126a1e..8558c2e 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/command/Command.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/command/Command.java @@ -198,7 +198,7 @@ public abstract class Command { } if (permissionMessage == null) { - target.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error."); + target.sendMessage(Bukkit.getServer().getPermissionMessage()); } else if (permissionMessage.length() != 0) { for (String line : permissionMessage.replace("", permission).split("\n")) { target.sendMessage(line); diff --git a/TacoSpigot-API/src/main/java/org/bukkit/entity/Player.java b/TacoSpigot-API/src/main/java/org/bukkit/entity/Player.java index 59fa188..7564452 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/entity/Player.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/entity/Player.java @@ -2,6 +2,7 @@ package org.bukkit.entity; import java.net.InetSocketAddress; +import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Achievement; import org.bukkit.ChatColor; import org.bukkit.Effect; @@ -1203,6 +1204,14 @@ public interface Player extends HumanEntity, Conversable, CommandSender, Offline // Paper - Undeprecate public void resetTitle(); + // KigPaper start + /** + + * Sends a message to the player's actionbar. + + * @param message the message to send + + */ + void sendActionbarMessage(BaseComponent... message); + // KigPaper end + // TacoSpigot start /** * Request that the player's client download and switch resource packs. diff --git a/TacoSpigot-API/src/main/java/org/bukkit/map/MapRenderer.java b/TacoSpigot-API/src/main/java/org/bukkit/map/MapRenderer.java index 322d0ce..9642a65 100644 --- a/TacoSpigot-API/src/main/java/org/bukkit/map/MapRenderer.java +++ b/TacoSpigot-API/src/main/java/org/bukkit/map/MapRenderer.java @@ -7,6 +7,7 @@ import org.bukkit.entity.Player; */ public abstract class MapRenderer { + private boolean drawCursors = true; // KigPaper private boolean contextual; /** @@ -53,4 +54,20 @@ public abstract class MapRenderer { */ abstract public void render(MapView map, MapCanvas canvas, Player player); + // KigPaper start + /** + * Returns whether this renderer should draw cursors. Implementors should respect this choice. + */ + public boolean getDrawCursors() { + return drawCursors; + } + + /** + * Sets whether to draw cursors + * @param drawCursors whether this renderer should draw cursors + */ + public void setDrawCursors(boolean drawCursors) { + this.drawCursors = drawCursors; + } + // KigPaper end } diff --git a/TacoSpigot-Server/pom.xml b/TacoSpigot-Server/pom.xml index d771e17..7bdcf33 100644 --- a/TacoSpigot-Server/pom.xml +++ b/TacoSpigot-Server/pom.xml @@ -133,6 +133,16 @@ velocity-native 1.1.0-SNAPSHOT + + org.lz4 + lz4-java + 1.8.0 + + + com.github.luben + zstd-jni + 1.5.2-3 + @@ -144,7 +154,7 @@ destroystokyo - https://ci.destroystokyo.com/plugin/repository/everything/ + https://papermc.io/repo/repository/maven-public/ 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 5c2fb6c..6a8ed0f 100644 --- a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigot.java +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigot.java @@ -6,6 +6,8 @@ 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.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.command.Command; import com.elevatemc.spigot.knockback.KnockbackHandler; @@ -13,14 +15,11 @@ import org.bukkit.craftbukkit.CraftServer; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; public class eSpigot { - - private final Set packetHandlers = new HashSet<>(); private final Set movementHandlers = new HashSet<>(); public static final ScheduledExecutorService EXECUTOR_SERVICE = diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigotFeature.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigotFeature.java index 01738fc..6e4dd0f 100644 --- a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigotFeature.java +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/eSpigotFeature.java @@ -11,7 +11,8 @@ public enum eSpigotFeature { NATURAL_MOB_SPAWNING(false), SHOW_HIDDEN_PLAYERS_IN_TAB(true), MOB_AI(false), - FIX_SPRINT_EAT_EXPLOIT(true); + FIX_SPRINT_EAT_EXPLOIT(true), + OBFUSCATE_HEALTH(true); private boolean enabled; 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 index 0e4044c..a666cfd 100644 --- a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/NamePriorityThreadFactory.java +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/NamePriorityThreadFactory.java @@ -13,7 +13,7 @@ public class NamePriorityThreadFactory implements ThreadFactory { private final int priority; private int idCounter = 0; - private String name = "gSpigotThread"; + private String name = "eSpigotThread"; private boolean isDaemon = false; private Queue> 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 index 6452f04..7720faa 100644 --- a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/ThreadingManager.java +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/threading/ThreadingManager.java @@ -10,7 +10,6 @@ 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; @@ -54,7 +53,7 @@ public class ThreadingManager { 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..."); + log.warn("eSpigot is still waiting for NBT files to be written to disk. " + this.nbtFiles.getTaskCount() + " to go..."); } catch(InterruptedException e) {} } if(!this.cachedThreadPool.isTerminated()) { @@ -65,7 +64,7 @@ public class ThreadingManager { e.printStackTrace(); } if(this.cachedThreadPoolFactory.getActiveCount() > 0) { - log.warn("gSpigot is still waiting for " + this.cachedThreadPoolFactory.getActiveCount() + " async threads to finish."); + log.warn("eSpigot is still waiting for " + this.cachedThreadPoolFactory.getActiveCount() + " async threads to finish."); Queue> queue = this.cachedThreadPoolFactory.getThreadList(); Iterator> iter = null; if(queue != null) { @@ -177,7 +176,7 @@ public class ThreadingManager { } } - private static boolean checkTickTime(float tickTime) { + public static boolean checkTickTime(float tickTime) { if(tickTime > 45.0F) { if(timerDelay > 40) { timerDelay--; diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/util/Dictionary.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/util/Dictionary.java new file mode 100644 index 0000000..0b8aa41 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/util/Dictionary.java @@ -0,0 +1,25 @@ +// KigPaper +package com.elevatemc.spigot.util; + +import net.minecraft.server.EnumParticle; +import org.bukkit.Effect; + +import java.util.EnumMap; + +public class Dictionary { + public static final EnumMap EFFECT_TO_PARTICLE = new EnumMap<>(Effect.class); + + static { + String tmp; + for (EnumParticle p : EnumParticle.values()) { + tmp = p.b().replace("_", ""); + for (Effect e : Effect.values()) { + // This is pretty much the original code, but we only call it once / effect & matching particle + if (e.getName() != null && e.getName().startsWith(tmp)) { + EFFECT_TO_PARTICLE.put(e, p); + break; + } + } + } + } +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/world/AutoSaveJob.java b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/world/AutoSaveJob.java new file mode 100644 index 0000000..82d5fe9 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/com/elevatemc/spigot/world/AutoSaveJob.java @@ -0,0 +1,63 @@ +package com.elevatemc.spigot.world; + +import co.aikar.timings.SpigotTimings; +import org.bukkit.Bukkit; +import org.bukkit.event.world.WorldSaveEvent; + +import net.minecraft.server.ExceptionWorldConflict; +import net.minecraft.server.FileIOThread; +import net.minecraft.server.IProgressUpdate; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.RegionFileCache; +import net.minecraft.server.WorldServer; + +public class AutoSaveJob { + + public enum JobDetail { + WORLD_SAVE, + WORLD_SAVEEVENT, + } + + private WorldServer worldserver; + private JobDetail jobDetail; + + public AutoSaveJob(JobDetail detail, WorldServer worldserver) { + this.jobDetail = detail; + this.worldserver = worldserver; + } + + /** + * + * @return true if the job shall be removed from the autosave queue + * @throws ExceptionWorldConflict + */ + + public boolean process() throws ExceptionWorldConflict { + if(this.isJob(JobDetail.WORLD_SAVE) && this.worldserver != null) { + SpigotTimings.worldSaveTimer.startTiming(); + MinecraftServer.getServer().info("[AutoSave] Saving world " + this.worldserver.getWorld().getName()); + this.worldserver.save(true, (IProgressUpdate) null); + FileIOThread.a().setNoDelay(true); + SpigotTimings.worldSaveTimer.stopTiming(); + } else if(this.isJob(JobDetail.WORLD_SAVEEVENT) && this.worldserver != null) { + if(FileIOThread.a().isDone()) { + SpigotTimings.worldSaveTimer.startTiming(); + FileIOThread.a().setNoDelay(false); + RegionFileCache.a(); + Bukkit.getPluginManager().callEvent(new WorldSaveEvent(this.worldserver.getWorld())); + SpigotTimings.worldSaveTimer.stopTiming(); + } else { + return false; + } + } + this.worldserver = null; + return true; + } + + private boolean isJob(JobDetail detail) { + if(this.jobDetail != null) { + return this.jobDetail.equals(detail); + } + return false; + } +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeDecorator.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeDecorator.java new file mode 100644 index 0000000..db8746d --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeDecorator.java @@ -0,0 +1,413 @@ +package net.minecraft.server; + +import java.util.Random; + +public class BiomeDecorator { + + protected World a; + protected Random b; + protected BlockPosition c; + protected CustomWorldSettingsFinal d; + protected WorldGenerator e = new WorldGenClay(4); + protected WorldGenerator f; + protected WorldGenerator g; + protected WorldGenerator h; + protected WorldGenerator i; + protected WorldGenerator j; + protected WorldGenerator k; + protected WorldGenerator l; + protected WorldGenerator m; + protected WorldGenerator n; + protected WorldGenerator o; + protected WorldGenerator p; + protected WorldGenerator q; + protected WorldGenerator r; + protected WorldGenFlowers s; + protected WorldGenerator t; + protected WorldGenerator u; + protected WorldGenerator v; + protected WorldGenerator w; + protected WorldGenerator x; + protected WorldGenerator y; + protected int z; + protected int A; + protected int B; + protected int C; + protected int D; + protected int E; + protected int F; + protected int G; + protected int H; + protected int I; + protected int J; + protected int K; + public boolean L; + + public BiomeDecorator() { + this.f = new WorldGenSand(Blocks.SAND, 7); + this.g = new WorldGenSand(Blocks.GRAVEL, 6); + this.s = new WorldGenFlowers(Blocks.YELLOW_FLOWER, BlockFlowers.EnumFlowerVarient.DANDELION); + this.t = new WorldGenMushrooms(Blocks.BROWN_MUSHROOM); + this.u = new WorldGenMushrooms(Blocks.RED_MUSHROOM); + this.v = new WorldGenHugeMushroom(); + this.w = new WorldGenReed(); + this.x = new WorldGenCactus(); + this.y = new WorldGenWaterLily(); + this.B = 2; + this.C = 1; + this.H = 1; + this.I = 3; + this.J = 1; + this.L = true; + } + + // Migot start + protected BiomeDecorator createShallowCopy() { + return new BiomeDecorator(this); + } + + protected BiomeDecorator(BiomeDecorator decorator) { + this.f = decorator.f; + this.g = decorator.g; + this.s = decorator.s; + this.t = decorator.t; + this.u = decorator.u; + this.v = decorator.v; + this.w = decorator.w; + this.x = decorator.x; + this.y = decorator.y; + this.z = decorator.z; + this.A = decorator.A; + this.B = decorator.B; + this.C = decorator.C; + this.D = decorator.D; + this.E = decorator.E; + this.F = decorator.F; + this.G = decorator.G; + this.H = decorator.H; + this.I = decorator.I; + this.J = decorator.J; + this.K = decorator.K; + this.L = decorator.L; + } + // Migot end + + public void a(World world, Random random, BiomeBase biomebase, BlockPosition blockposition) { + if (this.a != null) { + // Migot start + BiomeDecorator decorator = this.createShallowCopy(); + decorator.a = world; + String s = world.getWorldData().getGeneratorOptions(); + if (s != null) { + decorator.d = CustomWorldSettingsFinal.CustomWorldSettings.a(s).b(); + } else { + decorator.d = CustomWorldSettingsFinal.CustomWorldSettings.a("").b(); + } + decorator.b = random; + decorator.c = blockposition; + decorator.h = new WorldGenMinable(Blocks.DIRT.getBlockData(), decorator.d.I); + decorator.i = new WorldGenMinable(Blocks.GRAVEL.getBlockData(), decorator.d.M); + decorator.j = new WorldGenMinable(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.GRANITE), decorator.d.Q); + decorator.k = new WorldGenMinable(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.DIORITE), decorator.d.U); + decorator.l = new WorldGenMinable(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.ANDESITE), decorator.d.Y); + decorator.m = new WorldGenMinable(Blocks.COAL_ORE.getBlockData(), decorator.d.ac); + decorator.n = new WorldGenMinable(Blocks.IRON_ORE.getBlockData(), decorator.d.ag); + decorator.o = new WorldGenMinable(Blocks.GOLD_ORE.getBlockData(), decorator.d.ak); + decorator.p = new WorldGenMinable(Blocks.REDSTONE_ORE.getBlockData(), decorator.d.ao); + decorator.q = new WorldGenMinable(Blocks.DIAMOND_ORE.getBlockData(), decorator.d.as); + decorator.r = new WorldGenMinable(Blocks.LAPIS_ORE.getBlockData(), decorator.d.aw); + decorator.a(biomebase); + decorator.a = null; + decorator.b = null; + // Migot end + } else { + this.a = world; + String s = world.getWorldData().getGeneratorOptions(); + + if (s != null) { + this.d = CustomWorldSettingsFinal.CustomWorldSettings.a(s).b(); + } else { + this.d = CustomWorldSettingsFinal.CustomWorldSettings.a("").b(); + } + + this.b = random; + this.c = blockposition; + this.h = new WorldGenMinable(Blocks.DIRT.getBlockData(), this.d.I); + this.i = new WorldGenMinable(Blocks.GRAVEL.getBlockData(), this.d.M); + this.j = new WorldGenMinable(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.GRANITE), this.d.Q); + this.k = new WorldGenMinable(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.DIORITE), this.d.U); + this.l = new WorldGenMinable(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.ANDESITE), this.d.Y); + this.m = new WorldGenMinable(Blocks.COAL_ORE.getBlockData(), this.d.ac); + this.n = new WorldGenMinable(Blocks.IRON_ORE.getBlockData(), this.d.ag); + this.o = new WorldGenMinable(Blocks.GOLD_ORE.getBlockData(), this.d.ak); + this.p = new WorldGenMinable(Blocks.REDSTONE_ORE.getBlockData(), this.d.ao); + this.q = new WorldGenMinable(Blocks.DIAMOND_ORE.getBlockData(), this.d.as); + this.r = new WorldGenMinable(Blocks.LAPIS_ORE.getBlockData(), this.d.aw); + this.a(biomebase); + this.a = null; + this.b = null; + } + } + + protected void a(BiomeBase biomebase) { + this.a(); + + int i; + int j; + int k; + + for (i = 0; i < this.I; ++i) { + j = this.b.nextInt(16) + 8; + k = this.b.nextInt(16) + 8; + this.f.generate(this.a, this.b, this.a.r(this.c.a(j, 0, k))); + } + + for (i = 0; i < this.J; ++i) { + j = this.b.nextInt(16) + 8; + k = this.b.nextInt(16) + 8; + this.e.generate(this.a, this.b, this.a.r(this.c.a(j, 0, k))); + } + + for (i = 0; i < this.H; ++i) { + j = this.b.nextInt(16) + 8; + k = this.b.nextInt(16) + 8; + this.g.generate(this.a, this.b, this.a.r(this.c.a(j, 0, k))); + } + + i = this.A; + if (this.b.nextInt(10) == 0) { + ++i; + } + + int l; + BlockPosition blockposition; + + for (j = 0; j < i; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + WorldGenTreeAbstract worldgentreeabstract = biomebase.a(this.b); + + worldgentreeabstract.e(); + blockposition = this.a.getHighestBlockYAt(this.c.a(k, 0, l)); + if (worldgentreeabstract.generate(this.a, this.b, blockposition)) { + worldgentreeabstract.a(this.a, this.b, blockposition); + } + } + + for (j = 0; j < this.K; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + this.v.generate(this.a, this.b, this.a.getHighestBlockYAt(this.c.a(k, 0, l))); + } + + BlockPosition blockposition1; + int i1; + int j1; + + for (j = 0; j < this.B; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() + 32; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + blockposition1 = this.c.a(k, j1, l); + BlockFlowers.EnumFlowerVarient blockflowers_enumflowervarient = biomebase.a(this.b, blockposition1); + BlockFlowers blockflowers = blockflowers_enumflowervarient.a().a(); + + if (blockflowers.getMaterial() != Material.AIR) { + this.s.a(blockflowers, blockflowers_enumflowervarient); + this.s.generate(this.a, this.b, blockposition1); + } + } + } + + for (j = 0; j < this.C; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + biomebase.b(this.b).generate(this.a, this.b, this.c.a(k, j1, l)); + } + } + + for (j = 0; j < this.D; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + (new WorldGenDeadBush()).generate(this.a, this.b, this.c.a(k, j1, l)); + } + } + + for (j = 0; j < this.z; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + + BlockPosition blockposition2; + + for (blockposition1 = this.c.a(k, j1, l); blockposition1.getY() > 0; blockposition1 = blockposition2) { + blockposition2 = blockposition1.down(); + if (!this.a.isEmpty(blockposition2)) { + break; + } + } + + this.y.generate(this.a, this.b, blockposition1); + } + } + + for (j = 0; j < this.E; ++j) { + if (this.b.nextInt(4) == 0) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + BlockPosition blockposition3 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)); + + this.t.generate(this.a, this.b, blockposition3); + } + + if (this.b.nextInt(8) == 0) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + blockposition1 = this.c.a(k, j1, l); + this.u.generate(this.a, this.b, blockposition1); + } + } + } + + if (this.b.nextInt(4) == 0) { + j = this.b.nextInt(16) + 8; + k = this.b.nextInt(16) + 8; + l = this.a.getHighestBlockYAt(this.c.a(j, 0, k)).getY() * 2; + if (l > 0) { + i1 = this.b.nextInt(l); + this.t.generate(this.a, this.b, this.c.a(j, i1, k)); + } + } + + if (this.b.nextInt(8) == 0) { + j = this.b.nextInt(16) + 8; + k = this.b.nextInt(16) + 8; + l = this.a.getHighestBlockYAt(this.c.a(j, 0, k)).getY() * 2; + if (l > 0) { + i1 = this.b.nextInt(l); + this.u.generate(this.a, this.b, this.c.a(j, i1, k)); + } + } + + for (j = 0; j < this.F; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + this.w.generate(this.a, this.b, this.c.a(k, j1, l)); + } + } + + for (j = 0; j < 10; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + this.w.generate(this.a, this.b, this.c.a(k, j1, l)); + } + } + + if (this.b.nextInt(32) == 0) { + j = this.b.nextInt(16) + 8; + k = this.b.nextInt(16) + 8; + l = this.a.getHighestBlockYAt(this.c.a(j, 0, k)).getY() * 2; + if (l > 0) { + i1 = this.b.nextInt(l); + (new WorldGenPumpkin()).generate(this.a, this.b, this.c.a(j, i1, k)); + } + } + + for (j = 0; j < this.G; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.a.getHighestBlockYAt(this.c.a(k, 0, l)).getY() * 2; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + this.x.generate(this.a, this.b, this.c.a(k, j1, l)); + } + } + + if (this.L) { + for (j = 0; j < 50; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.b.nextInt(248) + 8; + if (i1 > 0) { + j1 = this.b.nextInt(i1); + blockposition1 = this.c.a(k, j1, l); + (new WorldGenLiquids(Blocks.FLOWING_WATER)).generate(this.a, this.b, blockposition1); + } + } + + for (j = 0; j < 20; ++j) { + k = this.b.nextInt(16) + 8; + l = this.b.nextInt(16) + 8; + i1 = this.b.nextInt(this.b.nextInt(this.b.nextInt(240) + 8) + 8); + blockposition = this.c.a(k, i1, l); + (new WorldGenLiquids(Blocks.FLOWING_LAVA)).generate(this.a, this.b, blockposition); + } + } + + } + + protected void a(int i, WorldGenerator worldgenerator, int j, int k) { + int l; + + if (k < j) { + l = j; + j = k; + k = l; + } else if (k == j) { + if (j < 255) { + ++k; + } else { + --j; + } + } + + for (l = 0; l < i; ++l) { + BlockPosition blockposition = this.c.a(this.b.nextInt(16), this.b.nextInt(k - j) + j, this.b.nextInt(16)); + + worldgenerator.generate(this.a, this.b, blockposition); + } + + } + + protected void b(int i, WorldGenerator worldgenerator, int j, int k) { + for (int l = 0; l < i; ++l) { + BlockPosition blockposition = this.c.a(this.b.nextInt(16), this.b.nextInt(k) + this.b.nextInt(k) + j - k, this.b.nextInt(16)); + + worldgenerator.generate(this.a, this.b, blockposition); + } + + } + + protected void a() { + this.a(this.d.J, this.h, this.d.K, this.d.L); + this.a(this.d.N, this.i, this.d.O, this.d.P); + this.a(this.d.V, this.k, this.d.W, this.d.X); + this.a(this.d.R, this.j, this.d.S, this.d.T); + this.a(this.d.Z, this.l, this.d.aa, this.d.ab); + this.a(this.d.ad, this.m, this.d.ae, this.d.af); + this.a(this.d.ah, this.n, this.d.ai, this.d.aj); + this.a(this.d.al, this.o, this.d.am, this.d.an); + this.a(this.d.ap, this.p, this.d.aq, this.d.ar); + this.a(this.d.at, this.q, this.d.au, this.d.av); + this.b(this.d.ax, this.r, this.d.ay, this.d.az); + } +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeTheEndDecorator.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeTheEndDecorator.java index 4128e9c..bbd0dc6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeTheEndDecorator.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/BiomeTheEndDecorator.java @@ -8,6 +8,18 @@ public class BiomeTheEndDecorator extends BiomeDecorator { this.M = new WorldGenEnder(Blocks.END_STONE); } + // Migot start + public BiomeTheEndDecorator(BiomeTheEndDecorator decorator) { + super(decorator); + this.M = decorator.M; + } + + @Override + protected BiomeDecorator createShallowCopy() { + return new BiomeTheEndDecorator(this); + } + // Migot end + protected void a(BiomeBase biomebase) { this.a(); if (this.b.nextInt(5) == 0) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockCactus.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockCactus.java index ddc2135..845b964 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockCactus.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockCactus.java @@ -4,6 +4,7 @@ import java.util.Iterator; import java.util.Random; import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit +import org.bukkit.event.block.BlockPhysicsEvent; public class BlockCactus extends Block { @@ -64,7 +65,10 @@ public class BlockCactus extends Block { public void doPhysics(World world, BlockPosition blockposition, IBlockData iblockdata, Block block) { if (!this.e(world, blockposition)) { - world.setAir(blockposition, true); + org.bukkit.block.Block bukkit = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); + BlockPhysicsEvent event = new BlockPhysicsEvent(bukkit, bukkit.getTypeId()); + world.getServer().getPluginManager().callEvent(event); + if(!event.isCancelled()) world.setAir(blockposition, true); } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockRedstoneWire.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockRedstoneWire.java index 532188e..625ea6a 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockRedstoneWire.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/BlockRedstoneWire.java @@ -64,10 +64,16 @@ public class BlockRedstoneWire extends Block { } private IBlockData e(World world, BlockPosition blockposition, IBlockData iblockdata) { - iblockdata = this.a(world, blockposition, blockposition, iblockdata); - ArrayList arraylist = Lists.newArrayList(this.R); + // Migot start + ArrayList arraylist; + synchronized(this.R) { + iblockdata = this.a(world, blockposition, blockposition, iblockdata); + arraylist = Lists.newArrayList(this.R); + + this.R.clear(); + } + // Migot end - this.R.clear(); Iterator iterator = arraylist.iterator(); while (iterator.hasNext()) { 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 aa099d6..1935ba6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/Chunk.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Chunk.java @@ -50,6 +50,19 @@ public class Chunk { private int v; private ConcurrentLinkedQueue w; protected gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // Spigot + + // Migot start + private boolean unloaded = false; + + public boolean wasUnloaded() { + return this.unloaded; + } + + public void markAsUnloaded() { + this.unloaded = true; + } + // Migot end + // PaperSpigot start - Asynchronous light updates public AtomicInteger pendingLightUpdates = new AtomicInteger(); public long lightUpdateTime; @@ -1061,7 +1074,7 @@ public class Chunk { if (this.r && this.world.getTime() != this.lastSaved || this.q) { return true; } - } else if (this.r && this.world.getTime() >= this.lastSaved + MinecraftServer.getServer().autosavePeriod * 4) { // Spigot - Only save if we've passed 2 auto save intervals without modification + } else if (this.r && this.world.getTime() >= 600L) { return true; } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkProviderServer.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkProviderServer.java index 9753401..bcaf636 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -36,13 +36,27 @@ public class ChunkProviderServer implements IChunkProvider { public LongSet unloadQueue = new LongArraySet(); // CraftBukkit - LongHashSet // TacoSpigot - LongHashSet -> HashArraySet public Chunk emptyChunk; public IChunkProvider chunkProvider; - private IChunkLoader chunkLoader; + public IChunkLoader chunkLoader; // KigPaper - private -> public public boolean forceChunkLoad = false; // CraftBukkit - true -> false public Long2ObjectMap chunks = new Long2ObjectOpenHashMap(4096, 0.5f); // TacoSpigot - use trove Long2ObjectOpenHashMap instead of craftbukkit implementation (using inital capacity and load factor chosen by Amaranth in an old impl) public WorldServer world; + // Migot start + private ChunkRegionLoader checkedRegionLoader = null; + + public boolean doesChunkExist(int x, int z) { + if(this.checkedRegionLoader == null && this.chunkLoader instanceof ChunkRegionLoader) { + this.checkedRegionLoader = (ChunkRegionLoader) this.chunkLoader; + } + if(this.checkedRegionLoader != null) { + return this.checkedRegionLoader.chunkExists(this.world, x, z); + } + return false; + } + // Migot end + public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, IChunkProvider ichunkprovider) { - this.emptyChunk = new EmptyChunk(worldserver, 0, 0); + this.emptyChunk = new EmptyChunk(worldserver, Integer.MIN_VALUE, Integer.MIN_VALUE); // Migot this.world = worldserver; this.chunkLoader = ichunkloader; this.chunkProvider = ichunkprovider; @@ -347,7 +361,7 @@ public class ChunkProviderServer implements IChunkProvider { this.saveChunk(chunk); chunk.f(false); ++i; - if (i == 24 && !flag && false) { // Spigot + if (i == 24 && !flag) { return false; } } @@ -381,6 +395,7 @@ public class ChunkProviderServer implements IChunkProvider { if (!event.isCancelled()) { if (chunk != null) { + chunk.markAsUnloaded(); // Migot chunk.removeEntities(); this.saveChunk(chunk); this.saveChunkNOP(chunk); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkRegionLoader.java index 6b24490..baadcc8 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkRegionLoader.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/ChunkRegionLoader.java @@ -17,8 +17,10 @@ import org.apache.logging.log4j.Logger; public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { private static final Logger a = LogManager.getLogger(); - private Map b = new ConcurrentHashMap(); - private Set c = Collections.newSetFromMap(new ConcurrentHashMap()); + // KigPaper start - make public + public Map b = new ConcurrentHashMap(); + public Set c = Collections.newSetFromMap(new ConcurrentHashMap()); + // KigPaper end private final File d; private boolean e = false; @@ -29,6 +31,14 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { // CraftBukkit start public boolean chunkExists(World world, int i, int j) { ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j); + // Migot start + return this.chunkExists(world, chunkcoordintpair); + } + + public boolean chunkExists(World world, ChunkCoordIntPair chunkcoordintpair) { + int i = chunkcoordintpair.x; + int j = chunkcoordintpair.z; + // Migot end if (this.c.contains(chunkcoordintpair)) { if (this.b.containsKey(chunkcoordintpair)) { @@ -62,13 +72,15 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { NBTTagCompound nbttagcompound = (NBTTagCompound) this.b.get(chunkcoordintpair); if (nbttagcompound == null) { - DataInputStream datainputstream = RegionFileCache.c(this.d, i, j); + // KigPaper - use try-with-resources + // While this is always a ByteArrayInputStream (which does nothing on close), this is not something to be relied upon. + try (DataInputStream datainputstream = RegionFileCache.c(this.d, i, j)) { + if (datainputstream == null) { + return null; + } - if (datainputstream == null) { - return null; + nbttagcompound = NBTCompressedStreamTools.a(datainputstream); } - - nbttagcompound = NBTCompressedStreamTools.a(datainputstream); } return this.a(world, i, j, nbttagcompound); @@ -175,10 +187,10 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { } private void b(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { - DataOutputStream dataoutputstream = RegionFileCache.d(this.d, chunkcoordintpair.x, chunkcoordintpair.z); - - NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream); - dataoutputstream.close(); + // KigPaper - use try-with-resources + try (DataOutputStream dataoutputstream = RegionFileCache.d(this.d, chunkcoordintpair.x, chunkcoordintpair.z)) { + NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream); + } } public void b(World world, Chunk chunk) throws IOException {} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/ContainerWorkbench.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/ContainerWorkbench.java index 48d524e..862ca2a 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/ContainerWorkbench.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/ContainerWorkbench.java @@ -9,7 +9,7 @@ public class ContainerWorkbench extends Container { public InventoryCrafting craftInventory; // CraftBukkit - move initialization into constructor public IInventory resultInventory; // CraftBukkit - move initialization into constructor - private World g; + public World g; // KigPaper - make public private BlockPosition h; // CraftBukkit start private CraftInventoryView bukkitEntity = null; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java index 088beb2..d826472 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java @@ -124,7 +124,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer this.propertyManager = new PropertyManager(this.options); // CraftBukkit - CLI argument support this.p = new EULA(new File("eula.txt")); // Spigot Start - boolean eulaAgreed = Boolean.getBoolean( "com.mojang.eula.agree" ); + boolean eulaAgreed = true; if ( eulaAgreed ) { System.err.println( "You have used the Spigot command line EULA agreement flag." ); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EnchantmentManager.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EnchantmentManager.java index 9865681..da928a6 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EnchantmentManager.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EnchantmentManager.java @@ -148,6 +148,9 @@ public class EnchantmentManager { EnchantmentManager.b.a = 0; } + // KigPaper start + EnchantmentManager.b.b = null; + // KigPaper end return (EnchantmentManager.b.a + 1 >> 1) + EnchantmentManager.a.nextInt((EnchantmentManager.b.a >> 1) + 1); } @@ -169,6 +172,10 @@ public class EnchantmentManager { a((EnchantmentManager.EnchantmentModifier) EnchantmentManager.d, entityliving.bA()); } + // KigPaper start + EnchantmentManager.d.a = null; + EnchantmentManager.d.b = null; + // KigPaper end } public static void b(EntityLiving entityliving, Entity entity) { @@ -182,6 +189,10 @@ public class EnchantmentManager { a((EnchantmentManager.EnchantmentModifier) EnchantmentManager.e, entityliving.bA()); } + // KigPaper start + EnchantmentManager.e.a = null; + EnchantmentManager.e.b = null; + // KigPaper end } public static int a(EntityLiving entityliving) { 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 68bf2e6..a4f426c 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/Entity.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Entity.java @@ -1,13 +1,11 @@ package net.minecraft.server; -import java.util.Iterator; -import java.util.List; -import java.util.Random; -import java.util.UUID; +import java.util.*; import java.util.concurrent.Callable; // CraftBukkit start import com.elevatemc.spigot.util.FastRandom; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -36,6 +34,7 @@ import org.bukkit.plugin.PluginManager; // CraftBukkit end // PaperSpigot start +import org.github.paperspigot.PaperSpigotConfig; import org.spigotmc.event.entity.EntityDismountEvent; // PaperSpigot end @@ -49,7 +48,7 @@ public abstract class Entity implements ICommandListener { // CraftBukikt end private static final AxisAlignedBB a = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D); - private static int entityCount; + private static int entityCount = 1; private int id; public double j; public boolean k; @@ -121,10 +120,6 @@ public abstract class Entity implements ICommandListener { public int portalCooldown; protected boolean ak; - public final boolean inPortal() { - return this.ak; - } // Paper - OBFHELPER - protected int al; public int dimension; protected BlockPosition an; @@ -163,6 +158,16 @@ public abstract class Entity implements ICommandListener { public void inactiveTick() { } // Spigot end + // Migot start + private int targetDimension; + private boolean isInLava; + private int lastLavaCheck = Integer.MIN_VALUE; + + public int getTargetDimension() { + return this.targetDimension; + } + // Migot end + public int getId() { return this.id; } @@ -191,6 +196,7 @@ public abstract class Entity implements ICommandListener { this.setPosition(0.0D, 0.0D, 0.0D); if (world != null) { this.dimension = world.worldProvider.getDimension(); + this.targetDimension = this.dimension; // Migot // Spigot start this.defaultActivationState = org.spigotmc.ActivationRange.initializeEntityActivationState(this, world.spigotConfig); } else { @@ -304,7 +310,7 @@ public abstract class Entity implements ICommandListener { this.lastZ = this.locZ; this.lastPitch = this.pitch; this.lastYaw = this.yaw; - if (!this.world.isClientSide && this.world instanceof WorldServer) { + if (!this.world.isClientSide && this.world instanceof WorldServer && !(this instanceof EntityProjectile) && !(this instanceof EntityArrow) && !(this instanceof EntityFireball)) { // Migot this.world.methodProfiler.a("portal"); MinecraftServer minecraftserver = ((WorldServer) this.world).getMinecraftServer(); int i = this.L(); @@ -842,10 +848,12 @@ public abstract class Entity implements ICommandListener { BlockPosition blockposition1 = new BlockPosition(this.getBoundingBox().d - 0.001D, this.getBoundingBox().e - 0.001D, this.getBoundingBox().f - 0.001D); if (this.world.areChunksLoadedBetween(blockposition, blockposition1)) { - for (int i = blockposition.getX(); i <= blockposition1.getX(); ++i) { - for (int j = blockposition.getY(); j <= blockposition1.getY(); ++j) { + // KigPaper - Start - invert loop + for (int i = blockposition1.getY(); i >= blockposition.getY(); --i) { + // KigPaper - End + for (int j = blockposition.getX(); j <= blockposition1.getX(); ++j) { for (int k = blockposition.getZ(); k <= blockposition1.getZ(); ++k) { - BlockPosition blockposition2 = new BlockPosition(i, j, k); + BlockPosition blockposition2 = new BlockPosition(j, i, k); IBlockData iblockdata = this.world.getType(blockposition2); try { @@ -898,6 +906,19 @@ public abstract class Entity implements ICommandListener { protected void a(double d0, boolean flag, Block block, BlockPosition blockposition) { if (flag) { if (this.fallDistance > 0.0F) { + // KigPaper start - run again if we need accurate detection at high falling speeds + if (PaperSpigotConfig.accurateBlockCollisions) { + try { + this.checkBlockCollisions(); + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.a(throwable, "Checking entity block collision"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being checked for collision"); + + this.appendEntityCrashDetails(crashreportsystemdetails); + throw new ReportedException(crashreport); + } + } + // KigPaper end if (block != null) { block.fallOn(this.world, blockposition, this, this.fallDistance); } else { @@ -943,7 +964,36 @@ public abstract class Entity implements ICommandListener { } public boolean W() { - if (this.world.a(this.getBoundingBox().grow(0.0D, -0.4000000059604645D, 0.0D).shrink(0.001D, 0.001D, 0.001D), Material.WATER, this)) { + AxisAlignedBB boundingBox = this.getBoundingBox(); + // KigPaper start + if (PaperSpigotConfig.accurateBlockCollisions && this instanceof EntityPlayer) { + // Account for vertical speed in minY + AxisAlignedBB tmp = new AxisAlignedBB(boundingBox.a, boundingBox.b + this.motY / 2, boundingBox.c, boundingBox.d, boundingBox.e, boundingBox.f); + + boolean useTmp = true; + int tmpX = MathHelper.floor(tmp.a); + int tmpMaxX = MathHelper.floor(tmp.d); + int tmpY = MathHelper.floor(tmp.b); + int tmpMaxY = MathHelper.floor(tmp.e); + int tmpZ = MathHelper.floor(tmp.c); + int tmpMaxZ = MathHelper.floor(tmp.f); + BlockPosition.MutableBlockPosition blockPosition = new BlockPosition.MutableBlockPosition(); + Block block; + for (int x = tmpX; x <= tmpMaxX; ++x) { + for (int y = tmpY; y <= tmpMaxY; ++y) { + for (int z = tmpZ; z <= tmpMaxZ; ++z) { + block = world.getType(blockPosition.c(x, y, z)).getBlock(); + + if (block.getMaterial().isSolid() || world.getType(blockPosition.c(x, Math.max(y - 1, 0), z)).getBlock().getMaterial().isSolid()) { + useTmp = false; + } + } + } + } + if (useTmp) boundingBox = tmp; + } + // KigPaper end + if (this.world.a(boundingBox.grow(0.0D, -0.4000000059604645D, 0.0D).shrink(0.001D, 0.001D, 0.001D), Material.WATER, this)) { if (!this.inWater && !this.justCreated) { this.X(); } @@ -1029,7 +1079,12 @@ public abstract class Entity implements ICommandListener { } public boolean ab() { - return this.world.a(this.getBoundingBox().grow(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.LAVA); + int currentTick = MinecraftServer.currentTick; + if (this.lastLavaCheck != currentTick) { + this.lastLavaCheck = currentTick; + this.isInLava = this.world.a(this.getBoundingBox().grow(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.LAVA); + } + return this.isInLava; } public void a(float f, float f1, float f2) { @@ -1649,7 +1704,7 @@ public abstract class Entity implements ICommandListener { this.vehicle = null; } else { // CraftBukkit start - if ((this.bukkitEntity instanceof LivingEntity) && (entity.getBukkitEntity() instanceof Vehicle) && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, true)) { + if ((this.bukkitEntity instanceof LivingEntity) && (entity.getBukkitEntity() instanceof Vehicle) && entity.world.isChunkLoaded(MathHelper.floor(entity.locX) >> 4, MathHelper.floor(entity.locZ) >> 4, true)) { // Migot - fix rounding error // It's possible to move from one vehicle to another. We need to check if they're already in a vehicle, and fire an exit event if they are. VehicleExitEvent exitEvent = null; if (this.vehicle != null && this.vehicle.getBukkitEntity() instanceof Vehicle) { @@ -1986,6 +2041,15 @@ public abstract class Entity implements ICommandListener { } public void c(int i) { + // Migot start - Entities will be queued and teleported after all worlds have been ticked + if(i != this.dimension) { + this.targetDimension = i; + this.world.queueEntityForDimensionChange(this); + } + } + + public void changeDimension(int i) { + // Migot end if (!this.world.isClientSide && !this.dead) { this.world.methodProfiler.a("changeDimension"); MinecraftServer minecraftserver = MinecraftServer.getServer(); @@ -2015,7 +2079,9 @@ public abstract class Entity implements ICommandListener { return; } exit = event.useTravelAgent() ? event.getPortalTravelAgent().findOrCreate(event.getTo()) : event.getTo(); - this.teleportTo(exit, true); + if(exit != null) { // Migot + this.teleportTo(exit, true); + } } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityArrow.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityArrow.java index 253a9d8..a4c41bf 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityArrow.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityArrow.java @@ -231,6 +231,8 @@ public class EntityArrow extends Entity implements IProjectile { if (!((EntityPlayer) shooter).getBukkitEntity().canSee(((EntityPlayer) movingobjectposition.entity).getBukkitEntity())) { movingobjectposition = null; } + } else if (movingobjectposition != null && movingobjectposition.entity instanceof EntityArmorStand && movingobjectposition.entity.isInvisible()) { + movingobjectposition = null; } // PaperSpigot end // TacoSpigot start - call better event @@ -290,7 +292,9 @@ public class EntityArrow extends Entity implements IProjectile { } if (this.shooter != null && movingobjectposition.entity != this.shooter && movingobjectposition.entity instanceof EntityHuman && this.shooter instanceof EntityPlayer) { - ((EntityPlayer) this.shooter).playerConnection.sendPacket(new PacketPlayOutGameStateChange(6, 0.0F)); + EntityPlayer shooter = (EntityPlayer) this.shooter; + shooter.p(movingobjectposition.entity); // KigPaper - set attacked entity (used for wolf pathfinding) + shooter.playerConnection.sendPacket(new PacketPlayOutGameStateChange(6, 0.0F)); } } 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 9835c96..694ba59 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityCreature.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityCreature.java @@ -43,7 +43,7 @@ public abstract class EntityCreature extends EntityInsentient { public void setSearchResult(PathSearchJobEntity pathSearchJobEntity, Entity target, PathEntity pathentity) { this.queuingManager.checkLastSearchResult(pathSearchJobEntity); - if (this.goalTarget != null && this.goalTarget.equals(target)) { + if (this.getGoalTarget() != null && this.getGoalTarget().equals(target)) { this.returnedPathEntity = pathentity; } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderman.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderman.java index f3afbbd..c3f528a 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderman.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityEnderman.java @@ -88,7 +88,7 @@ public class EntityEnderman extends EntityMonster { return false; } else { Vec3D vec3d = entityhuman.d(1.0F).a(); - Vec3D vec3d1 = new Vec3D(this.locX - entityhuman.locX, this.getBoundingBox().b + (double) (this.length / 2.0F) - (entityhuman.locY + (double) entityhuman.getHeadHeight()), this.locZ - entityhuman.locZ); + Vec3D vec3d1 = new Vec3D(this.locX - entityhuman.locX, (this.locY + (double) this.getHeadHeight()) - (entityhuman.locY + (double) entityhuman.getHeadHeight()), this.locZ - entityhuman.locZ); // Migot double d0 = vec3d1.b(); vec3d1 = vec3d1.a(); @@ -145,7 +145,7 @@ public class EntityEnderman extends EntityMonster { } protected boolean b(Entity entity) { - Vec3D vec3d = new Vec3D(this.locX - entity.locX, this.getBoundingBox().b + (double) (this.length / 2.0F) - entity.locY + (double) entity.getHeadHeight(), this.locZ - entity.locZ); + Vec3D vec3d = new Vec3D(this.locX - entity.locX, this.locY + (double) this.getHeadHeight() - entity.locY + (double) entity.getHeadHeight(), this.locZ - entity.locZ); // Migot vec3d = vec3d.a(); double d0 = 16.0D; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityExperienceOrb.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityExperienceOrb.java index 0035be9..f16e219 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityExperienceOrb.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityExperienceOrb.java @@ -59,11 +59,28 @@ public class EntityExperienceOrb extends Entity { this.j(this.locX, (this.getBoundingBox().b + this.getBoundingBox().e) / 2.0D, this.locZ); double d0 = 8.0D; + // Migot start + EntityHuman foundTarget = null; if (this.targetTime < this.a - 20 + this.getId() % 100) { if (this.targetPlayer == null || this.targetPlayer.h(this) > d0 * d0) { - this.targetPlayer = this.world.findNearbyPlayer(this, d0); + foundTarget = this.world.findNearbyPlayer(this, d0); + if(foundTarget == null) { + this.targetPlayer = foundTarget; + } else if(foundTarget != null && !foundTarget.equals(this.targetPlayer)) { + // CraftBukkit start + EntityTargetEvent event = CraftEventFactory.callEntityTargetEvent(this, foundTarget, EntityTargetEvent.TargetReason.CLOSEST_PLAYER); + Entity target = event.getTarget() == null ? null : ((org.bukkit.craftbukkit.entity.CraftEntity) event.getTarget()).getHandle(); + if(!event.isCancelled()) { + if(target == null) { + this.targetPlayer = null; + } else if(target instanceof EntityHuman) { + this.targetPlayer = (EntityHuman) target; + } + } + // CraftBukkit end + } } - + // Migot end this.targetTime = this.a; } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityFishingHook.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityFishingHook.java index 2a90f79..80c5acf 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityFishingHook.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityFishingHook.java @@ -192,6 +192,8 @@ public class EntityFishingHook extends Entity { if (!((EntityPlayer) owner).getBukkitEntity().canSee(((EntityPlayer) movingobjectposition.entity).getBukkitEntity())) { movingobjectposition = null; } + } else if (movingobjectposition != null && movingobjectposition.entity instanceof EntityArmorStand && movingobjectposition.entity.isInvisible()) { + movingobjectposition = null; } // PaperSpigot end @@ -360,9 +362,6 @@ public class EntityFishingHook extends Entity { this.motY *= (double) f2; this.motZ *= (double) f2; this.setPosition(this.locX, this.locY, this.locZ); - if (inPortal()) { - die(); - } } } } 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 fa26a31..c4ba464 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityInsentient.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityInsentient.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -25,7 +26,7 @@ public abstract class EntityInsentient extends EntityLiving { private Navigation navigation; public PathfinderGoalSelector goalSelector; public PathfinderGoalSelector targetSelector; - public EntityLiving goalTarget; + private WeakReference goalTarget; // KigPaper - wrap in WeakReference private EntitySenses bk; private ItemStack[] equipment = new ItemStack[5]; public float[] dropChances = new float[5]; @@ -86,7 +87,7 @@ public abstract class EntityInsentient extends EntityLiving { } public EntityLiving getGoalTarget() { - return this.goalTarget; + return this.goalTarget == null ? null : this.goalTarget.get(); // KigPaper - WeakReference } public void setGoalTarget(EntityLiving entityliving) { @@ -119,7 +120,7 @@ public abstract class EntityInsentient extends EntityLiving { entityliving = null; } } - this.goalTarget = entityliving; + this.goalTarget = new WeakReference<>(entityliving); // KigPaper - WeakReference // CraftBukkit end } @@ -277,6 +278,11 @@ public abstract class EntityInsentient extends EntityLiving { nbttagcompound.set("Leash", nbttagcompound1); } + // Migot start + else if (this.bq != null) { + nbttagcompound.set("Leash", this.bq); + } + // Migot end if (this.ce()) { nbttagcompound.setBoolean("NoAI", this.ce()); @@ -889,11 +895,12 @@ public abstract class EntityInsentient extends EntityLiving { EntityLiving entityliving = (EntityLiving) iterator.next(); if (entityliving.getUniqueID().equals(uuid)) { - this.bp = entityliving; + this.setLeashHolder(entityliving, true); // Migot break; } } - } else if (this.bq.hasKeyOfType("X", 99) && this.bq.hasKeyOfType("Y", 99) && this.bq.hasKeyOfType("Z", 99)) { + } + if (this.bp == null && this.bq.hasKeyOfType("X", 99) && this.bq.hasKeyOfType("Y", 99) && this.bq.hasKeyOfType("Z", 99)) { // Migot BlockPosition blockposition = new BlockPosition(this.bq.getInt("X"), this.bq.getInt("Y"), this.bq.getInt("Z")); EntityLeash entityleash = EntityLeash.b(this.world, blockposition); @@ -901,8 +908,9 @@ public abstract class EntityInsentient extends EntityLiving { entityleash = EntityLeash.a(this.world, blockposition); } - this.bp = entityleash; - } else { + this.setLeashHolder(entityleash, true); // Migot + } + if (this.bp == null) { // Migot this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit this.unleash(false, true); } 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 32b1df1..57431b8 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityLiving.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityLiving.java @@ -17,6 +17,7 @@ import com.google.common.collect.Lists; import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.util.CraftPotionUtil; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; @@ -1786,7 +1787,10 @@ public abstract class EntityLiving extends Entity { // CraftBukkit end // PaperSpigot start - make dismountEvent cancellable EntityDismountEvent dismountEvent = new EntityDismountEvent(this.getBukkitEntity(), this.vehicle.getBukkitEntity()); // Spigot - Bukkit.getPluginManager().callEvent(dismountEvent); + // KigPaper - only trigger EntityDismountEvent if the dismount was triggered by sneaking + if(!(this.bukkitEntity instanceof Player) || ((Player) this.bukkitEntity).isSneaking()) { + Bukkit.getPluginManager().callEvent(dismountEvent); + } if (dismountEvent.isCancelled()) return; // PaperSpigot end diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityPlayer.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityPlayer.java index 5a55be1..a2e1977 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityPlayer.java @@ -523,6 +523,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting { } public void c(int i) { + // Migot Start + super.c(i); + } + + public void changeDimension(int i) { + // Migot end // PaperSpigot start - Allow configurable end portal credits boolean endPortal = this.dimension == 1 && i == 1; if (endPortal) { @@ -532,7 +538,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { this.viewingCredits = true; this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(4, 0.0F)); } - // PaperSpigot end + // PaperSpigot end } else { if (this.dimension == 0 && i == 1) { this.b((Statistic) AchievementList.C); @@ -563,7 +569,6 @@ public class EntityPlayer extends EntityHuman implements ICrafting { this.bN = -1; } // PaperSpigot end - } public boolean a(EntityPlayer entityplayer) { 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 5eab0d0..18ed9a2 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityProjectile.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityProjectile.java @@ -158,6 +158,8 @@ public abstract class EntityProjectile extends Entity implements IProjectile { if (!((EntityPlayer) shooter).getBukkitEntity().canSee(((EntityPlayer) movingobjectposition.entity).getBukkitEntity())) { movingobjectposition = null; } + } else if (movingobjectposition != null && movingobjectposition.entity instanceof EntityArmorStand && movingobjectposition.entity.isInvisible()) { + movingobjectposition = null; } // PaperSpigot end diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityTrackerEntry.java index 421f871..b9a2fca 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityTrackerEntry.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/EntityTrackerEntry.java @@ -1,11 +1,9 @@ package net.minecraft.server; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import com.elevatemc.spigot.eSpigotFeature; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -275,7 +273,34 @@ public class EntityTrackerEntry { DataWatcher datawatcher = this.tracker.getDataWatcher(); if (datawatcher.a()) { - this.broadcastIncludingSelf(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false)); + if (eSpigotFeature.OBFUSCATE_HEALTH.isEnabled()) { + List changedMetadata = datawatcher.b(); + Iterator iter = changedMetadata.iterator(); + boolean found = false; + + while (iter.hasNext()) { + DataWatcher.WatchableObject watchable = iter.next(); + if (watchable.a() == 6) { + iter.remove(); + found = true; + } + } + + if (found) { + changedMetadata.add(new DataWatcher.WatchableObject(3, 6, 1.0F)); + } + + PacketPlayOutEntityMetadata metadataPacket = new PacketPlayOutEntityMetadata(this.tracker.getId(), changedMetadata); + + // Beanes - Broadcast the modified metadata packet to everyone + this.broadcast(metadataPacket); + + // Beanes - Send the correct metadata packet to the player + if (this.tracker instanceof EntityPlayer) + ((EntityPlayer) this.tracker).playerConnection.sendPacket(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false)); + } else { + this.broadcastIncludingSelf(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false)); + } } if (this.tracker instanceof EntityLiving) { @@ -405,7 +430,13 @@ public class EntityTrackerEntry { // CraftBukkit start - Fix for nonsensical head yaw this.i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F); - this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i)); + // KigPaper + if (this.tracker instanceof EntityLiving) { + this.i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F); + // CraftBukkit what the fuck were you thinking? + //this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i)); // KigPaper + entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i)); + } // CraftBukkit end if (this.tracker instanceof EntityLiving) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/FileIOThread.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/FileIOThread.java index c9b3bf4..4476f3b 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/FileIOThread.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/FileIOThread.java @@ -12,6 +12,16 @@ public class FileIOThread implements Runnable { private volatile long d; private volatile boolean e; + // Migot start + public boolean isDone() { + return this.c == this.d; + } + + public void setNoDelay(boolean active) { + this.e = active; + } + // Migot end + private FileIOThread() { Thread thread = new Thread(this, "File IO Thread"); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/IntCache.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/IntCache.java index 95060a4..3cab644 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/IntCache.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/IntCache.java @@ -1,63 +1,115 @@ package net.minecraft.server; import com.google.common.collect.Lists; + +// Migot start +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +// Migot end public class IntCache { - private static int a = 256; - private static List b = Lists.newArrayList(); - private static List c = Lists.newArrayList(); - private static List d = Lists.newArrayList(); - private static List e = Lists.newArrayList(); + // Migot start - Refactored IntCache to be thread local instead of static + private static final ThreadLocal caches = new ThreadLocal() { + @Override + protected IntCache initialValue() { + IntCache cache = new IntCache(); + synchronized(allCaches) { + allCaches.add(new WeakReference(cache)); + } + return new IntCache(); + } + }; - public static synchronized int[] a(int i) { + private static List> allCaches = new ArrayList>(); + + private int a = 256; + private List b = Lists.newArrayList(); + private List c = Lists.newArrayList(); + private List d = Lists.newArrayList(); + private List e = Lists.newArrayList(); + + public static int[] a(int i) { + return caches.get().aNonStatic(i); + } + + public int[] aNonStatic(int i) { int[] aint; if (i <= 256) { - if (IntCache.b.isEmpty()) { + if (this.b.isEmpty()) { aint = new int[256]; - if (c.size() < org.spigotmc.SpigotConfig.intCacheLimit) IntCache.c.add(aint); + if (c.size() < org.spigotmc.SpigotConfig.intCacheLimit) this.c.add(aint); return aint; } else { - aint = (int[]) IntCache.b.remove(IntCache.b.size() - 1); - if (c.size() < org.spigotmc.SpigotConfig.intCacheLimit) IntCache.c.add(aint); + aint = (int[]) this.b.remove(this.b.size() - 1); + if (c.size() < org.spigotmc.SpigotConfig.intCacheLimit) this.c.add(aint); return aint; } - } else if (i > IntCache.a) { - IntCache.a = i; - IntCache.d.clear(); - IntCache.e.clear(); - aint = new int[IntCache.a]; - if (e.size() < org.spigotmc.SpigotConfig.intCacheLimit) IntCache.e.add(aint); + } else if (i > this.a) { + this.a = i; + this.d.clear(); + this.e.clear(); + aint = new int[this.a]; + if (e.size() < org.spigotmc.SpigotConfig.intCacheLimit) this.e.add(aint); return aint; - } else if (IntCache.d.isEmpty()) { - aint = new int[IntCache.a]; - if (e.size() < org.spigotmc.SpigotConfig.intCacheLimit) IntCache.e.add(aint); + } else if (this.d.isEmpty()) { + aint = new int[this.a]; + if (e.size() < org.spigotmc.SpigotConfig.intCacheLimit) this.e.add(aint); return aint; } else { - aint = (int[]) IntCache.d.remove(IntCache.d.size() - 1); - if (e.size() < org.spigotmc.SpigotConfig.intCacheLimit) IntCache.e.add(aint); + aint = (int[]) this.d.remove(this.d.size() - 1); + if (e.size() < org.spigotmc.SpigotConfig.intCacheLimit) this.e.add(aint); return aint; } } - public static synchronized void a() { - if (!IntCache.d.isEmpty()) { - IntCache.d.remove(IntCache.d.size() - 1); - } - - if (!IntCache.b.isEmpty()) { - IntCache.b.remove(IntCache.b.size() - 1); - } - - IntCache.d.addAll(IntCache.e); - IntCache.b.addAll(IntCache.c); - IntCache.e.clear(); - IntCache.c.clear(); + public static void a() { + caches.get().aNonStatic(); } - public static synchronized String b() { - return "cache: " + IntCache.d.size() + ", tcache: " + IntCache.b.size() + ", allocated: " + IntCache.e.size() + ", tallocated: " + IntCache.c.size(); + public void aNonStatic() { + if (!this.d.isEmpty()) { + this.d.remove(this.d.size() - 1); + } + + if (!this.b.isEmpty()) { + this.b.remove(this.b.size() - 1); + } + + this.d.addAll(this.e); + this.b.addAll(this.c); + this.e.clear(); + this.c.clear(); } + + public static String b() { + int cache = 0; + int tcache = 0; + int allocated = 0; + int tallocated = 0; + int numberOfCaches; + + synchronized(allCaches) { + numberOfCaches = allCaches.size(); + Iterator> iter = allCaches.iterator(); + while(iter.hasNext()) { + WeakReference reference = iter.next(); + IntCache intcache = reference.get(); + if(intcache != null) { + cache += intcache.d.size(); + tcache += intcache.b.size(); + allocated += intcache.e.size(); + tallocated += intcache.c.size(); + } else { + iter.remove(); + } + } + } + + return String.valueOf(numberOfCaches) + " IntCaches. In Total => cache: " + cache + ", tcache: " + tcache + ", allocated: " + allocated + ", tallocated: " + tallocated; + } + // Migot end } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java index 60bff23..47a47c5 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1,6 +1,7 @@ package net.minecraft.server; import co.aikar.timings.SpigotTimings; +import com.elevatemc.spigot.threading.ThreadingManager; import com.google.common.base.Charsets; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; @@ -10,6 +11,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfileRepository; import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import com.elevatemc.spigot.world.AutoSaveJob; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; @@ -91,6 +93,49 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs public int autosavePeriod; public double[] recentTps = new double[3]; // PaperSpigot - Fine have your darn compat with bad plugins + // Migot start + private LinkedList autoSaveWorlds = new LinkedList(); + private int autoSaveDelay = 0; + private boolean autoSaveOrdered = false; + + private void queueWorldsForAutoSave() { + if (!this.N) { + this.autoSaveWorlds.clear(); + for (int j = 0; j < this.worlds.size(); ++j) { + WorldServer worldserver = this.worlds.get(j); + if(worldserver != null) { + this.autoSaveWorlds.add(new AutoSaveJob(AutoSaveJob.JobDetail.WORLD_SAVE, worldserver)); + this.autoSaveWorlds.add(new AutoSaveJob(AutoSaveJob.JobDetail.WORLD_SAVEEVENT, worldserver)); + } + } + int queuesize = this.autoSaveWorlds.size() / 2; + this.autoSaveDelay = 0; + this.autoSaveOrdered = true; + this.info("[AutoSave] " + queuesize + " worlds - Starting ..."); + } + } + + private void autoSaveNextWorld() throws ExceptionWorldConflict { + if(!this.autoSaveWorlds.isEmpty()) { + if(this.autoSaveDelay++ > 20) { // delay of 1 seconds between checks of the auto-save job queue + this.autoSaveDelay = 0; + if(this.autoSaveWorlds.getFirst().process()) { + this.autoSaveWorlds.removeFirst(); + } + } + } else if(this.autoSaveOrdered){ + this.info("[AutoSave] Done."); + this.autoSaveOrdered = false; + } + } + + public void cancelHeavyCalculationsForAllWorlds(boolean cancel) { + for(WorldServer ws: this.worlds) { + ws.cancelHeavyCalculations(cancel); + } + } + // Migot end + private ServerConnection q; // Spigot private String serverIp; private int u = -1; @@ -128,9 +173,12 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs // CraftBukkit start private boolean hasStopped = false; + private final ThreadingManager threadingManager; + public MinecraftServer(OptionSet options, Proxy proxy, File file1) { io.netty.util.ResourceLeakDetector.setEnabled(false); // Spigot - disable this.e = proxy; + this.threadingManager = new ThreadingManager(); MinecraftServer.l = this; // this.universe = file; // CraftBukkit // this.q = new ServerConnection(this); // Spigot @@ -634,6 +682,8 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs this.Z.c(); } //Spigot end + + this.threadingManager.shutdown(); } } @@ -687,17 +737,17 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs if (wait > 0L) { if (catchupTime < 2E6) { wait += Math.abs(catchupTime); - } - if (wait < catchupTime) { + } else /* KigPaper */ if (wait < catchupTime) { catchupTime -= wait; wait = 0L; - } else if (catchupTime > 2E6) { + } else /*if (catchupTime > 2E6)*/ { // KigPaper wait -= catchupTime; catchupTime = 0L; } } if (wait > 0L) { Thread.sleep(1L); + curTime = System.nanoTime(); // KigPaper wait = MinecraftServer.TICK_TIME - (curTime - lastTick); } @@ -790,19 +840,24 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs if (file.isFile()) { ByteBuf bytebuf = Unpooled.buffer(); + ByteBuf faviconBuffer = null; // KigPaper try { BufferedImage bufferedimage = ImageIO.read(file); Validate.validState(bufferedimage.getWidth() == 64, "Must be 64 pixels wide"); Validate.validState(bufferedimage.getHeight() == 64, "Must be 64 pixels high"); ImageIO.write(bufferedimage, "PNG", new ByteBufOutputStream(bytebuf)); - ByteBuf bytebuf1 = Base64.encode(bytebuf); + //ByteBuf bytebuf1 = Base64.encode(bytebuf); // KigPaper + faviconBuffer = Base64.encode(bytebuf); - serverping.setFavicon("data:image/png;base64," + bytebuf1.toString(Charsets.UTF_8)); + serverping.setFavicon("data:image/png;base64," + faviconBuffer.toString(Charsets.UTF_8)); } catch (Exception exception) { MinecraftServer.LOGGER.error("Couldn't load server icon", exception); } finally { bytebuf.release(); + // KigPaper start + if(faviconBuffer != null) faviconBuffer.release(); + // KigPaper end } } @@ -846,24 +901,23 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs } if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit - SpigotTimings.worldSaveTimer.startTiming(); // Spigot + //SpigotTimings.worldSaveTimer.startTiming(); // Spigot // Migot - moved to com.elevatemc.spigot.world.AutoSaveJob this.methodProfiler.a("save"); this.v.savePlayers(); - // Spigot Start - // We replace this with saving each individual world as this.saveChunks(...) is broken, - // and causes the main thread to sleep for random amounts of time depending on chunk activity - // Also pass flag to only save modified chunks - server.playerCommandState = true; - for (World world : worlds) { - world.getWorld().save(false); - } - server.playerCommandState = false; - // this.saveChunks(true); - // Spigot End + this.queueWorldsForAutoSave(); // Migot this.methodProfiler.b(); - SpigotTimings.worldSaveTimer.stopTiming(); // Spigot + //SpigotTimings.worldSaveTimer.stopTiming(); // Spigot // Migot - moved to com.elevatemc.spigot.world.AutoSaveJob } + // Migot start + if(this.autoSaveOrdered) { + this.autoSaveNextWorld(); + } + + long tickTime = System.nanoTime() - i; + ThreadingManager.checkTickTime(tickTime); + // Migot end + this.methodProfiler.a("tallying"); this.h[this.ticks % 100] = System.nanoTime() - i; this.methodProfiler.b(); @@ -1013,6 +1067,12 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs // this.i[i][this.ticks % 100] = System.nanoTime() - j; // CraftBukkit } + // Migot start + for(i = 0; i < this.worlds.size(); ++i) { + this.worlds.get(i).processDimensionChangeQueue(); + } + // Migot end + this.methodProfiler.c("connection"); SpigotTimings.connectionTimer.startTiming(); // Spigot this.aq().c(); @@ -1083,7 +1143,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs } public String getVersion() { - return "1.8.8"; + return "1.8.9"; } public int I() { @@ -1118,7 +1178,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs } public String getServerModName() { - return "TacoSpigot"; // TacoSpigot - TacoSpigot // PaperSpigot - PaperSpigot > // Spigot - Spigot > // CraftBukkit - cb > vanilla! + return "eSpigot"; // eSpigot - eSpigot // TacoSpigot - TacoSpigot // PaperSpigot - PaperSpigot > // Spigot - Spigot > // CraftBukkit - cb > vanilla! } public CrashReport b(CrashReport crashreport) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/MobSpawnerAbstract.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/MobSpawnerAbstract.java index 897f8f1..637bb86 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/MobSpawnerAbstract.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/MobSpawnerAbstract.java @@ -30,6 +30,7 @@ public abstract class MobSpawnerAbstract { private int requiredPlayerRange = 16; private int spawnRange = 4; private int tickDelay = 0; // PaperSpigot + private int spawningPenalty = 0; // Migot public MobSpawnerAbstract() {} @@ -138,6 +139,14 @@ public abstract class MobSpawnerAbstract { if (flag) { this.h(); } + // Migot start + else { + this.spawnDelay += this.spawningPenalty; + if(this.spawningPenalty < 40) { + this.spawningPenalty++; + } + } + // Migot end } } @@ -238,6 +247,8 @@ public abstract class MobSpawnerAbstract { this.spawnDelay = this.minSpawnDelay + this.a().random.nextInt(i); } + this.spawningPenalty = 0; // Migot + if (this.mobs.size() > 0) { this.a((MobSpawnerAbstract.a) WeightedRandom.a(this.a().random, this.mobs)); } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTBase.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTBase.java index 8756b63..e158c5d 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTBase.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTBase.java @@ -16,6 +16,21 @@ public abstract class NBTBase { public abstract byte getTypeId(); + // Migot start + protected static java.util.concurrent.ConcurrentHashMap storedStrings = new java.util.concurrent.ConcurrentHashMap(16, 0.75f, 2); + + public static String getStoredString(String name, boolean store) { + String str = storedStrings.get(name); + if(str == null) { + if(store) { + storedStrings.put(name, name); + } + str = name; + } + return str; + } + // Migot end + protected NBTBase() {} protected static NBTBase createTag(byte b0) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagCompound.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagCompound.java index b6231d9..a013256 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagCompound.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagCompound.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import com.google.common.collect.Maps; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -10,42 +11,46 @@ import java.util.Map.Entry; import java.util.concurrent.Callable; public class NBTTagCompound extends NBTBase { + private it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - reduce memory footprint of NBTTagCompound - public NBTTagCompound() { - } + public NBTTagCompound() {} public NBTTagCompound(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap map) { this.map = map; } - void write(DataOutput var1) throws IOException { - Iterator var2 = this.map.keySet().iterator(); + void write(DataOutput dataoutput) throws IOException { + Iterator iterator = this.map.keySet().iterator(); - while(var2.hasNext()) { - String var3 = (String)var2.next(); - NBTBase var4 = (NBTBase)this.map.get(var3); - a(var3, var4, var1); + while (iterator.hasNext()) { + String s = (String) iterator.next(); + NBTBase nbtbase = (NBTBase) this.map.get(s); + + a(s, nbtbase, dataoutput); } - var1.writeByte(0); + dataoutput.writeByte(0); } - void load(DataInput var1, int var2, NBTReadLimiter var3) throws IOException { - var3.a(384L); - if (var2 > 512) { + void load(DataInput datainput, int i, NBTReadLimiter nbtreadlimiter) throws IOException { + nbtreadlimiter.a(384L); + if (i > 512) { throw new RuntimeException("Tried to read NBT tag with too high complexity, depth > 512"); } else { this.map.clear(); - byte var4; - while((var4 = a(var1, var3)) != 0) { - String var5 = b(var1, var3); - var3.a((long)(224 + 16 * var5.length())); - NBTBase var6 = a(var4, var5, var1, var2 + 1, var3); - if (this.map.put(var5, var6) != null) { - var3.a(288L); + byte b0; + + while ((b0 = a(datainput, nbtreadlimiter)) != 0) { + String s = getStoredString(b(datainput, nbtreadlimiter), true); // Migot + + nbtreadlimiter.a((long) (224 + 16 * s.length())); + NBTBase nbtbase = a(b0, s, datainput, i + 1, nbtreadlimiter); + + if (this.map.put(s, nbtbase) != null) { + nbtreadlimiter.a(288L); } } @@ -57,214 +62,228 @@ public class NBTTagCompound extends NBTBase { } public byte getTypeId() { - return 10; + return (byte) 10; } - public void set(String var1, NBTBase var2) { - this.map.put(var1, var2); + public void set(String s, NBTBase nbtbase) { + this.map.put(s, nbtbase); } - public void setByte(String var1, byte var2) { - this.map.put(var1, new NBTTagByte(var2)); + public void setByte(String s, byte b0) { + this.map.put(s, new NBTTagByte(b0)); } - public void setShort(String var1, short var2) { - this.map.put(var1, new NBTTagShort(var2)); + public void setShort(String s, short short0) { + this.map.put(s, new NBTTagShort(short0)); } - public void setInt(String var1, int var2) { - this.map.put(var1, new NBTTagInt(var2)); + public void setInt(String s, int i) { + this.map.put(s, new NBTTagInt(i)); } - public void setLong(String var1, long var2) { - this.map.put(var1, new NBTTagLong(var2)); + public void setLong(String s, long i) { + this.map.put(s, new NBTTagLong(i)); } - public void setFloat(String var1, float var2) { - this.map.put(var1, new NBTTagFloat(var2)); + public void setFloat(String s, float f) { + this.map.put(s, new NBTTagFloat(f)); } - public void setDouble(String var1, double var2) { - this.map.put(var1, new NBTTagDouble(var2)); + public void setDouble(String s, double d0) { + this.map.put(s, new NBTTagDouble(d0)); } - public void setString(String var1, String var2) { - this.map.put(var1, new NBTTagString(var2)); + public void setString(String s, String s1) { + this.map.put(s, new NBTTagString(s1)); } - public void setByteArray(String var1, byte[] var2) { - this.map.put(var1, new NBTTagByteArray(var2)); + public void setByteArray(String s, byte[] abyte) { + this.map.put(s, new NBTTagByteArray(abyte)); } - public void setIntArray(String var1, int[] var2) { - this.map.put(var1, new NBTTagIntArray(var2)); + public void setIntArray(String s, int[] aint) { + this.map.put(s, new NBTTagIntArray(aint)); } - public void setBoolean(String var1, boolean var2) { - this.setByte(var1, (byte)(var2 ? 1 : 0)); + public void setBoolean(String s, boolean flag) { + this.setByte(s, (byte) (flag ? 1 : 0)); } - public NBTBase get(String var1) { - return (NBTBase)this.map.get(var1); + public NBTBase get(String s) { + return (NBTBase) this.map.get(s); } - public byte b(String var1) { - NBTBase var2 = (NBTBase)this.map.get(var1); - return var2 != null ? var2.getTypeId() : 0; + public byte b(String s) { + NBTBase nbtbase = (NBTBase) this.map.get(s); + + return nbtbase != null ? nbtbase.getTypeId() : 0; } - public boolean hasKey(String var1) { - return this.map.containsKey(var1); + public boolean hasKey(String s) { + return this.map.containsKey(s); } - public boolean hasKeyOfType(String var1, int var2) { - byte var3 = this.b(var1); - if (var3 == var2) { + public boolean hasKeyOfType(String s, int i) { + byte b0 = this.b(s); + + if (b0 == i) { return true; - } else if (var2 != 99) { - if (var3 > 0) { + } else if (i != 99) { + if (b0 > 0) { + ; } return false; } else { - return var3 == 1 || var3 == 2 || var3 == 3 || var3 == 4 || var3 == 5 || var3 == 6; + return b0 == 1 || b0 == 2 || b0 == 3 || b0 == 4 || b0 == 5 || b0 == 6; } } - public byte getByte(String var1) { + public byte getByte(String s) { try { - return !this.hasKeyOfType(var1, 99) ? 0 : ((NBTNumber)this.map.get(var1)).f(); - } catch (ClassCastException var3) { + return !this.hasKeyOfType(s, 99) ? 0 : ((NBTBase.NBTNumber) this.map.get(s)).f(); + } catch (ClassCastException classcastexception) { + return (byte) 0; + } + } + + public short getShort(String s) { + try { + return !this.hasKeyOfType(s, 99) ? 0 : ((NBTBase.NBTNumber) this.map.get(s)).e(); + } catch (ClassCastException classcastexception) { + return (short) 0; + } + } + + public int getInt(String s) { + try { + return !this.hasKeyOfType(s, 99) ? 0 : ((NBTBase.NBTNumber) this.map.get(s)).d(); + } catch (ClassCastException classcastexception) { return 0; } } - public short getShort(String var1) { + public long getLong(String s) { try { - return !this.hasKeyOfType(var1, 99) ? 0 : ((NBTNumber)this.map.get(var1)).e(); - } catch (ClassCastException var3) { - return 0; - } - } - - public int getInt(String var1) { - try { - return !this.hasKeyOfType(var1, 99) ? 0 : ((NBTNumber)this.map.get(var1)).d(); - } catch (ClassCastException var3) { - return 0; - } - } - - public long getLong(String var1) { - try { - return !this.hasKeyOfType(var1, 99) ? 0L : ((NBTNumber)this.map.get(var1)).c(); - } catch (ClassCastException var3) { + return !this.hasKeyOfType(s, 99) ? 0L : ((NBTBase.NBTNumber) this.map.get(s)).c(); + } catch (ClassCastException classcastexception) { return 0L; } } - public float getFloat(String var1) { + public float getFloat(String s) { try { - return !this.hasKeyOfType(var1, 99) ? 0.0F : ((NBTNumber)this.map.get(var1)).h(); - } catch (ClassCastException var3) { + return !this.hasKeyOfType(s, 99) ? 0.0F : ((NBTBase.NBTNumber) this.map.get(s)).h(); + } catch (ClassCastException classcastexception) { return 0.0F; } } - public double getDouble(String var1) { + public double getDouble(String s) { try { - return !this.hasKeyOfType(var1, 99) ? 0.0D : ((NBTNumber)this.map.get(var1)).g(); - } catch (ClassCastException var3) { + return !this.hasKeyOfType(s, 99) ? 0.0D : ((NBTBase.NBTNumber) this.map.get(s)).g(); + } catch (ClassCastException classcastexception) { return 0.0D; } } - public String getString(String var1) { + public String getString(String s) { try { - return !this.hasKeyOfType(var1, 8) ? "" : ((NBTBase)this.map.get(var1)).a_(); - } catch (ClassCastException var3) { + return !this.hasKeyOfType(s, 8) ? "" : ((NBTBase) this.map.get(s)).a_(); + } catch (ClassCastException classcastexception) { return ""; } } - public byte[] getByteArray(String var1) { + public byte[] getByteArray(String s) { try { - return !this.hasKeyOfType(var1, 7) ? new byte[0] : ((NBTTagByteArray)this.map.get(var1)).c(); - } catch (ClassCastException var3) { - throw new ReportedException(this.a(var1, 7, var3)); + return !this.hasKeyOfType(s, 7) ? new byte[0] : ((NBTTagByteArray) this.map.get(s)).c(); + } catch (ClassCastException classcastexception) { + throw new ReportedException(this.a(s, 7, classcastexception)); } } - public int[] getIntArray(String var1) { + public int[] getIntArray(String s) { try { - return !this.hasKeyOfType(var1, 11) ? new int[0] : ((NBTTagIntArray)this.map.get(var1)).c(); - } catch (ClassCastException var3) { - throw new ReportedException(this.a(var1, 11, var3)); + return !this.hasKeyOfType(s, 11) ? new int[0] : ((NBTTagIntArray) this.map.get(s)).c(); + } catch (ClassCastException classcastexception) { + throw new ReportedException(this.a(s, 11, classcastexception)); } } - public NBTTagCompound getCompound(String var1) { + public NBTTagCompound getCompound(String s) { try { - return !this.hasKeyOfType(var1, 10) ? new NBTTagCompound() : (NBTTagCompound)this.map.get(var1); - } catch (ClassCastException var3) { - throw new ReportedException(this.a(var1, 10, var3)); + return !this.hasKeyOfType(s, 10) ? new NBTTagCompound() : (NBTTagCompound) this.map.get(s); + } catch (ClassCastException classcastexception) { + throw new ReportedException(this.a(s, 10, classcastexception)); } } - public NBTTagList getList(String var1, int var2) { + public NBTTagList getList(String s, int i) { try { - if (this.b(var1) != 9) { + if (this.b(s) != 9) { return new NBTTagList(); } else { - NBTTagList var3 = (NBTTagList)this.map.get(var1); - return var3.size() > 0 && var3.f() != var2 ? new NBTTagList() : var3; + NBTTagList nbttaglist = (NBTTagList) this.map.get(s); + + return nbttaglist.size() > 0 && nbttaglist.f() != i ? new NBTTagList() : nbttaglist; } - } catch (ClassCastException var4) { - throw new ReportedException(this.a(var1, 9, var4)); + } catch (ClassCastException classcastexception) { + throw new ReportedException(this.a(s, 9, classcastexception)); } } - public boolean getBoolean(String var1) { - return this.getByte(var1) != 0; + public boolean getBoolean(String s) { + return this.getByte(s) != 0; } - public void remove(String var1) { - this.map.remove(var1); + public void remove(String s) { + this.map.remove(s); } public String toString() { - StringBuilder var1 = new StringBuilder("{"); + StringBuilder stringbuilder = new StringBuilder("{"); - Entry var3; - for(Iterator var2 = this.map.entrySet().iterator(); var2.hasNext(); var1.append((String)var3.getKey()).append(':').append(var3.getValue())) { - var3 = (Entry)var2.next(); - if (var1.length() != 1) { - var1.append(','); + Entry entry; + + for (Iterator iterator = this.map.entrySet().iterator(); iterator.hasNext(); stringbuilder.append((String) entry.getKey()).append(':').append(entry.getValue())) { + entry = (Entry) iterator.next(); + if (stringbuilder.length() != 1) { + stringbuilder.append(','); } } - return var1.append('}').toString(); + return stringbuilder.append('}').toString(); } public boolean isEmpty() { return this.map.isEmpty(); } - private CrashReport a(final String var1, final int var2, ClassCastException var3) { - CrashReport var4 = CrashReport.a(var3, "Reading NBT data"); - CrashReportSystemDetails var5 = var4.a("Corrupt NBT tag", 1); - var5.a("Tag type found", new Callable() { - public String call() throws Exception { - return NBTBase.a[((NBTBase)NBTTagCompound.this.map.get(var1)).getTypeId()]; + private CrashReport a(final String s, final int i, ClassCastException classcastexception) { + CrashReport crashreport = CrashReport.a(classcastexception, "Reading NBT data"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Corrupt NBT tag", 1); + + crashreportsystemdetails.a("Tag type found", new Callable() { + public String a() throws Exception { + return NBTBase.a[((NBTBase) NBTTagCompound.this.map.get(s)).getTypeId()]; + } + + public Object call() throws Exception { + return this.a(); } }); - var5.a("Tag type expected", new Callable() { - public String call() throws Exception { - return NBTBase.a[var2]; + crashreportsystemdetails.a("Tag type expected", new Callable() { + public String a() throws Exception { + return NBTBase.a[i]; + } + + public Object call() throws Exception { + return this.a(); } }); - var5.a("Tag name", var1); - return var4; + crashreportsystemdetails.a("Tag name", (Object) s); + return crashreport; } public NBTBase clone() { @@ -278,10 +297,12 @@ public class NBTTagCompound extends NBTBase { return new NBTTagCompound(ret); } - public boolean equals(Object var1) { - if (super.equals(var1)) { - NBTTagCompound var2 = (NBTTagCompound)var1; - return this.map.entrySet().equals(var2.map.entrySet()); + + public boolean equals(Object object) { + if (super.equals(object)) { + NBTTagCompound nbttagcompound = (NBTTagCompound) object; + + return this.map.entrySet().equals(nbttagcompound.map.entrySet()); } else { return false; } @@ -291,54 +312,57 @@ public class NBTTagCompound extends NBTBase { return super.hashCode() ^ this.map.hashCode(); } - private static void a(String var0, NBTBase var1, DataOutput var2) throws IOException { - var2.writeByte(var1.getTypeId()); - if (var1.getTypeId() != 0) { - var2.writeUTF(var0); - var1.write(var2); + private static void a(String s, NBTBase nbtbase, DataOutput dataoutput) throws IOException { + dataoutput.writeByte(nbtbase.getTypeId()); + if (nbtbase.getTypeId() != 0) { + dataoutput.writeUTF(s); + nbtbase.write(dataoutput); } } - private static byte a(DataInput var0, NBTReadLimiter var1) throws IOException { - return var0.readByte(); + private static byte a(DataInput datainput, NBTReadLimiter nbtreadlimiter) throws IOException { + return datainput.readByte(); } - private static String b(DataInput var0, NBTReadLimiter var1) throws IOException { - return var0.readUTF(); + private static String b(DataInput datainput, NBTReadLimiter nbtreadlimiter) throws IOException { + return datainput.readUTF(); } - static NBTBase a(byte var0, String var1, DataInput var2, int var3, NBTReadLimiter var4) throws IOException { - NBTBase var5 = NBTBase.createTag(var0); + static NBTBase a(byte b0, String s, DataInput datainput, int i, NBTReadLimiter nbtreadlimiter) throws IOException { + NBTBase nbtbase = NBTBase.createTag(b0); try { - var5.load(var2, var3, var4); - return var5; - } catch (IOException var9) { - CrashReport var7 = CrashReport.a(var9, "Loading NBT data"); - CrashReportSystemDetails var8 = var7.a("NBT Tag"); - var8.a("Tag name", var1); - var8.a("Tag type", var0); - throw new ReportedException(var7); + nbtbase.load(datainput, i, nbtreadlimiter); + return nbtbase; + } catch (IOException ioexception) { + CrashReport crashreport = CrashReport.a(ioexception, "Loading NBT data"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("NBT Tag"); + + crashreportsystemdetails.a("Tag name", (Object) s); + crashreportsystemdetails.a("Tag type", (Object) Byte.valueOf(b0)); + throw new ReportedException(crashreport); } } - public void a(NBTTagCompound var1) { - Iterator var2 = var1.map.keySet().iterator(); + public void a(NBTTagCompound nbttagcompound) { + Iterator iterator = nbttagcompound.map.keySet().iterator(); - while(var2.hasNext()) { - String var3 = (String)var2.next(); - NBTBase var4 = (NBTBase)var1.map.get(var3); - if (var4.getTypeId() == 10) { - if (this.hasKeyOfType(var3, 10)) { - NBTTagCompound var5 = this.getCompound(var3); - var5.a((NBTTagCompound)var4); + while (iterator.hasNext()) { + String s = (String) iterator.next(); + NBTBase nbtbase = (NBTBase) nbttagcompound.map.get(s); + + if (nbtbase.getTypeId() == 10) { + if (this.hasKeyOfType(s, 10)) { + NBTTagCompound nbttagcompound1 = this.getCompound(s); + + nbttagcompound1.a((NBTTagCompound) nbtbase); } else { - this.set(var3, var4.clone()); + this.set(s, nbtbase.clone()); } } else { - this.set(var3, var4.clone()); + this.set(s, nbtbase.clone()); } } } -} \ No newline at end of file +} diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagString.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagString.java new file mode 100644 index 0000000..487a6d8 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/NBTTagString.java @@ -0,0 +1,65 @@ +package net.minecraft.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class NBTTagString extends NBTBase { + + private String data; + + public NBTTagString() { + this.data = ""; + } + + public NBTTagString(String s) { + this.data = s; + if (s == null) { + throw new IllegalArgumentException("Empty string not allowed"); + } + } + + void write(DataOutput dataoutput) throws IOException { + dataoutput.writeUTF(this.data); + } + + void load(DataInput datainput, int i, NBTReadLimiter nbtreadlimiter) throws IOException { + nbtreadlimiter.a(288L); + this.data = getStoredString(datainput.readUTF(), true); // Migot + nbtreadlimiter.a((long) (16 * this.data.length())); + } + + public byte getTypeId() { + return (byte) 8; + } + + public String toString() { + return "\"" + this.data.replace("\"", "\\\"") + "\""; + } + + public NBTBase clone() { + return new NBTTagString(this.data); + } + + public boolean isEmpty() { + return this.data.isEmpty(); + } + + public boolean equals(Object object) { + if (!super.equals(object)) { + return false; + } else { + NBTTagString nbttagstring = (NBTTagString) object; + + return this.data == null && nbttagstring.data == null || this.data != null && this.data.equals(nbttagstring.data); + } + } + + public int hashCode() { + return super.hashCode() ^ this.data.hashCode(); + } + + public String a_() { + return this.data; + } +} 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 014c0e6..a83817b 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/NetworkManager.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/NetworkManager.java @@ -387,6 +387,7 @@ public class NetworkManager extends SimpleChannelInboundHandler { } public void close(IChatBaseComponent ichatbasecomponent) { + this.i.clear(); // KigPaper // Spigot Start this.preparing = false; // Spigot End diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketDataSerializer.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketDataSerializer.java index 21ab829..46cdf66 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketDataSerializer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketDataSerializer.java @@ -249,6 +249,28 @@ public class PacketDataSerializer extends ByteBuf { } } + // KigPaper start + public String readCappedString(int maxLength) { + int toRead = this.e(); + + if (toRead > maxLength * 4) { + throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + toRead + " > " + maxLength * 4 + ")"); + } else if (toRead < 0) { + throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!"); + } else { + int len = Math.min(toRead, maxLength); + String s = new String(this.readBytes(len).array(), Charsets.UTF_8); + + int remaining = toRead - len; + if (remaining > 0) { + this.skipBytes(remaining); + } + + return s; + } + } + // KigPaper end + public PacketDataSerializer a(String s) { byte[] abyte = s.getBytes(Charsets.UTF_8); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInBlockPlace.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInBlockPlace.java index 02d8e07..b305ee0 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInBlockPlace.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInBlockPlace.java @@ -1,5 +1,7 @@ package net.minecraft.server; +import io.netty.handler.codec.DecoderException; + import java.io.IOException; public class PacketPlayInBlockPlace implements Packet { @@ -33,7 +35,12 @@ public class PacketPlayInBlockPlace implements Packet { timestamp = System.currentTimeMillis(); // CraftBukkit this.b = packetdataserializer.c(); this.c = packetdataserializer.readUnsignedByte(); - this.d = packetdataserializer.i(); + // KigPaper start - don't parse itemstack + // this.d = packetdataserializer.i(); + // Consume everything and leave 3 bytes at the end + if (packetdataserializer.readableBytes() < 3) throw new DecoderException("Expected 3 facing bytes"); + packetdataserializer.skipBytes(packetdataserializer.readableBytes() - 3); + // KigPaper end this.e = (float) packetdataserializer.readUnsignedByte() / 16.0F; this.f = (float) packetdataserializer.readUnsignedByte() / 16.0F; this.g = (float) packetdataserializer.readUnsignedByte() / 16.0F; diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInChat.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInChat.java index 18358b4..6b71d97 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInChat.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayInChat.java @@ -1,5 +1,7 @@ package net.minecraft.server; +import org.github.paperspigot.PaperSpigotConfig; + import java.io.IOException; public class PacketPlayInChat implements Packet { @@ -17,7 +19,7 @@ public class PacketPlayInChat implements Packet { } public void a(PacketDataSerializer packetdataserializer) throws IOException { - this.a = packetdataserializer.c(100); + this.a = PaperSpigotConfig.kickChatMessageLength ? packetdataserializer.c(100) : packetdataserializer.readCappedString(100); // KigPaper } public void b(PacketDataSerializer packetdataserializer) throws IOException { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java index 2377f35..74f8bdb 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PacketPlayOutEntityMetadata.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.Setter; import java.io.IOException; +import java.util.Iterator; import java.util.List; @Getter @@ -13,6 +14,7 @@ public class PacketPlayOutEntityMetadata implements Packet b; + private boolean found = false; // MineHQ public PacketPlayOutEntityMetadata() {} @@ -23,7 +25,11 @@ public class PacketPlayOutEntityMetadata implements Packet list) { + this.a = i; + this.b = list; } public void a(PacketDataSerializer packetdataserializer) throws IOException { @@ -39,5 +45,4 @@ public class PacketPlayOutEntityMetadata implements Packet 49.0D) { + } else if (this.a.h(target) > 49.0D) { this.a.a(-1); - } else if (!this.a.getEntitySenses().a(this.b)) { + } else if (!this.a.getEntitySenses().a(target)) { this.a.a(-1); } else { this.a.a(1); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PersistentCollection.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PersistentCollection.java index 4233449..50e0ec4 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PersistentCollection.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PersistentCollection.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import com.elevatemc.spigot.threading.ThreadingManager; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.io.DataInputStream; @@ -96,10 +97,15 @@ public class PersistentCollection { NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound1.set("data", nbttagcompound); + // Migot start + /* FileOutputStream fileoutputstream = new FileOutputStream(file); NBTCompressedStreamTools.a(nbttagcompound1, (OutputStream) fileoutputstream); fileoutputstream.close(); + */ + ThreadingManager.saveNBTFileStatic((NBTTagCompound) (nbttagcompound1.clone()), file); + // Migot end } } catch (Exception exception) { exception.printStackTrace(); 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 ac5b2fe..bbb070c 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerConnection.java @@ -92,6 +92,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList private double q; private boolean checkMovement = true; private boolean processedDisconnect; // CraftBukkit - added + private boolean disconnecting; // KigPaper - added public PlayerConnection(MinecraftServer minecraftserver, NetworkManager networkmanager, EntityPlayer entityplayer) { this.minecraftServer = minecraftserver; @@ -107,6 +108,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList private final org.bukkit.craftbukkit.CraftServer server; private int lastTick = MinecraftServer.currentTick; private int lastDropTick = MinecraftServer.currentTick; + private int lastBookTick = MinecraftServer.currentTick; private int dropCount = 0; private static final int SURVIVAL_PLACE_DISTANCE_SQUARED = 6 * 6; private static final int CREATIVE_PLACE_DISTANCE_SQUARED = 7 * 7; @@ -163,6 +165,8 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList } public void disconnect(String s) { + // KigPaper - if already disconnecting, do nothing + if(disconnecting) return; // CraftBukkit start - fire PlayerKickEvent String leaveMessage = EnumChatFormat.YELLOW + this.player.getName() + " left the game."; @@ -176,6 +180,9 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList // Do not kick the player return; } + // KigPaper - mark the player as disconnecting, so all other disconnect requests are ignored. + disconnecting = true; + // Send the possibly modified leave message s = event.getReason(); // CraftBukkit end @@ -805,6 +812,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList if (itemstack != null && itemstack.count == 0) { this.player.inventory.items[this.player.inventory.itemInHandIndex] = null; itemstack = null; + always = true; // KigPaper - send update packet } if (itemstack == null || itemstack.l() == 0) { @@ -815,7 +823,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList this.player.activeContainer.b(); this.player.g = false; // CraftBukkit - TODO CHECK IF NEEDED -- new if structure might not need 'always'. Kept it in for now, but may be able to remove in future - if (!ItemStack.matches(this.player.inventory.getItemInHand(), packetplayinblockplace.getItemStack()) || always) { + if (!ItemStack.matches(this.player.inventory.getItemInHand(), itemstack) || always) { // KigPaper - use saved itemstack instead of stack from packet this.sendPacket(new PacketPlayOutSetSlot(this.player.activeContainer.windowId, slot.rawSlotIndex, this.player.inventory.getItemInHand())); } } @@ -1357,6 +1365,47 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList this.player.resetIdleTimer(); if (entity != null) { + // KigPaper start - allow hitting the vehicle when hitboxes collide / allow the player to hit others if they are being ridden by something + if(PaperSpigotConfig.betterVehicleHitboxes) { + if (entity instanceof EntityPlayer && entity.vehicle != null && !((EntityPlayer) entity).collidesWithEntities) { + // Allow hitting the vehicle when hitboxes collide + // Ray trace to see if the player should hit the vehicle instead + double maxDist = 3.0; + Vec3D look = player.ap(); + Vec3D eyePos = new Vec3D(player.locX, player.locY + player.getBukkitEntity().getEyeHeight(), player.locZ); + Vec3D maxDistLook = eyePos.add(look.a * maxDist, look.b * maxDist, look.c * maxDist); + Entity vehicle = entity.vehicle; + List collisions = worldserver.a(player, player.getBoundingBox() + .a(look.a * maxDist, look.b * maxDist, look.c * maxDist) // add coords + .grow(1D, 1D, 1D), e -> e == vehicle); // Only check for the vehicle + for (Entity match : collisions) { + AxisAlignedBB expandedHitbox = match.getBoundingBox().grow(0.1D, 0.1D, 0.1D); // Hit box is collision box + 0.1 + if (expandedHitbox.a(eyePos) || expandedHitbox.a(eyePos, maxDistLook) != null) { + entity = match; + break; + } + } + } else if (entity == player.passenger) { // player hit passenger + // Allow the player to hit others if they are being ridden by something + // Ray trace to see if the player should hit someone else instead + double maxDist = 3.0; + Vec3D look = player.ap(); + Vec3D eyePos = new Vec3D(player.locX, player.locY + player.getBukkitEntity().getEyeHeight(), player.locZ); + Vec3D maxDistLook = eyePos.add(look.a * maxDist, look.b * maxDist, look.c * maxDist); + Entity passenger = entity.passenger; + List collisions = worldserver.a(player, player.getBoundingBox() + .a(look.a * maxDist, look.b * maxDist, look.c * maxDist) // add coords + .grow(1D, 1D, 1D), e -> e != passenger); // Don't include passenger + for (Entity match : collisions) { + AxisAlignedBB expandedHitbox = match.getBoundingBox().grow(0.1D, 0.1D, 0.1D); // Hit box is collision box + 0.1 + if (expandedHitbox.a(eyePos) || expandedHitbox.a(eyePos, maxDistLook) != null) { + entity = match; + break; + } + } + } + } + // KigPaper end boolean flag = this.player.hasLineOfSight(entity); double d0 = 36.0D; @@ -1892,7 +1941,6 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList } } } - } public void a(PacketPlayInTransaction packetplayintransaction) { @@ -2016,7 +2064,13 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList try { // CraftBukkit if ("MC|BEdit".equals(packetplayincustompayload.a())) { + if (!PaperSpigotConfig.enableBookDeserialization) return; // KigPaper packetdataserializer = new PacketDataSerializer(Unpooled.wrappedBuffer(packetplayincustompayload.b())); + if (this.lastBookTick + 20 > MinecraftServer.currentTick) { + this.disconnect("Book edited too quickly! (Attempted server crash?)"); + return; + } + this.lastBookTick = MinecraftServer.currentTick; try { itemstack = packetdataserializer.i(); @@ -2048,6 +2102,12 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList return; } else if ("MC|BSign".equals(packetplayincustompayload.a())) { + if (!PaperSpigotConfig.enableBookDeserialization) return; // KigPaper + if (this.lastBookTick + 20 > MinecraftServer.currentTick) { + this.disconnect("Book edited too quickly! (Attempted server crash?)"); + return; + } + this.lastBookTick = MinecraftServer.currentTick; packetdataserializer = new PacketDataSerializer(Unpooled.wrappedBuffer(packetplayincustompayload.b())); try { 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 f89e840..4ce613b 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerList.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PlayerList.java @@ -28,6 +28,7 @@ import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.TravelAgent; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerChangedWorldEvent; @@ -38,6 +39,7 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.util.Vector; +import org.github.paperspigot.PaperSpigotConfig; import org.spigotmc.event.player.PlayerSpawnLocationEvent; // CraftBukkit end @@ -88,11 +90,12 @@ public abstract class PlayerList { public void a(NetworkManager networkmanager, EntityPlayer entityplayer) { GameProfile gameprofile = entityplayer.getProfile(); + boolean loadUserCache = PaperSpigotConfig.savePlayerFiles; UserCache usercache = this.server.getUserCache(); - GameProfile gameprofile1 = usercache.a(gameprofile.getId()); + GameProfile gameprofile1 = loadUserCache ? usercache.a(gameprofile.getId()) : null; // KigPaper - only load if savePlayerFiles is enabled String s = gameprofile1 == null ? gameprofile.getName() : gameprofile1.getName(); - usercache.a(gameprofile); + if (loadUserCache) usercache.a(gameprofile); // KigPaper - only save if savePlayerFiles is enabled NBTTagCompound nbttagcompound = this.a(entityplayer); // CraftBukkit start - Better rename detection if (nbttagcompound != null && nbttagcompound.hasKey("bukkit")) { @@ -272,7 +275,7 @@ public abstract class PlayerList { } worldserver1.getPlayerChunkMap().addPlayer(entityplayer); - worldserver1.chunkProviderServer.getChunkAt((int) entityplayer.locX >> 4, (int) entityplayer.locZ >> 4); + worldserver1.chunkProviderServer.getChunkAt(MathHelper.floor(entityplayer.locX) >> 4, MathHelper.floor(entityplayer.locZ) >> 4); // Migot - fix rounding error } public int d() { @@ -295,6 +298,7 @@ public abstract class PlayerList { } protected void savePlayerFile(EntityPlayer entityplayer) { + if (!PaperSpigotConfig.savePlayerFiles) return; // KigPaper this.playerFileData.save(entityplayer); ServerStatisticManager serverstatisticmanager = (ServerStatisticManager) this.o.get(entityplayer.getUniqueID()); @@ -362,7 +366,8 @@ public abstract class PlayerList { // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(entityplayer); - PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(entityplayer), "\u00A7e" + entityplayer.getName() + " left the game."); + Player bukkit = cserver.getPlayer(entityplayer); // KigPaper + PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(bukkit, "\u00A7e" + entityplayer.getName() + " left the game."); cserver.getPluginManager().callEvent(playerQuitEvent); entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); // CraftBukkit end @@ -405,6 +410,12 @@ public abstract class PlayerList { ChunkIOExecutor.adjustPoolSize(this.getPlayerCount()); // CraftBukkit + // KigPaper start - fix memory leak + CraftingManager craftingManager = CraftingManager.getInstance(); + CraftInventoryView lastView = (CraftInventoryView) craftingManager.lastCraftView; + if (lastView != null && lastView.getHandle() instanceof ContainerPlayer && lastView.getPlayer() == bukkit) craftingManager.lastCraftView = null; + // KigPaper end + return playerQuitEvent.getQuitMessage(); // CraftBukkit } @@ -599,7 +610,7 @@ public abstract class PlayerList { entityplayer1.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // CraftBukkit end - worldserver.chunkProviderServer.getChunkAt((int) entityplayer1.locX >> 4, (int) entityplayer1.locZ >> 4); + worldserver.chunkProviderServer.getChunkAt(MathHelper.floor(entityplayer1.locX) >> 4, MathHelper.floor(entityplayer1.locZ) >> 4); // Migot - fix rounding error // eSpigot - Don't check for entities while (avoidSuffocation && !worldserver.getCubesNoEntities(entityplayer1, entityplayer1.getBoundingBox()).isEmpty() && entityplayer1.locY < 256.0D) { @@ -1060,7 +1071,7 @@ public abstract class PlayerList { EntityPlayer entityplayer = (EntityPlayer) this.players.get(j); // CraftBukkit start - Test if player receiving packet can see the source of the packet - if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { + if (entityhuman != null && entityplayer != entityhuman && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { continue; } // CraftBukkit end @@ -1078,6 +1089,31 @@ public abstract class PlayerList { } + // KigPaper start + public void sendPacketNearbyIncludingSelf(EntityHuman entityhuman, double d0, double d1, double d2, double d3, int i, Packet packet) { + for (int j = 0; j < this.players.size(); ++j) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(j); + + // CraftBukkit start - Test if player receiving packet can see the source of the packet + if (entityhuman != null && entityplayer != entityhuman && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { + continue; + } + // CraftBukkit end + + if (entityplayer.dimension == i) { + double d4 = d0 - entityplayer.locX; + double d5 = d1 - entityplayer.locY; + double d6 = d2 - entityplayer.locZ; + + if (d4 * d4 + d5 * d5 + d6 * d6 < d3 * d3) { + entityplayer.playerConnection.sendPacket(packet); + } + } + } + + } + // KigPaper end + public void savePlayers() { for (int i = 0; i < this.players.size(); ++i) { this.savePlayerFile((EntityPlayer) this.players.get(i)); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/PortalTravelAgent.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/PortalTravelAgent.java index 72f3735..8e03192 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/PortalTravelAgent.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/PortalTravelAgent.java @@ -94,7 +94,13 @@ public class PortalTravelAgent { public boolean b(Entity entity, float f) { // CraftBukkit start - Modularize portal search process and entity teleportation - BlockPosition found = this.findPortal(entity.locX, entity.locY, entity.locZ, 128); + // Migot start + BlockPosition found = this.findPortal(entity.locX, entity.locY, entity.locZ, 10); + if (found == null) { + found = this.findPortal(entity.locX, entity.locY, entity.locZ, 128); + } + // Migot end + if (found == null) { return false; } @@ -132,28 +138,33 @@ public class PortalTravelAgent { flag1 = false; } else { BlockPosition blockposition = new BlockPosition(x, y, z); + // Migot start + BlockPosition.MutableBlockPosition mutableblockposition = new BlockPosition.MutableBlockPosition(); - for (int l = -searchRadius; l <= searchRadius; ++l) { // Paper - actually use search radius - BlockPosition blockposition1; - - for (int i1 = -searchRadius; i1 <= searchRadius; ++i1) { // Paper - actually use search radius - for (BlockPosition blockposition2 = blockposition.a(l, this.a.V() - 1 - blockposition.getY(), i1); blockposition2.getY() >= 0; blockposition2 = blockposition1) { - blockposition1 = blockposition2.down(); - if (this.a.getType(blockposition2).getBlock() == Blocks.PORTAL) { - while (this.a.getType(blockposition1 = blockposition2.down()).getBlock() == Blocks.PORTAL) { - blockposition2 = blockposition1; + int zOffset = 0, yOffset = 0; + for (int xDiff = -searchRadius; xDiff <= searchRadius; ++xDiff) { + zOffset = (zOffset + 1) % 2; + for (int zDiff = -searchRadius + zOffset; zDiff <= searchRadius; zDiff = zDiff + 2) { // skipping every 2nd block in z direction and alternating from row to row in x direction + yOffset = (yOffset + 1) % 3; + for (int yPos = this.a.V() - (1 + yOffset) ; yPos >= 0; yPos = yPos - 3) { // checking only every 3rd block in y direction and alternating in height in each column + mutableblockposition.c(blockposition.getX() + xDiff, yPos, blockposition.getZ() + zDiff); + if (this.a.getType(mutableblockposition).getBlock() == Blocks.PORTAL) { + int lowestCorrectHeight = mutableblockposition.getY(); + while (this.a.getType(mutableblockposition.c(mutableblockposition.getX(), mutableblockposition.getY() - 1, mutableblockposition.getZ())).getBlock() == Blocks.PORTAL) { + lowestCorrectHeight = mutableblockposition.getY(); } - double d1 = blockposition2.i(blockposition); + double d1 = mutableblockposition.c(mutableblockposition.getX(), lowestCorrectHeight, mutableblockposition.getZ()).i(blockposition); if (d0 < 0.0D || d1 < d0) { d0 = d1; - object = blockposition2; + object = new BlockPosition(mutableblockposition); } } } } } + // Migot end } if (d0 >= 0.0D) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFile.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFile.java index 348706f..f026924 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFile.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFile.java @@ -1,20 +1,24 @@ package net.minecraft.server; +import com.github.luben.zstd.ZstdInputStreamNoFinalizer; +import com.github.luben.zstd.ZstdOutputStreamNoFinalizer; import com.google.common.collect.Lists; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; +import net.jpountz.lz4.LZ4Factory; +import org.github.paperspigot.PaperSpigotConfig; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; import java.util.List; import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import java.util.zip.InflaterInputStream; public class RegionFile { + private static final LZ4Factory lz4Factory = LZ4Factory.fastestJavaInstance(); // KigPaper private static final byte[] a = new byte[4096]; // Spigot - note: if this ever changes to not be 4096 bytes, update constructor! // PAIL: empty 4k block private final File b; @@ -25,6 +29,18 @@ public class RegionFile { private int g; private long h; + // Migot start + private boolean[] existingChunkCache = new boolean[1024]; + + private boolean checkExistingChunkCache(int i, int j) { + return this.existingChunkCache[i + j * 32]; + } + + private void addCoordinatesToCache(int i, int j) { + this.existingChunkCache[i + j * 32] = true; + } + // Migot end + public RegionFile(File file) { this.b = file; this.g = 0; @@ -66,8 +82,18 @@ public class RegionFile { int k; + // KigPaper start - Paper-0098 + ByteBuffer header = ByteBuffer.allocate(8192); + while (header.hasRemaining()) { + if (this.c.getChannel().read(header) == -1) throw new EOFException(); + } + header.clear(); + IntBuffer headerAsInts = header.asIntBuffer(); + // KigPaper end + for (j = 0; j < 1024; ++j) { - k = this.c.readInt(); + //k = this.c.readInt(); // KigPaper + k = headerAsInts.get(); this.d[j] = k; if (k != 0 && (k >> 8) + (k & 255) <= this.f.size()) { for (int l = 0; l < (k & 255); ++l) { @@ -77,7 +103,8 @@ public class RegionFile { } for (j = 0; j < 1024; ++j) { - k = this.c.readInt(); + //k = this.c.readInt(); // KigPaper + k = headerAsInts.get(); this.e[j] = k; } } catch (IOException ioexception) { @@ -91,6 +118,11 @@ public class RegionFile { if (this.d(i, j)) { return false; } else { + // Migot start + if(checkExistingChunkCache(i, j)) { + return true; + } + // Migot end try { int k = this.e(i, j); @@ -113,6 +145,7 @@ public class RegionFile { byte b0 = this.c.readByte(); if (b0 == 1 || b0 == 2) { + this.addCoordinatesToCache(i, j); // Migot return true; } } @@ -152,15 +185,34 @@ public class RegionFile { byte b0 = this.c.readByte(); byte[] abyte; - if (b0 == 1) { + // KigPaper - add additional compression algorithms, and remove usage of BufferedInputStreams (as they're buffering a byte array) + if (b0 == CompressionAlgorithm.NONE.ordinal()) { + // KigPaper start - add no decompression abyte = new byte[j1 - 1]; this.c.read(abyte); - return new DataInputStream(new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(abyte)))); - } else if (b0 == 2) { + return new DataInputStream(new ByteArrayInputStream(abyte)); + // KigPaper end + } else if (b0 == CompressionAlgorithm.GZIP.ordinal()) { abyte = new byte[j1 - 1]; this.c.read(abyte); - return new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(abyte)))); - } else { + return new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(abyte))); + } else if (b0 == CompressionAlgorithm.ZLIB.ordinal()) { + abyte = new byte[j1 - 1]; + this.c.read(abyte); + return new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(abyte))); + } else if (b0 == CompressionAlgorithm.LZ4.ordinal()) { + // KigPaper start - add LZ4 decompression + abyte = new byte[j1 - 1]; + this.c.read(abyte); + + return new DataInputStream(new LZ4BlockInputStream(new ByteArrayInputStream(abyte), lz4Factory.fastDecompressor())); + // KigPaper end + } else if (b0 == CompressionAlgorithm.ZSTD.ordinal()) { + // KigPaper start - add Zstandard decompression + abyte = new byte[j1 - 1]; + this.c.read(abyte); + return new DataInputStream(new ZstdInputStreamNoFinalizer(new ByteArrayInputStream(abyte))); + }else { return null; } } @@ -172,9 +224,35 @@ public class RegionFile { } } - public DataOutputStream b(int i, int j) { // PAIL: getChunkOutputStream + public DataOutputStream b(int i, int j) throws IOException { // PAIL: getChunkOutputStream // KigPaper - add throws // PAIL: isInvalidRegion - return this.d(i, j) ? null : new DataOutputStream(new java.io.BufferedOutputStream(new DeflaterOutputStream(new RegionFile.ChunkBuffer(i, j)))); // Spigot - use a BufferedOutputStream to greatly improve file write performance + if (this.d(i, j)) { + return null; + } + // KigPaper start - add alternative compression algorithms + ChunkBuffer buffer = new RegionFile.ChunkBuffer(i, j); + OutputStream stream; + switch (PaperSpigotConfig.regionCompressionAlgorithm) { + case NONE: + stream = buffer; + break; + case GZIP: + stream = new GZIPOutputStream(buffer); // Normally not supported by the Notchian server + break; + case ZLIB: + stream = new DeflaterOutputStream(buffer); + break; + case LZ4: + stream = new LZ4BlockOutputStream(buffer, 65536, lz4Factory.fastCompressor()); + break; + case ZSTD: + stream = new ZstdOutputStreamNoFinalizer(buffer); + break; + default: + throw new UnsupportedEncodingException("invalid compression algorithm"); + } + return new DataOutputStream(new BufferedOutputStream(stream)); + // KigPaper end } protected synchronized void a(int i, int j, byte[] abyte, int k) { @@ -252,9 +330,9 @@ public class RegionFile { } private void a(int i, byte[] abyte, int j) throws IOException { - this.c.seek((long) (i * 4096)); + this.c.seek(i * 4096L); this.c.writeInt(j + 1); - this.c.writeByte(2); + this.c.writeByte(PaperSpigotConfig.regionCompressionAlgorithm.ordinal()); this.c.write(abyte, 0, j); } @@ -304,4 +382,14 @@ public class RegionFile { RegionFile.this.a(this.b, this.c, this.buf, this.count); } } + + // KigPaper start + public enum CompressionAlgorithm { + NONE, + GZIP, + ZLIB, + LZ4, // KigPaper + ZSTD // KigPaper + } + // KigPaper end } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFileCache.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFileCache.java index 5b000c4..b025458 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFileCache.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/RegionFileCache.java @@ -65,7 +65,7 @@ public class RegionFileCache { return regionfile.a(i & 31, j & 31); } - public static DataOutputStream d(File file, int i, int j) { + public static DataOutputStream d(File file, int i, int j) throws IOException { // KigPaper - add throws RegionFile regionfile = a(file, i, j); return regionfile.b(i & 31, j & 31); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/ServerConnection.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/ServerConnection.java index 4e523bd..7809983 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/ServerConnection.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/ServerConnection.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.Callable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.github.paperspigot.PaperSpigotConfig; public class ServerConnection { @@ -68,6 +69,16 @@ public class ServerConnection { this.d = true; } + // KigPaper start - Paper-0117 by Aikar + private final List pending = Collections.synchronizedList(Lists.newArrayList()); + private void addPending() { + synchronized (pending) { + this.h.addAll(pending); + pending.clear(); + } + } + // KigPaper end + public void a(InetAddress inetaddress, int i) throws IOException { List list = this.g; @@ -98,10 +109,14 @@ public class ServerConnection { ; } - channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("legacy_query", new LegacyPingHandler(ServerConnection.this)).addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND)).addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND)); + // KigPaper start + if(PaperSpigotConfig.nettyReadTimeout) channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)); + // KigPaper end + channel.pipeline().addLast("legacy_query", new LegacyPingHandler(ServerConnection.this)).addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND)).addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND)); NetworkManager networkmanager = new NetworkManager(EnumProtocolDirection.SERVERBOUND); - ServerConnection.this.h.add(networkmanager); + //ServerConnection.this.h.add(networkmanager); + pending.add(networkmanager); // KigPaper channel.pipeline().addLast("packet_handler", networkmanager); networkmanager.a((PacketListener) (new HandshakeListener(ServerConnection.this.f, networkmanager))); } @@ -138,6 +153,7 @@ public class ServerConnection { synchronized (this.h) { // Spigot Start + addPending(); // KigPaper // This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0 ) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/SpawnerCreature.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/SpawnerCreature.java index ea17d7e..4009e89 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/SpawnerCreature.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -81,7 +81,7 @@ public final class SpawnerCreature { long chunkCoords = LongHash.toLong(i1 + l, k + j); if (!this.b.contains(chunkCoords)) { ++i; - if (!flag3 && worldserver.getWorldBorder().isInBounds(i1 + l, k + j)) { + if (!flag3 && worldserver.isChunkLoaded(i1 + l, k + j, true) && worldserver.getWorldBorder().isInBounds(i1 + l, k + j)) { // Migot this.b.add(chunkCoords); } } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/StructureGenerator.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/StructureGenerator.java index e76acfc..fdfa1fb 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/StructureGenerator.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/StructureGenerator.java @@ -198,7 +198,7 @@ public abstract class StructureGenerator extends WorldGenBase { private void a(World world) { if (this.d == null) { // Spigot Start - if ( world.spigotConfig.saveStructureInfo && !this.a().equals( "Mineshaft" ) ) + if ( world.spigotConfig.saveStructureInfo && ( !this.a().equals( "Mineshaft" ) || world.spigotConfig.saveMineshaftStructureInfo ) ) // Migot { this.d = (PersistentStructure) world.a(PersistentStructure.class, this.a()); } else diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntityFurnace.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntityFurnace.java index 0e3f35a..ecccf1e 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntityFurnace.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/TileEntityFurnace.java @@ -4,6 +4,7 @@ package net.minecraft.server; import java.util.List; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.LongHash; import org.bukkit.entity.HumanEntity; import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceSmeltEvent; @@ -206,7 +207,7 @@ public class TileEntityFurnace extends TileEntityContainer implements IUpdatePla if (!this.isBurning() && this.cookTime > 0) { this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.cookTimeTotal); } - } else { + } else if (this.items[1] != null && this.items[1].getItem() != Items.BUCKET) { // Migot // CraftBukkit start - Handle multiple elapsed ticks if (this.burnTime <= 0 && this.canBurn()) { // CraftBukkit - == to <= CraftItemStack fuel = CraftItemStack.asCraftMirror(this.items[1]); @@ -271,6 +272,7 @@ public class TileEntityFurnace extends TileEntityContainer implements IUpdatePla return false; } else { ItemStack itemstack = RecipesFurnace.getInstance().getResult(this.items[0]); + if(!this.world.isLoaded(this.position) || ((WorldServer) this.world).chunkProviderServer.unloadQueue.contains(LongHash.toLong(this.position.getX() >> 4, this.position.getZ() >> 4))) { return false; } // Migot // CraftBukkit - consider resultant count instead of current count return itemstack == null ? false : (this.items[2] == null ? true : (!this.items[2].doMaterialsMatch(itemstack) ? false : (this.items[2].count + itemstack.count <= this.getMaxStackSize() && this.items[2].count < this.items[2].getMaxStackSize() ? true : this.items[2].count + itemstack.count <= itemstack.getMaxStackSize()))); diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/Village.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/Village.java index 4bb971f..78b9402 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/Village.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/Village.java @@ -41,7 +41,33 @@ public class Village { this.a = world; } + // Migot start + private BlockPosition[] positions = null; + + private void calculateNewCheckPositions() { + if(this.d == null || this.d.equals(BlockPosition.ZERO)) { + this.positions = null; + } else { + this.positions = new BlockPosition[] { this.d.a(-this.e, 0, -this.e), + this.d.a(-this.e, 0, this.e), + this.d.a(this.e, 0, -this.e), + this.d.a(this.e, 0, this.e), + this.d}; + } + } + + public boolean isVillageAreaLoaded() { + for(int i = 0; this.positions != null && i < this.positions.length; i++) { + if(this.a.isLoaded(this.positions[i])) { + return true; + } + } + return false; + } + // Migot end + public void a(int i) { + if(!this.isVillageAreaLoaded()) { return; } // Migot this.g = i; this.m(); this.l(); @@ -402,6 +428,7 @@ public class Village { } } + this.calculateNewCheckPositions(); // Migot } public void b(NBTTagCompound nbttagcompound) { 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 194a70d..2ef88af 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/World.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/World.java @@ -170,6 +170,28 @@ public abstract class World implements IBlockAccess { public final co.aikar.timings.WorldTimingsHandler timings; // Spigot public final net.techcable.tacospigot.TacoSpigotWorldConfig tacoSpigotConfig; + // Migot start + private Chunk dummyChunk = new EmptyChunk(this, Integer.MIN_VALUE, Integer.MIN_VALUE); + private Chunk lastChunkAccessed = dummyChunk; + final Object chunkLock = new Object(); + public ChunkProviderServer chunkProviderServer; // moved here from WorldServer + protected boolean cancelHeavyCalculations = false; + private List dimensionChangeQueue = java.util.Collections.synchronizedList(new ArrayList()); + + public void queueEntityForDimensionChange(Entity entity) { + this.dimensionChangeQueue.add(entity); + } + + public void processDimensionChangeQueue() { + Iterator iter = this.dimensionChangeQueue.iterator(); + while(iter.hasNext()) { + Entity entity = iter.next(); + entity.changeDimension(entity.getTargetDimension()); + iter.remove(); + } + } + // Migot end + public CraftWorld getWorld() { return this.world; } @@ -362,8 +384,30 @@ public abstract class World implements IBlockAccess { return this.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4); } + // Migot start + private void cacheLastChunkAccess(Chunk foundChunk) { + this.lastChunkAccessed = ((foundChunk == null || foundChunk.isEmpty() || foundChunk.wasUnloaded()) ? this.dummyChunk : foundChunk); + } + // Migot end + public Chunk getChunkAt(int i, int j) { - return this.chunkProvider.getOrCreateChunk(i, j); + // Migot start + Chunk last = this.lastChunkAccessed; + if(last.a(i,j) && !last.wasUnloaded()) { + return last; + } else { + Chunk result = null; + if(this.chunkProviderServer.isChunkLoaded(i, j)) { + result = this.chunkProviderServer.getChunkAt(i, j); + } else { + synchronized (this.chunkLock) { + result = this.chunkProvider.getOrCreateChunk(i, j); + } + } + this.cacheLastChunkAccess(result); + return result; + } + // Migot end } public boolean setTypeAndData(BlockPosition blockposition, IBlockData iblockdata, int i) { @@ -1013,7 +1057,23 @@ public abstract class World implements IBlockAccess { } } + // KigPaper start + public void playSoundIncludingSelf(EntityHuman entityhuman, String s, float f, float f1) { + for (IWorldAccess worldAccess : this.u) { + if (worldAccess instanceof WorldManager) { + ((WorldManager) worldAccess).broadcastPacketIncludingSelf(entityhuman, s, entityhuman.locX, entityhuman.locY, entityhuman.locZ, f, f1); + } + } + } + // KigPaper end + public void makeSound(Entity entity, String s, float f, float f1) { + // KigPaper start - respect visibility for players + if (entity instanceof EntityHuman) { + this.playSoundIncludingSelf((EntityHuman) entity, s, f, f1); + return; + } + // KigPaper end for (int i = 0; i < this.u.size(); ++i) { ((IWorldAccess) this.u.get(i)).a(s, entity.locX, entity.locY, entity.locZ, f, f1); } diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldManager.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldManager.java index 55a2112..2ade8fb 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldManager.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldManager.java @@ -33,6 +33,13 @@ public class WorldManager implements IWorldAccess { this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world.dimension, new PacketPlayOutNamedSoundEffect(s, d0, d1, d2, f, f1)); } + // KigPaper start + public void broadcastPacketIncludingSelf(EntityHuman entityhuman, String s, double d0, double d1, double d2, float f, float f1) { + // CraftBukkit - this.world.dimension + this.a.getPlayerList().sendPacketNearbyIncludingSelf(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world.dimension, new PacketPlayOutNamedSoundEffect(s, d0, d1, d2, f, f1)); + } + // KigPaper end + public void a(int i, int j, int k, int l, int i1, int j1) {} public void a(BlockPosition blockposition) { diff --git a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldNBTStorage.java b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldNBTStorage.java index e5124af..8293ba0 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldNBTStorage.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldNBTStorage.java @@ -15,6 +15,7 @@ import org.apache.logging.log4j.Logger; import java.util.UUID; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.github.paperspigot.PaperSpigotConfig; // CraftBukkit end public class WorldNBTStorage implements IDataManager, IPlayerFileData { @@ -196,13 +197,15 @@ public class WorldNBTStorage implements IDataManager, IPlayerFileData { } public NBTTagCompound load(EntityHuman entityhuman) { + if (!PaperSpigotConfig.savePlayerFiles) return null; // KigPaper NBTTagCompound nbttagcompound = null; try { File file = new File(this.playerDir, entityhuman.getUniqueID().toString() + ".dat"); // Spigot Start boolean usingWrongFile = false; - if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // PaperSpigot - Check online mode first + boolean normalFile = file.exists() && file.isFile(); // KigPaper + if ( org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // PaperSpigot - Check online mode first { file = new File( this.playerDir, UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + entityhuman.getName() ).getBytes( "UTF-8" ) ).toString() + ".dat"); if ( file.exists() ) @@ -213,7 +216,7 @@ public class WorldNBTStorage implements IDataManager, IPlayerFileData { } // Spigot End - if (file.exists() && file.isFile()) { + if (normalFile) { // KigPaper nbttagcompound = NBTCompressedStreamTools.a((InputStream) (new FileInputStream(file))); } // Spigot Start 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 e7ad12f..85da369 100644 --- a/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java +++ b/TacoSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java @@ -36,7 +36,7 @@ public class WorldServer extends World implements IAsyncTaskHandler { private final PlayerChunkMap manager; private final HashTreeSet M = new HashTreeSet<>(); // CraftBukkit - HashTreeSet // PAIL: Rename nextTickList private final Map entitiesByUUID = Maps.newHashMap(); - public ChunkProviderServer chunkProviderServer; + //public ChunkProviderServer chunkProviderServer; // Migot - moved to World public boolean savingDisabled; private boolean O; private int emptyTime; @@ -48,6 +48,12 @@ public class WorldServer extends World implements IAsyncTaskHandler { private static final List U = Lists.newArrayList(new StructurePieceTreasure[] { new StructurePieceTreasure(Items.STICK, 0, 1, 3, 10), new StructurePieceTreasure(Item.getItemOf(Blocks.PLANKS), 0, 1, 3, 10), new StructurePieceTreasure(Item.getItemOf(Blocks.LOG), 0, 1, 3, 10), new StructurePieceTreasure(Items.STONE_AXE, 0, 1, 1, 3), new StructurePieceTreasure(Items.WOODEN_AXE, 0, 1, 1, 5), new StructurePieceTreasure(Items.STONE_PICKAXE, 0, 1, 1, 3), new StructurePieceTreasure(Items.WOODEN_PICKAXE, 0, 1, 1, 5), new StructurePieceTreasure(Items.APPLE, 0, 2, 3, 5), new StructurePieceTreasure(Items.BREAD, 0, 2, 3, 3), new StructurePieceTreasure(Item.getItemOf(Blocks.LOG2), 0, 1, 3, 10)}); private List V = Lists.newArrayList(); + // Migot start + public void cancelHeavyCalculations(boolean cancel) { + this.cancelHeavyCalculations = cancel; + } + // Migot end + // CraftBukkit start public final int dimension; diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 9cea326..dca53b7 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -52,13 +52,7 @@ import org.bukkit.craftbukkit.command.VanillaCommandWrapper; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.generator.CraftChunkData; import org.bukkit.craftbukkit.help.SimpleHelpMap; -import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe; -import org.bukkit.craftbukkit.inventory.CraftInventoryCustom; -import org.bukkit.craftbukkit.inventory.CraftItemFactory; -import org.bukkit.craftbukkit.inventory.CraftRecipe; -import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; -import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; -import org.bukkit.craftbukkit.inventory.RecipeIterator; +import org.bukkit.craftbukkit.inventory.*; import org.bukkit.craftbukkit.map.CraftMapView; import org.bukkit.craftbukkit.metadata.EntityMetadataStore; import org.bukkit.craftbukkit.metadata.PlayerMetadataStore; @@ -103,6 +97,8 @@ import org.bukkit.plugin.messaging.StandardMessenger; import org.bukkit.scheduler.BukkitWorker; import org.bukkit.util.StringUtil; import org.bukkit.util.permissions.DefaultPermissions; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.error.MarkedYAMLException; @@ -125,6 +121,7 @@ import io.netty.buffer.Unpooled; import io.netty.handler.codec.base64.Base64; import jline.console.ConsoleReader; import net.md_5.bungee.api.chat.BaseComponent; +import org.yaml.snakeyaml.representer.Representer; public final class CraftServer implements Server { private static final Player[] EMPTY_PLAYER_ARRAY = new Player[0]; @@ -143,7 +140,10 @@ public final class CraftServer implements Server { private final Map worlds = new LinkedHashMap(); private YamlConfiguration configuration; private YamlConfiguration commandsConfiguration; - private final Yaml yaml = new Yaml(new SafeConstructor()); + // KigPaper start - CVE-2017-18640 + private final LoaderOptions loaderOptions = new LoaderOptions(); + private final Yaml yaml = new Yaml(new SafeConstructor(), new Representer(), new DumperOptions(), loaderOptions); + // KigPaper end private final Map offlinePlayers = new MapMaker().softValues().makeMap(); private final EntityMetadataStore entityMetadata = new EntityMetadataStore(); private final PlayerMetadataStore playerMetadata = new PlayerMetadataStore(); @@ -178,6 +178,7 @@ public final class CraftServer implements Server { } public CraftServer(MinecraftServer console, PlayerList playerList) { + loaderOptions.setMaxAliasesForCollections(32); // KigPaper - CVE-2017-18640 this.console = console; this.playerList = (DedicatedPlayerList) playerList; this.playerView = Collections.unmodifiableList(Lists.transform(playerList.players, new Function() { @@ -1005,11 +1006,32 @@ public final class CraftServer implements Server { } catch (ExceptionWorldConflict ex) { getLogger().log(Level.SEVERE, null, ex); } + } else { // KigPaper start + ChunkProviderServer cps = handle.chunkProviderServer; + ChunkRegionLoader loader = (ChunkRegionLoader) cps.chunkLoader; + loader.b.clear(); + loader.c.clear(); + try { + FileIOThread.a().b(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + cps.chunkLoader = null; + cps.chunkProvider = null; + cps.chunks.clear(); + // KigPaper end } worlds.remove(world.getName().toLowerCase()); console.worlds.remove(console.worlds.indexOf(handle)); + // KigPaper start - fix memory leak + CraftingManager craftingManager = CraftingManager.getInstance(); + CraftInventoryView lastView = (CraftInventoryView) craftingManager.lastCraftView; + if (lastView != null && lastView.getHandle() instanceof ContainerWorkbench + && ((ContainerWorkbench) lastView.getHandle()).g == handle) craftingManager.lastCraftView = null; + // KigPaper end + File parentFolder = world.getWorldFolder().getAbsoluteFile(); // Synchronized because access to RegionFileCache.a is guarded by this lock. @@ -1834,4 +1856,11 @@ public final class CraftServer implements Server { { return spigot; } + + // KigPaper start + @Override + public String getPermissionMessage() { + return configuration.getString("settings.permission-message", ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error."); + } + // KigPaper end } diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftSound.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftSound.java index 0cc8f9b..7b6fee6 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftSound.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftSound.java @@ -216,6 +216,19 @@ public class CraftSound { // Tile set(PISTON_EXTEND, "tile.piston.out"); set(PISTON_RETRACT, "tile.piston.in"); + // KigPaper start - Guardian sounds + set(GUARDIAN_IDLE, "mob.guardian.idle"); + set(GUARDIAN_IDLE_LAND, "mob.guardian.land.idle"); + set(GUARDIAN_IDLE_ELDER, "mob.guardian.elder.idle"); + set(GUARDIAN_HIT, "mob.guardian.hit"); + set(GUARDIAN_HIT_LAND, "mob.guardian.land.hit"); + set(GUARDIAN_HIT_ELDER, "mob.guardian.elder.hit"); + set(GUARDIAN_DEATH, "mob.guardian.death"); + set(GUARDIAN_DEATH_LAND, "mob.guardian.land.death"); + set(GUARDIAN_DEATH_ELDER, "mob.guardian.elder.death"); + set(GUARDIAN_FLOP, "mob.guardian.flop"); + set(GUARDIAN_CURSE, "mob.guardian.curse"); + // KigPaper end } private static void set(Sound sound, String key) { diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java index cae65cf..60ccaec 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java @@ -44,7 +44,12 @@ public class CraftTravelAgent extends PortalTravelAgent implements TravelAgent { @Override public Location findPortal(Location location) { PortalTravelAgent pta = ((CraftWorld) location.getWorld()).getHandle().getTravelAgent(); - BlockPosition found = pta.findPortal(location.getX(), location.getY(), location.getZ(), this.getSearchRadius()); + // Migot start + BlockPosition found = pta.findPortal(location.getX(), location.getY(), location.getZ(), 10); + if (found == null) { + found = pta.findPortal(location.getX(), location.getY(), location.getZ(), this.getSearchRadius()); + } + // Migot end return found != null ? new Location(location.getWorld(), found.getX(), found.getY(), found.getZ(), location.getYaw(), location.getPitch()) : null; } 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 e0fe200..ff0ec00 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit; +import com.elevatemc.spigot.util.Dictionary; import com.google.common.base.Preconditions; import java.io.File; import java.util.ArrayList; @@ -35,6 +36,7 @@ import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.entity.*; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.metadata.BlockMetadataStore; +import org.bukkit.craftbukkit.metadata.SpecializedBlockMetadataStore; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.LongHash; import org.bukkit.entity.*; @@ -51,6 +53,7 @@ import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataStore; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.messaging.StandardMessenger; @@ -65,7 +68,10 @@ public class CraftWorld implements World { private final CraftServer server = (CraftServer) Bukkit.getServer(); private final ChunkGenerator generator; private final List populators = new ArrayList(); - private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this); + // KigPaper start + //private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this); + private final MetadataStore blockMetadata = new SpecializedBlockMetadataStore(this); + // KigPaper end private int monsterSpawn = -1; private int animalSpawn = -1; private int waterAnimalSpawn = -1; @@ -235,6 +241,7 @@ public class CraftWorld implements World { save = true; } + chunk.markAsUnloaded(); // Migot chunk.removeEntities(); // Always remove entities - even if discarding, need to get them out of world table if (save && !(chunk instanceof EmptyChunk)) { @@ -787,17 +794,12 @@ public class CraftWorld implements World { } public void save() { - // Spigot start - save(true); - } - public void save(boolean forceSave) { - // Spigot end this.server.checkSaveState(); try { boolean oldSave = world.savingDisabled; world.savingDisabled = false; - world.save(forceSave, null); // Spigot + world.save(true, null); // Spigot world.savingDisabled = oldSave; } catch (ExceptionWorldConflict ex) { @@ -821,7 +823,7 @@ public class CraftWorld implements World { return Difficulty.getByValue(this.getHandle().getDifficulty().ordinal()); } - public BlockMetadataStore getBlockMetadata() { + public MetadataStore getBlockMetadata() { // KigPaper - change type return blockMetadata; } @@ -1457,22 +1459,16 @@ public class CraftWorld implements World { { net.minecraft.server.EnumParticle particle = null; int[] extra = null; - for ( net.minecraft.server.EnumParticle p : net.minecraft.server.EnumParticle.values() ) - { - if ( effect.getName().startsWith( p.b().replace("_", "") ) ) + if ((particle = Dictionary.EFFECT_TO_PARTICLE.get(effect)) != null) { + if ( effect.getData() != null ) { - particle = p; - if ( effect.getData() != null ) + if ( effect.getData().equals( Material.class ) ) { - if ( effect.getData().equals( org.bukkit.Material.class ) ) - { - extra = new int[]{ id }; - } else - { - extra = new int[]{ (data << 12) | (id & 0xFFF) }; - } + extra = new int[]{ id }; + } else + { + extra = new int[]{ (data << 12) | (id & 0xFFF) }; } - break; } } if ( extra == null ) diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java index b339cf3..72f99df 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java @@ -12,18 +12,19 @@ import org.bukkit.plugin.Plugin; import java.util.Set; public abstract class ServerCommandSender implements CommandSender { - private static PermissibleBase blockPermInst; + //private static PermissibleBase blockPermInst; // KigPaper - fix memory leak private final PermissibleBase perm; public ServerCommandSender() { - if (this instanceof CraftBlockCommandSender) { + /* if (this instanceof CraftBlockCommandSender) { if (blockPermInst == null) { blockPermInst = new PermissibleBase(this); } this.perm = blockPermInst; } else { this.perm = new PermissibleBase(this); - } + } */ // KigPaper + this.perm = new PermissibleBase(this); } public boolean isPermissionSet(String name) { diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 0be2129..998cdef 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -43,7 +43,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { protected final CraftServer server; protected Entity entity; - private EntityDamageEvent lastDamageEvent; + //private EntityDamageEvent lastDamageEvent; // KigPaper - this is almost never used and only leads to memory leaks public CraftEntity(final CraftServer server, final Entity entity) { this.server = server; @@ -259,6 +259,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { // entity.world = ((CraftWorld) location.getWorld()).getHandle(); // Spigot end entity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + entity.f(location.getYaw()); // KigPaper - update head yaw to keep consistency with /tp entity.world.entityJoinedWorld(entity, false); // PaperSpigot - Fix issues with entities not being switched to their new chunk // entity.setLocation() throws no event, and so cannot be cancelled return true; @@ -358,11 +359,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } public void setLastDamageCause(EntityDamageEvent event) { - lastDamageEvent = event; + // lastDamageEvent = event; } public EntityDamageEvent getLastDamageCause() { - return lastDamageEvent; + return null; } public UUID getUniqueId() { 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 3f1b541..07ad9a8 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,6 +1,7 @@ package org.bukkit.craftbukkit.entity; import com.elevatemc.spigot.event.PlayerHealthChangeEvent; +import com.elevatemc.spigot.util.Dictionary; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.mojang.authlib.GameProfile; @@ -289,6 +290,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } } + @Override + public void sendActionbarMessage(BaseComponent... message) { + if(getHandle().playerConnection == null) return; + PacketPlayOutChat packet = new PacketPlayOutChat(null, (byte) 2); + packet.components = message; + getHandle().playerConnection.sendPacket(packet); + } + // KigPaper end + @Override public boolean equals(Object obj) { if (!(obj instanceof OfflinePlayer)) { @@ -532,7 +542,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } if (entity.passenger != null) { - return false; + // KigPaper - only cancel if not unknown + // if a PlayerMoveEvent is cancelled using setTo and the player has a passenger, the event won't set the user back. + if (cause != PlayerTeleportEvent.TeleportCause.UNKNOWN) { + return false; + } } // From = Players current Location @@ -1244,7 +1258,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setFlying(boolean value) { - boolean needsUpdate = getHandle().abilities.canFly != value; // PaperSpigot - Only refresh abilities if needed + boolean needsUpdate = getHandle().abilities.isFlying != value; // PaperSpigot - Only refresh abilities if needed if (!getAllowFlight() && value) { throw new IllegalArgumentException("Cannot make player fly if getAllowFlight() is false"); } @@ -1508,22 +1522,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { { net.minecraft.server.EnumParticle particle = null; int[] extra = null; - for ( net.minecraft.server.EnumParticle p : net.minecraft.server.EnumParticle.values() ) - { - if ( effect.getName().startsWith( p.b().replace("_", "") ) ) + if ((particle = Dictionary.EFFECT_TO_PARTICLE.get(effect)) != null) { + if ( effect.getData() != null ) { - particle = p; - if ( effect.getData() != null ) + if ( effect.getData().equals( org.bukkit.Material.class ) ) { - if ( effect.getData().equals( org.bukkit.Material.class ) ) - { - extra = new int[]{ id }; - } else - { - extra = new int[]{ (data << 12) | (id & 0xFFF) }; - } + extra = new int[]{ id }; + } else + { + extra = new int[]{ (data << 12) | (id & 0xFFF) }; } - break; } } if ( extra == null ) diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index db91503..6adc8f6 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -188,7 +188,7 @@ public class CraftEventFactory { if (action != Action.LEFT_CLICK_AIR && action != Action.RIGHT_CLICK_AIR) { throw new IllegalArgumentException(String.format("%s performing %s with %s", who, action, itemstack)); // Spigot } - return callPlayerInteractEvent(who, action, new BlockPosition(0, 256, 0), EnumDirection.SOUTH, itemstack); + return callPlayerInteractEvent(who, action, /*new BlockPosition(0, 256, 0) KigPaper */ null, EnumDirection.SOUTH, itemstack); } public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, BlockPosition position, EnumDirection direction, ItemStack itemstack) { @@ -202,11 +202,11 @@ public class CraftEventFactory { CraftWorld craftWorld = (CraftWorld) player.getWorld(); CraftServer craftServer = (CraftServer) player.getServer(); - Block blockClicked = craftWorld.getBlockAt(position.getX(), position.getY(), position.getZ()); - BlockFace blockFace = CraftBlock.notchToBlockFace(direction); - - if (position.getY() > 255) { - blockClicked = null; + // Block blockClicked = craftWorld.getBlockAt(position.getX(), position.getY(), position.getZ()); // KigPaper + Block blockClicked = null; + if (position != null) { + blockClicked = craftWorld.getBlockAt(position.getX(), position.getY(), position.getZ()); + } else { switch (action) { case LEFT_CLICK_BLOCK: action = Action.LEFT_CLICK_AIR; @@ -217,6 +217,8 @@ public class CraftEventFactory { } } + BlockFace blockFace = CraftBlock.notchToBlockFace(direction); // KigPaper - moved down + if (itemInHand.getType() == Material.AIR || itemInHand.getAmount() == 0) { itemInHand = null; } @@ -532,7 +534,8 @@ public class CraftEventFactory { } else if (source == DamageSource.FALL) { cause = DamageCause.FALL; } else if (source == DamageSource.GENERIC) { - return new EntityDamageEvent(entity.getBukkitEntity(), null, modifiers, modifierFunctions); + //return new EntityDamageEvent(entity.getBukkitEntity(), null, modifiers, modifierFunctions); + cause = DamageCause.CUSTOM; // KigPaper } if (cause != null) { diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java index 0b5ada0..2463640 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java @@ -33,8 +33,10 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta { static final ItemMetaKey BOOK_PAGES = new ItemMetaKey("pages"); static final ItemMetaKey RESOLVED = new ItemMetaKey("resolved"); static final ItemMetaKey GENERATION = new ItemMetaKey("generation"); - static final int MAX_PAGE_LENGTH = Short.MAX_VALUE; // TODO: Check me - static final int MAX_TITLE_LENGTH = 0xffff; + static final int MAX_PAGES = 50; + static final int MAX_PAGE_LENGTH = 256; + static final int MAX_TITLE_LENGTH = 16; + protected String title; protected String author; @@ -61,11 +63,11 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta { super(tag); if (tag.hasKey(BOOK_TITLE.NBT)) { - this.title = limit( tag.getString(BOOK_TITLE.NBT), 1024 ); // Spigot + this.title = limit( tag.getString(BOOK_TITLE.NBT), 32 ); // Spigot // KigPaper - tighter limits } if (tag.hasKey(BOOK_AUTHOR.NBT)) { - this.author = limit( tag.getString(BOOK_AUTHOR.NBT), 1024 ); // Spigot + this.author = limit( tag.getString(BOOK_AUTHOR.NBT), 16 ); // Spigot // KigPaper - tighter limits } boolean resolved = false; @@ -80,6 +82,7 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta { if (tag.hasKey(BOOK_PAGES.NBT) && handlePages) { NBTTagList pages = tag.getList(BOOK_PAGES.NBT, 8); + if (pages.size() > MAX_PAGES) return; // KigPaper - limit pages for (int i = 0; i < pages.size(); i++) { String page = pages.getString(i); if (resolved) { @@ -90,7 +93,7 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta { // Ignore and treat as an old book } } - addPage( limit( page, 2048 ) ); // Spigot + addPage( limit( page, MAX_PAGE_LENGTH ) ); // Spigot // KigPaper - tighter limits } } } @@ -103,13 +106,17 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta { setTitle(SerializableMeta.getString(map, BOOK_TITLE.BUKKIT, true)); Iterable pages = SerializableMeta.getObject(Iterable.class, map, BOOK_PAGES.BUKKIT, true); + // KigPaper start - limit pages if(pages != null) { + int count = 0; for (Object page : pages) { + if (count++ > MAX_PAGES) break; if (page instanceof String) { addPage((String) page); } } } + // KigPaper end generation = SerializableMeta.getObject(Integer.class, map, GENERATION.BUKKIT, true); } @@ -225,10 +232,14 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta { public void addPage(final String... pages) { for (String page : pages) { + if (this.pages.size() >= MAX_PAGES) { + return; + } if (page == null) { page = ""; } else if (page.length() > MAX_PAGE_LENGTH) { - page = page.substring(0, MAX_PAGE_LENGTH); + //page = page.substring(0, MAX_PAGE_LENGTH); + return; // KigPaper } this.pages.add(CraftChatMessage.fromString(page, true)[0]); diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java index ad47bdd..7e43bdb 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java @@ -35,15 +35,17 @@ public class CraftMapRenderer extends MapRenderer { cursors.removeCursor(cursors.getCursor(0)); } - for (UUID key : worldMap.decorations.keySet()) { // Spigot string -> uuid. - // If this cursor is for a player check visibility with vanish system - Player other = Bukkit.getPlayer(key); // Spigot - if (other != null && !player.canSee(other)) { - continue; + if (getDrawCursors()) { + for (UUID key : worldMap.decorations.keySet()) { // Spigot string -> uuid. + // If this cursor is for a player check visibility with vanish system + Player other = Bukkit.getPlayer(key); // Spigot + if (other != null && !player.canSee(other)) { + continue; + } + + MapIcon decoration = (MapIcon) worldMap.decorations.get(key); + cursors.addCursor(decoration.getX(), decoration.getY(), (byte) (decoration.getRotation() & 15), decoration.getType()); } - - MapIcon decoration = (MapIcon) worldMap.decorations.get(key); - cursors.addCursor(decoration.getX(), decoration.getY(), (byte) (decoration.getRotation() & 15), decoration.getType()); } } diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/SpecializedBlockMetadataStore.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/SpecializedBlockMetadataStore.java new file mode 100644 index 0000000..920d968 --- /dev/null +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/SpecializedBlockMetadataStore.java @@ -0,0 +1,175 @@ +package org.bukkit.craftbukkit.metadata; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.metadata.MetadataStore; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; + +import java.util.*; + +/** + * An alternative to {@link BlockMetadataStore} that uses specialized collections and bit-packing for faster + * operations and a lower memory footprint. + * + *

This can be a drop-in replacement, though keep in mind methods will throw an {@link IllegalArgumentException} + * if invalid block coordinates are provided. + */ +public class SpecializedBlockMetadataStore implements MetadataStore { + // Allows storing 25 bits (up to 33,554,432 - MC supports up to 30,000,000) sign + private static final int MASK_26_BITS = 0b111_111_111_111_111_111_111_111_11; + + private final Map> metadata = new HashMap<>(); + private final World owningWorld; + + // Cached key used for (synchronized) lookups, saves allocations. + // The key stored inside is usually cleared after use, so that the reference doesn't live too long. + private final StoreKey cachedKey = new StoreKey(null, 0); + + public SpecializedBlockMetadataStore(World owningWorld) { + this.owningWorld = owningWorld; + } + + @Override + public synchronized List getMetadata(Block block, String metadataKey) { + Preconditions.checkArgument(block.getWorld() == owningWorld, "block is from another world"); + + List list = Collections.emptyList(); + Map pluginMetadata = getEntry(metadataKey, block); + if (pluginMetadata == null) { + return list; + } + list = ImmutableList.copyOf(pluginMetadata.values()); + + return list; + } + + @Override + public synchronized boolean hasMetadata(Block block, String metadataKey) { + Preconditions.checkArgument(block.getWorld() == owningWorld, "block is from another world"); + Map pluginMetadata = getEntry(metadataKey, block); + return pluginMetadata != null && !pluginMetadata.isEmpty(); + } + + @Override + public synchronized void removeMetadata(Block block, String metadataKey, Plugin owningPlugin) { + Preconditions.checkArgument(block.getWorld() == owningWorld, "block is from another world"); + Preconditions.checkNotNull(owningPlugin, "plugin is null"); + + long id = getBlockId(block); + Map pluginMetadata = getEntry(metadataKey, id); + if (pluginMetadata == null) { + return; + } + // Clear empty entries + if (pluginMetadata.remove(owningPlugin) != null && pluginMetadata.isEmpty()) { + StoreKey key = getCachedKey(metadataKey, id); + this.metadata.remove(key); + key.metadataKey = null; + } + } + + @Override + public synchronized void setMetadata(Block block, String metadataKey, MetadataValue newMetadataValue) { + Preconditions.checkArgument(block.getWorld() == owningWorld, "block is from another world"); + Preconditions.checkNotNull(newMetadataValue, "value is null"); + Plugin owningPlugin = newMetadataValue.getOwningPlugin(); + Preconditions.checkNotNull(owningPlugin, "plugin is null"); + + Map entry = metadata.computeIfAbsent(new StoreKey(metadataKey, getBlockId(block)), + k -> new WeakHashMap<>(1)); + entry.put(owningPlugin, newMetadataValue); + } + + @Override + public synchronized void invalidateAll(Plugin owningPlugin) { + Preconditions.checkNotNull(owningPlugin, "plugin is null"); + for (Map values : metadata.values()) { + MetadataValue value = values.get(owningPlugin); + if (value != null) { + value.invalidate(); + } + } + } + + private Map getEntry(String key, Block block) { + return getEntry(key, getBlockId(block)); + } + + private Map getEntry(String key, long id) { + StoreKey storeKey = getCachedKey(key, id); + Map ret = metadata.get(storeKey); + storeKey.metadataKey = null; + return ret; + } + + private StoreKey getCachedKey(String metadataKey, long id) { + cachedKey.block = id; + cachedKey.metadataKey = metadataKey; + return cachedKey; + } + + static long getBlockId(Block block) { + int x = block.getX(); + int y = block.getY(); + int z = block.getZ(); + Preconditions.checkArgument(x >= -30_000_000 && x <= 30_000_000, + "block X out of range"); + Preconditions.checkArgument(y >= 0 && y <= 255, "block Y out of range"); + Preconditions.checkArgument(z >= -30_000_000 && z <= 30_000_000, + "block Z out of range"); + // X (26 bits) + Y (8 bits) + Z (26 bits) + return ((long) (x & MASK_26_BITS) << 34) | ((long) (y & 0xFF) << 26) | (z & MASK_26_BITS); + } + + /** + * Used for tests. + */ + static Location toLocation(World world, long id) { + int x = (int) (id >> 34); + int y = (int) ((id >> 26) & 0xFF); + int z = (int) id; + + // Restore sign + if ((x & (1 << 25)) > 0) { + x |= ~MASK_26_BITS; + } else { + x &= MASK_26_BITS; + } + + if ((z & (1 << 25)) > 0) { + z |= ~MASK_26_BITS; + } else { + z &= MASK_26_BITS; + } + + return new Location(world, x, y, z); + } + + private static class StoreKey { + private String metadataKey; + private long block; + + private StoreKey(String metadataKey, long block) { + this.metadataKey = metadataKey; + this.block = block; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StoreKey storeKey = (StoreKey) o; + return block == storeKey.block && Objects.equal(metadataKey, storeKey.metadataKey); + } + + @Override + public int hashCode() { + return Objects.hashCode(metadataKey, block); + } + } +} \ No newline at end of file diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java index dd37ed2..1077fab 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java @@ -10,7 +10,7 @@ import org.bukkit.metadata.MetadataStoreBase; public class WorldMetadataStore extends MetadataStoreBase implements MetadataStore { /** * Generates a unique metadata key for a {@link World} object based on the world UID. - * @see WorldMetadataStore#disambiguate(Object, String) + * @see WorldMetadataStore#disambiguate(World, String) * @param world the world * @param metadataKey The name identifying the metadata value * @return a unique metadata key diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index d76ec40..1b0899b 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -32,7 +32,7 @@ import org.bukkit.scheduler.BukkitWorker; *

  • Changing the period on a task is delicate. * Any future task needs to notify waiting threads. * Async tasks must be synchronized to make sure that any thread that's finishing will remove itself from {@link #runners}. - * Another utility method is provided for this, {@link #cancelTask(CraftTask)}
  • + * Another utility method is provided for this, {@link #cancelTask(int)} *
  • {@link #runners} provides a moderately up-to-date view of active tasks. * If the linked head to tail set is read, all remaining tasks that were active at the time execution started will be located in runners.
  • *
  • Async tasks are responsible for removing themselves from runners
  • @@ -47,7 +47,7 @@ public class CraftScheduler implements BukkitScheduler { */ private final AtomicInteger ids = new AtomicInteger(1); /** - * Current head of linked-list. This reference is always stale, {@link CraftTask#next} is the live reference. + * Current head of linked-list. This reference is always stale, {@code CraftTask#next} is the live reference. */ private volatile CraftTask head = new CraftTask(); /** diff --git a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java index 38ef821..74f9799 100644 --- a/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +++ b/TacoSpigot-Server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java @@ -22,7 +22,8 @@ public final class CraftChatMessage { private static final Pattern LINK_PATTERN = Pattern.compile("((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " \\n]|$))))"); private static class StringMessage { private static final Map formatMap; - private static final Pattern INCREMENTAL_PATTERN = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-or])|(\\n)|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " \\n]|$))))", Pattern.CASE_INSENSITIVE); + //private static final Pattern INCREMENTAL_PATTERN = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-or])|(\\n)|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " \\n]|$))))", Pattern.CASE_INSENSITIVE); + private static final Pattern INCREMENTAL_PATTERN = Pattern.compile("(§[0-9a-fk-or])|(\\n)|(https?://[^\\s/$.?#].[^\\s§]*)", Pattern.CASE_INSENSITIVE); // KigPaper - better regex static { Builder builder = ImmutableMap.builder(); diff --git a/TacoSpigot-Server/src/main/java/org/github/paperspigot/PaperSpigotConfig.java b/TacoSpigot-Server/src/main/java/org/github/paperspigot/PaperSpigotConfig.java index 6e9bec7..d4fe328 100644 --- a/TacoSpigot-Server/src/main/java/org/github/paperspigot/PaperSpigotConfig.java +++ b/TacoSpigot-Server/src/main/java/org/github/paperspigot/PaperSpigotConfig.java @@ -13,6 +13,7 @@ import java.util.logging.Level; import net.minecraft.server.Item; import net.minecraft.server.Items; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.RegionFile; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -227,4 +228,41 @@ public class PaperSpigotConfig private static void saveEmptyScoreboardTeams() { saveEmptyScoreboardTeams = getBoolean("save-empty-scoreboard-teams", false); } + + // KigPaper start + public static boolean betterVehicleHitboxes; + private static void betterVehicleHitboxes() { + betterVehicleHitboxes = getBoolean("better-vehicle-hitboxes", true); + } + + public static boolean nettyReadTimeout; + private static void nettyReadTimeout() { + nettyReadTimeout = getBoolean("netty-read-timeout", true); + } + + public static boolean savePlayerFiles; + private static void savePlayerFiles() { + savePlayerFiles = getBoolean("save-player-files", true); + } + + public static boolean enableBookDeserialization; + private static void enableBookDeserialization() { + enableBookDeserialization = getBoolean("enable-book-deserialization", false); + } + + public static boolean accurateBlockCollisions; + private static void accurateBlockCollisions() { + accurateBlockCollisions = getBoolean("accurate-block-collisions", true); + } + + public static RegionFile.CompressionAlgorithm regionCompressionAlgorithm; + private static void regionCompressionAlgorithm() { + regionCompressionAlgorithm = RegionFile.CompressionAlgorithm.valueOf(getString("region-compression-algo", "ZLIB").toUpperCase(Locale.ROOT)); + } + + public static boolean kickChatMessageLength; + private static void kickChatMessageLength() { + kickChatMessageLength = getBoolean("kick-chat-message-length", false); + } + // KigPaper end } diff --git a/TacoSpigot-Server/src/main/java/org/spigotmc/ActivationRange.java b/TacoSpigot-Server/src/main/java/org/spigotmc/ActivationRange.java index d3767d2..4b5f87d 100644 --- a/TacoSpigot-Server/src/main/java/org/spigotmc/ActivationRange.java +++ b/TacoSpigot-Server/src/main/java/org/spigotmc/ActivationRange.java @@ -67,7 +67,7 @@ public class ActivationRange * These entities are excluded from Activation range checks. * * @param entity - * @param world + * @param config * @return boolean If it should always tick. */ public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config) diff --git a/TacoSpigot-Server/src/main/java/org/spigotmc/Metrics.java b/TacoSpigot-Server/src/main/java/org/spigotmc/Metrics.java index f653050..bdecae2 100644 --- a/TacoSpigot-Server/src/main/java/org/spigotmc/Metrics.java +++ b/TacoSpigot-Server/src/main/java/org/spigotmc/Metrics.java @@ -344,7 +344,7 @@ public class Metrics { */ private void postPlugin(final boolean isPing) throws IOException { // Server software specific section - String pluginName = "TacoSpigot"; // PaperSpigot - We need some usage data // TacoSpigot - its *my* usage data + String pluginName = "eSpigot"; // PaperSpigot - We need some usage data // TacoSpigot - its *my* usage data // eSpigot boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled String pluginVersion = (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"; String serverVersion = Bukkit.getVersion(); diff --git a/TacoSpigot-Server/src/main/java/org/spigotmc/SpigotWorldConfig.java b/TacoSpigot-Server/src/main/java/org/spigotmc/SpigotWorldConfig.java index 8e86212..471d1aa 100644 --- a/TacoSpigot-Server/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/TacoSpigot-Server/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -191,10 +191,15 @@ public class SpigotWorldConfig } public boolean saveStructureInfo; + public boolean saveMineshaftStructureInfo; // Migot private void structureInfo() { saveStructureInfo = getBoolean( "save-structure-info", true ); log( "Structure Info Saving: " + saveStructureInfo ); + // Migot start + saveMineshaftStructureInfo = getBoolean( "save-mineshaft-structure-info", false); + log( "Mineshaft Structure Info Saving: " + saveMineshaftStructureInfo ); + // Migot end if ( !saveStructureInfo ) { log( "*** WARNING *** You have selected to NOT save structure info. This may cause structures such as fortresses to not spawn mobs!" ); diff --git a/TacoSpigot-Server/src/main/java/org/spigotmc/WatchdogThread.java b/TacoSpigot-Server/src/main/java/org/spigotmc/WatchdogThread.java index c8f619a..9fba1c7 100644 --- a/TacoSpigot-Server/src/main/java/org/spigotmc/WatchdogThread.java +++ b/TacoSpigot-Server/src/main/java/org/spigotmc/WatchdogThread.java @@ -56,9 +56,8 @@ public class WatchdogThread extends Thread { Logger log = Bukkit.getServer().getLogger(); log.log( Level.SEVERE, "The server has stopped responding!" ); - log.log( Level.SEVERE, "Please report this to PaperSpigot directly!" ); - log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" ); - log.log( Level.SEVERE, "PaperSpigot version: " + Bukkit.getServer().getVersion() ); + log.log( Level.SEVERE, "This is all alf's fault." ); + log.log( Level.SEVERE, "Version: " + Bukkit.getServer().getVersion() ); // if(net.minecraft.server.World.haveWeSilencedAPhysicsCrash) { diff --git a/TacoSpigot-Server/src/test/java/org/bukkit/craftbukkit/metadata/BlockMetadataTest.java b/TacoSpigot-Server/src/test/java/org/bukkit/craftbukkit/metadata/BlockMetadataTest.java new file mode 100644 index 0000000..2427c90 --- /dev/null +++ b/TacoSpigot-Server/src/test/java/org/bukkit/craftbukkit/metadata/BlockMetadataTest.java @@ -0,0 +1,62 @@ +package org.bukkit.craftbukkit.metadata; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataStore; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.List; + +public class BlockMetadataTest { + @Test + public void oldNewComparison() { + MetadataStore oldStore = new BlockMetadataStore(null); + MetadataStore newStore = new SpecializedBlockMetadataStore(null); + Plugin plugin = Mockito.mock(Plugin.class); + + for (int x = 2, y = 0, z = 2, i = 0; i < 20; i++, x += 300, z += 200, y += 10) { + Block block = makeBlock(i % 2 == 0 ? x : -x, y, i % 2 == 0 ? z : -z); + MetadataValue value = new FixedMetadataValue(plugin, i); + + oldStore.setMetadata(block, "test", value); + oldStore.setMetadata(block, "test" + i, value); + newStore.setMetadata(block, "test", value); + newStore.setMetadata(block, "test" + i, value); + + Assert.assertTrue(newStore.hasMetadata(block, "test")); + Assert.assertTrue(newStore.hasMetadata(block, "test" + i)); + + List test = newStore.getMetadata(block, "test"); + Assert.assertEquals(test, oldStore.getMetadata(block, "test")); + Assert.assertTrue("value in newStore[\"test\"]", test.contains(value)); + + List indexTest = newStore.getMetadata(block, "test" + i); + Assert.assertEquals(indexTest, oldStore.getMetadata(block, "test" + i)); + Assert.assertTrue("value in newStore[\"test\" + i]", indexTest.contains(value)); + } + } + + @Test + public void compareIds() { + for (int x = 3, y = 1, z = 2, i = 0; i < 20; i++, x += 300, z += 200, y += 10) { + Block block = makeBlock(i % 2 == 0 ? x : -x, y, i % 2 == 0 ? z : -z); + Location location = new Location(null, block.getX(), block.getY(), block.getZ()); + + Assert.assertEquals(location, SpecializedBlockMetadataStore.toLocation(null, + SpecializedBlockMetadataStore.getBlockId(block))); + } + } + + private static Block makeBlock(int x, int y, int z) { + Block block = Mockito.mock(Block.class); + Mockito.when(block.getX()).thenReturn(x); + Mockito.when(block.getY()).thenReturn(y); + Mockito.when(block.getZ()).thenReturn(z); + return block; + } +} \ No newline at end of file