Upstream Paper
This commit is contained in:
@@ -111,8 +111,12 @@ public class PaperCommand extends Command {
|
||||
break;
|
||||
case "ver":
|
||||
case "version":
|
||||
org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version").execute(sender, commandLabel, new String[0]);
|
||||
break;
|
||||
Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
|
||||
if (ver != null) {
|
||||
ver.execute(sender, commandLabel, new String[0]);
|
||||
break;
|
||||
}
|
||||
// else - fall through to default
|
||||
default:
|
||||
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||
return false;
|
||||
|
||||
@@ -71,8 +71,8 @@ public class PaperConfig {
|
||||
commands = new HashMap<String, Command>();
|
||||
commands.put("paper", new PaperCommand("paper"));
|
||||
|
||||
version = getInt("config-version", 17);
|
||||
set("config-version", 17);
|
||||
version = getInt("config-version", 18);
|
||||
set("config-version", 18);
|
||||
readConfig(PaperConfig.class, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,10 +129,19 @@ public class PaperWorldConfig {
|
||||
if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf);
|
||||
}
|
||||
|
||||
public boolean netherVoidTopDamage;
|
||||
private void netherVoidTopDamage() {
|
||||
netherVoidTopDamage = getBoolean( "nether-ceiling-void-damage", false );
|
||||
log("Top of the nether void damage: " + netherVoidTopDamage);
|
||||
public int netherVoidTopDamageHeight;
|
||||
public boolean doNetherTopVoidDamage() { return netherVoidTopDamageHeight > 0; }
|
||||
private void netherVoidTopDamageHeight() {
|
||||
netherVoidTopDamageHeight = getInt("nether-ceiling-void-damage-height", 0);
|
||||
log("Top of the nether void damage height: " + netherVoidTopDamageHeight);
|
||||
|
||||
if (PaperConfig.version < 18) {
|
||||
boolean legacy = getBoolean("nether-ceiling-void-damage", false);
|
||||
if (legacy) {
|
||||
netherVoidTopDamageHeight = 128;
|
||||
set("nether-ceiling-void-damage-height", netherVoidTopDamageHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean queueLightUpdates;
|
||||
@@ -545,11 +554,6 @@ public class PaperWorldConfig {
|
||||
log("ArmorStand ticking is " + (this.armorStandTick ? "enabled" : "disabled") + " by default");
|
||||
}
|
||||
|
||||
public boolean optimizeLight = true;
|
||||
private void optimizeLight() {
|
||||
this.optimizeLight = getBoolean("optimize-light", optimizeLight);
|
||||
}
|
||||
|
||||
public boolean antiXray;
|
||||
public boolean asynchronous;
|
||||
public EngineMode engineMode;
|
||||
|
||||
@@ -583,7 +583,7 @@ public class Chunk implements IChunkAccess {
|
||||
} else {
|
||||
if (flag1) {
|
||||
this.initLighting();
|
||||
} else if (!world.paperConfig.optimizeLight || block != block1) { // Paper - Optimize light recalculations
|
||||
} else {
|
||||
this.runOrQueueLightUpdate(() -> { // Paper - Queue light update
|
||||
int i1 = iblockdata.b(this.world, blockposition);
|
||||
int j1 = iblockdata1.b(this.world, blockposition);
|
||||
@@ -732,40 +732,41 @@ public class Chunk implements IChunkAccess {
|
||||
if (k >= this.entitySlices.length) {
|
||||
k = this.entitySlices.length - 1;
|
||||
}
|
||||
// Paper - remove from any old list if its in one
|
||||
List<Entity> nextSlice = this.entitySlices[k]; // the next list to be added to
|
||||
List<Entity> currentSlice = entity.entitySlice;
|
||||
if (nextSlice == currentSlice) {
|
||||
if (World.DEBUG_ENTITIES) MinecraftServer.LOGGER.warn("Entity was already in this chunk!" + entity, new Throwable());
|
||||
return; // ??? silly plugins
|
||||
}
|
||||
if (currentSlice != null && currentSlice.contains(entity)) {
|
||||
// Still in an old chunk...
|
||||
if (World.DEBUG_ENTITIES) MinecraftServer.LOGGER.warn("Entity is still in another chunk!" + entity, new Throwable());
|
||||
Chunk chunk = entity.getCurrentChunk();
|
||||
if (chunk != null) {
|
||||
chunk.removeEntity(entity);
|
||||
} else {
|
||||
removeEntity(entity);
|
||||
}
|
||||
currentSlice.remove(entity); // Just incase the above did not remove from the previous slice
|
||||
}
|
||||
// Paper end
|
||||
|
||||
if (!entity.inChunk || entity.getCurrentChunk() != this) entityCounts.increment(entity.getMinecraftKeyString()); // Paper
|
||||
entity.inChunk = true;
|
||||
entity.setCurrentChunk(this); // Paper
|
||||
entity.chunkX = this.locX;
|
||||
entity.chunkY = k;
|
||||
entity.chunkZ = this.locZ;
|
||||
|
||||
this.entitySlices[k].add(entity);
|
||||
// Paper start
|
||||
List<Entity> entitySlice = this.entitySlices[k];
|
||||
boolean inThis = entitySlice.contains(entity);
|
||||
List<Entity> currentSlice = entity.entitySlice;
|
||||
if (inThis || (currentSlice != null && currentSlice.contains(entity))) {
|
||||
if (currentSlice == entitySlice || inThis) {
|
||||
return;
|
||||
} else {
|
||||
Chunk chunk = entity.getCurrentChunk();
|
||||
if (chunk != null) {
|
||||
chunk.removeEntity(entity);
|
||||
} else {
|
||||
removeEntity(entity);
|
||||
}
|
||||
currentSlice.remove(entity); // Just incase the above did not remove from this target slice
|
||||
}
|
||||
}
|
||||
entity.entitySlice = entitySlice;
|
||||
entitySlice.add(entity);
|
||||
|
||||
entity.entitySlice = this.entitySlices[k]; // Paper
|
||||
this.markDirty();
|
||||
if (entity instanceof EntityItem) {
|
||||
itemCounts[k]++;
|
||||
} else if (entity instanceof IInventory) {
|
||||
inventoryEntityCounts[k]++;
|
||||
}
|
||||
entity.setCurrentChunk(this);
|
||||
entityCounts.increment(entity.getMinecraftKeyString());
|
||||
// Paper end
|
||||
}
|
||||
|
||||
@@ -773,7 +774,7 @@ public class Chunk implements IChunkAccess {
|
||||
((HeightMap) this.heightMap.get(heightmap_type)).a(along);
|
||||
}
|
||||
|
||||
public void removeEntity(Entity entity) { b(entity); } // Paper - OBFHELPER
|
||||
public void removeEntity(Entity entity) { this.b(entity); } // Paper - OBFHELPER
|
||||
public void b(Entity entity) {
|
||||
this.a(entity, entity.chunkY);
|
||||
}
|
||||
@@ -787,17 +788,19 @@ public class Chunk implements IChunkAccess {
|
||||
i = this.entitySlices.length - 1;
|
||||
}
|
||||
// Paper start
|
||||
if (entity.entitySlice == null || !entity.entitySlice.contains(entity) || entitySlices[i] == entity.entitySlice) {
|
||||
if (entity.currentChunk != null && entity.currentChunk.get() == this) entity.setCurrentChunk(null);
|
||||
if (entitySlices[i] == entity.entitySlice) {
|
||||
entity.entitySlice = null;
|
||||
}
|
||||
if (!this.entitySlices[i].remove(entity)) { return; }
|
||||
if (!this.entitySlices[i].remove(entity)) {
|
||||
return;
|
||||
}
|
||||
this.markDirty();
|
||||
if (entity instanceof EntityItem) {
|
||||
itemCounts[i]--;
|
||||
} else if (entity instanceof IInventory) {
|
||||
inventoryEntityCounts[i]--;
|
||||
}
|
||||
entity.setCurrentChunk(null);
|
||||
entityCounts.decrement(entity.getMinecraftKeyString());
|
||||
// Paper end
|
||||
}
|
||||
@@ -1071,8 +1074,6 @@ public class Chunk implements IChunkAccess {
|
||||
}
|
||||
}
|
||||
// Spigot End
|
||||
entity.setCurrentChunk(null); // Paper
|
||||
entity.entitySlice = null; // Paper
|
||||
|
||||
// Do not pass along players, as doing so can get them stuck outside of time.
|
||||
// (which for example disables inventory icon updates and prevents block breaking)
|
||||
|
||||
@@ -204,10 +204,13 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
|
||||
}
|
||||
}
|
||||
|
||||
private final Object legacyStructureLock = new Object(); // Paper
|
||||
public void getPersistentStructureLegacy(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection) { this.a(dimensionmanager, persistentcollection); } // Paper
|
||||
public void a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection) {
|
||||
if (this.e == null) {
|
||||
synchronized (legacyStructureLock){ if (this.e == null) { // Paper
|
||||
this.e = PersistentStructureLegacy.a(dimensionmanager, persistentcollection);
|
||||
}
|
||||
} } } // Paper
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -501,7 +501,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
||||
this.aa();
|
||||
}
|
||||
*/
|
||||
this.checkAndDoHeightDamage();
|
||||
this.performVoidDamage();
|
||||
// Paper end
|
||||
|
||||
if (!this.world.isClientSide) {
|
||||
@@ -513,9 +513,12 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
||||
}
|
||||
|
||||
// Paper start
|
||||
protected void checkAndDoHeightDamage() {
|
||||
if (this.locY < -64.0D || (this.world.paperConfig.netherVoidTopDamage && this.world.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this.locY >= 128.0D)) {
|
||||
this.kill();
|
||||
protected void performVoidDamage() {
|
||||
if (this.locY < -64.0D || (this.world.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
|
||||
&& world.paperConfig.doNetherTopVoidDamage()
|
||||
&& this.locY >= world.paperConfig.netherVoidTopDamageHeight)) {
|
||||
|
||||
this.doVoidDamage();
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
@@ -587,7 +590,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
||||
this.fireTicks = 0;
|
||||
}
|
||||
|
||||
protected final void kill() { this.aa(); } // Paper - OBFHELPER
|
||||
protected final void doVoidDamage() { this.aa(); } // Paper - OBFHELPER
|
||||
protected void aa() {
|
||||
this.die();
|
||||
}
|
||||
@@ -1890,7 +1893,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private java.lang.ref.WeakReference<Chunk> currentChunk = null;
|
||||
java.lang.ref.WeakReference<Chunk> currentChunk = null;
|
||||
|
||||
public void setCurrentChunk(Chunk chunk) {
|
||||
this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
|
||||
|
||||
@@ -404,6 +404,7 @@ public class EntityFishingHook extends Entity {
|
||||
} else {
|
||||
this.h = MathHelper.nextInt(this.random, world.paperConfig.fishingMinTicks, world.paperConfig.fishingMaxTicks); // Paper
|
||||
this.h -= this.aA * 20 * 5;
|
||||
this.h = Math.max(0, this.h); // Paper - Don't allow negative values
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ public abstract class EntityInsentient extends EntityLiving {
|
||||
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (isTypeNotPersistent() && hasBeenCounted == this.isPersistent()) ((com.destroystokyo.paper.PaperWorldEntityList) this.world.entityList).updateEntityCount(this, hasBeenCounted ? -1 : 1); // Paper - adjust count if persistence state changes
|
||||
if (!this.world.isClientSide) {
|
||||
this.dl();
|
||||
if (this.ticksLived % 5 == 0) {
|
||||
|
||||
@@ -200,7 +200,7 @@ public abstract class EntityMinecartAbstract extends Entity implements INamableT
|
||||
this.aa();
|
||||
}
|
||||
*/
|
||||
this.checkAndDoHeightDamage();
|
||||
this.performVoidDamage();
|
||||
// Paper end
|
||||
|
||||
int i;
|
||||
|
||||
@@ -490,6 +490,46 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
});
|
||||
}
|
||||
|
||||
// Paper start - process inventory
|
||||
private static void processKeep(org.bukkit.event.entity.PlayerDeathEvent event, NonNullList<ItemStack> inv) {
|
||||
List<org.bukkit.inventory.ItemStack> itemsToKeep = event.getItemsToKeep();
|
||||
if (inv == null) {
|
||||
// remainder of items left in toKeep - plugin added stuff on death that wasn't in the initial loot?
|
||||
if (!itemsToKeep.isEmpty()) {
|
||||
for (org.bukkit.inventory.ItemStack itemStack : itemsToKeep) {
|
||||
event.getEntity().getInventory().addItem(itemStack);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack item = inv.get(i);
|
||||
if (EnchantmentManager.shouldNotDrop(item) || itemsToKeep.isEmpty() || item.isEmpty()) {
|
||||
inv.set(i, ItemStack.NULL_ITEM);
|
||||
continue;
|
||||
}
|
||||
|
||||
final org.bukkit.inventory.ItemStack bukkitStack = item.getBukkitStack();
|
||||
boolean keep = false;
|
||||
final Iterator<org.bukkit.inventory.ItemStack> iterator = itemsToKeep.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final org.bukkit.inventory.ItemStack itemStack = iterator.next();
|
||||
if (bukkitStack.equals(itemStack)) {
|
||||
iterator.remove();
|
||||
keep = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
inv.set(i, ItemStack.NULL_ITEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public void die(DamageSource damagesource) {
|
||||
boolean flag = this.world.getGameRules().getBoolean("showDeathMessages");
|
||||
// CraftBukkit start - fire PlayerDeathEvent
|
||||
@@ -567,8 +607,14 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
this.releaseShoulderEntities();
|
||||
// we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
|
||||
if (!event.getKeepInventory()) {
|
||||
this.inventory.clear();
|
||||
// Paper start - replace logic
|
||||
for (NonNullList<ItemStack> inv : this.inventory.getComponents()) {
|
||||
processKeep(event, inv);
|
||||
}
|
||||
processKeep(event, null);
|
||||
// Paper end
|
||||
}
|
||||
|
||||
this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DEATH); // Paper
|
||||
this.setSpectatorTarget(this); // Remove spectated target
|
||||
// CraftBukkit end
|
||||
|
||||
@@ -98,7 +98,7 @@ public class EntityTrackerEntry {
|
||||
}
|
||||
|
||||
// PAIL : rename
|
||||
if (this.tracker instanceof EntityItemFrame && this.a % 20 == 0) { // Paper
|
||||
if (this.tracker instanceof EntityItemFrame /*&& this.a % 10 == 0*/) { // CraftBukkit - Moved below, should always enter this block
|
||||
EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker;
|
||||
ItemStack itemstack = entityitemframe.getItem();
|
||||
|
||||
|
||||
@@ -20,11 +20,19 @@ import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.omg.CORBA.DefinitionKind;
|
||||
|
||||
public class GameRules {
|
||||
|
||||
private static final TreeMap<String, GameRules.GameRuleDefinition> a = (TreeMap<String, GameRules.GameRuleDefinition>) SystemUtils.a(new TreeMap<String, GameRules.GameRuleDefinition>(), (treemap) -> { // Akarin - fixes decompile error
|
||||
// Paper start - Optimize GameRules
|
||||
private static final int RULES_SIZE = 256;
|
||||
|
||||
private static <K, V> java.util.LinkedHashMap<K, V> linkedMapOf(final int capacity, final TreeMap<K, V> map) {
|
||||
final java.util.LinkedHashMap<K, V> ret = new java.util.LinkedHashMap<>(capacity);
|
||||
ret.putAll(map);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static final java.util.LinkedHashMap<String, GameRuleDefinition> a = GameRules.linkedMapOf(RULES_SIZE, SystemUtils.a(new TreeMap(), (treemap) -> { // Paper - decompile fix
|
||||
// Paper end
|
||||
treemap.put("doFireTick", new GameRules.GameRuleDefinition("true", GameRules.EnumGameRuleType.BOOLEAN_VALUE));
|
||||
treemap.put("mobGriefing", new GameRules.GameRuleDefinition("true", GameRules.EnumGameRuleType.BOOLEAN_VALUE));
|
||||
treemap.put("keepInventory", new GameRules.GameRuleDefinition("false", GameRules.EnumGameRuleType.BOOLEAN_VALUE));
|
||||
@@ -58,12 +66,10 @@ public class GameRules {
|
||||
treemap.put("doLimitedCrafting", new GameRules.GameRuleDefinition("false", GameRules.EnumGameRuleType.BOOLEAN_VALUE));
|
||||
treemap.put("maxCommandChainLength", new GameRules.GameRuleDefinition("65536", GameRules.EnumGameRuleType.NUMERICAL_VALUE));
|
||||
treemap.put("announceAdvancements", new GameRules.GameRuleDefinition("true", GameRules.EnumGameRuleType.BOOLEAN_VALUE));
|
||||
});
|
||||
private final HashObjObjMap<String, GameRules.GameRuleValue> b = HashObjObjMaps.newImmutableMap(Maps.transformValues(GameRules.a, GameRules.GameRuleDefinition::a)); // Akarin
|
||||
})); // Paper - Optimize GameRules
|
||||
private final java.util.LinkedHashMap<String, GameRuleValue> b = new java.util.LinkedHashMap<>(RULES_SIZE); // Paper - Optimize GameRules
|
||||
|
||||
public GameRules() {
|
||||
// Akarin start
|
||||
/*
|
||||
Iterator iterator = GameRules.a.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -71,8 +77,6 @@ public class GameRules {
|
||||
|
||||
this.b.put(entry.getKey(), ((GameRules.GameRuleDefinition) entry.getValue()).a());
|
||||
}
|
||||
*/
|
||||
// Akarin end
|
||||
|
||||
}
|
||||
|
||||
@@ -127,7 +131,7 @@ public class GameRules {
|
||||
return (GameRules.GameRuleValue) this.b.get(s);
|
||||
}
|
||||
|
||||
public static TreeMap<String, GameRuleDefinition> getGameRules() {
|
||||
public static java.util.LinkedHashMap<String, GameRuleDefinition> getGameRules() { // Paper - Optimize GameRules
|
||||
return GameRules.a;
|
||||
}
|
||||
|
||||
@@ -144,7 +148,7 @@ public class GameRules {
|
||||
private final Supplier<ArgumentType<?>> d;
|
||||
private final BiFunction<CommandContext<CommandListenerWrapper>, String, String> e;
|
||||
|
||||
private EnumGameRuleType(Supplier supplier, BiFunction<CommandContext<CommandListenerWrapper>, String, String> bifunction) { // Akarin - fixes decompile error
|
||||
private EnumGameRuleType(Supplier supplier, BiFunction<CommandContext<CommandListenerWrapper>, String, String> bifunction) { // Paper - decompile fix
|
||||
this.d = supplier;
|
||||
this.e = bifunction;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import javax.annotation.Nullable;
|
||||
|
||||
public interface IChunkLoader {
|
||||
|
||||
void getPersistentStructureLegacy(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection); // Paper
|
||||
void loadEntities(NBTTagCompound nbttagcompound, Chunk chunk); // Paper - Async Chunks
|
||||
Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException; // Paper - Async Chunks
|
||||
@Nullable
|
||||
|
||||
@@ -38,10 +38,19 @@ import org.bukkit.event.world.StructureGrowEvent;
|
||||
public final class ItemStack {
|
||||
|
||||
private static final Logger c = LogManager.getLogger();
|
||||
public static final ItemStack a = new ItemStack((Item) null);
|
||||
public static final ItemStack a = new ItemStack((Item) null);public static final ItemStack NULL_ITEM = a; // Paper - OBFHELPER
|
||||
public static final DecimalFormat b = D();
|
||||
private int count;
|
||||
private int e;
|
||||
// Paper start
|
||||
private org.bukkit.craftbukkit.inventory.CraftItemStack bukkitStack;
|
||||
public org.bukkit.inventory.ItemStack getBukkitStack() {
|
||||
if (bukkitStack == null || bukkitStack.getHandle() != this) {
|
||||
bukkitStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this);
|
||||
}
|
||||
return bukkitStack;
|
||||
}
|
||||
// Paper end
|
||||
@Deprecated
|
||||
private Item item;
|
||||
NBTTagCompound tag; // Paper -> package private
|
||||
@@ -232,15 +241,7 @@ public final class ItemStack {
|
||||
enuminteractionresult = EnumInteractionResult.FAIL; // cancel placement
|
||||
// PAIL: Remove this when MC-99075 fixed
|
||||
placeEvent.getPlayer().updateInventory();
|
||||
|
||||
// Paper start
|
||||
for (Map.Entry<BlockPosition, TileEntity> e : world.capturedTileEntities.entrySet()) {
|
||||
if (e.getValue() instanceof TileEntityLootable) {
|
||||
((TileEntityLootable) e.getValue()).setLootTable(null);
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
world.capturedTileEntities.clear(); // Paper - clear out tile entities as chests and such will pop loot
|
||||
// revert back all captured blocks
|
||||
for (BlockState blockstate : blocks) {
|
||||
blockstate.update(true, false);
|
||||
@@ -787,6 +788,7 @@ public final class ItemStack {
|
||||
// CraftBukkit start
|
||||
@Deprecated
|
||||
public void setItem(Item item) {
|
||||
this.bukkitStack = null; // Paper
|
||||
this.item = item;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
@@ -286,6 +286,36 @@ public class LoginListener implements PacketLoginInListener, ITickable {
|
||||
}
|
||||
}
|
||||
|
||||
// Paper start - Delay async prelogin until plugins are ready
|
||||
private static volatile Object blockingLogins = new Object();
|
||||
|
||||
public static void checkStartupAndBlock() {
|
||||
final Object lock = LoginListener.blockingLogins;
|
||||
if (lock != null) {
|
||||
synchronized (lock) {
|
||||
for (;;) {
|
||||
if (LoginListener.blockingLogins == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (final InterruptedException ignore) {// handled by the if statement above
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void allowLogins() {
|
||||
final Object lock = LoginListener.blockingLogins;
|
||||
synchronized (lock) {
|
||||
LoginListener.blockingLogins = null;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
// Spigot start
|
||||
public class LoginHandler {
|
||||
|
||||
@@ -296,6 +326,7 @@ public class LoginListener implements PacketLoginInListener, ITickable {
|
||||
return;
|
||||
}
|
||||
// Paper end
|
||||
LoginListener.checkStartupAndBlock(); // Paper - Delay async login events until plugins are ready
|
||||
String playerName = i.getName();
|
||||
java.net.InetAddress address = ((java.net.InetSocketAddress) networkManager.getSocketAddress()).getAddress();
|
||||
java.util.UUID uniqueId = i.getId();
|
||||
|
||||
@@ -609,6 +609,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
this.x = 0;
|
||||
// CraftBukkit Start
|
||||
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
|
||||
LoginListener.allowLogins(); // Paper - Allow logins once postworld
|
||||
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
|
||||
// CraftBukkit end
|
||||
}
|
||||
@@ -932,6 +933,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Paper // Akarin
|
||||
this.slackActivityAccountant.tickStarted(); // Spigot
|
||||
long i = SystemUtils.getMonotonicNanos(); long startTime = i; // Paper
|
||||
new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.ticks+1).callEvent(); // Paper
|
||||
|
||||
++this.ticks;
|
||||
if (this.S) {
|
||||
@@ -1000,7 +1002,12 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
PaperLightingQueue.processQueue(startTime); // Paper
|
||||
expiringMaps.removeIf(ExpiringMap::clean); // Paper
|
||||
this.slackActivityAccountant.tickEnded(l); // Spigot
|
||||
co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper // Akarin
|
||||
// Paper start
|
||||
long endTime = System.nanoTime();
|
||||
long remaining = (TICK_TIME - (endTime - lastTick)) - catchupTime;
|
||||
new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.ticks, ((double)(endTime - lastTick) / 1000000D), remaining).callEvent();
|
||||
// Paper end
|
||||
co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper
|
||||
}
|
||||
|
||||
public void b(BooleanSupplier booleansupplier) {
|
||||
|
||||
@@ -20,7 +20,7 @@ public class PlayerInventory implements IInventory {
|
||||
public final NonNullList<ItemStack> items;
|
||||
public final NonNullList<ItemStack> armor;
|
||||
public final NonNullList<ItemStack> extraSlots;
|
||||
private final List<NonNullList<ItemStack>> f;
|
||||
private final List<NonNullList<ItemStack>> f;List<NonNullList<ItemStack>> getComponents() { return f; } // Paper - OBFHELPER
|
||||
public int itemInHandIndex;
|
||||
public EntityHuman player;
|
||||
private ItemStack carried;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class RegionFile {
|
||||
private RandomAccessFile c;private RandomAccessFile getDataFile() { return c; } // Paper - OBFHELPER
|
||||
private final int[] d = new int[1024];private int[] offsets = d; // Paper - OBFHELPER
|
||||
private final int[] e = new int[1024];private int[] timestamps = e; // Paper - OBFHELPER
|
||||
private List<Boolean> f;
|
||||
private List<Boolean> f; private List<Boolean> getFreeSectors() { return this.f; } // Paper - OBFHELPER
|
||||
private int g;
|
||||
private long h;
|
||||
|
||||
@@ -211,32 +211,31 @@ public class RegionFile {
|
||||
protected synchronized void a(int i, int j, byte[] abyte, int k) {
|
||||
try {
|
||||
int l = this.getOffset(i, j);
|
||||
int i1 = l >> 8;
|
||||
int j1 = l & 255;
|
||||
int i1 = l >> 8; final int oldSectorOffset = i1; // Paper - store variable for later
|
||||
int j1 = l & 255; final int oldSectorCount; // Paper - store variable for later
|
||||
// Spigot start
|
||||
if (j1 == 255) {
|
||||
this.c.seek(i1 * 4096);
|
||||
j1 = (this.c.readInt() + 4) / 4096 + 1;
|
||||
}
|
||||
// Spigot end
|
||||
oldSectorCount = j1; // Paper - store variable for later (watch out for re-assignments of j1)
|
||||
int k1 = (k + 5) / 4096 + 1;
|
||||
|
||||
if (k1 >= 256) {
|
||||
// Spigot start
|
||||
if (!USE_SPIGOT_OVERSIZED_METHOD) throw new ChunkTooLargeException(i, j, k1); // Paper - throw error instead
|
||||
if (!USE_SPIGOT_OVERSIZED_METHOD && !RegionFileCache.isOverzealous()) throw new ChunkTooLargeException(i, j, k1); // Paper - throw error instead
|
||||
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING,"Large Chunk Detected: ({0}, {1}) Size: {2} {3}", new Object[]{i, j, k1, this.b});
|
||||
if (!ENABLE_EXTENDED_SAVE) return;
|
||||
// Spigot end
|
||||
}
|
||||
|
||||
if (i1 != 0 && j1 == k1) {
|
||||
if (false && i1 != 0 && j1 == k1) { // Paper - We never want to overrite old data
|
||||
this.a(i1, abyte, k);
|
||||
} else {
|
||||
int l1;
|
||||
|
||||
for (l1 = 0; l1 < j1; ++l1) {
|
||||
this.f.set(i1 + l1, true);
|
||||
}
|
||||
// Paper - We do not free old sectors until we are done writing the new chunk data
|
||||
|
||||
l1 = this.f.indexOf(true);
|
||||
int i2 = 0;
|
||||
@@ -263,13 +262,13 @@ public class RegionFile {
|
||||
|
||||
if (i2 >= k1) {
|
||||
i1 = l1;
|
||||
this.a(i, j, l1 << 8 | (k1 > 255 ? 255 : k1)); // Spigot
|
||||
//this.a(i, j, l1 << 8 | (k1 > 255 ? 255 : k1)); // Spigot // Paper - We only write to header after we've written chunk data
|
||||
|
||||
for (j2 = 0; j2 < k1; ++j2) {
|
||||
this.f.set(i1 + j2, false);
|
||||
}
|
||||
|
||||
this.a(i1, abyte, k);
|
||||
this.writeChunk(i, j,i1 << 8 | (k1 > 255 ? 255 : k1), i1, abyte, k); // Paper - Ensure we do not corrupt region files
|
||||
} else {
|
||||
this.c.seek(this.c.length());
|
||||
i1 = this.f.size();
|
||||
@@ -280,9 +279,14 @@ public class RegionFile {
|
||||
}
|
||||
|
||||
this.g += 4096 * k1;
|
||||
this.a(i1, abyte, k);
|
||||
this.a(i, j, i1 << 8 | (k1 > 255 ? 255 : k1)); // Spigot
|
||||
this.writeChunk(i, j, i1 << 8 | (k1 > 255 ? 255 : k1), i1, abyte, k); // Paper - Ensure we do not corrupt region files
|
||||
}
|
||||
|
||||
// Paper start - Now that we've written the new chunk we can free the old data
|
||||
for (int off = 0; off < oldSectorCount; ++off) {
|
||||
this.getFreeSectors().set(oldSectorOffset + off, true);
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
|
||||
this.b(i, j, (int) (SystemUtils.getTimeMillis() / 1000L));
|
||||
@@ -292,10 +296,10 @@ public class RegionFile {
|
||||
|
||||
}
|
||||
|
||||
private void writeChunkData(final int sectorOffset, final byte[] data, final int dataLength) throws IOException { this.a(sectorOffset, data, dataLength); } // Paper - OBFHELPER
|
||||
private void a(int i, byte[] abyte, int j) throws IOException {
|
||||
this.c.seek((long) (i * 4096));
|
||||
this.c.writeInt(j + 1);
|
||||
this.c.writeByte(2);
|
||||
this.writeIntAndByte(j + 1, (byte)2); // Paper - Avoid 4 io write calls
|
||||
this.c.write(abyte, 0, j);
|
||||
}
|
||||
|
||||
@@ -311,16 +315,17 @@ public class RegionFile {
|
||||
return this.getOffset(i, j) != 0;
|
||||
}
|
||||
|
||||
private void updateChunkHeader(final int x, final int z, final int offset) throws IOException { this.a(x, z, offset); } // Paper - OBFHELPER
|
||||
private void a(int i, int j, int k) throws IOException {
|
||||
this.d[i + j * 32] = k;
|
||||
this.c.seek((long) ((i + j * 32) * 4));
|
||||
this.c.writeInt(k);
|
||||
this.writeInt(k); // Paper - Avoid 3 io write calls
|
||||
}
|
||||
|
||||
private void b(int i, int j, int k) throws IOException {
|
||||
this.e[i + j * 32] = k;
|
||||
this.c.seek((long) (4096 + (i + j * 32) * 4));
|
||||
this.c.writeInt(k);
|
||||
this.writeInt(k); // Paper - Avoid 3 io write calls
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
@@ -331,6 +336,40 @@ public class RegionFile {
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private static final boolean FLUSH_ON_SAVE = Boolean.getBoolean("paper.flush-on-save");
|
||||
private void syncRegionFile() throws IOException {
|
||||
if (!FLUSH_ON_SAVE) {
|
||||
return;
|
||||
}
|
||||
this.getDataFile().getFD().sync(); // rethrow exception as we want to avoid corrupting a regionfile
|
||||
}
|
||||
|
||||
private final java.nio.ByteBuffer scratchBuffer = java.nio.ByteBuffer.allocate(8);
|
||||
|
||||
private void writeInt(final int value) throws IOException {
|
||||
synchronized (scratchBuffer) {
|
||||
this.scratchBuffer.putInt(0, value);
|
||||
this.getDataFile().write(this.scratchBuffer.array(), 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// writes v1 then v2
|
||||
private void writeIntAndByte(final int v1, final byte v2) throws IOException {
|
||||
synchronized (scratchBuffer) {
|
||||
this.scratchBuffer.putInt(0, v1);
|
||||
this.scratchBuffer.put(4, v2);
|
||||
this.getDataFile().write(this.scratchBuffer.array(), 0, 5);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeChunk(final int x, final int z, final int chunkHeaderData,
|
||||
final int chunkOffset, final byte[] chunkData, final int chunkDataLength) throws IOException {
|
||||
this.writeChunkData(chunkOffset, chunkData, chunkDataLength);
|
||||
this.syncRegionFile(); // Sync is required to ensure the previous data is written successfully
|
||||
this.updateChunkHeader(x, z, chunkHeaderData);
|
||||
this.syncRegionFile(); // Ensure header changes go through
|
||||
}
|
||||
|
||||
public synchronized void deleteChunk(int j1) {
|
||||
backup();
|
||||
int k = offsets[j1];
|
||||
@@ -501,31 +540,26 @@ public class RegionFile {
|
||||
int length = out.size();
|
||||
|
||||
RegionFile.this.a(this.b, this.c, bytes, length); // Paper - change to bytes/length
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] compressionBuffer = new byte[1024 * 64]; // 64k fits most standard chunks input size even, ideally 1 pass through zlib
|
||||
private static final java.util.zip.Deflater deflater = new java.util.zip.Deflater();
|
||||
// since file IO is single threaded, no benefit to using per-region file buffers/synchronization, we can change that later if it becomes viable.
|
||||
private static DirectByteArrayOutputStream compressData(byte[] buf, int length) throws IOException {
|
||||
final java.util.zip.Deflater deflater;
|
||||
if (length > 1024 * 512) {
|
||||
deflater = new java.util.zip.Deflater(9);
|
||||
} else if (length > 1024 * 128) {
|
||||
deflater = new java.util.zip.Deflater(8);
|
||||
} else {
|
||||
deflater = new java.util.zip.Deflater(6);
|
||||
synchronized (deflater) {
|
||||
deflater.setInput(buf, 0, length);
|
||||
deflater.finish();
|
||||
|
||||
DirectByteArrayOutputStream out = new DirectByteArrayOutputStream(length);
|
||||
while (!deflater.finished()) {
|
||||
out.write(compressionBuffer, 0, deflater.deflate(compressionBuffer));
|
||||
}
|
||||
out.close();
|
||||
deflater.reset();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
deflater.setInput(buf, 0, length);
|
||||
deflater.finish();
|
||||
|
||||
DirectByteArrayOutputStream out = new DirectByteArrayOutputStream(length);
|
||||
byte[] buffer = new byte[1024 * (length > 1024 * 124 ? 32 : 16)];
|
||||
while (!deflater.finished()) {
|
||||
out.write(buffer, 0, deflater.deflate(buffer));
|
||||
}
|
||||
out.close();
|
||||
deflater.end();
|
||||
return out;
|
||||
}
|
||||
// Paper end
|
||||
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ public class RegionFileCache {
|
||||
}
|
||||
|
||||
private static final int DEFAULT_SIZE_THRESHOLD = 1024 * 8;
|
||||
private static final int OVERZEALOUS_THRESHOLD = 1024 * 2;
|
||||
private static final int OVERZEALOUS_TOTAL_THRESHOLD = 1024 * 64;
|
||||
private static final int OVERZEALOUS_THRESHOLD = 1024;
|
||||
private static int SIZE_THRESHOLD = DEFAULT_SIZE_THRESHOLD;
|
||||
private static void resetFilterThresholds() {
|
||||
SIZE_THRESHOLD = Math.max(1024 * 4, Integer.getInteger("Paper.FilterThreshhold", DEFAULT_SIZE_THRESHOLD));
|
||||
@@ -97,6 +98,11 @@ public class RegionFileCache {
|
||||
static {
|
||||
resetFilterThresholds();
|
||||
}
|
||||
|
||||
static boolean isOverzealous() {
|
||||
return SIZE_THRESHOLD == OVERZEALOUS_THRESHOLD;
|
||||
}
|
||||
|
||||
private static void writeRegion(File file, int x, int z, NBTTagCompound nbttagcompound) throws IOException {
|
||||
RegionFile regionfile = getRegionFile(file, x, z);
|
||||
|
||||
@@ -146,11 +152,15 @@ public class RegionFileCache {
|
||||
private static void filterChunkList(NBTTagCompound level, NBTTagCompound extra, String key) {
|
||||
NBTTagList list = level.getList(key, 10);
|
||||
NBTTagList newList = extra.getList(key, 10);
|
||||
int totalSize = 0;
|
||||
for (Iterator<NBTBase> iterator = list.list.iterator(); iterator.hasNext(); ) {
|
||||
NBTBase object = iterator.next();
|
||||
if (getNBTSize(object) > SIZE_THRESHOLD) {
|
||||
int nbtSize = getNBTSize(object);
|
||||
if (nbtSize > SIZE_THRESHOLD || (SIZE_THRESHOLD == OVERZEALOUS_THRESHOLD && totalSize > OVERZEALOUS_TOTAL_THRESHOLD)) {
|
||||
newList.add(object);
|
||||
iterator.remove();
|
||||
} else {
|
||||
totalSize += nbtSize;
|
||||
}
|
||||
}
|
||||
level.set(key, list);
|
||||
|
||||
@@ -114,7 +114,7 @@ public final class SpawnerCreature {
|
||||
|
||||
if ((!enumcreaturetype.c() || flag1) && (enumcreaturetype.c() || flag) && (!enumcreaturetype.d() || flag2)) {
|
||||
k = limit * i / SpawnerCreature.b; // CraftBukkit - use per-world limits
|
||||
int l1 = worldserver.entityList.getCreatureCount(enumcreaturetype); // Paper - entity count cache
|
||||
int l1 = ((com.destroystokyo.paper.PaperWorldEntityList) worldserver.entityList).getCreatureCount(enumcreaturetype); // Paper - entity count cache
|
||||
|
||||
if (l1 <= k) {
|
||||
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
|
||||
|
||||
@@ -53,7 +53,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
||||
private static final EnumDirection[] a = EnumDirection.values();
|
||||
private int b = 63;
|
||||
// Spigot start - guard entity list from removals
|
||||
public final com.destroystokyo.paper.PaperWorldEntityList entityList = new com.destroystokyo.paper.PaperWorldEntityList(this);
|
||||
public final List<Entity> entityList = new com.destroystokyo.paper.PaperWorldEntityList(this);
|
||||
/* // Paper start
|
||||
{
|
||||
@Override
|
||||
@@ -1235,11 +1235,10 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
||||
int i = entity.chunkX;
|
||||
int j = entity.chunkZ;
|
||||
|
||||
if (entity.inChunk && this.isChunkLoaded(i, j, true)) {
|
||||
this.getChunkAt(i, j).b(entity);
|
||||
}
|
||||
Chunk chunk = entity.getCurrentChunk(); // Paper
|
||||
if (chunk != null) chunk.removeEntity(entity); // Paper
|
||||
entity.shouldBeRemoved = true; // Paper
|
||||
entityList.updateEntityCount(entity, -1); // Paper
|
||||
((com.destroystokyo.paper.PaperWorldEntityList) entityList).updateEntityCount(entity, -1); // Paper
|
||||
|
||||
if (!guardEntityList) { // Spigot - It will get removed after the tick if we are ticking // Paper - always remove from current chunk above
|
||||
// CraftBukkit start - Decrement loop variable field if we've already ticked this entity
|
||||
@@ -1329,20 +1328,17 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
||||
|
||||
int j;
|
||||
// Paper start - Set based removal lists
|
||||
for (Entity e : this.g) {
|
||||
/*
|
||||
j = e.getChunkZ();
|
||||
int k = e.getChunkX();
|
||||
for (Iterator<Entity> it = this.g.iterator(); it.hasNext() ; ) {
|
||||
entity = it.next(); // Paper
|
||||
int k = entity.chunkX;
|
||||
|
||||
if (e.inChunk && this.isChunkLoaded(k, j, true)) {
|
||||
this.getChunkAt(k, j).b(e);
|
||||
}*/
|
||||
Chunk chunk = e.inChunk ? e.getCurrentChunk() : null;
|
||||
if (chunk != null) chunk.removeEntity(e);
|
||||
}
|
||||
j = entity.chunkZ;
|
||||
Chunk chunk = entity.getCurrentChunk(); // Paper
|
||||
if (chunk != null) chunk.removeEntity(entity); // Paper
|
||||
//} // Paper - merge
|
||||
|
||||
for (Entity e : this.g) {
|
||||
this.c(e);
|
||||
//for (Entity e : this.g) { // Paper - merge
|
||||
this.c(entity); // Paper use entity
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -1399,15 +1395,11 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
||||
//this.methodProfiler.exit(); // Akarin - remove caller
|
||||
//this.methodProfiler.enter(* // Akarin - remove caller
|
||||
if (entity.dead) {
|
||||
// Paper start
|
||||
/*
|
||||
j = entity.chunkX;
|
||||
int l = entity.chunkZ;
|
||||
|
||||
if (entity.inChunk && this.isChunkLoaded(j, l, true)) {
|
||||
this.getChunkAt(j, l).b(entity);
|
||||
}*/
|
||||
Chunk chunk = entity.inChunk ? entity.getCurrentChunk() : null;
|
||||
// Paper start
|
||||
Chunk chunk = entity.getCurrentChunk();
|
||||
if (chunk != null) chunk.removeEntity(entity);
|
||||
// Paper end
|
||||
|
||||
@@ -1988,12 +1980,13 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
||||
return null;
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
if (capturedTileEntities.containsKey(blockposition)) {
|
||||
return capturedTileEntities.get(blockposition);
|
||||
TileEntity tileentity = null; // Paper
|
||||
if (!capturedTileEntities.isEmpty() && (tileentity = capturedTileEntities.get(blockposition)) != null) { // Paper
|
||||
return tileentity; // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
TileEntity tileentity = null;
|
||||
//TileEntity tileentity = null; // Paper - move up
|
||||
|
||||
if (this.J) {
|
||||
tileentity = this.E(blockposition);
|
||||
|
||||
@@ -39,6 +39,7 @@ public class WorldPersistentData {
|
||||
|
||||
@Nullable
|
||||
public <T extends PersistentBase> T a(Function<String, T> function, String s) {
|
||||
if ("Mineshaft_index".equals(s) || "Mineshaft".equals(s)) return null; // Paper - mineshaft is useless data
|
||||
T persistentbase = (T) this.data.get(s); // Paper - decompile fix
|
||||
|
||||
if (persistentbase == null && this.e != null) {
|
||||
@@ -49,14 +50,15 @@ public class WorldPersistentData {
|
||||
persistentbase = function.apply(s); // Paper - decompile fix
|
||||
persistentbase.a(a(this.e, this.b, s, 1631).getCompound("data"));
|
||||
this.data.put(s, persistentbase);
|
||||
}
|
||||
} else this.data.put(s, NO_RESULT); // Paper
|
||||
} catch (Exception exception) {
|
||||
WorldPersistentData.a.error("Error loading saved data: {}", s, exception);
|
||||
}
|
||||
}
|
||||
|
||||
return persistentbase;
|
||||
return persistentbase == NO_RESULT ? null : persistentbase; // Paper
|
||||
}
|
||||
private static final PersistentBase NO_RESULT = new ForcedChunk("chunks"); // Paper
|
||||
|
||||
public void a(String s, PersistentBase persistentbase) {
|
||||
this.data.put(s, persistentbase);
|
||||
@@ -126,6 +128,7 @@ public class WorldPersistentData {
|
||||
}
|
||||
|
||||
public static NBTTagCompound a(IDataManager idatamanager, DimensionManager dimensionmanager, String s, int i) throws IOException {
|
||||
if ("Mineshaft".equals(s) || "Mineshaft_index".equals(s)) return new NBTTagCompound(); // Paper
|
||||
File file = idatamanager.getDataFile(dimensionmanager, s);
|
||||
FileInputStream fileinputstream = new FileInputStream(file);
|
||||
Throwable throwable = null;
|
||||
|
||||
@@ -85,6 +85,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
|
||||
this.P();
|
||||
this.Q();
|
||||
this.getWorldBorder().a(minecraftserver.au());
|
||||
MCUtil.scheduleAsyncTask(() -> this.getChunkProvider().chunkLoader.getPersistentStructureLegacy(worldProvider.getDimensionManager(), worldMaps)); // Paper
|
||||
}
|
||||
|
||||
public WorldServer i_() {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.permissions.ServerOperator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
@@ -330,6 +331,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return entity.world.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRotation(float yaw, float pitch) {
|
||||
NumberConversions.checkFinite(pitch, "pitch not finite");
|
||||
NumberConversions.checkFinite(yaw, "yaw not finite");
|
||||
|
||||
yaw = Location.normalizeYaw(yaw);
|
||||
pitch = Location.normalizePitch(pitch);
|
||||
|
||||
entity.yaw = yaw;
|
||||
entity.pitch = pitch;
|
||||
entity.lastYaw = yaw;
|
||||
entity.lastPitch = pitch;
|
||||
entity.setHeadRotation(yaw);
|
||||
}
|
||||
|
||||
public boolean teleport(Location location) {
|
||||
return teleport(location, TeleportCause.PLUGIN);
|
||||
}
|
||||
|
||||
@@ -697,6 +697,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
getHandle().playerConnection.sendPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRotation(float yaw, float pitch) {
|
||||
throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) {
|
||||
Preconditions.checkArgument(location != null, "location");
|
||||
|
||||
@@ -437,7 +437,7 @@ public class CraftEventFactory {
|
||||
} // Paper end - End iteration skip check - All tweaking ends here
|
||||
}
|
||||
// Spigot end
|
||||
} else {
|
||||
} else if (!(entity instanceof EntityPlayer)) {
|
||||
event = CraftEventFactory.callEntitySpawnEvent(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.bukkit.craftbukkit.generator;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import net.minecraft.server.BlockPosition;
|
||||
import net.minecraft.server.Blocks;
|
||||
import net.minecraft.server.ChunkSection;
|
||||
import net.minecraft.server.IBlockData;
|
||||
@@ -17,6 +20,7 @@ import org.bukkit.material.MaterialData;
|
||||
public final class CraftChunkData implements ChunkGenerator.ChunkData {
|
||||
private final int maxHeight;
|
||||
private final ChunkSection[] sections;
|
||||
private Set<BlockPosition> tiles;
|
||||
private World world; // Paper - Anti-Xray
|
||||
|
||||
public CraftChunkData(World world) {
|
||||
@@ -142,6 +146,14 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
|
||||
}
|
||||
ChunkSection section = getChunkSection(y, true);
|
||||
section.setType(x, y & 0xf, z, type);
|
||||
|
||||
if (type.getBlock().isTileEntity()) {
|
||||
if (tiles == null) {
|
||||
tiles = new HashSet<>();
|
||||
}
|
||||
|
||||
tiles.add(new BlockPosition(x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
private ChunkSection getChunkSection(int y, boolean create) {
|
||||
@@ -155,4 +167,8 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
|
||||
ChunkSection[] getRawChunkData() {
|
||||
return sections;
|
||||
}
|
||||
|
||||
Set<BlockPosition> getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ public class CustomChunkGenerator extends InternalChunkGenerator<GeneratorSettin
|
||||
|
||||
ChunkData data = generator.generateChunkData(this.world.getWorld(), random, x, z, biomegrid);
|
||||
Preconditions.checkArgument(data instanceof CraftChunkData, "Plugins must use createChunkData(World) rather than implementing ChunkData: %s", data);
|
||||
ChunkSection[] sections = ((CraftChunkData) data).getRawChunkData();
|
||||
CraftChunkData craftData = (CraftChunkData) data;
|
||||
ChunkSection[] sections = craftData.getRawChunkData();
|
||||
|
||||
ChunkSection[] csect = ichunkaccess.getSections();
|
||||
int scnt = Math.min(csect.length, sections.length);
|
||||
@@ -87,6 +88,20 @@ public class CustomChunkGenerator extends InternalChunkGenerator<GeneratorSettin
|
||||
|
||||
// Set biome grid
|
||||
ichunkaccess.a(biomegrid.biome);
|
||||
|
||||
if (craftData.getTiles() != null) {
|
||||
for (BlockPosition pos : craftData.getTiles()) {
|
||||
int tx = pos.getX();
|
||||
int ty = pos.getY();
|
||||
int tz = pos.getZ();
|
||||
Block block = craftData.getTypeId(tx, ty, tz).getBlock();
|
||||
|
||||
if (block.isTileEntity()) {
|
||||
TileEntity tile = ((ITileEntity) block).a(world);
|
||||
ichunkaccess.a(new BlockPosition((x << 4) + tx, ty, (z << 4) + tz), tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -95,6 +95,7 @@ public final class CraftItemStack extends ItemStack {
|
||||
}
|
||||
|
||||
net.minecraft.server.ItemStack handle;
|
||||
public net.minecraft.server.ItemStack getHandle() { return handle; } // Paper
|
||||
|
||||
/**
|
||||
* Mirror
|
||||
|
||||
@@ -66,6 +66,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
@@ -1326,7 +1327,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, List<Object>> mods = new HashMap<>();
|
||||
Map<String, List<Object>> mods = new LinkedHashMap<>();
|
||||
for (Map.Entry<Attribute, AttributeModifier> entry : modifiers.entries()) {
|
||||
if (entry.getKey() == null) {
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user