More more patches

This commit is contained in:
Nassim Jahnke 2023-03-14 19:36:39 +01:00
parent cf4eac0a17
commit 9a731dc325
No known key found for this signature in database
GPG key ID: 6BE3B555EBC5982B
125 changed files with 689 additions and 434 deletions

View file

@ -1,66 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 1 Mar 2016 23:52:34 -0600
Subject: [PATCH] Prevent tile entity and entity crashes
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 4b2aadae3a7595a5aee2bc71216adc34fa0f2cf9..e082e4a8c8fbce341bcf00115d1579b4bed4b2a4 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -729,11 +729,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
try {
tickConsumer.accept(entity);
} catch (Throwable throwable) {
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
-
- entity.fillCrashReportCategory(crashreportsystemdetails);
- throw new ReportedException(crashreport);
+ // Paper start - Prevent tile entity and entity crashes
+ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
+ MinecraftServer.LOGGER.error(msg, throwable);
+ entity.discard();
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index b300d12e9e00519028b53aca9c3fb01f589eaa91..63acd109a79ed752a05df3d4f1b99309297c2055 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -213,7 +213,12 @@ public abstract class BlockEntity {
return minecraftkey + " // " + this.getClass().getCanonicalName();
});
if (this.level != null) {
- CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.getBlockState());
+ // Paper start - Prevent TileEntity and Entity crashes
+ BlockState block = this.getBlockState();
+ if (block != null) {
+ CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, block);
+ }
+ // Paper end
CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.level.getBlockState(this.worldPosition));
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 8c2b562e46a35369389da453012b7af570145380..f21ae1ae8af79c1c0c6f2feaa933638add0aa065 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1184,11 +1184,11 @@ public class LevelChunk extends ChunkAccess {
gameprofilerfiller.pop();
} catch (Throwable throwable) {
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking block entity");
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block entity being ticked");
-
- this.blockEntity.fillCrashReportCategory(crashreportsystemdetails);
- throw new ReportedException(crashreport);
+ // Paper start - Prevent tile entity and entity crashes
+ final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
+ net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
+ LevelChunk.this.removeBlockEntity(this.getPos());
+ // Paper end
// Spigot start
} finally {
this.blockEntity.tickTimer.stopTiming();

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 23:58:50 -0600
Subject: [PATCH] Configurable top of nether void damage
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 5cf04b209ae3fa6c52ad45e726343418d0de311f..128dd4749590905fdfa85907d33adc4e4dbe6c33 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -705,7 +705,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
public void checkOutOfWorld() {
- if (this.getY() < (double) (this.level.getMinBuildHeight() - 64)) {
+ // Paper start - Configurable nether ceiling damage
+ if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
+ && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v)
+ && (!(this instanceof Player player) || !player.getAbilities().invulnerable))) {
+ // Paper end
this.outOfWorld();
}
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
index 98cdf291a5d0248091891ad30104adef708eec55..ff57611088eabfb7e2db8fcf6344b1551b17b87b 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -55,7 +55,7 @@ public class PortalForcer {
Optional<PoiRecord> optional = villageplace.getInSquare((holder) -> {
return holder.is(PoiTypes.NETHER_PORTAL);
}, blockposition, i, PoiManager.Occupancy.ANY).filter((villageplacerecord) -> {
- return worldborder.isWithinBounds(villageplacerecord.getPos());
+ return worldborder.isWithinBounds(villageplacerecord.getPos()) && !this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> villageplacerecord.getPos().getY() >= v); // Paper - don't teleport into void damage
}).sorted(Comparator.comparingDouble((PoiRecord villageplacerecord) -> { // CraftBukkit - decompile error
return villageplacerecord.getPos().distSqr(blockposition);
}).thenComparingInt((villageplacerecord) -> {
@@ -90,6 +90,11 @@ public class PortalForcer {
BlockPos blockposition2 = null;
WorldBorder worldborder = this.level.getWorldBorder();
int i = Math.min(this.level.getMaxBuildHeight(), this.level.getMinBuildHeight() + this.level.getLogicalHeight()) - 1;
+ // Paper start - if ceiling void damage is enabled, make sure the max height doesn't exceed the void damage height
+ if (this.level.paperConfig().environment.netherCeilingVoidDamageHeight.enabled()) {
+ i = Math.min(i, this.level.paperConfig().environment.netherCeilingVoidDamageHeight.intValue() - 1);
+ }
+ // Paper end
BlockPos.MutableBlockPos blockposition_mutableblockposition = blockposition.mutable();
Iterator iterator = BlockPos.spiralAround(blockposition, createRadius, Direction.EAST, Direction.SOUTH).iterator(); // CraftBukkit

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 2 Mar 2016 00:03:55 -0600
Subject: [PATCH] Check online mode before converting and renaming player data
diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
index bf4c895794c2bc2ad65faa128c6fa92cb0656841..6909b6be840e8d4feadcc8b0c5a44fc1b9c81a54 100644
--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -56,7 +56,7 @@ public class PlayerDataStorage {
File file = new File(this.playerDir, player.getStringUUID() + ".dat");
// Spigot Start
boolean usingWrongFile = false;
- if ( !file.exists() )
+ if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first
{
file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + player.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat");
if ( file.exists() )

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 2 Mar 2016 00:32:25 -0600
Subject: [PATCH] Always tick falling blocks
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index d3639643cda7d8ccf3c1208502605120590a2d30..e2dfc4d9a16a738dd0fe91838603e1d4370afa56 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -89,6 +89,7 @@ public class ActivationRange
|| entity instanceof AbstractHurtingProjectile
|| entity instanceof LightningBolt
|| entity instanceof PrimedTnt
+ || entity instanceof net.minecraft.world.entity.item.FallingBlockEntity // Paper - Always tick falling blocks
|| entity instanceof EndCrystal
|| entity instanceof FireworkRocketEntity
|| entity instanceof ThrownTrident )

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: DoctorDark <doctordark11@gmail.com>
Date: Wed, 16 Mar 2016 02:21:39 -0500
Subject: [PATCH] Configurable end credits
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 650d28ce34239d3ae9caa3852e1bac518790fd83..ecb57a664da6be49611b95bf6bde3d9c3f893e82 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1011,6 +1011,7 @@ public class ServerPlayer extends Player {
this.unRide();
this.getLevel().removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
if (!this.wonGame) {
+ if (level.paperConfig().misc.disableEndCredits) this.seenCredits = true; // Paper - Toggle to always disable end credits
this.wonGame = true;
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, this.seenCredits ? 0.0F : 1.0F));
this.seenCredits = true;

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Iceee <andrew@opticgaming.tv>
Date: Wed, 2 Mar 2016 01:39:52 -0600
Subject: [PATCH] Fix lag from explosions processing dead entities
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index 5ab38db6305d885ab61ee2c25ccb5ee77bb31370..c5544f952be057bae9407725d885798f461081ea 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -202,7 +202,7 @@ public class Explosion {
int i1 = Mth.floor(this.y + (double) f2 + 1.0D);
int j1 = Mth.floor(this.z - (double) f2 - 1.0D);
int k1 = Mth.floor(this.z + (double) f2 + 1.0D);
- List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1));
+ List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities
Vec3 vec3d = new Vec3(this.x, this.y, this.z);
for (int l1 = 0; l1 < list.size(); ++l1) {

View file

@ -1,133 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 11:59:48 -0600
Subject: [PATCH] Optimize explosions
The process of determining an entity's exposure from explosions can be
expensive when there are hundreds or more entities in range.
This patch adds a per-tick cache that is used for storing and retrieving
an entity's exposure during an explosion.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index ac81428f19e2d445f315000d34173c2d650a9aeb..28d58f402f15ee37cc1bfa3114839db281fc5f57 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1396,6 +1396,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.profiler.pop();
this.profiler.pop();
+ worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
}
this.profiler.popPush("connection");
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index c5544f952be057bae9407725d885798f461081ea..b71cd16a63889d8a286b642158f9ab45af89b7c4 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -221,7 +221,7 @@ public class Explosion {
d8 /= d11;
d9 /= d11;
d10 /= d11;
- double d12 = (double) Explosion.getSeenPercent(vec3d, entity);
+ double d12 = this.getBlockDensity(vec3d, entity); // Paper - Optimize explosions
double d13 = (1.0D - d7) * d12;
// CraftBukkit start
@@ -494,4 +494,84 @@ public class Explosion {
private BlockInteraction() {}
}
+ // Paper start - Optimize explosions
+ private float getBlockDensity(Vec3 vec3d, Entity entity) {
+ if (!this.level.paperConfig().environment.optimizeExplosions) {
+ return getSeenPercent(vec3d, entity);
+ }
+ CacheKey key = new CacheKey(this, entity.getBoundingBox());
+ Float blockDensity = this.level.explosionDensityCache.get(key);
+ if (blockDensity == null) {
+ blockDensity = getSeenPercent(vec3d, entity);
+ this.level.explosionDensityCache.put(key, blockDensity);
+ }
+
+ return blockDensity;
+ }
+
+ static class CacheKey {
+ private final Level world;
+ private final double posX, posY, posZ;
+ private final double minX, minY, minZ;
+ private final double maxX, maxY, maxZ;
+
+ public CacheKey(Explosion explosion, AABB aabb) {
+ this.world = explosion.level;
+ this.posX = explosion.x;
+ this.posY = explosion.y;
+ this.posZ = explosion.z;
+ this.minX = aabb.minX;
+ this.minY = aabb.minY;
+ this.minZ = aabb.minZ;
+ this.maxX = aabb.maxX;
+ this.maxY = aabb.maxY;
+ this.maxZ = aabb.maxZ;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CacheKey cacheKey = (CacheKey) o;
+
+ if (Double.compare(cacheKey.posX, posX) != 0) return false;
+ if (Double.compare(cacheKey.posY, posY) != 0) return false;
+ if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
+ if (Double.compare(cacheKey.minX, minX) != 0) return false;
+ if (Double.compare(cacheKey.minY, minY) != 0) return false;
+ if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
+ if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
+ if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
+ if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
+ return world.equals(cacheKey.world);
+ }
+
+ @Override
+ public int hashCode() {
+ int result;
+ long temp;
+ result = world.hashCode();
+ temp = Double.doubleToLongBits(posX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(posY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(posZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index e082e4a8c8fbce341bcf00115d1579b4bed4b2a4..746cab58dc67b47bb57889343c625e038dda4851 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -164,6 +164,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
public CraftWorld getWorld() {
return this.world;

View file

@ -1,55 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 14:48:03 -0600
Subject: [PATCH] Disable explosion knockback
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index c6ce813f7ea6c4dcbd45e9d8c55f56c29dc3ea53..7e4f95e04a880ecb459228c90be462cbbec14620 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1400,6 +1400,7 @@ public abstract class LivingEntity extends Entity {
}
}
+ boolean knockbackCancelled = level.paperConfig().environment.disableExplosionKnockback && source.isExplosion() && this instanceof net.minecraft.world.entity.player.Player; // Paper - Disable explosion knockback
if (flag1) {
if (flag) {
this.level.broadcastEntityEvent(this, (byte) 29);
@@ -1420,6 +1421,7 @@ public abstract class LivingEntity extends Entity {
b0 = 2;
}
+ if (!knockbackCancelled) // Paper - Disable explosion knockback
this.level.broadcastEntityEvent(this, b0);
}
@@ -1443,6 +1445,7 @@ public abstract class LivingEntity extends Entity {
}
}
+ if (knockbackCancelled) this.level.broadcastEntityEvent(this, (byte) 2); // Paper - Disable explosion knockback
if (this.isDeadOrDying()) {
if (!this.checkTotemDeathProtection(source)) {
SoundEvent soundeffect = this.getDeathSound();
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index b71cd16a63889d8a286b642158f9ab45af89b7c4..a9f45dbc2997c4deeba932d04a52e21f4dbfea95 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -260,14 +260,14 @@ public class Explosion {
double d14 = d13;
if (entity instanceof LivingEntity) {
- d14 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13);
+ d14 = entity instanceof Player && level.paperConfig().environment.disableExplosionKnockback ? 0 : ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13); // Paper - Disable explosion knockback
}
entity.setDeltaMovement(entity.getDeltaMovement().add(d8 * d14, d9 * d14, d10 * d14));
if (entity instanceof Player) {
Player entityhuman = (Player) entity;
- if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying)) {
+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Disable explosion knockback
this.hitPlayers.put(entityhuman, new Vec3(d8 * d13, d9 * d13, d10 * d13));
}
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 14:52:43 -0600
Subject: [PATCH] Disable thunder
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index b1771e25c13b555d3316aca35f8a97ed4ce8f275..f6b62d26e99d7bec49279a41475948a4fd4b92d9 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -692,7 +692,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
gameprofilerfiller.push("thunder");
BlockPos blockposition;
- if (flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot
+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder
blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
if (this.isRainingAt(blockposition)) {
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 14:57:24 -0600
Subject: [PATCH] Disable ice and snow
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index f6b62d26e99d7bec49279a41475948a4fd4b92d9..9c9c8178cd11e37aaef400e40092fb1095fa6c5f 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -722,7 +722,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
gameprofilerfiller.popPush("iceandsnow");
int l;
- if (this.random.nextInt(16) == 0) {
+ if (!this.paperConfig().environment.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow
blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15));
BlockPos blockposition1 = blockposition.below();
Biome biomebase = (Biome) this.getBiome(blockposition).value();

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 15:03:53 -0600
Subject: [PATCH] Configurable mob spawner tick rate
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 3e83bff81a0656d5e1d079ad9e63c7d27561c8e3..b214a79efc4f5279d3dd29feb1f79efc45788a8d 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -45,6 +45,7 @@ public abstract class BaseSpawner {
public int maxNearbyEntities = 6;
public int requiredPlayerRange = 16;
public int spawnRange = 4;
+ private int tickDelay = 0; // Paper
public BaseSpawner() {}
@@ -79,13 +80,18 @@ public abstract class BaseSpawner {
}
public void serverTick(ServerLevel world, BlockPos pos) {
+ // Paper start - Configurable mob spawner tick rate
+ if (spawnDelay > 0 && --tickDelay > 0) return;
+ tickDelay = world.paperConfig().tickRates.mobSpawner;
+ if (tickDelay == -1) { return; } // If disabled
+ // Paper end
if (this.isNearPlayer(world, pos)) {
- if (this.spawnDelay == -1) {
+ if (this.spawnDelay < -tickDelay) {
this.delay(world, pos);
}
if (this.spawnDelay > 0) {
- --this.spawnDelay;
+ this.spawnDelay -= tickDelay; // Paper
} else {
boolean flag = false;
RandomSource randomsource = world.getRandom();
@@ -152,8 +158,7 @@ public abstract class BaseSpawner {
((Mob) entity).finalizeSpawn(world, world.getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.SPAWNER, (SpawnGroupData) null, (CompoundTag) null);
}
// Spigot Start
- if ( entityinsentient.level.spigotConfig.nerfSpawnerMobs )
- {
+ if (entityinsentient.level.spigotConfig.nerfSpawnerMobs) {
entityinsentient.aware = false;
}
// Spigot End

View file

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Isaac Moore <rmsy@me.com>
Date: Tue, 19 Apr 2016 14:09:31 -0500
Subject: [PATCH] Implement PlayerLocaleChangeEvent
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index ecb57a664da6be49611b95bf6bde3d9c3f893e82..c0651c446bdcc4d96df36ad201b77f5ffffa5a7d 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1787,7 +1787,7 @@ public class ServerPlayer extends Player {
return s;
}
- public String locale = "en_us"; // CraftBukkit - add, lowercase
+ public String locale = null; // CraftBukkit - add, lowercase // Paper - default to null
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
public void updateOptions(ServerboundClientInformationPacket packet) {
// CraftBukkit start
@@ -1795,9 +1795,10 @@ public class ServerPlayer extends Player {
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
this.server.server.getPluginManager().callEvent(event);
}
- if (!this.locale.equals(packet.language)) {
+ if (this.locale == null || !this.locale.equals(packet.language)) { // Paper - check for null
PlayerLocaleChangeEvent event = new PlayerLocaleChangeEvent(this.getBukkitEntity(), packet.language);
this.server.server.getPluginManager().callEvent(event);
+ this.server.server.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerLocaleChangeEvent(this.getBukkitEntity(), this.locale, packet.language)); // Paper
}
this.locale = packet.language;
// Paper start
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 27f4387a3ac750114c99e41e855c8fb8081a507d..31172053e26a8df53d0987e816b3e03a560332e6 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2113,8 +2113,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public String getLocale() {
- return this.getHandle().locale;
-
+ // Paper start - Locale change event
+ final String locale = this.getHandle().locale;
+ return locale != null ? locale : "en_us";
+ // Paper end
}
// Paper start

View file

@ -1,62 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 23:30:53 -0600
Subject: [PATCH] Add BeaconEffectEvent
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
index e1a720afaf9f3d843065ed1e8e4ce71019a0fea2..3a17c143de499d81109ae7d6e9fe18718139c5b7 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
@@ -41,6 +41,10 @@ import net.minecraft.world.phys.AABB;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.potion.PotionEffect;
// CraftBukkit end
+// Paper start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import com.destroystokyo.paper.event.block.BeaconEffectEvent;
+// Paper end
public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Nameable {
@@ -280,15 +284,23 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
}
}
- private static void applyEffect(List list, MobEffect mobeffectlist, int j, int b0) {
- {
+ private static void applyEffect(List list, MobEffect effects, int i, int b0, boolean isPrimary, BlockPos worldPosition) { // Paper - BeaconEffectEvent
+ if (!list.isEmpty()) { // Paper - BeaconEffectEvent
Iterator iterator = list.iterator();
Player entityhuman;
+ // Paper start - BeaconEffectEvent
+ org.bukkit.block.Block block = ((Player) list.get(0)).level.getWorld().getBlockAt(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
+ PotionEffect effect = CraftPotionUtil.toBukkit(new MobEffectInstance(effects, i, b0, true, true));
+ // Paper end
while (iterator.hasNext()) {
- entityhuman = (Player) iterator.next();
- entityhuman.addEffect(new MobEffectInstance(mobeffectlist, j, b0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
+ // Paper start - BeaconEffectEvent
+ entityhuman = (ServerPlayer) iterator.next();
+ BeaconEffectEvent event = new BeaconEffectEvent(block, effect, (org.bukkit.entity.Player) entityhuman.getBukkitEntity(), isPrimary);
+ if (CraftEventFactory.callEvent(event).isCancelled()) continue;
+ entityhuman.addEffect(new MobEffectInstance(CraftPotionUtil.fromBukkit(event.getEffect())), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
+ // Paper end
}
}
}
@@ -311,10 +323,10 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
int j = BeaconBlockEntity.getLevel(beaconLevel);
List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel);
- BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0);
+ BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0, true, pos); // Paper - BeaconEffectEvent
if (BeaconBlockEntity.hasSecondaryEffect(beaconLevel, primaryEffect, secondaryEffect)) {
- BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0);
+ BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0, false, pos); // Paper - BeaconEffectEvent
}
}

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 23:34:44 -0600
Subject: [PATCH] Configurable container update tick rate
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index c0651c446bdcc4d96df36ad201b77f5ffffa5a7d..cba9b5586048500d91081cc8ef2ad7ae2bb7a816 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -233,6 +233,7 @@ public class ServerPlayer extends Player {
private int containerCounter;
public int latency;
public boolean wonGame;
+ private int containerUpdateDelay; // Paper
// CraftBukkit start
public String displayName;
@@ -623,7 +624,12 @@ public class ServerPlayer extends Player {
--this.invulnerableTime;
}
- this.containerMenu.broadcastChanges();
+ // Paper start - Configurable container update tick rate
+ if (--containerUpdateDelay <= 0) {
+ this.containerMenu.broadcastChanges();
+ containerUpdateDelay = level.paperConfig().tickRates.containerUpdate;
+ }
+ // Paper end
if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
this.closeContainer();
this.containerMenu = this.inventoryMenu;

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Wed, 2 Mar 2016 23:42:37 -0600
Subject: [PATCH] Use UserCache for player heads
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
index 30865eece58ba2f3c991f9d373a128ada3385b4f..85b9baad074634a2f21c15adbb393ebc5924bdd8 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
@@ -208,7 +208,13 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
if (name == null) {
this.setProfile(null);
} else {
- this.setProfile(new GameProfile(null, name));
+ // Paper start - Use Online Players Skull
+ GameProfile newProfile = null;
+ net.minecraft.server.level.ServerPlayer player = net.minecraft.server.MinecraftServer.getServer().getPlayerList().getPlayerByName(name);
+ if (player != null) newProfile = player.getGameProfile();
+ if (newProfile == null) newProfile = new GameProfile(null, name);
+ this.setProfile(newProfile);
+ // Paper end
}
return true;

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 2 Mar 2016 23:45:17 -0600
Subject: [PATCH] Disable spigot tick limiters
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 746cab58dc67b47bb57889343c625e038dda4851..6457384bded7b65f22547704eba74875a6b84ebb 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -695,9 +695,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Spigot start
// Iterator iterator = this.blockEntityTickers.iterator();
int tilesThisCycle = 0;
- for (this.tileLimiter.initTick();
- tilesThisCycle < this.blockEntityTickers.size() && (tilesThisCycle % 10 != 0 || this.tileLimiter.shouldContinue());
- this.tileTickPosition++, tilesThisCycle++) {
+ for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(tileTickPosition);
// Spigot start

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Steve Anton <anxuiz.nx@gmail.com>
Date: Thu, 3 Mar 2016 00:09:38 -0600
Subject: [PATCH] Add PlayerInitialSpawnEvent
For modifying a player's initial spawn location as they join the server
This is a duplicate API from spigot, so use our duplicate subclass and
improve setPosition to use raw
== AT ==
public net.minecraft.world.entity.Entity setRot(FF)V
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 8a75650f1e1b8a223723ece379beab0eb8f17ce9..ea766e18fb19dbb78e07357748bbf83095253275 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -229,7 +229,7 @@ public abstract class PlayerList {
// Spigot start - spawn location event
Player spawnPlayer = player.getBukkitEntity();
- org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent(spawnPlayer, spawnPlayer.getLocation());
+ org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.getLocation()); // Paper use our duplicate event
this.cserver.getPluginManager().callEvent(ev);
Location loc = ev.getSpawnLocation();
@@ -237,7 +237,10 @@ public abstract class PlayerList {
player.spawnIn(worldserver1);
player.gameMode.setLevel((ServerLevel) player.level);
- player.absMoveTo(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
+ // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
+ player.setPosRaw(loc.getX(), loc.getY(), loc.getZ());
+ player.setRot(loc.getYaw(), loc.getPitch());
+ // Paper end
// Spigot end
// CraftBukkit - Moved message to after join

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 01:13:45 -0600
Subject: [PATCH] Configurable Disabling Cat Chest Detection
Offers a gameplay feature to stop cats from blocking chests
diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
index ccde1bef18a7ffe338d71a6feb2dd88228004c34..c6b57d45383441aa35510e759ce3cb82bc98f305 100644
--- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
@@ -361,6 +361,11 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
}
private static boolean isCatSittingOnChest(LevelAccessor world, BlockPos pos) {
+ // Paper start - Option to disable chest cat detection
+ if (world.getMinecraftWorld().paperConfig().entities.behavior.disableChestCatDetection) {
+ return false;
+ }
+ // Paper end
List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB((double) pos.getX(), (double) (pos.getY() + 1), (double) pos.getZ(), (double) (pos.getX() + 1), (double) (pos.getY() + 2), (double) (pos.getZ() + 1)));
if (!list.isEmpty()) {

View file

@ -1,170 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 01:17:12 -0600
Subject: [PATCH] Ensure commands are not ran async
Plugins calling Player.chat("/foo") or Server.dispatchCommand() could
trigger the server to execute a command while on another thread.
These commands would then process EXPECTING to be on the main thread, leaving to
very hard to trace concurrency issues.
This change will synchronize the command execution back to the main thread, causing a
big slowdown in execution but throwing an exception at same time to raise awareness
that it is happening so that plugin authors can fix their code to stop executing commands async.
This also properly splits up the chat and command handling to reflect the server now
having separate packets for both, and the client always using the correct packet. Text
from a chat packet should never be parsed into a command, even if it starts with the `/`
character.
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index fe315458cead06c3f01473e84b050dadb5ad2726..301d90618f51b90a4a7b0158deef7373fba9cca8 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2040,7 +2040,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
return true;
}
- private static boolean isChatMessageIllegal(String message) {
+ public static boolean isChatMessageIllegal(String message) { // Paper - private -> public
for (int i = 0; i < message.length(); ++i) {
if (!SharedConstants.isAllowedChatCharacter(message.charAt(i))) {
return true;
@@ -2057,7 +2057,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
OutgoingChatMessage outgoing = OutgoingChatMessage.create(original);
- if (!async && s.startsWith("/")) {
+ if (false && !async && s.startsWith("/")) { // Paper - don't handle commands in chat logic
this.handleCommand(s);
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
// Do nothing, this is coming from a plugin
@@ -2147,7 +2147,29 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
}
- private void handleCommand(String s) {
+ public void handleCommand(String s) { // Paper - private -> public
+ // Paper Start
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) {
+ LOGGER.error("Command Dispatched Async: " + s);
+ LOGGER.error("Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
+ Waitable<Void> wait = new Waitable<>() {
+ @Override
+ protected Void evaluate() {
+ ServerGamePacketListenerImpl.this.handleCommand(s);
+ return null;
+ }
+ };
+ server.processQueue.add(wait);
+ try {
+ wait.get();
+ return;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
+ } catch (Exception e) {
+ throw new RuntimeException("Exception processing chat command", e.getCause());
+ }
+ }
+ // Paper End
co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper
if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot
this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index babde3ac7af9b5659bcc7e0298d1d77e7b2d60e2..369657f5c54dae7b03b09aec1c672dc3f2cba090 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -857,6 +857,28 @@ public final class CraftServer implements Server {
Validate.notNull(commandLine, "CommandLine cannot be null");
org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot
+ // Paper Start
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !Bukkit.isPrimaryThread()) {
+ final CommandSender fSender = sender;
+ final String fCommandLine = commandLine;
+ Bukkit.getLogger().log(Level.SEVERE, "Command Dispatched Async: " + commandLine);
+ Bukkit.getLogger().log(Level.SEVERE, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
+ org.bukkit.craftbukkit.util.Waitable<Boolean> wait = new org.bukkit.craftbukkit.util.Waitable<Boolean>() {
+ @Override
+ protected Boolean evaluate() {
+ return dispatchCommand(fSender, fCommandLine);
+ }
+ };
+ net.minecraft.server.MinecraftServer.getServer().processQueue.add(wait);
+ try {
+ return wait.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
+ } catch (Exception e) {
+ throw new RuntimeException("Exception processing dispatch command", e.getCause());
+ }
+ }
+ // Paper End
if (this.commandMap.dispatch(sender, commandLine)) {
return true;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 31172053e26a8df53d0987e816b3e03a560332e6..59e0a9b6f07342120ee5ca00434905b26faf04ca 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -504,7 +504,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public void chat(String msg) {
if (this.getHandle().connection == null) return;
- this.getHandle().connection.chat(msg, PlayerChatMessage.system(msg), false);
+ // Paper start - improve chat handling
+ if (ServerGamePacketListenerImpl.isChatMessageIllegal(msg)) {
+ this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS);
+ } else {
+ if (msg.startsWith("/")) {
+ this.getHandle().connection.handleCommand(msg);
+ } else {
+ final PlayerChatMessage playerChatMessage = PlayerChatMessage.system(msg).withResult(new net.minecraft.network.chat.ChatDecorator.ModernResult(Component.literal(msg), true, false));
+ // TODO chat decorating
+ // TODO text filtering
+ this.getHandle().connection.chat(msg, playerChatMessage, false);
+ }
+ }
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
index 19c44daaa407b7c1c7a7ffe56fef8c8814c6d5b2..6a073a9dc44d93eba296a0e18a9c7be8a7881725 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
@@ -13,6 +13,7 @@ public class ServerShutdownThread extends Thread {
public void run() {
try {
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
this.server.close();
} finally {
try {
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
index 05e94702e42b8f5c35d2a112c486d57948a3acba..5409f230fdd53b70fc03c58177438534731ad4e6 100644
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
@@ -6,6 +6,7 @@ public class AsyncCatcher
{
public static boolean enabled = true;
+ public static boolean shuttingDown = false; // Paper
public static void catchOp(String reason)
{
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
index 882e93ad4471e3688f2fcfb1e6f16926786ee5e7..94d8ba376cd1f024b244654cac9bb62bb19e3060 100644
--- a/src/main/java/org/spigotmc/RestartCommand.java
+++ b/src/main/java/org/spigotmc/RestartCommand.java
@@ -43,6 +43,7 @@ public class RestartCommand extends Command
private static void restart(final String restartScript)
{
AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
try
{
String[] split = restartScript.split( " " );

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: vemacs <d@nkmem.es>
Date: Thu, 3 Mar 2016 01:19:22 -0600
Subject: [PATCH] All chunks are slime spawn chunks toggle
diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java
index 64c4b88f0a64436c126cf32d6e289b3876af8dfb..85abd62434cbe3beb63f61262504372b971d9684 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
@@ -318,7 +318,7 @@ public class Slime extends Mob implements Enemy {
}
ChunkPos chunkcoordintpair = new ChunkPos(pos);
- boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot
+ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
return checkMobSpawnRules(type, world, spawnReason, pos, random);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index a895c81ea6af0822c8371ae93cfe4b72d419439d..e4a533ace96829414844607a013831dba7a1e73e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -177,7 +177,7 @@ public class CraftChunk implements Chunk {
@Override
public boolean isSlimeChunk() {
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
- return WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0;
+ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
}
@Override

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 3 Mar 2016 02:15:57 -0600
Subject: [PATCH] Expose server CommandMap
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 369657f5c54dae7b03b09aec1c672dc3f2cba090..5d2ac8720d38b9c8485a3c3da906b0124bb99a03 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1992,6 +1992,7 @@ public final class CraftServer implements Server {
return this.helpMap;
}
+ @Override // Paper - add override
public SimpleCommandMap getCommandMap() {
return this.commandMap;
}

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 3 Mar 2016 02:18:39 -0600
Subject: [PATCH] Be a bit more informative in maxHealth exception
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 489153b3d22b37f01a027b0effc091d4715e7f7b..c2407224e8bc5e872e153de14090d60e66bb07bc 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -102,7 +102,10 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
public void setHealth(double health) {
health = (float) health;
if ((health < 0) || (health > this.getMaxHealth())) {
- throw new IllegalArgumentException("Health must be between 0 and " + this.getMaxHealth() + "(" + health + ")");
+ // Paper - Be more informative
+ throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth() + ", but was " + health
+ + ". (attribute base value: " + this.getHandle().getAttribute(Attributes.MAX_HEALTH).getBaseValue()
+ + (this instanceof CraftPlayer ? ", player: " + this.getName() + ')' : ')'));
}
// during world generation, we don't want to run logic for dropping items and xp

View file

@ -1,176 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Thu, 3 Mar 2016 02:32:10 -0600
Subject: [PATCH] Player Tab List and Title APIs
diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
index e5ef4acbc74f3ef50ed8e162d3b2a7ae881a4b7a..76914b08c17a62a117319d458a6693070fc46348 100644
--- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java
+++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
@@ -501,6 +501,11 @@ public class FriendlyByteBuf extends ByteBuf {
public FriendlyByteBuf writeComponent(final net.kyori.adventure.text.Component component) {
return this.writeUtf(PaperAdventure.asJsonString(component, this.adventure$locale), 262144);
}
+
+ @Deprecated
+ public FriendlyByteBuf writeComponent(final net.md_5.bungee.api.chat.BaseComponent[] component) {
+ return this.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(component), 262144);
+ }
// Paper end
public FriendlyByteBuf writeComponent(Component text) {
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
index c44a276d201fdfa5144d45d319d7761583c60639..f68a1a6dc6add9496e25cb52c318e086e356e2bb 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetSubtitleTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetSubtitleTextPacket(Component subtitle) {
this.text = subtitle;
@@ -21,6 +22,8 @@ public class ClientboundSetSubtitleTextPacket implements Packet<ClientGamePacket
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
index bd808eb312ade7122973a47f4b96505829511da5..bf0f9cab7c66c089f35b851e799ba4a43420b437 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetTitleTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetTitleTextPacket(Component title) {
this.text = title;
@@ -21,6 +22,8 @@ public class ClientboundSetTitleTextPacket implements Packet<ClientGamePacketLis
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 59e0a9b6f07342120ee5ca00434905b26faf04ca..0a92f895922f5eacb87fc6cf4cd9e3783703cdf9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.entity;
+import com.destroystokyo.paper.Title;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
@@ -350,6 +351,100 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
}
+ // Paper start
+ @Override
+ public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
+ if (header != null) {
+ String headerJson = net.md_5.bungee.chat.ComponentSerializer.toString(header);
+ playerListHeader = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(headerJson);
+ } else {
+ playerListHeader = null;
+ }
+
+ if (footer != null) {
+ String footerJson = net.md_5.bungee.chat.ComponentSerializer.toString(footer);
+ playerListFooter = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(footerJson);
+ } else {
+ playerListFooter = null;
+ }
+
+ updatePlayerListHeaderFooter();
+ }
+
+ @Override
+ public void setPlayerListHeaderFooter(BaseComponent header, BaseComponent footer) {
+ this.setPlayerListHeaderFooter(header == null ? null : new BaseComponent[]{header},
+ footer == null ? null : new BaseComponent[]{footer});
+ }
+
+
+ @Override
+ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ getHandle().connection.send(new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks));
+ }
+
+ @Override
+ public void setSubtitle(BaseComponent[] subtitle) {
+ final ClientboundSetSubtitleTextPacket packet = new ClientboundSetSubtitleTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = subtitle;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void setSubtitle(BaseComponent subtitle) {
+ setSubtitle(new BaseComponent[]{subtitle});
+ }
+
+ @Override
+ public void showTitle(BaseComponent[] title) {
+ final ClientboundSetTitleTextPacket packet = new ClientboundSetTitleTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = title;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void showTitle(BaseComponent title) {
+ showTitle(new BaseComponent[]{title});
+ }
+
+ @Override
+ public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
+ setSubtitle(subtitle);
+ showTitle(title);
+ }
+
+ @Override
+ public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
+ setSubtitle(subtitle);
+ showTitle(title);
+ }
+
+ @Override
+ public void sendTitle(Title title) {
+ Preconditions.checkNotNull(title, "Title is null");
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
+ setSubtitle(title.getSubtitle() == null ? new BaseComponent[0] : title.getSubtitle());
+ showTitle(title.getTitle());
+ }
+
+ @Override
+ public void updateTitle(Title title) {
+ Preconditions.checkNotNull(title, "Title is null");
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
+ if (title.getSubtitle() != null) {
+ setSubtitle(title.getSubtitle());
+ }
+ showTitle(title.getTitle());
+ }
+
+ @Override
+ public void hideTitle() {
+ getHandle().connection.send(new ClientboundClearTitlesPacket(false));
+ }
+ // Paper end
+
@Override
public String getDisplayName() {
if(true) return io.papermc.paper.adventure.DisplayNames.getLegacy(this); // Paper

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:46:17 -0600
Subject: [PATCH] Add configurable portal search radius
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 128dd4749590905fdfa85907d33adc4e4dbe6c33..575ce3bb03c7eef215e71d238a46aa1cc8510f89 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3029,7 +3029,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
double d0 = DimensionType.getTeleportationScale(this.level.dimensionType(), destination.dimensionType());
BlockPos blockposition = worldborder.clampToBounds(this.getX() * d0, this.getY(), this.getZ() * d0);
// CraftBukkit start
- CraftPortalEvent event = this.callPortalEvent(this, destination, new PositionImpl(blockposition.getX(), blockposition.getY(), blockposition.getZ()), PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, flag2 ? 16 : 128, 16);
+ // Paper start
+ int portalSearchRadius = destination.paperConfig().environment.portalSearchRadius;
+ if (level.paperConfig().environment.portalSearchVanillaDimensionScaling && flag2) { // == THE_NETHER
+ portalSearchRadius = (int) (portalSearchRadius / destination.dimensionType().coordinateScale());
+ }
+ // Paper end
+ CraftPortalEvent event = this.callPortalEvent(this, destination, new PositionImpl(blockposition.getX(), blockposition.getY(), blockposition.getZ()), PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, destination.paperConfig().environment.portalCreateRadius); // Paper start - configurable portal radius
if (event == null) {
return null;
}
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
index ff57611088eabfb7e2db8fcf6344b1551b17b87b..d1c7eba29c64a6dbf55d3062ced9769eecb548ed 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -43,7 +43,7 @@ public class PortalForcer {
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos pos, boolean destIsNether, WorldBorder worldBorder) {
// CraftBukkit start
- return this.findPortalAround(pos, worldBorder, destIsNether ? 16 : 128); // Search Radius
+ return this.findPortalAround(pos, worldBorder, destIsNether ? level.paperConfig().environment.portalCreateRadius : level.paperConfig().environment.portalSearchRadius); // Search Radius // Paper - search Radius
}
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos blockposition, WorldBorder worldborder, int i) {

View file

@ -1,88 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:48:12 -0600
Subject: [PATCH] Add velocity warnings
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 5d2ac8720d38b9c8485a3c3da906b0124bb99a03..7f32015fbcbd94ed514a5749484527c2b1657036 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -294,6 +294,7 @@ public final class CraftServer implements Server {
public boolean ignoreVanillaPermissions = false;
private final List<CraftPlayer> playerView;
public int reloadCount;
+ public static Exception excessiveVelEx; // Paper - Velocity warnings
static {
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 62c2780b165a520e85f17fdf5c0d1c29b7579ebc..91c0354f554edbf2fc68748a8fbf182cd8d93de5 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -454,10 +454,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public void setVelocity(Vector velocity) {
Preconditions.checkArgument(velocity != null, "velocity");
velocity.checkFinite();
+ // Paper start - Warn server owners when plugins try to set super high velocities
+ if (!(this instanceof org.bukkit.entity.Projectile || this instanceof org.bukkit.entity.Minecart) && isUnsafeVelocity(velocity)) {
+ CraftServer.excessiveVelEx = new Exception("Excessive velocity set detected: tried to set velocity of entity " + entity.getScoreboardName() + " id #" + getEntityId() + " to (" + velocity.getX() + "," + velocity.getY() + "," + velocity.getZ() + ").");
+ }
+ // Paper end
this.entity.setDeltaMovement(CraftVector.toNMS(velocity));
entity.hurtMarked = true;
}
+ // Paper start
+ /**
+ * Checks if the given velocity is not necessarily safe in all situations.
+ * This function returning true does not mean the velocity is dangerous or to be avoided, only that it may be
+ * a detriment to performance on the server.
+ *
+ * It is not to be used as a hard rule of any sort.
+ * Paper only uses it to warn server owners in watchdog crashes.
+ *
+ * @param vel incoming velocity to check
+ * @return if the velocity has the potential to be a performance detriment
+ */
+ private static boolean isUnsafeVelocity(Vector vel) {
+ final double x = vel.getX();
+ final double y = vel.getY();
+ final double z = vel.getZ();
+
+ if (x > 4 || x < -4 || y > 4 || y < -4 || z > 4 || z < -4) {
+ return true;
+ }
+
+ return false;
+ }
+ // Paper end
+
@Override
public double getHeight() {
return this.getHandle().getBbHeight();
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 11d7ede26b46d0bf9cced65e8c3bcc41c8b66dbf..3ad14bf0697e682a2e777baa8faeb323d127fb13 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -80,7 +80,19 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" );
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
}
- //
+ // Paper start - Warn in watchdog if an excessive velocity was ever set
+ if ( org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null )
+ {
+ log.log( Level.SEVERE, "------------------------------" );
+ log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
+ log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
+ log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
+ for ( StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace() )
+ {
+ log.log( Level.SEVERE, "\t\t" + stack );
+ }
+ }
+ // Paper end
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Thu, 3 Mar 2016 02:50:31 -0600
Subject: [PATCH] Configurable inter-world teleportation safety
People are able to abuse the way Bukkit handles teleportation across worlds since it provides a built in teleportation
safety check.
To abuse the safety check, players are required to get into a location deemed unsafe by Bukkit e.g. be within a chest
or door block. While they are in this block, they accept a teleport request from a player within a different world. Once
the player teleports, Minecraft will recursively search upwards for a safe location, this could eventually land within a
player's skybase.
Example setup to perform the glitch: http://puu.sh/ng3PC/cf072dcbdb.png
The wanted destination was on top of the emerald block however the player ended on top of the diamond block.
This only is the case if the player is teleporting between worlds.
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0a92f895922f5eacb87fc6cf4cd9e3783703cdf9..8b97cf87bff848b60f506ae0cde14e369e4afca8 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1155,7 +1155,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
if (fromWorld == toWorld) {
entity.connection.teleport(to);
} else {
- server.getHandle().respawn(entity, toWorld, true, to, true);
+ server.getHandle().respawn(entity, toWorld, true, to, !toWorld.paperConfig().environment.disableTeleportationSuffocationCheck); // Paper
}
return true;
}

View file

@ -1,225 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 03:15:41 -0600
Subject: [PATCH] Add exception reporting event
diff --git a/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea853ea86e7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
@@ -0,0 +1,38 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Preconditions;
+import org.bukkit.craftbukkit.scheduler.CraftTask;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerSchedulerException;
+
+/**
+ * Reporting wrapper to catch exceptions not natively
+ */
+public class ServerSchedulerReportingWrapper implements Runnable {
+
+ private final CraftTask internalTask;
+
+ public ServerSchedulerReportingWrapper(CraftTask internalTask) {
+ this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
+ }
+
+ @Override
+ public void run() {
+ try {
+ internalTask.run();
+ } catch (RuntimeException e) {
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
+ );
+ throw e;
+ } catch (Throwable t) {
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
+ ); //Do not rethrow, since it is not permitted with Runnable#run
+ }
+ }
+
+ public CraftTask getInternalTask() {
+ return internalTask;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
index 439ff01be1521c283d60cacb110fcb4993933057..da98f074ccd5a40c635824112c97fd174c393cb1 100644
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
@@ -1,5 +1,6 @@
package net.minecraft.server.players;
+import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
@@ -363,6 +364,7 @@ public class OldUsersConverter {
root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
} catch (Exception exception) {
exception.printStackTrace();
+ ServerInternalException.reportInternalException(exception); // Paper
}
if (root != null) {
@@ -376,6 +378,7 @@ public class OldUsersConverter {
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
} catch (Exception exception) {
exception.printStackTrace();
+ ServerInternalException.reportInternalException(exception); // Paper
}
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
index c6fb4c33d7ea52b88d8fc0d90748cbab7387c565..fed09b886f4fa0006d160e5f2abb00dfee45434d 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
@@ -118,6 +118,7 @@ public class VillageSiege implements CustomSpawner {
entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null, (CompoundTag) null);
} catch (Exception exception) {
VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
return;
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 6457384bded7b65f22547704eba74875a6b84ebb..383bf9fe7263bc6153a2e1cbc21657215a3bdb79 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1,5 +1,10 @@
package net.minecraft.world.level;
+import co.aikar.timings.Timing;
+import co.aikar.timings.Timings;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerInternalException;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.mojang.serialization.Codec;
import java.io.IOException;
@@ -731,6 +736,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
MinecraftServer.LOGGER.error(msg, throwable);
+ getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
entity.discard();
// Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 0e4f6893a2fce69782c4246c52e03926fe2df26f..5c58031279c0b74d2061c802e60b7bed50f27156 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -291,6 +291,7 @@ public final class NaturalSpawner {
NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type));
} catch (Exception exception) {
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
}
return null;
@@ -404,6 +405,7 @@ public final class NaturalSpawner {
entity = biomesettingsmobs_c.type.create(world.getLevel());
} catch (Exception exception) {
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
continue;
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index f21ae1ae8af79c1c0c6f2feaa933638add0aa065..ba24e32f96797ed8c8bd82391d1903f6ad2a9813 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.chunk;
import com.google.common.collect.ImmutableList;
+import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.collect.Maps;
import com.google.common.collect.UnmodifiableIterator;
import com.mojang.logging.LogUtils;
@@ -605,10 +606,16 @@ public class LevelChunk extends ChunkAccess {
// CraftBukkit start
} else {
- System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
- + " (" + this.getBlockState(blockposition) + ") where there was no entity tile!");
- System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
- new Exception().printStackTrace();
+ // Paper start
+ ServerInternalException e = new ServerInternalException(
+ "Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + ","
+ + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
+ + " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
+ "Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16) +
+ "\nWorld: " + level.getLevel().dimension().location());
+ e.printStackTrace();
+ ServerInternalException.reportInternalException(e);
+ // Paper end
// CraftBukkit end
}
}
@@ -1187,6 +1194,7 @@ public class LevelChunk extends ChunkAccess {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new ServerInternalException(msg, throwable)));
LevelChunk.this.removeBlockEntity(this.getPos());
// Paper end
// Spigot start
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index e68205fe7169c7c5b7c6fdada2ee97d86107ca97..aa8972fd1a1fade05d60ab69efb8ff24f344508a 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -275,6 +275,7 @@ public class RegionFile implements AutoCloseable {
return true;
}
} catch (IOException ioexception) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
return false;
}
}
@@ -356,6 +357,7 @@ public class RegionFile implements AutoCloseable {
((java.nio.Buffer) buf).position(5); // CraftBukkit - decompile error
filechannel.write(buf);
} catch (Throwable throwable) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper
if (filechannel != null) {
try {
filechannel.close();
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index 07c4d9cd5081378e1b903518f7174fca959cd9e3..dfc2789009fcaa08baa8054bdac915590b8701d6 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -17,6 +17,9 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.logging.Level;
+import com.destroystokyo.paper.ServerSchedulerReportingWrapper;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerSchedulerException;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.IllegalPluginAccessException;
import org.bukkit.plugin.Plugin;
@@ -434,6 +437,8 @@ public class CraftScheduler implements BukkitScheduler {
msg,
throwable);
}
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(msg, throwable, task)));
// Paper end
} finally {
this.currentTask = null;
@@ -441,7 +446,7 @@ public class CraftScheduler implements BukkitScheduler {
this.parsePending();
} else {
this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
- this.executor.execute(task);
+ this.executor.execute(new ServerSchedulerReportingWrapper(task)); // Paper
// We don't need to parse pending
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
}

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Tue, 8 Mar 2016 18:28:43 -0800
Subject: [PATCH] Don't nest if we don't need to when cerealising text
components
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java
index 55e21c7b13826f60e3c656f76e1507e0242e0af3..1387e3597c43fd652f2fc82ca6fc2e83039604e2 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java
@@ -14,7 +14,7 @@ public record ClientboundSystemChatPacket(@javax.annotation.Nullable net.kyori.a
}
public ClientboundSystemChatPacket(net.md_5.bungee.api.chat.BaseComponent[] content, boolean overlay) {
- this(null, net.md_5.bungee.chat.ComponentSerializer.toString(content), overlay); // Paper - Adventure
+ this(null, improveBungeeComponentSerialization(content), overlay); // Paper - Adventure
}
// Spigot end
// Paper start
@@ -25,6 +25,14 @@ public record ClientboundSystemChatPacket(@javax.annotation.Nullable net.kyori.a
public ClientboundSystemChatPacket(net.kyori.adventure.text.Component content, boolean overlay) {
this(content, null, overlay);
}
+
+ private static String improveBungeeComponentSerialization(net.md_5.bungee.api.chat.BaseComponent[] content) {
+ if (content.length == 1) {
+ return net.md_5.bungee.chat.ComponentSerializer.toString(content[0]);
+ } else {
+ return net.md_5.bungee.chat.ComponentSerializer.toString(content);
+ }
+ }
// Paper end
public ClientboundSystemChatPacket(FriendlyByteBuf buf) {

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 8 Mar 2016 23:25:45 -0500
Subject: [PATCH] Disable Scoreboards for non players by default
Entities collision is checking for scoreboards setting.
This is very heavy to do map lookups for every collision to check
this setting.
So avoid looking up scoreboards and short circuit to the "not on a team"
logic which is most likely to be true.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 575ce3bb03c7eef215e71d238a46aa1cc8510f89..98067f625b49d93fdd91af5114790848a2228ac0 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2660,6 +2660,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
@Nullable
public Team getTeam() {
+ if (!this.level.paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper
return this.level.getScoreboard().getPlayersTeam(this.getScoreboardName());
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 7e4f95e04a880ecb459228c90be462cbbec14620..eec1467eaaadaa66febc06e51372c5f602216fb5 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -822,6 +822,7 @@ public abstract class LivingEntity extends Entity {
if (nbt.contains("Team", 8)) {
String s = nbt.getString("Team");
PlayerTeam scoreboardteam = this.level.getScoreboard().getPlayerTeam(s);
+ if (!level.paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper
boolean flag = scoreboardteam != null && this.level.getScoreboard().addPlayerToTeam(this.getStringUUID(), scoreboardteam);
if (!flag) {

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: mrapple <tony@oc.tc>
Date: Sun, 25 Nov 2012 13:43:39 -0600
Subject: [PATCH] Add methods for working with arrows stuck in living entities
Upstream added methods for this, original methods are now
deprecated
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index c2407224e8bc5e872e153de14090d60e66bb07bc..3fae28c52f2aac63ac6a4e8eb6af2d7226e6bec6 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -266,9 +266,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
}
@Override
- public void setArrowsInBody(int count) {
+ public void setArrowsInBody(final int count, final boolean fireEvent) { // Paper
Preconditions.checkArgument(count >= 0, "New arrow amount must be >= 0");
+ if (!fireEvent) { // Paper
this.getHandle().getEntityData().set(net.minecraft.world.entity.LivingEntity.DATA_ARROW_COUNT_ID, count);
+ // Paper start
+ } else {
+ this.getHandle().setArrowCount(count);
+ }
+ // Paper end
}
@Override
@@ -764,4 +770,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
this.getHandle().persistentInvisibility = invisible;
this.getHandle().setSharedFlag(5, invisible);
}
+
+ // Paper start
+ @Override
+ public int getArrowsStuck() {
+ return this.getHandle().getArrowCount();
+ }
+
+ @Override
+ public void setArrowsStuck(final int arrows) {
+ this.getHandle().setArrowCount(arrows);
+ }
+ // Paper end
}

View file

@ -1,51 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 4 Mar 2013 23:46:10 -0500
Subject: [PATCH] Chunk Save Reattempt
We commonly have "Stream Closed" errors on chunk saving, so this code should re-try to save the chunk in the event of failure and hopefully prevent rollbacks.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index aa8972fd1a1fade05d60ab69efb8ff24f344508a..ddcc212ba83d9365adb842b3d3ced64e3d7dd155 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -275,7 +275,7 @@ public class RegionFile implements AutoCloseable {
return true;
}
} catch (IOException ioexception) {
- com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioexception); // Paper - we want the upper try/catch to retry this
return false;
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 18ef7025f7f4dc2a4aff85ca65ff5a2d35a1ef06..64e957650dafc9fc30fa997e7f7d3fd47cf60089 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -167,6 +167,7 @@ public class RegionFileStorage implements AutoCloseable {
}
// Paper end - rewrite chunk system
try { // Paper
+ int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
if (nbt == null) {
regionfile.clear(pos);
@@ -191,7 +192,18 @@ public class RegionFileStorage implements AutoCloseable {
dataoutputstream.close();
}
}
+ // Paper start
+ return;
+ } catch (Exception ex) {
+ laste = ex;
+ }
+ }
+ if (laste != null) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(laste);
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk " + pos, laste);
+ }
+ // Paper end
} finally { // Paper start
regionfile.fileLock.unlock();
} // Paper end

View file

@ -1,93 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Sat, 4 Apr 2015 23:17:52 -0400
Subject: [PATCH] Complete resource pack API
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 301d90618f51b90a4a7b0158deef7373fba9cca8..eaf0e468d7ebf54290ae9e2df9f4a2c252142f65 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1764,8 +1764,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName());
this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
}
- this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()])); // CraftBukkit
-
+ // Paper start
+ PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()];
+ player.getBukkitEntity().setResourcePackStatus(packStatus);
+ this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), packStatus)); // CraftBukkit
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 8b97cf87bff848b60f506ae0cde14e369e4afca8..673e4dc85e5c3ae43170564108f6b74187720d07 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -152,6 +152,7 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.StandardMessenger;
import org.bukkit.profile.PlayerProfile;
import org.bukkit.scoreboard.Scoreboard;
+import org.jetbrains.annotations.NotNull;
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
@@ -170,6 +171,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
private double healthScale = 20;
private CraftWorldBorder clientWorldBorder = null;
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
+ // Paper start
+ private org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus;
+ private String resourcePackHash;
+ // Paper end
public CraftPlayer(CraftServer server, ServerPlayer entity) {
super(server, entity);
@@ -2236,6 +2241,45 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public boolean getAffectsSpawning() {
return this.getHandle().affectsSpawning;
}
+
+ @Override
+ public void setResourcePack(@NotNull String url, @NotNull String hash) {
+ this.setResourcePack(url, hash, false, null);
+ }
+
+ @Override
+ public void setResourcePack(@NotNull String url, @NotNull String hash, boolean required) {
+ this.setResourcePack(url, hash, required, null);
+ }
+
+ @Override
+ public void setResourcePack(@NotNull String url, @NotNull String hash, boolean required, net.kyori.adventure.text.Component resourcePackPrompt) {
+ Validate.notNull(url, "Resource pack URL cannot be null");
+ Validate.notNull(hash, "Hash cannot be null");
+ net.minecraft.network.chat.Component promptComponent = resourcePackPrompt != null ?
+ io.papermc.paper.adventure.PaperAdventure.asVanilla(resourcePackPrompt) :
+ null;
+ this.getHandle().sendTexturePack(url, hash, required, promptComponent);
+ }
+
+ @Override
+ public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status getResourcePackStatus() {
+ return this.resourcePackStatus;
+ }
+
+ @Override
+ public String getResourcePackHash() {
+ return this.resourcePackHash;
+ }
+
+ @Override
+ public boolean hasResourcePack() {
+ return this.resourcePackStatus == org.bukkit.event.player.PlayerResourcePackStatusEvent.Status.SUCCESSFULLY_LOADED;
+ }
+
+ public void setResourcePackStatus(org.bukkit.event.player.PlayerResourcePackStatusEvent.Status status) {
+ this.resourcePackStatus = status;
+ }
// Paper end
@Override

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 13:17:38 -0400
Subject: [PATCH] Default loading permissions.yml before plugins
Under previous behavior, plugins were not able to check if a player had a permission
if it was defined in permissions.yml. there is no clean way for a plugin to fix that either.
This will change the order so that by default, permissions.yml loads BEFORE plugins instead of after.
This gives plugins expected permission checks.
It also helps improve the expected logic, as servers should set the initial defaults, and then let plugins
modify that. Under the previous logic, plugins were unable (cleanly) override permissions.yml.
A config option has been added for those who depend on the previous behavior, but I don't expect that.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 7f32015fbcbd94ed514a5749484527c2b1657036..6c7b1fe353a4d9bd9e307e7984f9348dd5914ff1 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -454,6 +454,7 @@ public final class CraftServer implements Server {
if (type == PluginLoadOrder.STARTUP) {
this.helpMap.clear();
this.helpMap.initializeGeneralTopics();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions(); // Paper
}
Plugin[] plugins = this.pluginManager.getPlugins();
@@ -473,7 +474,7 @@ public final class CraftServer implements Server {
this.commandMap.registerServerAliases();
DefaultPermissions.registerCorePermissions();
CraftDefaultPermissions.registerCorePermissions();
- this.loadCustomPermissions();
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) this.loadCustomPermissions(); // Paper
this.helpMap.initializeCommands();
this.syncCommands();
}

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William <admin@domnian.com>
Date: Fri, 18 Mar 2016 03:30:17 -0400
Subject: [PATCH] Allow Reloading of Custom Permissions
https://github.com/PaperMC/Paper/issues/49
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 6c7b1fe353a4d9bd9e307e7984f9348dd5914ff1..318b3e22cad28ef3a49ff005808c5e3525ccbcf4 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2546,5 +2546,23 @@ public final class CraftServer implements Server {
}
return this.adventure$audiences;
}
+
+ @Override
+ public void reloadPermissions() {
+ pluginManager.clearPermissions();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions();
+ for (Plugin plugin : pluginManager.getPlugins()) {
+ for (Permission perm : plugin.getDescription().getPermissions()) {
+ try {
+ pluginManager.addPermission(perm);
+ } catch (IllegalArgumentException ex) {
+ getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex);
+ }
+ }
+ }
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions();
+ DefaultPermissions.registerCorePermissions();
+ CraftDefaultPermissions.registerCorePermissions();
+ }
// Paper end
}

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 13:50:14 -0400
Subject: [PATCH] Remove Metadata on reload
Metadata is not meant to persist reload as things break badly with non primitive types
This will remove metadata on reload so it does not crash everything if a plugin uses it.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 318b3e22cad28ef3a49ff005808c5e3525ccbcf4..3a046d3eb6bca6f45f8018a3844c58ac8cba43ac 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -944,8 +944,16 @@ public final class CraftServer implements Server {
world.spigotConfig.init(); // Spigot
}
+ Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
this.pluginManager.clearPlugins();
this.commandMap.clearCommands();
+ // Paper start
+ for (Plugin plugin : pluginClone) {
+ entityMetadata.removeAll(plugin);
+ worldMetadata.removeAll(plugin);
+ playerMetadata.removeAll(plugin);
+ }
+ // Paper end
this.reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper

View file

@ -1,321 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 28 May 2015 23:00:19 -0400
Subject: [PATCH] Handle Item Meta Inconsistencies
First, Enchantment order would blow away seeing 2 items as the same,
however the Client forces enchantment list in a certain order, as well
as does the /enchant command. Anvils can insert it into forced order,
causing 2 same items to be considered different.
This change makes unhandled NBT Tags and Enchantments use a sorted tree map,
so they will always be in a consistent order.
Additionally, the old enchantment API was never updated when ItemMeta
was added, resulting in 2 different ways to modify an items enchantments.
For consistency, the old API methods now forward to use the
ItemMeta API equivalents, and should deprecate the old API's.
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index cf810a1d645dd63595702a5f07456cd48393ee79..87031aa69148118d9f5bf16cb8a55cf72f9d0a1d 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -155,6 +155,23 @@ public final class ItemStack {
return this.getItem().getTooltipImage(this);
}
+ // Paper start
+ private static final java.util.Comparator<? super CompoundTag> enchantSorter = java.util.Comparator.comparing(o -> o.getString("id"));
+ private void processEnchantOrder(@Nullable CompoundTag tag) {
+ if (tag == null || !tag.contains("Enchantments", 9)) {
+ return;
+ }
+ ListTag list = tag.getList("Enchantments", 10);
+ if (list.size() < 2) {
+ return;
+ }
+ try {
+ //noinspection unchecked
+ list.sort((java.util.Comparator<? super net.minecraft.nbt.Tag>) enchantSorter); // Paper
+ } catch (Exception ignored) {}
+ }
+ // Paper end
+
public ItemStack(ItemLike item) {
this(item, 1);
}
@@ -206,6 +223,7 @@ public final class ItemStack {
// CraftBukkit start - make defensive copy as this data may be coming from the save thread
this.tag = nbttagcompound.getCompound("tag").copy();
// CraftBukkit end
+ this.processEnchantOrder(this.tag); // Paper
this.getItem().verifyTagAfterLoad(this.tag);
}
@@ -780,6 +798,7 @@ public final class ItemStack {
public void setTag(@Nullable CompoundTag nbt) {
this.tag = nbt;
+ this.processEnchantOrder(this.tag); // Paper
if (this.getItem().canBeDepleted()) {
this.setDamageValue(this.getDamageValue());
}
@@ -1073,6 +1092,7 @@ public final class ItemStack {
ListTag nbttaglist = this.tag.getList("Enchantments", 10);
nbttaglist.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (byte) level));
+ processEnchantOrder(this.tag); // Paper
}
public boolean isEnchanted() {
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 781a1e5e4220d2198467c0fd3956f5e0387a7aff..3c3f5a4b7109ec8b47b550f9e766556f8d1546ec 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -6,7 +6,6 @@ import java.util.Map;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.item.Item;
-import net.minecraft.world.item.enchantment.EnchantmentHelper;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@@ -178,28 +177,11 @@ public final class CraftItemStack extends ItemStack {
public void addUnsafeEnchantment(Enchantment ench, int level) {
Validate.notNull(ench, "Cannot add null enchantment");
- if (!CraftItemStack.makeTag(this.handle)) {
- return;
- }
- ListTag list = CraftItemStack.getEnchantmentList(this.handle);
- if (list == null) {
- list = new ListTag();
- this.handle.getTag().put(ENCHANTMENTS.NBT, list);
- }
- int size = list.size();
-
- for (int i = 0; i < size; i++) {
- CompoundTag tag = (CompoundTag) list.get(i);
- String id = tag.getString(ENCHANTMENTS_ID.NBT);
- if (ench.getKey().equals(NamespacedKey.fromString(id))) {
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
- return;
- }
- }
- CompoundTag tag = new CompoundTag();
- tag.putString(ENCHANTMENTS_ID.NBT, ench.getKey().toString());
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
- list.add(tag);
+ // Paper start - Replace whole method
+ final ItemMeta itemMeta = this.getItemMeta();
+ itemMeta.addEnchant(ench, level, true);
+ this.setItemMeta(itemMeta);
+ // Paper end
}
static boolean makeTag(net.minecraft.world.item.ItemStack item) {
@@ -225,57 +207,29 @@ public final class CraftItemStack extends ItemStack {
if (this.handle == null) {
return 0;
}
- return EnchantmentHelper.getItemEnchantmentLevel(CraftEnchantment.getRaw(ench), handle);
+ return net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(CraftEnchantment.getRaw(ench), handle); // Paper
}
@Override
public int removeEnchantment(Enchantment ench) {
Validate.notNull(ench, "Cannot remove null enchantment");
- ListTag list = CraftItemStack.getEnchantmentList(this.handle), listCopy;
- if (list == null) {
- return 0;
- }
- int index = Integer.MIN_VALUE;
- int level = Integer.MIN_VALUE;
- int size = list.size();
-
- for (int i = 0; i < size; i++) {
- CompoundTag enchantment = (CompoundTag) list.get(i);
- String id = enchantment.getString(ENCHANTMENTS_ID.NBT);
- if (ench.getKey().equals(NamespacedKey.fromString(id))) {
- index = i;
- level = 0xffff & enchantment.getShort(ENCHANTMENTS_LVL.NBT);
- break;
- }
- }
-
- if (index == Integer.MIN_VALUE) {
- return 0;
- }
- if (size == 1) {
- this.handle.getTag().remove(ENCHANTMENTS.NBT);
- if (this.handle.getTag().isEmpty()) {
- this.handle.setTag(null);
- }
- return level;
- }
-
- // This is workaround for not having an index removal
- listCopy = new ListTag();
- for (int i = 0; i < size; i++) {
- if (i != index) {
- listCopy.add(list.get(i));
- }
+ // Paper start - replace entire method
+ int level = getEnchantmentLevel(ench);
+ if (level > 0) {
+ final ItemMeta itemMeta = this.getItemMeta();
+ if (itemMeta == null) return 0;
+ itemMeta.removeEnchant(ench);
+ this.setItemMeta(itemMeta);
}
- this.handle.getTag().put(ENCHANTMENTS.NBT, listCopy);
+ // Paper end
return level;
}
@Override
public Map<Enchantment, Integer> getEnchantments() {
- return CraftItemStack.getEnchantments(this.handle);
+ return this.hasItemMeta() ? this.getItemMeta().getEnchants() : ImmutableMap.<Enchantment, Integer>of(); // Paper - use Item Meta
}
static Map<Enchantment, Integer> getEnchantments(net.minecraft.world.item.ItemStack item) {
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 78029398774f1060e3522e4613259be894d68c22..9823ddae9edb40be805332ca1ef4325f9c1df14b 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.ImmutableSortedMap; // Paper
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
@@ -23,6 +24,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
+import java.util.Comparator; // Paper
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
@@ -33,6 +35,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeMap; // Paper
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
@@ -273,7 +276,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
private List<String> lore; // null and empty are two different states internally
private Integer customModelData;
private CompoundTag blockData;
- private Map<Enchantment, Integer> enchantments;
+ private EnchantmentMap enchantments; // Paper
private Multimap<Attribute, AttributeModifier> attributeModifiers;
private int repairCost;
private int hideFlag;
@@ -284,7 +287,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
private CompoundTag internalTag;
- final Map<String, Tag> unhandledTags = new HashMap<String, Tag>(); // Visible for testing only
+ final Map<String, Tag> unhandledTags = new TreeMap<String, Tag>(); // Visible for testing only // Paper
private CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftMetaItem.DATA_TYPE_REGISTRY);
private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only
@@ -305,7 +308,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
this.blockData = meta.blockData;
if (meta.enchantments != null) { // Spigot
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(meta.enchantments);
+ this.enchantments = new EnchantmentMap(meta.enchantments); // Paper
}
if (meta.hasAttributeModifiers()) {
@@ -388,13 +391,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
- static Map<Enchantment, Integer> buildEnchantments(CompoundTag tag, ItemMetaKey key) {
+ static EnchantmentMap buildEnchantments(CompoundTag tag, ItemMetaKey key) { // Paper
if (!tag.contains(key.NBT)) {
return null;
}
ListTag ench = tag.getList(key.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND);
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
for (int i = 0; i < ench.size(); i++) {
String id = ((CompoundTag) ench.get(i)).getString(ENCHANTMENTS_ID.NBT);
@@ -547,13 +550,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
- static Map<Enchantment, Integer> buildEnchantments(Map<String, Object> map, ItemMetaKey key) {
+ static EnchantmentMap buildEnchantments(Map<String, Object> map, ItemMetaKey key) { // Paper
Map<?, ?> ench = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true);
if (ench == null) {
return null;
}
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
for (Map.Entry<?, ?> entry : ench.entrySet()) {
// Doctor older enchants
String enchantKey = entry.getKey().toString();
@@ -829,14 +832,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Override
public Map<Enchantment, Integer> getEnchants() {
- return this.hasEnchants() ? ImmutableMap.copyOf(enchantments) : ImmutableMap.<Enchantment, Integer>of();
+ return this.hasEnchants() ? ImmutableSortedMap.copyOfSorted(this.enchantments) : ImmutableMap.<Enchantment, Integer>of(); // Paper
}
@Override
public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) {
Validate.notNull(ench, "Enchantment cannot be null");
if (this.enchantments == null) {
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(4);
+ this.enchantments = new EnchantmentMap(); // Paper
}
if (ignoreRestrictions || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) {
@@ -1224,7 +1227,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
clone.customModelData = this.customModelData;
clone.blockData = this.blockData;
if (this.enchantments != null) {
- clone.enchantments = new LinkedHashMap<Enchantment, Integer>(this.enchantments);
+ clone.enchantments = new EnchantmentMap(this.enchantments); // Paper
}
if (this.hasAttributeModifiers()) {
clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers);
@@ -1460,4 +1463,22 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
return CraftMetaItem.HANDLED_TAGS;
}
}
+
+ // Paper start
+ private static class EnchantmentMap extends TreeMap<Enchantment, Integer> {
+ private EnchantmentMap(Map<Enchantment, Integer> enchantments) {
+ this();
+ putAll(enchantments);
+ }
+
+ private EnchantmentMap() {
+ super(Comparator.comparing(o -> o.getKey().toString()));
+ }
+
+ public EnchantmentMap clone() {
+ return (EnchantmentMap) super.clone();
+ }
+ }
+ // Paper end
+
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 15:12:22 -0400
Subject: [PATCH] Configurable Non Player Arrow Despawn Rate
Can set a much shorter despawn rate for arrows that players can not pick up.
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
index 3e1f5fcf589ad7916adb44b53490ccac947a8799..d4b8364fd860ee2cc632d8c752435b9b311c7ece 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -312,7 +312,7 @@ public abstract class AbstractArrow extends Projectile {
protected void tickDespawn() {
++this.life;
- if (this.life >= ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)) { // Spigot
+ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? level.paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? level.paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init?
this.discard();
}

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 20:16:03 -0400
Subject: [PATCH] Add World Util Methods
Methods that can be used for other patches to help improve logic.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 9c9c8178cd11e37aaef400e40092fb1095fa6c5f..d4b101d0f1835b57f34f68653d728df2bb78faa1 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -219,7 +219,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final LevelStorageSource.LevelStorageAccess convertable;
public final UUID uuid;
- public LevelChunk getChunkIfLoaded(int x, int z) {
+ @Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
return this.chunkSource.getChunk(x, z, false);
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 383bf9fe7263bc6153a2e1cbc21657215a3bdb79..47d24d64d16f00e481d4773487163bc1e46ae4a8 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -337,6 +337,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return chunk == null ? null : chunk.getFluidState(blockposition);
}
+ public final boolean isLoadedAndInBounds(BlockPos blockposition) { // Paper - final for inline
+ return getWorldBorder().isWithinBounds(blockposition) && getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null;
+ }
+
+ public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { // Overridden in WorldServer for ABI compat which has final
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(x, z);
+ }
+ public final @Nullable LevelChunk getChunkIfLoaded(BlockPos blockposition) {
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ }
+
+ // reduces need to do isLoaded before getType
+ public final @Nullable BlockState getBlockStateIfLoadedAndInBounds(BlockPos blockposition) {
+ return getWorldBorder().isWithinBounds(blockposition) ? getBlockStateIfLoaded(blockposition) : null;
+ }
+
@Override
public final ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { // Paper - final for inline
// Paper end

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Sun, 21 Jun 2015 15:07:20 -0400
Subject: [PATCH] Custom replacement for eaten items
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index eec1467eaaadaa66febc06e51372c5f602216fb5..29495ff2d2c31f6b6ef6e2817662d143e538f926 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3639,10 +3639,11 @@ public abstract class LivingEntity extends Entity {
this.triggerItemUseEffects(this.useItem, 16);
// CraftBukkit start - fire PlayerItemConsumeEvent
ItemStack itemstack;
+ PlayerItemConsumeEvent event = null; // Paper
if (this instanceof ServerPlayer) {
org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.useItem);
org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(enumhand);
- PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand);
+ event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand); // Paper
level.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
@@ -3656,6 +3657,13 @@ public abstract class LivingEntity extends Entity {
} else {
itemstack = this.useItem.finishUsingItem(this.level, this);
}
+
+ // Paper start - save the default replacement item and change it if necessary
+ final ItemStack defaultReplacement = itemstack;
+ if (event != null && event.getReplacement() != null) {
+ itemstack = CraftItemStack.asNMSCopy(event.getReplacement());
+ }
+ // Paper end
// CraftBukkit end
if (itemstack != this.useItem) {
@@ -3663,6 +3671,11 @@ public abstract class LivingEntity extends Entity {
}
this.stopUsingItem();
+ // Paper start - if the replacement is anything but the default, update the client inventory
+ if (this instanceof ServerPlayer && !com.google.common.base.Objects.equal(defaultReplacement, itemstack)) {
+ ((ServerPlayer) this).getBukkitEntity().updateInventory();
+ }
+ // Paper end
}
}

View file

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 27 Sep 2015 01:18:02 -0400
Subject: [PATCH] handle NaN health/absorb values and repair bad data
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 29495ff2d2c31f6b6ef6e2817662d143e538f926..b2871726eb4dd7f16d161097cbf0f287839e10ba 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -783,7 +783,13 @@ public abstract class LivingEntity extends Entity {
@Override
public void readAdditionalSaveData(CompoundTag nbt) {
- this.setAbsorptionAmount(nbt.getFloat("AbsorptionAmount"));
+ // Paper start - jvm keeps optimizing the setter
+ float absorptionAmount = nbt.getFloat("AbsorptionAmount");
+ if (Float.isNaN(absorptionAmount)) {
+ absorptionAmount = 0;
+ }
+ this.setAbsorptionAmount(absorptionAmount);
+ // Paper end
if (nbt.contains("Attributes", 9) && this.level != null && !this.level.isClientSide) {
this.getAttributes().load(nbt.getList("Attributes", 10));
}
@@ -1270,6 +1276,10 @@ public abstract class LivingEntity extends Entity {
}
public void setHealth(float health) {
+ // Paper start
+ if (Float.isNaN(health)) { health = getMaxHealth(); if (this.valid) {
+ System.err.println("[NAN-HEALTH] " + getScoreboardName() + " had NaN health set");
+ } } // Paper end
// CraftBukkit start - Handle scaled health
if (this instanceof ServerPlayer) {
org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity();
@@ -3472,7 +3482,7 @@ public abstract class LivingEntity extends Entity {
}
public void setAbsorptionAmount(float amount) {
- if (amount < 0.0F) {
+ if (amount < 0.0F || Float.isNaN(amount)) { // Paper
amount = 0.0F;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 673e4dc85e5c3ae43170564108f6b74187720d07..b08b72f8c029faae9b9d425e8ce77a1ff23addd7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2041,6 +2041,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
public void setRealHealth(double health) {
+ if (Double.isNaN(health)) {return;} // Paper
this.health = health;
}

View file

@ -1,113 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 22 Mar 2016 00:33:47 -0400
Subject: [PATCH] Use a Shared Random for Entities
Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 98067f625b49d93fdd91af5114790848a2228ac0..c070fd1b224aeeaa9ebb054105a0f73285956da1 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -159,6 +159,79 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
}
+ // Paper start
+ public static RandomSource SHARED_RANDOM = new RandomRandomSource();
+ private static final class RandomRandomSource extends java.util.Random implements net.minecraft.world.level.levelgen.BitRandomSource {
+ private boolean locked = false;
+
+ @Override
+ public synchronized void setSeed(long seed) {
+ if (locked) {
+ LOGGER.error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
+ } else {
+ super.setSeed(seed);
+ locked = true;
+ }
+ }
+
+ @Override
+ public RandomSource fork() {
+ return new net.minecraft.world.level.levelgen.LegacyRandomSource(this.nextLong());
+ }
+
+ @Override
+ public net.minecraft.world.level.levelgen.PositionalRandomFactory forkPositional() {
+ return new net.minecraft.world.level.levelgen.LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong());
+ }
+
+ // these below are added to fix reobf issues that I don't wanna deal with right now
+ @Override
+ public int next(int bits) {
+ return super.next(bits);
+ }
+
+ @Override
+ public int nextInt(int origin, int bound) {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(origin, bound);
+ }
+
+ @Override
+ public long nextLong() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextLong();
+ }
+
+ @Override
+ public int nextInt() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt();
+ }
+
+ @Override
+ public int nextInt(int bound) {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(bound);
+ }
+
+ @Override
+ public boolean nextBoolean() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextBoolean();
+ }
+
+ @Override
+ public float nextFloat() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextFloat();
+ }
+
+ @Override
+ public double nextDouble() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextDouble();
+ }
+
+ @Override
+ public double nextGaussian() {
+ return super.nextGaussian();
+ }
+ }
+ // Paper end
+
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
@@ -398,7 +471,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.bb = Entity.INITIAL_AABB;
this.stuckSpeedMultiplier = Vec3.ZERO;
this.nextStep = 1.0F;
- this.random = RandomSource.create();
+ this.random = SHARED_RANDOM; // Paper
this.remainingFireTicks = -this.getFireImmuneTicks();
this.fluidHeight = new Object2DoubleArrayMap(2);
this.fluidOnEyes = new HashSet();
diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java
index 8e63ab510e4c2e458da726ca67be4d3b5274e7b7..a51424d29ac353cf1bec4d1484db0acb63bebba5 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java
@@ -46,7 +46,7 @@ public class Squid extends WaterAnimal {
public Squid(EntityType<? extends Squid> type, Level world) {
super(type, world);
- this.random.setSeed((long) this.getId());
+ //this.random.setSeed((long) this.getId()); // Paper - we set the random to shared, do not clobber the seed
this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 22 Mar 2016 12:04:28 -0500
Subject: [PATCH] Configurable spawn chances for skeleton horses
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index d4b101d0f1835b57f34f68653d728df2bb78faa1..87a81cdd00b19ba020f6506eedd8ac4bf20d32ef 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -696,7 +696,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
if (this.isRainingAt(blockposition)) {
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
- boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * 0.01D && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD);
+ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper
if (flag1) {
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this);

View file

@ -1,166 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 02:07:55 -0600
Subject: [PATCH] Optimize isInWorldBounds and getBlockState for inlining
Hot methods, so reduce # of instructions for the method.
Move is valid location test to the BlockPosition class so that it can access local variables.
Replace all calls to the new place to the unnecessary forward.
Optimize getType and getBlockData to manually inline and optimize the calls
diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java
index 3b254a89484ac8a9dba399c7eb081328ff69a7b2..a6a6aaf226655d0e44bc229288112882a9c04e3b 100644
--- a/src/main/java/net/minecraft/core/Vec3i.java
+++ b/src/main/java/net/minecraft/core/Vec3i.java
@@ -33,6 +33,12 @@ public class Vec3i implements Comparable<Vec3i> {
return CODEC.flatXmap(checkOffsetAxes(maxAbsValue), checkOffsetAxes(maxAbsValue));
}
+ // Paper start
+ public final boolean isInsideBuildHeightAndWorldBoundsHorizontal(net.minecraft.world.level.LevelHeightAccessor levelHeightAccessor) {
+ return getX() >= -30000000 && getZ() >= -30000000 && getX() < 30000000 && getZ() < 30000000 && !levelHeightAccessor.isOutsideBuildHeight(getY());
+ }
+ // Paper end
+
public Vec3i(int x, int y, int z) {
this.x = x;
this.y = y;
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 47d24d64d16f00e481d4773487163bc1e46ae4a8..4d2a64a38a94cc82767030dbdf219b5ee1002a7d 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -279,7 +279,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
public boolean isInWorldBounds(BlockPos pos) {
- return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
+ return pos.isInsideBuildHeightAndWorldBoundsHorizontal(this); // Paper - use better/optimized check
}
public static boolean isInSpawnableBounds(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
index 1b7496cec0ba5a95615a069e3168bd46308d0b40..508c2fff8d8e0c6f37b6c4e3b72ba772c2ab2ee5 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -160,6 +160,7 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
return GameEventListenerRegistry.NOOP;
}
+ public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper
@Nullable
public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean moved);
diff --git a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
index 2eb92dde607d7c8968cb07c6f3c24e1c45e9990f..908f71721daf4305692f424d7712cbfdddddae83 100644
--- a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
@@ -55,6 +55,12 @@ public class EmptyLevelChunk extends LevelChunk {
public void setBlockEmptinessMap(final boolean[] emptinessMap) {}
// Paper end - starlight
+ // Paper start
+ @Override
+ public BlockState getBlockState(int x, int y, int z) {
+ return Blocks.VOID_AIR.defaultBlockState();
+ }
+ // Paper end
@Override
public BlockState getBlockState(BlockPos pos) {
return Blocks.VOID_AIR.defaultBlockState();
diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
index 8033c8741a0f73919a357893652592b317bfb417..9a1cffd51aaf97f759a9057aefbf50bd6f5ed028 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
@@ -89,6 +89,12 @@ public class ImposterProtoChunk extends ProtoChunk {
public BlockState getBlockState(BlockPos pos) {
return this.wrapped.getBlockState(pos);
}
+ // Paper start
+ @Override
+ public final BlockState getBlockState(final int x, final int y, final int z) {
+ return this.wrapped.getBlockStateFinal(x, y, z);
+ }
+ // Paper end
@Override
public FluidState getFluidState(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index ba24e32f96797ed8c8bd82391d1903f6ad2a9813..2efeccb33d1d5fb148a12f71eae870fbdcb6e0fd 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -342,12 +342,29 @@ public class LevelChunk extends ChunkAccess {
}
}
+ // Paper start - Optimize getBlockData to reduce instructions
@Override
public BlockState getBlockState(BlockPos pos) {
- int i = pos.getX();
- int j = pos.getY();
- int k = pos.getZ();
+ return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
+ }
+
+ @Override
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ return this.getBlockStateFinal(x, y, z);
+ }
+ public final BlockState getBlockStateFinal(final int x, final int y, final int z) {
+ // Method body / logic copied from below
+ final int i = this.getSectionIndex(y);
+ if (i < 0 || i >= this.sections.length || this.sections[i].nonEmptyBlockCount == 0 || this.sections[i].hasOnlyAir()) {
+ return Blocks.AIR.defaultBlockState();
+ }
+ // Inlined ChunkSection.getType() and DataPaletteBlock.a(int,int,int)
+ return this.sections[i].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
+ }
+
+ public BlockState getBlockState_unused(int i, int j, int k) {
+ // Paper end
if (this.level.isDebug()) {
BlockState iblockdata = null;
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index dddae1e226d8f58cdcfc597e25d4228cd3245cb4..ae37e97e52557b48f129cc02eeea395378a48444 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -21,7 +21,7 @@ public class LevelChunkSection {
public static final int SECTION_SIZE = 4096;
public static final int BIOME_CONTAINER_BITS = 2;
private final int bottomBlockY;
- private short nonEmptyBlockCount;
+ short nonEmptyBlockCount; // Paper - package-private
private short tickingBlockCount;
private short tickingFluidCount;
public final PalettedContainer<BlockState> states;
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
index 0b67858f8d6689b34816f9556f3424af512a7401..c24b4c6a560aab2df07783b3481981deb8571a50 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -94,14 +94,18 @@ public class ProtoChunk extends ChunkAccess {
@Override
public BlockState getBlockState(BlockPos pos) {
- int i = pos.getY();
- if (this.isOutsideBuildHeight(i)) {
+ // Paper start
+ return getBlockState(pos.getX(), pos.getY(), pos.getZ());
+ }
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ if (this.isOutsideBuildHeight(y)) {
return Blocks.VOID_AIR.defaultBlockState();
} else {
- LevelChunkSection levelChunkSection = this.getSection(this.getSectionIndex(i));
- return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(pos.getX() & 15, i & 15, pos.getZ() & 15);
+ LevelChunkSection levelChunkSection = this.getSections()[this.getSectionIndex(y)];
+ return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(x & 15, y & 15, z & 15);
}
}
+ // Paper end
@Override
public FluidState getFluidState(BlockPos pos) {

View file

@ -1,70 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 19:55:45 -0400
Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener
Saves on some object allocation and processing when no plugin listens to this
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 28d58f402f15ee37cc1bfa3114839db281fc5f57..e62aa86afb05d8f00d8dd2b676407bfa7d0ed9fb 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1357,6 +1357,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
+ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
this.profiler.push(() -> {
return worldserver + " " + worldserver.dimension().location();
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 87a81cdd00b19ba020f6506eedd8ac4bf20d32ef..a487331d9df8fa0d58cfb0859c25a8fffe376ac2 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -218,6 +218,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
// CraftBukkit start
public final LevelStorageSource.LevelStorageAccess convertable;
public final UUID uuid;
+ public boolean hasPhysicsEvent = true; // Paper
@Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
return this.chunkSource.getChunk(x, z, false);
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 4d2a64a38a94cc82767030dbdf219b5ee1002a7d..00911231201f84b781048d052495b60a47fb5277 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -497,7 +497,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// CraftBukkit start
iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam
CraftWorld world = ((ServerLevel) this).getWorld();
- if (world != null) {
+ if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata));
this.getCraftServer().getPluginManager().callEvent(event);
diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java
index d40e791529911ca81398ac267a819415da91502a..03fde6e47c4a347c62fe9b4a3351769aedf874f6 100644
--- a/src/main/java/net/minecraft/world/level/block/BushBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java
@@ -24,7 +24,7 @@ public class BushBlock extends Block {
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
// CraftBukkit start
if (!state.canSurvive(world, pos)) {
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
+ if (!(world instanceof net.minecraft.server.level.ServerLevel && ((net.minecraft.server.level.ServerLevel) world).hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
return Blocks.AIR.defaultBlockState();
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
index 12bf4125bc697092a038600955318f8436bdb5d7..e234ae13fe9793db237adb6f6216fa32638cfc4f 100644
--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
@@ -95,7 +95,7 @@ public class DoublePlantBlock extends BushBlock {
protected static void preventCreativeDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) {
// CraftBukkit start
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
+ if (((net.minecraft.server.level.ServerLevel)world).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
return;
}
// CraftBukkit end

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 20:32:58 -0400
Subject: [PATCH] Entity AddTo/RemoveFrom World Events
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index a487331d9df8fa0d58cfb0859c25a8fffe376ac2..e7d07d1f86af49b8729f6ac66b398ee6aae5ab4a 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2225,6 +2225,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
}
// Paper end
+ new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
}
public void onTrackingEnd(Entity entity) {
@@ -2300,6 +2301,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
}
// CraftBukkit end
+ new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
}
public void onSectionChange(Entity entity) {

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 20:46:14 -0400
Subject: [PATCH] Configurable Chunk Inhabited Time
Vanilla stores how long a chunk has been active on a server, and dynamically scales some
aspects of vanilla gameplay to this factor.
For people who want all chunks to be treated equally, you can chose a fixed value.
This allows to fine-tune vanilla gameplay.
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 2efeccb33d1d5fb148a12f71eae870fbdcb6e0fd..b4c76e53eef8dc0efec98848352a243931ffc1f3 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -327,6 +327,13 @@ public class LevelChunk extends ChunkAccess {
return new ChunkAccess.TicksToSave(this.blockTicks, this.fluidTicks);
}
+ // Paper start
+ @Override
+ public long getInhabitedTime() {
+ return this.level.paperConfig().chunks.fixedChunkInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig().chunks.fixedChunkInhabitedTime;
+ }
+ // Paper end
+
@Override
public GameEventListenerRegistry getListenerRegistry(int ySectionCoord) {
Level world = this.level;

View file

@ -1,149 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 21:22:26 -0400
Subject: [PATCH] EntityPathfindEvent
Fires when an Entity decides to start moving to a location.
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
index a8f69e48937b3ebd2f57a4da747e6762c4a77934..acd0b946cab86eb173e713535194d3a9347c7d48 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
@@ -40,7 +40,7 @@ public class FlyingPathNavigation extends PathNavigation {
@Override
public Path createPath(Entity entity, int distance) {
- return this.createPath(entity.blockPosition(), distance);
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - Forward target entity
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
index 6b24f94f1762570547c0fc484b3939de73fbd309..80b3fd4150d749af7d584f95ee3d0b8ed664ead9 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
@@ -39,14 +39,14 @@ public class GroundPathNavigation extends PathNavigation {
}
@Override
- public Path createPath(BlockPos target, int distance) {
+ public Path createPath(BlockPos target, @javax.annotation.Nullable Entity entity, int distance) { // Paper
if (this.level.getBlockState(target).isAir()) {
BlockPos blockPos;
for(blockPos = target.below(); blockPos.getY() > this.level.getMinBuildHeight() && this.level.getBlockState(blockPos).isAir(); blockPos = blockPos.below()) {
}
if (blockPos.getY() > this.level.getMinBuildHeight()) {
- return super.createPath(blockPos.above(), distance);
+ return super.createPath(blockPos.above(), entity, distance); // Paper
}
while(blockPos.getY() < this.level.getMaxBuildHeight() && this.level.getBlockState(blockPos).isAir()) {
@@ -57,19 +57,19 @@ public class GroundPathNavigation extends PathNavigation {
}
if (!this.level.getBlockState(target).getMaterial().isSolid()) {
- return super.createPath(target, distance);
+ return super.createPath(target, entity, distance); // Paper
} else {
BlockPos blockPos2;
for(blockPos2 = target.above(); blockPos2.getY() < this.level.getMaxBuildHeight() && this.level.getBlockState(blockPos2).getMaterial().isSolid(); blockPos2 = blockPos2.above()) {
}
- return super.createPath(blockPos2, distance);
+ return super.createPath(blockPos2, entity, distance); // Paper
}
}
@Override
public Path createPath(Entity entity, int distance) {
- return this.createPath(entity.blockPosition(), distance);
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - Forward target entity
}
private int getSurfaceY() {
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
index ec1bd2fff121aa00b50b0d65c0e53e4146c3deb9..bd782c8935db6e0aa3489725d3c4ee401f9bf242 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -109,7 +109,13 @@ public abstract class PathNavigation {
@Nullable
public Path createPath(BlockPos target, int distance) {
- return this.createPath(ImmutableSet.of(target), 8, false, distance);
+ // Paper start - add target entity parameter
+ return this.createPath(target, null, distance);
+ }
+ @Nullable
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) {
+ return this.createPath(ImmutableSet.of(target), entity, 8, false, distance);
+ // Paper end
}
@Nullable
@@ -119,7 +125,7 @@ public abstract class PathNavigation {
@Nullable
public Path createPath(Entity entity, int distance) {
- return this.createPath(ImmutableSet.of(entity.blockPosition()), 16, true, distance);
+ return this.createPath(ImmutableSet.of(entity.blockPosition()), entity, 16, true, distance); // Paper
}
@Nullable
@@ -129,6 +135,16 @@ public abstract class PathNavigation {
@Nullable
protected Path createPath(Set<BlockPos> positions, int range, boolean useHeadPos, int distance, float followRange) {
+ return this.createPath(positions, null, range, useHeadPos, distance, followRange);
+ }
+
+ @Nullable
+ protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance) {
+ return this.createPath(positions, target, range, useHeadPos, distance, (float) this.mob.getAttributeValue(Attributes.FOLLOW_RANGE));
+ }
+
+ @Nullable protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance, float followRange) {
+ // Paper end
if (positions.isEmpty()) {
return null;
} else if (this.mob.getY() < (double)this.level.getMinBuildHeight()) {
@@ -138,6 +154,23 @@ public abstract class PathNavigation {
} else if (this.path != null && !this.path.isDone() && positions.contains(this.targetPos)) {
return this.path;
} else {
+ // Paper start - Pathfind event
+ boolean copiedSet = false;
+ for (BlockPos possibleTarget : positions) {
+ if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(),
+ io.papermc.paper.util.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) {
+ if (!copiedSet) {
+ copiedSet = true;
+ positions = new java.util.HashSet<>(positions);
+ }
+ // note: since we copy the set this remove call is safe, since we're iterating over the old copy
+ positions.remove(possibleTarget);
+ if (positions.isEmpty()) {
+ return null;
+ }
+ }
+ }
+ // Paper end
this.level.getProfiler().push("pathfind");
BlockPos blockPos = useHeadPos ? this.mob.blockPosition().above() : this.mob.blockPosition();
int i = (int)(followRange + (float)range);
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
index d11e9f4f7ae5f2666d67878309b4a1359ef90e39..de1f178fa18ae3ff3c73bc59b10eb39857800bf9 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
@@ -16,9 +16,9 @@ public class WallClimberNavigation extends GroundPathNavigation {
}
@Override
- public Path createPath(BlockPos target, int distance) {
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) { // Paper
this.pathToPosition = target;
- return super.createPath(target, distance);
+ return super.createPath(target, entity, distance); // Paper
}
@Override

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antony Riley <antony@cyberiantiger.org>
Date: Tue, 29 Mar 2016 08:22:55 +0300
Subject: [PATCH] Sanitise RegionFileCache and make configurable.
RegionFileCache prior to this patch would close every single open region
file upon reaching a size of 256.
This patch modifies that behaviour so it closes the the least recently
used RegionFile.
The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap).
The maximum size of the RegionFileCache is also made configurable.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 64e957650dafc9fc30fa997e7f7d3fd47cf60089..1a1ade7538263f4c1a91eb122086a150af3d86ba 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -57,7 +57,7 @@ public class RegionFileStorage implements AutoCloseable {
// Paper end
return regionfile;
} else {
- if (this.regionCache.size() >= 256) {
+ if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable
((RegionFile) this.regionCache.removeLast()).close();
}

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 31 Mar 2016 19:17:58 -0400
Subject: [PATCH] Do not load chunks for Pathfinding
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
index 243740ee9debe3ca0a988b0a448af09a5845b96d..04406fdb2961a85d8e6bffbb8e233e8c4dcf4390 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
@@ -465,7 +465,12 @@ public class WalkNodeEvaluator extends NodeEvaluator {
for(int n = -1; n <= 1; ++n) {
if (l != 0 || n != 0) {
pos.set(i + l, j + m, k + n);
- BlockState blockState = world.getBlockState(pos);
+ // Paper start
+ BlockState blockState = world.getBlockStateIfLoaded(pos);
+ if (blockState == null) {
+ return BlockPathTypes.BLOCKED;
+ } else {
+ // Paper end
if (blockState.is(Blocks.CACTUS)) {
return BlockPathTypes.DANGER_CACTUS;
}
@@ -481,6 +486,7 @@ public class WalkNodeEvaluator extends NodeEvaluator {
if (world.getFluidState(pos).is(FluidTags.WATER)) {
return BlockPathTypes.WATER_BORDER;
}
+ } // Paper
}
}
}
@@ -490,7 +496,8 @@ public class WalkNodeEvaluator extends NodeEvaluator {
}
protected static BlockPathTypes getBlockPathTypeRaw(BlockGetter world, BlockPos pos) {
- BlockState blockState = world.getBlockState(pos);
+ BlockState blockState = world.getBlockStateIfLoaded(pos); // Paper
+ if (blockState == null) return BlockPathTypes.BLOCKED; // Paper
Block block = blockState.getBlock();
Material material = blockState.getMaterial();
if (blockState.isAir()) {

View file

@ -1,65 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Sat, 2 Apr 2016 05:09:16 -0400
Subject: [PATCH] Add PlayerUseUnknownEntityEvent
== AT ==
public net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
index a5d57cc862036012d83b090bb1b3ccf4115a88b3..21068f766b75c414d5818073b7dca083d8ff4409 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
@@ -10,8 +10,8 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
public class ServerboundInteractPacket implements Packet<ServerGamePacketListener> {
- private final int entityId;
- private final ServerboundInteractPacket.Action action;
+ private final int entityId; public final int getEntityId() { return this.entityId; } // Paper - add accessor
+ private final ServerboundInteractPacket.Action action; public final ServerboundInteractPacket.ActionType getActionType() { return this.action.getType(); } // Paper - add accessor
private final boolean usingSecondaryAction;
static final ServerboundInteractPacket.Action ATTACK_ACTION = new ServerboundInteractPacket.Action() {
@Override
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index eaf0e468d7ebf54290ae9e2df9f4a2c252142f65..050e8f545f5cc86985d3dbbe3192f632b64af66f 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2525,8 +2525,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
});
}
}
+ // Paper start - fire event
+ else {
+ packet.dispatch(new net.minecraft.network.protocol.game.ServerboundInteractPacket.Handler() {
+ @Override
+ public void onInteraction(net.minecraft.world.InteractionHand hand) {
+ ServerGamePacketListenerImpl.this.callPlayerUseUnknownEntityEvent(packet, hand);
+ }
+
+ @Override
+ public void onInteraction(net.minecraft.world.InteractionHand hand, net.minecraft.world.phys.Vec3 pos) {
+ ServerGamePacketListenerImpl.this.callPlayerUseUnknownEntityEvent(packet, hand);
+ }
+
+ @Override
+ public void onAttack() {
+ ServerGamePacketListenerImpl.this.callPlayerUseUnknownEntityEvent(packet, net.minecraft.world.InteractionHand.MAIN_HAND);
+ }
+ });
+ }
+
+ }
+ private void callPlayerUseUnknownEntityEvent(ServerboundInteractPacket packet, InteractionHand hand) {
+ this.cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent(
+ this.getCraftPlayer(),
+ packet.getEntityId(),
+ packet.getActionType() == ServerboundInteractPacket.ActionType.ATTACK,
+ hand == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND
+ ));
}
+ // Paper end
@Override
public void handleClientCommand(ServerboundClientCommandPacket packet) {

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 Apr 2016 16:28:17 -0400
Subject: [PATCH] Configurable Grass Spread Tick Rate
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
index bd5a45765b53bf4f2f9aaea4769c71ffb008741d..61783f17b655cbb6430d22fb3a81931ab3ea130c 100644
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
@@ -2,6 +2,7 @@ package net.minecraft.world.level.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.RandomSource;
@@ -39,6 +40,7 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper
if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 Apr 2016 17:48:50 -0400
Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index e7d07d1f86af49b8729f6ac66b398ee6aae5ab4a..0d08690aade0e3334c583b62e0abf7bbab9a0c59 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1458,6 +1458,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
@Override
public void updateNeighborsAt(BlockPos pos, Block sourceBlock) {
+ if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null);
}

View file

@ -1,118 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 5 Apr 2016 21:38:58 -0400
Subject: [PATCH] Optimize DataBits
Remove Debug checks as these are super hot and causing noticeable hits
Before: http://i.imgur.com/nQsMzAE.png
After: http://i.imgur.com/nJ46crB.png
Optimize redundant converting of static fields into an unsigned long each call by precomputing it in ctor
diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java
index c8ae9d25eedb7cb2d9f95b799a507727b655f11f..9b81ce9d85cba07e9752c29fb5a842c4b00aa873 100644
--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java
+++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java
@@ -11,8 +11,8 @@ public class SimpleBitStorage implements BitStorage {
private final long mask;
private final int size;
private final int valuesPerLong;
- private final int divideMul;
- private final int divideAdd;
+ private final int divideMul; private final long divideMulUnsigned; // Paper - referenced in b(int) with 2 Integer.toUnsignedLong calls
+ private final int divideAdd; private final long divideAddUnsigned; // Paper
private final int divideShift;
public SimpleBitStorage(int elementBits, int size, int[] data) {
@@ -56,8 +56,8 @@ public class SimpleBitStorage implements BitStorage {
this.mask = (1L << elementBits) - 1L;
this.valuesPerLong = (char)(64 / elementBits);
int i = 3 * (this.valuesPerLong - 1);
- this.divideMul = MAGIC[i + 0];
- this.divideAdd = MAGIC[i + 1];
+ this.divideMul = MAGIC[i + 0]; this.divideMulUnsigned = Integer.toUnsignedLong(this.divideMul); // Paper
+ this.divideAdd = MAGIC[i + 1]; this.divideAddUnsigned = Integer.toUnsignedLong(this.divideAdd); // Paper
this.divideShift = MAGIC[i + 2];
int j = (size + this.valuesPerLong - 1) / this.valuesPerLong;
if (data != null) {
@@ -73,15 +73,15 @@ public class SimpleBitStorage implements BitStorage {
}
private int cellIndex(int index) {
- long l = Integer.toUnsignedLong(this.divideMul);
- long m = Integer.toUnsignedLong(this.divideAdd);
- return (int)((long)index * l + m >> 32 >> this.divideShift);
+ //long l = Integer.toUnsignedLong(this.divideMul); // Paper
+ //long m = Integer.toUnsignedLong(this.divideAdd); // Paper
+ return (int) ((long) index * this.divideMulUnsigned + this.divideAddUnsigned >> 32 >> this.divideShift); // Paper
}
@Override
- public int getAndSet(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, this.mask, (long)value);
+ public final int getAndSet(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper
int i = this.cellIndex(index);
long l = this.data[i];
int j = (index - i * this.valuesPerLong) * this.bits;
@@ -91,9 +91,9 @@ public class SimpleBitStorage implements BitStorage {
}
@Override
- public void set(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, this.mask, (long)value);
+ public final void set(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper
int i = this.cellIndex(index);
long l = this.data[i];
int j = (index - i * this.valuesPerLong) * this.bits;
@@ -101,8 +101,8 @@ public class SimpleBitStorage implements BitStorage {
}
@Override
- public int get(int index) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
+ public final int get(int index) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
int i = this.cellIndex(index);
long l = this.data[i];
int j = (index - i * this.valuesPerLong) * this.bits;
diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java
index 172e7a0761724cc802387e613258830a0defb04a..9686ce7536c9924b1b2aced4f013f46759cbc72e 100644
--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java
+++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java
@@ -13,21 +13,21 @@ public class ZeroBitStorage implements BitStorage {
}
@Override
- public int getAndSet(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, 0L, (long)value);
+ public final int getAndSet(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper
return 0;
}
@Override
- public void set(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, 0L, (long)value);
+ public final void set(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper
}
@Override
- public int get(int index) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
+ public final int get(int index) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
return 0;
}

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 6 Apr 2016 01:04:23 -0500
Subject: [PATCH] Option to use vanilla per-world scoreboard coloring on names
This change is basically a bandaid to fix CB's complete and utter lack
of support for vanilla scoreboard name modifications.
In the future, finding a way to merge the vanilla expectations in with
bukkit's concept of a display name would be preferable. There was a PR
for this on CB at one point but I can't find it. We may need to do this
ourselves at some point in the future.
diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
index e7bcc08e3d3fe0ecb97e65cb2c32582750e22c28..309fe1162db195c7c3c94d785d6aa2700e42b08a 100644
--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
@@ -28,7 +28,9 @@ import net.minecraft.network.chat.PlayerChatMessage;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.ChatColor;
import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.util.LazyPlayerSet;
import org.bukkit.craftbukkit.util.Waitable;
@@ -364,10 +366,16 @@ public final class ChatProcessor {
}
static String legacyDisplayName(final CraftPlayer player) {
+ if (((org.bukkit.craftbukkit.CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
+ return legacySection().serialize(player.teamDisplayName()) + ChatColor.RESET;
+ }
return player.getDisplayName();
}
static Component displayName(final CraftPlayer player) {
+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
+ return player.teamDisplayName();
+ }
return player.displayName();
}

View file

@ -1,109 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 13 Apr 2016 02:10:49 -0400
Subject: [PATCH] Configurable Player Collision
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
index 1294b38262505b0d54089e428df9b363219de1f0..ee37ec0de1ca969144824427ae42b0c81434a1b4 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
@@ -193,7 +193,7 @@ public class ClientboundSetPlayerTeamPacket implements Packet<ClientGamePacketLi
buf.writeComponent(this.displayName);
buf.writeByte(this.options);
buf.writeUtf(this.nametagVisibility);
- buf.writeUtf(this.collisionRule);
+ buf.writeUtf(!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions ? "never" : this.collisionRule); // Paper
buf.writeEnum(this.color);
buf.writeComponent(this.playerPrefix);
buf.writeComponent(this.playerSuffix);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index e62aa86afb05d8f00d8dd2b676407bfa7d0ed9fb..aab7ea2bbc9066b206b15cceb4db49aa230ebafd 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -586,6 +586,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld()));
}
+ // Paper start - Handle collideRule team for player collision toggle
+ final ServerScoreboard scoreboard = this.getScoreboard();
+ final java.util.Collection<String> toRemove = scoreboard.getPlayerTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(net.minecraft.world.scores.PlayerTeam::getName).collect(java.util.stream.Collectors.toList());
+ for (String teamName : toRemove) {
+ scoreboard.removePlayerTeam(scoreboard.getPlayerTeam(teamName)); // Clean up after ourselves
+ }
+
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) {
+ this.getPlayerList().collideRuleTeamName = org.apache.commons.lang3.StringUtils.left("collideRule_" + java.util.concurrent.ThreadLocalRandom.current().nextInt(), 16);
+ net.minecraft.world.scores.PlayerTeam collideTeam = scoreboard.addPlayerTeam(this.getPlayerList().collideRuleTeamName);
+ collideTeam.setSeeFriendlyInvisibles(false); // Because we want to mimic them not being on a team at all
+ }
+ // Paper end
+
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
this.connection.acceptConnections();
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index ea766e18fb19dbb78e07357748bbf83095253275..e39619717f089162e2e3bf12cd00eb390a59c4bf 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -98,6 +98,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.PlayerTeam;
+import net.minecraft.world.scores.Scoreboard; // Paper
import net.minecraft.world.scores.Team;
import org.slf4j.Logger;
@@ -160,6 +161,7 @@ public abstract class PlayerList {
// CraftBukkit start
private CraftServer cserver;
private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>();
+ public @Nullable String collideRuleTeamName; // Paper - Team name used for collideRule
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registryManager, PlayerDataStorage saveHandler, int maxPlayers) {
this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
@@ -399,6 +401,13 @@ public abstract class PlayerList {
player.initInventoryMenu();
// CraftBukkit - Moved from above, added world
+ // Paper start - Add to collideRule team if needed
+ final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName);
+ if (this.collideRuleTeamName != null && collideRuleTeam != null && player.getTeam() == null) {
+ scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
+ }
+ // Paper end
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
}
@@ -518,6 +527,16 @@ public abstract class PlayerList {
entityplayer.doTick(); // SPIGOT-924
// CraftBukkit end
+ // Paper start - Remove from collideRule team if needed
+ if (this.collideRuleTeamName != null) {
+ final Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName);
+ if (entityplayer.getTeam() == team && team != null) {
+ scoreBoard.removePlayerFromTeam(entityplayer.getScoreboardName(), team);
+ }
+ }
+ // Paper end
+
this.save(entityplayer);
if (entityplayer.isPassenger()) {
Entity entity = entityplayer.getRootVehicle();
@@ -1149,6 +1168,13 @@ public abstract class PlayerList {
}
// CraftBukkit end
+ // Paper start - Remove collideRule team if it exists
+ if (this.collideRuleTeamName != null) {
+ final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam team = scoreboard.getPlayersTeam(this.collideRuleTeamName);
+ if (team != null) scoreboard.removePlayerTeam(team);
+ }
+ // Paper end
}
// CraftBukkit start

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Wed, 13 Apr 2016 20:21:38 -0700
Subject: [PATCH] Add handshake event to allow plugins to handle client
handshaking logic themselves
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
index 5948138f3697c0cce9638524a0f481eb368da911..8284d49c8e30645d00be952c847bab7ce5753d78 100644
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
@@ -88,9 +88,36 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
this.connection.disconnect(ichatmutablecomponent);
} else {
this.connection.setListener(new ServerLoginPacketListenerImpl(this.server, this.connection));
+ // Paper start - handshake event
+ boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee;
+ boolean handledByEvent = false;
+ // Try and handle the handshake through the event
+ if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me?
+ java.net.SocketAddress socketAddress = this.connection.address;
+ String hostnameOfRemote = socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getHostString() : InetAddress.getLoopbackAddress().getHostAddress();
+ com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packet.hostName, hostnameOfRemote, !proxyLogicEnabled);
+ if (event.callEvent()) {
+ // If we've failed somehow, let the client know so and go no further.
+ if (event.isFailed()) {
+ Component component = io.papermc.paper.adventure.PaperAdventure.asVanilla(event.failMessage());
+ this.connection.send(new ClientboundLoginDisconnectPacket(component));
+ this.connection.disconnect(component);
+ return;
+ }
+
+ if (event.getServerHostname() != null) packet.hostName = event.getServerHostname();
+ if (event.getSocketAddressHostname() != null) this.connection.address = new java.net.InetSocketAddress(event.getSocketAddressHostname(), socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0);
+ this.connection.spoofedUUID = event.getUniqueId();
+ this.connection.spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class);
+ handledByEvent = true; // Hooray, we did it!
+ }
+ }
// Spigot Start
String[] split = packet.hostName.split("\00");
- if (org.spigotmc.SpigotConfig.bungee) {
+ // Don't try and handle default logic if it's been handled by the event.
+ if (!handledByEvent && proxyLogicEnabled) {
+ // Paper end
+ // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) {
packet.hostName = split[0];
connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort());

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 16 Apr 2016 00:39:33 -0400
Subject: [PATCH] Configurable RCON IP address
For servers with multiple IP's, ability to bind to a specific interface.
== AT ==
public net.minecraft.server.dedicated.Settings getStringRaw(Ljava/lang/String;)Ljava/lang/String;
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
index 666dc4b22569e1ae26ff988c7d4ac1113acd32f3..e72fb5c548a9baef09ae547863c4bdc439ce28b2 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
@@ -108,6 +108,8 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
private final DedicatedServerProperties.WorldDimensionData worldDimensionData;
public final WorldOptions worldOptions;
+ public final String rconIp; // Paper - Add rcon ip
+
// CraftBukkit start
public DedicatedServerProperties(Properties properties, OptionSet optionset) {
super(properties, optionset);
@@ -165,6 +167,10 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
}, WorldPresets.NORMAL.location().toString()));
this.serverResourcePackInfo = DedicatedServerProperties.getServerPackInfo(this.get("resource-pack", ""), this.get("resource-pack-sha1", ""), this.getLegacyString("resource-pack-hash"), this.get("require-resource-pack", false), this.get("resource-pack-prompt", ""));
this.initialDataPackConfiguration = DedicatedServerProperties.getDatapackConfig(this.get("initial-enabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getEnabled())), this.get("initial-disabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getDisabled())));
+ // Paper start - Configurable rcon ip
+ final String rconIp = this.getStringRaw("rcon.ip");
+ this.rconIp = rconIp == null ? this.serverIp : rconIp;
+ // Paper end
}
// CraftBukkit start
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
index cb61eaf8447c8340c4b4e1079c0a6aecd41a6116..3bf60f640aa9fa4cabd2b3e5d3931e8467b9df24 100644
--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
@@ -60,7 +60,7 @@ public class RconThread extends GenericThread {
@Nullable
public static RconThread create(ServerInterface server) {
DedicatedServerProperties dedicatedServerProperties = server.getProperties();
- String string = server.getServerIp();
+ String string = dedicatedServerProperties.rconIp; // Paper - Configurable rcon ip
if (string.isEmpty()) {
string = "0.0.0.0";
}

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Fri, 22 Apr 2016 01:43:11 -0500
Subject: [PATCH] EntityRegainHealthEvent isFastRegen API
Don't even get me started
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index b2871726eb4dd7f16d161097cbf0f287839e10ba..16ec3763e6d13a2dd3e1cc8cd898c6d783ac070c 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1249,10 +1249,16 @@ public abstract class LivingEntity extends Entity {
}
public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) {
+ // Paper start - Forward
+ heal(f, regainReason, false);
+ }
+
+ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) {
+ // Paper end
float f1 = this.getHealth();
if (f1 > 0.0F) {
- EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason);
+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason, isFastRegen); // Paper
// Suppress during worldgen
if (this.valid) {
this.level.getCraftServer().getPluginManager().callEvent(event);
diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java
index ae323c786b5a0d61d9292469baa50a3ad8e4ccff..2934b6de1f1fb914a532ee20184df99d1acd8e65 100644
--- a/src/main/java/net/minecraft/world/food/FoodData.java
+++ b/src/main/java/net/minecraft/world/food/FoodData.java
@@ -84,7 +84,7 @@ public class FoodData {
if (this.tickTimer >= this.saturatedRegenRate) { // CraftBukkit
float f = Math.min(this.saturationLevel, 6.0F);
- player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason
+ player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen
// this.addExhaustion(f); CraftBukkit - EntityExhaustionEvent
player.causeFoodExhaustion(f, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent
this.tickTimer = 0;

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 21 Apr 2016 23:51:55 -0700
Subject: [PATCH] Add ability to configure frosted_ice properties
diff --git a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
index e1916fe8a7aa736d9266efde954bbfbda38a3a65..331b642c36af97f7f05bd63f96d42d1af443e5a3 100644
--- a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
@@ -32,6 +32,7 @@ public class FrostedIceBlock extends IceBlock {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ if (!world.paperConfig().environment.frostedIce.enabled) return; // Paper - add ability to disable frosted ice
if ((random.nextInt(3) == 0 || this.fewerNeigboursThan(world, pos, 4)) && world.getMaxLocalRawBrightness(pos) > 11 - state.getValue(AGE) - state.getLightBlock(world, pos) && this.slightlyMelt(state, world, pos)) {
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
@@ -39,12 +40,12 @@ public class FrostedIceBlock extends IceBlock {
mutableBlockPos.setWithOffset(pos, direction);
BlockState blockState = world.getBlockState(mutableBlockPos);
if (blockState.is(this) && !this.slightlyMelt(blockState, world, mutableBlockPos)) {
- world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, 20, 40));
+ world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - use configurable min/max delay
}
}
} else {
- world.scheduleTick(pos, this, Mth.nextInt(random, 20, 40));
+ world.scheduleTick(pos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - use configurable min/max delay
}
}

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 28 Apr 2016 00:57:27 -0400
Subject: [PATCH] remove null possibility for getServer singleton
to stop IDE complaining about potential NPE
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index aab7ea2bbc9066b206b15cceb4db49aa230ebafd..3ed50490121f34ab5b247565b9a4555bf6a46dff 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -193,6 +193,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements CommandSource, AutoCloseable {
+ private static MinecraftServer SERVER; // Paper
public static final Logger LOGGER = LogUtils.getLogger();
public static final String VANILLA_BRAND = "vanilla";
private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F;
@@ -318,6 +319,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
super("Server");
+ SERVER = this; // Paper - better singleton
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
this.profiler = this.metricsRecorder.getProfiler();
this.onMetricsRecordingStopped = (methodprofilerresults) -> {
@@ -2304,9 +2306,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return false;
}
- @Deprecated
public static MinecraftServer getServer() {
- return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null;
+ return SERVER; // Paper
}
// CraftBukkit end

View file

@ -1,128 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 29 Apr 2016 20:02:00 -0400
Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes
Maps used a modified version of rendering to support plugin controlled
imaging on maps. The Craft Map Renderer is much slower than Vanilla,
causing maps in item frames to cause a noticeable hit on server performance.
This updates the map system to not use the Craft system if we detect that no
custom renderers are in use, defaulting to the much simpler Vanilla system.
Additionally, numerous issues to player position tracking on maps has been fixed.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0d08690aade0e3334c583b62e0abf7bbab9a0c59..349a9f4596cd1411ec3a69cd7d6f5414971b74ef 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2246,6 +2246,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
{
if ( iter.next().player == entity )
{
+ map.decorations.remove(entity.getName().getString()); // Paper
iter.remove();
}
}
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 60fb74537fdc96005cbf6aa1670e773c0faa2f26..7322c15921e05aaf0dafed89e1d90f2748efb2a9 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -758,6 +758,14 @@ public abstract class Player extends LivingEntity {
return null;
}
// CraftBukkit end
+ // Paper start - remove player from map on drop
+ if (itemstack.getItem() == Items.FILLED_MAP) {
+ net.minecraft.world.level.saveddata.maps.MapItemSavedData worldmap = net.minecraft.world.item.MapItem.getSavedData(itemstack, this.level);
+ if (worldmap != null) {
+ worldmap.tickCarriedBy(this, itemstack);
+ }
+ }
+ // Paper end
return entityitem;
}
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 1fd305ccedfd311dc5238810003889b2c1897089..984da6264cdaf57a49a15861b9ce834a9efac1a7 100644
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -63,6 +63,7 @@ public class MapItemSavedData extends SavedData {
public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
private int trackedDecorationCount;
+ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
// CraftBukkit start
public final CraftMapView mapView;
@@ -83,6 +84,7 @@ public class MapItemSavedData extends SavedData {
// CraftBukkit start
this.mapView = new CraftMapView(this);
this.server = (CraftServer) org.bukkit.Bukkit.getServer();
+ this.vanillaRender.buffer = colors; // Paper
// CraftBukkit end
}
@@ -138,6 +140,7 @@ public class MapItemSavedData extends SavedData {
if (abyte.length == 16384) {
worldmap.colors = abyte;
}
+ worldmap.vanillaRender.buffer = abyte; // Paper
ListTag nbttaglist = nbt.getList("banners", 10);
@@ -548,6 +551,21 @@ public class MapItemSavedData extends SavedData {
public class HoldingPlayer {
+ // Paper start
+ private void addSeenPlayers(java.util.Collection<MapDecoration> icons) {
+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity();
+ MapItemSavedData.this.decorations.forEach((name, mapIcon) -> {
+ // If this cursor is for a player check visibility with vanish system
+ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot
+ if (other == null || player.canSee(other)) {
+ icons.add(mapIcon);
+ }
+ });
+ }
+ private boolean shouldUseVanillaMap() {
+ return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class;
+ }
+ // Paper end
public final Player player;
private boolean dirtyData = true;
private int minDirtyX;
@@ -581,7 +599,9 @@ public class MapItemSavedData extends SavedData {
@Nullable
Packet<?> nextUpdatePacket(int mapId) {
MapItemSavedData.MapPatch worldmap_b;
- org.bukkit.craftbukkit.map.RenderData render = MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit
+ if (!this.dirtyData && this.tick % 5 != 0) { this.tick++; return null; } // Paper - this won't end up sending, so don't render it!
+ boolean vanillaMaps = shouldUseVanillaMap(); // Paper
+ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; // CraftBukkit // Paper
if (this.dirtyData) {
this.dirtyData = false;
@@ -597,6 +617,8 @@ public class MapItemSavedData extends SavedData {
// CraftBukkit start
java.util.Collection<MapDecoration> icons = new java.util.ArrayList<MapDecoration>();
+ if (vanillaMaps) addSeenPlayers(icons); // Paper
+
for (org.bukkit.map.MapCursor cursor : render.cursors) {
if (cursor.isVisible()) {
icons.add(new MapDecoration(MapDecoration.Type.byIcon(cursor.getRawType()), cursor.getX(), cursor.getY(), cursor.getDirection(), PaperAdventure.asVanilla(cursor.caption()))); // Paper - Adventure
diff --git a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
index 256a131781721c86dd6cdbc329335964570cbe8c..5768cd512ec166f1e8d1f4a28792015347297c3f 100644
--- a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
+++ b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
@@ -5,7 +5,7 @@ import org.bukkit.map.MapCursor;
public class RenderData {
- public final byte[] buffer;
+ public byte[] buffer; // Paper
public final ArrayList<MapCursor> cursors;
public RenderData() {

View file

@ -1,770 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 1 May 2016 21:19:14 -0400
Subject: [PATCH] LootTable API & Replenishable Lootables Feature
Provides an API to control the loot table for an object.
Also provides a feature that any Lootable Inventory (Chests in Structures)
can automatically replenish after a given time.
This feature is good for long term worlds so that newer players
do not suffer with "Every chest has been looted"
== AT ==
public org.bukkit.craftbukkit.block.CraftBlockEntityState getTileEntity()Lnet/minecraft/world/level/block/entity/BlockEntity;
public org.bukkit.craftbukkit.block.CraftLootable setLootTable(Lorg/bukkit/loot/LootTable;J)V
public org.bukkit.craftbukkit.entity.CraftMinecartContainer setLootTable(Lorg/bukkit/loot/LootTable;J)V
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..88e32ed64f90bfd277dac84ba4bd84f0d943f5f8
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.vehicle.AbstractMinecartContainer;
+import net.minecraft.world.entity.vehicle.ContainerEntity;
+import net.minecraft.world.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperContainerEntityLootableInventory implements PaperLootableEntityInventory {
+
+ private final ContainerEntity entity;
+
+ public PaperContainerEntityLootableInventory(ContainerEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ entity.setLootTableSeed(seed);
+ }
+
+ @Override
+ public long getSeed() {
+ return entity.getLootTableSeed();
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ entity.setLootTable((table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()));
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return entity.getLootableData();
+ }
+
+ @Override
+ public Entity getHandle() {
+ return entity.getEntity();
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ return (LootableInventory) entity.getEntity().getBukkitEntity();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return entity.getLevel();
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..70ca5625ff5d13a8e9cd64953066a7e1547ff223
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
@@ -0,0 +1,33 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Chunk;
+import org.bukkit.block.Block;
+
+public interface PaperLootableBlockInventory extends LootableBlockInventory, PaperLootableInventory {
+
+ RandomizableContainerBlockEntity getTileEntity();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return getTileEntity().getLevel();
+ }
+
+ default Block getBlock() {
+ final BlockPos position = getTileEntity().getBlockPos();
+ final Chunk bukkitChunk = getTileEntity().getLevel().getChunkAt(position).bukkitChunk;
+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ());
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return getTileEntity().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fba5bc0f982e143ad5f5bda55d768edc5f847df
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
@@ -0,0 +1,28 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.level.Level;
+import org.bukkit.entity.Entity;
+
+public interface PaperLootableEntityInventory extends LootableEntityInventory, PaperLootableInventory {
+
+ net.minecraft.world.entity.Entity getHandle();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ default Entity getEntity() {
+ return getHandle().getBukkitEntity();
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return getHandle().getCommandSenderWorld();
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return getHandle().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce135d990c785b02df468391ea622aa236290f07
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
@@ -0,0 +1,70 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.loot.Lootable;
+import java.util.UUID;
+import net.minecraft.world.level.Level;
+
+public interface PaperLootableInventory extends LootableInventory, Lootable {
+
+ PaperLootableInventoryData getLootableData();
+ LootableInventory getAPILootableInventory();
+
+ Level getNMSWorld();
+
+ default org.bukkit.World getBukkitWorld() {
+ return getNMSWorld().getWorld();
+ }
+
+ @Override
+ default boolean isRefillEnabled() {
+ return getNMSWorld().paperConfig().lootables.autoReplenish;
+ }
+
+ @Override
+ default boolean hasBeenFilled() {
+ return getLastFilled() != -1;
+ }
+
+ @Override
+ default boolean hasPlayerLooted(UUID player) {
+ return getLootableData().hasPlayerLooted(player);
+ }
+
+ @Override
+ default Long getLastLooted(UUID player) {
+ return getLootableData().getLastLooted(player);
+ }
+
+ @Override
+ default boolean setHasPlayerLooted(UUID player, boolean looted) {
+ final boolean hasLooted = hasPlayerLooted(player);
+ if (hasLooted != looted) {
+ getLootableData().setPlayerLootedState(player, looted);
+ }
+ return hasLooted;
+ }
+
+ @Override
+ default boolean hasPendingRefill() {
+ long nextRefill = getLootableData().getNextRefill();
+ return nextRefill != -1 && nextRefill > getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getLastFilled() {
+ return getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getNextRefill() {
+ return getLootableData().getNextRefill();
+ }
+
+ @Override
+ default long setNextRefill(long refillAt) {
+ if (refillAt < -1) {
+ refillAt = -1;
+ }
+ return getLootableData().setNextRefill(refillAt);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5ea9f27a1936ed9e329e74317c91c5df89b9fbd
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
@@ -0,0 +1,179 @@
+package com.destroystokyo.paper.loottable;
+
+import io.papermc.paper.configuration.WorldConfiguration;
+import org.bukkit.entity.Player;
+import org.bukkit.loot.LootTable;
+import javax.annotation.Nullable;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+
+public class PaperLootableInventoryData {
+
+ private static final Random RANDOM = new Random();
+
+ private long lastFill = -1;
+ private long nextRefill = -1;
+ private int numRefills = 0;
+ private Map<UUID, Long> lootedPlayers;
+ private final PaperLootableInventory lootable;
+
+ public PaperLootableInventoryData(PaperLootableInventory lootable) {
+ this.lootable = lootable;
+ }
+
+ long getLastFill() {
+ return this.lastFill;
+ }
+
+ long getNextRefill() {
+ return this.nextRefill;
+ }
+
+ long setNextRefill(long nextRefill) {
+ long prev = this.nextRefill;
+ this.nextRefill = nextRefill;
+ return prev;
+ }
+
+ public boolean shouldReplenish(@Nullable net.minecraft.world.entity.player.Player player) {
+ LootTable table = this.lootable.getLootTable();
+
+ // No Loot Table associated
+ if (table == null) {
+ return false;
+ }
+
+ // ALWAYS process the first fill or if the feature is disabled
+ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig().lootables.autoReplenish) {
+ return true;
+ }
+
+ // Only process refills when a player is set
+ if (player == null) {
+ return false;
+ }
+
+ // Chest is not scheduled for refill
+ if (this.nextRefill == -1) {
+ return false;
+ }
+
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+
+ // Check if max refills has been hit
+ if (paperConfig.lootables.maxRefills != -1 && this.numRefills >= paperConfig.lootables.maxRefills) {
+ return false;
+ }
+
+ // Refill has not been reached
+ if (this.nextRefill > System.currentTimeMillis()) {
+ return false;
+ }
+
+
+ final Player bukkitPlayer = (Player) player.getBukkitEntity();
+ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory());
+ if (paperConfig.lootables.restrictPlayerReloot && hasPlayerLooted(player.getUUID())) {
+ event.setCancelled(true);
+ }
+ return event.callEvent();
+ }
+ public void processRefill(@Nullable net.minecraft.world.entity.player.Player player) {
+ this.lastFill = System.currentTimeMillis();
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+ if (paperConfig.lootables.autoReplenish) {
+ long min = paperConfig.lootables.refreshMin.seconds();
+ long max = paperConfig.lootables.refreshMax.seconds();
+ this.nextRefill = this.lastFill + (min + RANDOM.nextLong(max - min + 1)) * 1000L;
+ this.numRefills++;
+ if (paperConfig.lootables.resetSeedOnFill) {
+ this.lootable.setSeed(0);
+ }
+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific
+ this.setPlayerLootedState(player.getUUID(), true);
+ }
+ } else {
+ this.lootable.clearLootTable();
+ }
+ }
+
+
+ public void loadNbt(CompoundTag base) {
+ if (!base.contains("Paper.LootableData", 10)) { // 10 = compound
+ return;
+ }
+ CompoundTag comp = base.getCompound("Paper.LootableData");
+ if (comp.contains("lastFill")) {
+ this.lastFill = comp.getLong("lastFill");
+ }
+ if (comp.contains("nextRefill")) {
+ this.nextRefill = comp.getLong("nextRefill");
+ }
+
+ if (comp.contains("numRefills")) {
+ this.numRefills = comp.getInt("numRefills");
+ }
+ if (comp.contains("lootedPlayers", 9)) { // 9 = list
+ ListTag list = comp.getList("lootedPlayers", 10); // 10 = compound
+ final int size = list.size();
+ if (size > 0) {
+ this.lootedPlayers = new HashMap<>(list.size());
+ }
+ for (int i = 0; i < size; i++) {
+ final CompoundTag cmp = list.getCompound(i);
+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
+ }
+ }
+ }
+ public void saveNbt(CompoundTag base) {
+ CompoundTag comp = new CompoundTag();
+ if (this.nextRefill != -1) {
+ comp.putLong("nextRefill", this.nextRefill);
+ }
+ if (this.lastFill != -1) {
+ comp.putLong("lastFill", this.lastFill);
+ }
+ if (this.numRefills != 0) {
+ comp.putInt("numRefills", this.numRefills);
+ }
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
+ ListTag list = new ListTag();
+ for (Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
+ CompoundTag cmp = new CompoundTag();
+ cmp.putUUID("UUID", entry.getKey());
+ cmp.putLong("Time", entry.getValue());
+ list.add(cmp);
+ }
+ comp.put("lootedPlayers", list);
+ }
+
+ if (!comp.isEmpty()) {
+ base.put("Paper.LootableData", comp);
+ }
+ }
+
+ void setPlayerLootedState(UUID player, boolean looted) {
+ if (looted && this.lootedPlayers == null) {
+ this.lootedPlayers = new HashMap<>();
+ }
+ if (looted) {
+ if (!this.lootedPlayers.containsKey(player)) {
+ this.lootedPlayers.put(player, System.currentTimeMillis());
+ }
+ } else if (this.lootedPlayers != null) {
+ this.lootedPlayers.remove(player);
+ }
+ }
+
+ boolean hasPlayerLooted(UUID player) {
+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player);
+ }
+
+ Long getLastLooted(UUID player) {
+ return lootedPlayers != null ? lootedPlayers.get(player) : null;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fafcc0158e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.loottable;
+
+import io.papermc.paper.util.MCUtil;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperTileEntityLootableInventory implements PaperLootableBlockInventory {
+ private RandomizableContainerBlockEntity tileEntityLootable;
+
+ public PaperTileEntityLootableInventory(RandomizableContainerBlockEntity tileEntityLootable) {
+ this.tileEntityLootable = tileEntityLootable;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ tileEntityLootable.lootTable = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ tileEntityLootable.lootTableSeed = seed;
+ }
+
+ @Override
+ public long getSeed() {
+ return tileEntityLootable.lootTableSeed;
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return tileEntityLootable.lootableData;
+ }
+
+ @Override
+ public RandomizableContainerBlockEntity getTileEntity() {
+ return tileEntityLootable;
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ Level world = tileEntityLootable.getLevel();
+ if (world == null) {
+ return null;
+ }
+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, tileEntityLootable.getBlockPos())).getState();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return tileEntityLootable.getLevel();
+ }
+}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index c070fd1b224aeeaa9ebb054105a0f73285956da1..0c0060cdc35e0d8d3098a0ade8080f91dbc81a2b 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -232,6 +232,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
// Paper end
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
index 9347faecdaa3ef8c375fe8b0a89fc3385b6823bd..cc74eeb45913fab03e85969957215d2811252a83 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
@@ -32,6 +32,20 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
public ResourceLocation lootTable;
public long lootTableSeed;
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
@@ -134,12 +148,14 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
+ this.lootableData.saveNbt(nbt); // Paper
this.addChestVehicleSaveData(nbt);
}
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
this.readChestVehicleSaveData(nbt);
}
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
index e1c4289ff790c691fdae8f7653414a60eb196dc2..a99e2586962952332dd9904ef5bb50a0d3083266 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
@@ -65,12 +65,14 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
+ this.lootableData.saveNbt(nbt); // Paper
this.addChestVehicleSaveData(nbt);
}
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
this.readChestVehicleSaveData(nbt);
}
@@ -226,6 +228,20 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
}
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
index e2a9782e0ae60eb5557dce0831084c5722687df6..6ae9cccb28b2354ee47e6682082f92f3ecd56a67 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
@@ -61,7 +61,7 @@ public interface ContainerEntity extends Container, MenuProvider {
if (this.getLootTableSeed() != 0L) {
nbt.putLong("LootTableSeed", this.getLootTableSeed());
}
- } else {
+ } else if (true) { // Paper - always load the items, table may still remain
ContainerHelper.saveAllItems(nbt, this.getItemStacks());
}
@@ -72,7 +72,7 @@ public interface ContainerEntity extends Container, MenuProvider {
if (nbt.contains("LootTable", 8)) {
this.setLootTable(new ResourceLocation(nbt.getString("LootTable")));
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
- } else {
+ } else if (true) { // Paper - always load the items, table may still remain
ContainerHelper.loadAllItems(nbt, this.getItemStacks());
}
@@ -104,13 +104,15 @@ public interface ContainerEntity extends Container, MenuProvider {
default void unpackChestVehicleLootTable(@Nullable Player player) {
MinecraftServer minecraftServer = this.getLevel().getServer();
- if (this.getLootTable() != null && minecraftServer != null) {
+ if (this.getLootableData().shouldReplenish(player) && minecraftServer != null) { // Paper
LootTable lootTable = minecraftServer.getLootTables().get(this.getLootTable());
if (player != null) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.getLootTable());
}
- this.setLootTable((ResourceLocation)null);
+ // this.setLootTable((ResourceLocation)null); // Paper
+ this.getLootableData().processRefill(player); // Paper
+
LootContext.Builder builder = (new LootContext.Builder((ServerLevel)this.getLevel())).withParameter(LootContextParams.ORIGIN, this.position()).withOptionalRandomSeed(this.getLootTableSeed());
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
@@ -184,4 +186,13 @@ public interface ContainerEntity extends Container, MenuProvider {
default boolean isChestVehicleStillValid(Player player) {
return !this.isRemoved() && this.position().closerThan(player.position(), 8.0D);
}
+ // Paper start
+ default Entity getEntity() {
+ throw new UnsupportedOperationException();
+ }
+
+ default com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ throw new UnsupportedOperationException();
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index 216fc20326d71121098430dc1b9f7477265a91b7..e3bee2df77d87630e96621470e940d9d9e152e7f 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -28,6 +28,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Nullable
public ResourceLocation lootTable;
public long lootTableSeed;
+ public final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperTileEntityLootableInventory(this)); // Paper
protected RandomizableContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
@@ -42,16 +43,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
}
protected boolean tryLoadLootTable(CompoundTag nbt) {
+ this.lootableData.loadNbt(nbt); // Paper
if (nbt.contains("LootTable", 8)) {
this.lootTable = new ResourceLocation(nbt.getString("LootTable"));
+ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate
this.lootTableSeed = nbt.getLong("LootTableSeed");
- return true;
+ return false; // Paper - always load the items, table may still remain
} else {
return false;
}
}
protected boolean trySaveLootTable(CompoundTag nbt) {
+ this.lootableData.saveNbt(nbt); // Paper
if (this.lootTable == null) {
return false;
} else {
@@ -60,18 +64,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
nbt.putLong("LootTableSeed", this.lootTableSeed);
}
- return true;
+ return false; // Paper - always save the items, table may still remain
}
}
public void unpackLootTable(@Nullable Player player) {
- if (this.lootTable != null && this.level.getServer() != null) {
+ if (this.lootableData.shouldReplenish(player) && this.level.getServer() != null) { // Paper
LootTable lootTable = this.level.getServer().getLootTables().get(this.lootTable);
if (player instanceof ServerPlayer) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.lootTable);
}
- this.lootTable = null;
+ //this.lootTable = null; // Paper
+ this.lootableData.processRefill(player); // Paper
LootContext.Builder builder = (new LootContext.Builder((ServerLevel)this.level)).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(this.worldPosition)).withOptionalRandomSeed(this.lootTableSeed);
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
index b31fa63019822bc172d85427b3f3f2c154d7e179..82b3f3b3aced73ce136b6b94fe212972ac6090ef 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
@@ -12,8 +12,9 @@ import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
import org.bukkit.inventory.Inventory;
+import com.destroystokyo.paper.loottable.PaperLootableBlockInventory; // Paper
-public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest {
+public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest, PaperLootableBlockInventory { // Paper
public CraftChest(World world, ChestBlockEntity tileEntity) {
super(world, tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
index 982adacb361b0590799dc68f9b7c13c7195627fd..e49eece9bff3a53469673d03a7bbf8f9cf8776b8 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
@@ -9,7 +9,7 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.Lootable;
-public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable {
+public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable, com.destroystokyo.paper.loottable.PaperLootableBlockInventory { // Paper
public CraftLootable(World world, T tileEntity) {
super(world, tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
index ae07db69b11b993b50782c94aa5c45b97d949612..06a96f027f90fd5bf05de72c8722ff5a81608b66 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
@@ -11,8 +11,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.inventory.Inventory;
import org.bukkit.loot.LootTable;
-public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat {
-
+public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final Inventory inventory;
public CraftChestBoat(CraftServer server, ChestBoat entity) {
@@ -66,7 +65,7 @@ public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.Chest
return this.getHandle().getLootTableSeed();
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - change visibility since it overrides a public method
ResourceLocation newKey = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
this.getHandle().setLootTable(newKey);
this.getHandle().setLootTableSeed(seed);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
index eb21b8457774d5ac765fa9008157cb29d9b72509..abf58bef2042a9efba5a78fd7f97339deceaa780 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
@@ -8,7 +8,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.inventory.Inventory;
@SuppressWarnings("deprecation")
-public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart {
+public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartChest(CraftServer server, MinecartChest entity) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
index 34b8f103625f087bb725bed595dd9c30f4a6f70c..ee9648739fb39c5842063d7442df6eb5c9336d7f 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
@@ -7,7 +7,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.inventory.Inventory;
-public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart {
+public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartHopper(CraftServer server, MinecartHopper entity) {

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 7 May 2016 23:33:08 -0400
Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat
diff --git a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
index b837b6616a2384b253cca8ed62c9488b639f6298..2be7a697f08045b974579e6942b38571e744efac 100644
--- a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
+++ b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
@@ -136,6 +136,7 @@ public class ScoreboardSaveData extends SavedData {
ListTag listTag = new ListTag();
for(PlayerTeam playerTeam : this.scoreboard.getPlayerTeams()) {
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.saveEmptyScoreboardTeams && playerTeam.getPlayers().isEmpty()) continue; // Paper
CompoundTag compoundTag = new CompoundTag();
compoundTag.putString("Name", playerTeam.getName());
compoundTag.putString("DisplayName", Component.Serializer.toJson(playerTeam.getDisplayName()));

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 12 May 2016 23:02:58 -0500
Subject: [PATCH] System property for disabling watchdoge
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 3ad14bf0697e682a2e777baa8faeb323d127fb13..a9897c494b3dc56d900356d74030359832febbaa 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -61,7 +61,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
while ( !this.stopping )
{
//
- if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime )
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
{
Logger log = Bukkit.getServer().getLogger();
log.log( Level.SEVERE, "------------------------------" );

View file

@ -1,86 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 16 May 2016 20:47:41 -0400
Subject: [PATCH] Async GameProfileCache saving
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 3ed50490121f34ab5b247565b9a4555bf6a46dff..0a419ec121bbddffa0424147c642f79d4e5eb817 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -934,7 +934,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} catch (java.lang.InterruptedException ignored) {} // Paper
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
MinecraftServer.LOGGER.info("Saving usercache.json");
- this.getProfileCache().save();
+ this.getProfileCache().save(false); // Paper
}
// Spigot end
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 18f7d73fd8a780753e2249a9fec6bb335ebfdeed..35904c69e14c4c0addda204d5e3788518c2e16c4 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -242,7 +242,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
if (this.convertOldUsers()) {
- this.getProfileCache().save();
+ this.getProfileCache().save(false); // Paper
}
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index d246563021c32127e570809f4d849b6a156f4dc6..225e15d686675e21969c4210fa38fef58d920355 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -127,7 +127,7 @@ public class GameProfileCache {
GameProfileCache.GameProfileInfo usercache_usercacheentry = new GameProfileCache.GameProfileInfo(profile, date);
this.safeAdd(usercache_usercacheentry);
- if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(); // Spigot - skip saving if disabled
+ if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(true); // Spigot - skip saving if disabled // Paper - async
}
private long getNextOperation() {
@@ -160,7 +160,7 @@ public class GameProfileCache {
}
if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
- this.save();
+ this.save(true); // Paper
}
return optional;
@@ -274,7 +274,7 @@ public class GameProfileCache {
return arraylist;
}
- public void save() {
+ public void save(boolean asyncSave) { // Paper
JsonArray jsonarray = new JsonArray();
DateFormat dateformat = GameProfileCache.createDateFormat();
@@ -282,6 +282,7 @@ public class GameProfileCache {
jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat));
});
String s = this.gson.toJson(jsonarray);
+ Runnable save = () -> { // Paper
try {
BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
@@ -306,6 +307,14 @@ public class GameProfileCache {
} catch (IOException ioexception) {
;
}
+ // Paper start
+ };
+ if (asyncSave) {
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save);
+ } else {
+ save.run();
+ }
+ // Paper end
}

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sun, 22 May 2016 20:20:55 -0500
Subject: [PATCH] Optional TNT doesn't move in water
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 6b372ac843e992820ac0a8ebb9c3c5d9795cc6b0..841bb7741ae6b0e9cb98120ee1649b93ef4c3dab 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -69,7 +69,7 @@ public class ServerEntity {
@Nullable
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
// CraftBukkit start
- private final Set<ServerPlayerConnection> trackedPlayers;
+ final Set<ServerPlayerConnection> trackedPlayers; // Paper - private -> package
public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayerConnection> trackedPlayers) {
this.trackedPlayers = trackedPlayers;
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index aa0dfd08aefbb9363ec96080432f0f75d71b0b95..4b81d62d3250b99cbcb4eb2468ef81c149bf177e 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -94,6 +94,27 @@ public class PrimedTnt extends Entity {
}
}
+ // Paper start - Optional prevent TNT from moving in water
+ if (!this.isRemoved() && this.wasTouchingWater && this.level.paperConfig().fixes.preventTntFromMovingInWater) {
+ /*
+ * Author: Jedediah Smith <jedediah@silencegreys.com>
+ */
+ // Send position and velocity updates to nearby players on every tick while the TNT is in water.
+ // This does pretty well at keeping their clients in sync with the server.
+ net.minecraft.server.level.ChunkMap.TrackedEntity ete = ((net.minecraft.server.level.ServerLevel)this.level).getChunkSource().chunkMap.entityMap.get(this.getId());
+ if (ete != null) {
+ net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this);
+ net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = new net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket(this);
+
+ ete.seenBy.stream()
+ .filter(viewer -> (viewer.getPlayer().getX() - this.getX()) * (viewer.getPlayer().getY() - this.getY()) * (viewer.getPlayer().getZ() - this.getZ()) < 16 * 16)
+ .forEach(viewer -> {
+ viewer.send(velocityPacket);
+ viewer.send(positionPacket);
+ });
+ }
+ }
+ // Paper end
}
private void explode() {
@@ -144,4 +165,11 @@ public class PrimedTnt extends Entity {
public int getFuse() {
return (Integer) this.entityData.get(PrimedTnt.DATA_FUSE_ID);
}
+
+ // Paper start - Optional prevent TNT from moving in water
+ @Override
+ public boolean isPushedByFluid() {
+ return !level.paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
+ }
+ // Paper end
}

View file

@ -1,81 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Panzer <postremus1996@googlemail.com>
Date: Mon, 23 May 2016 12:12:37 +0200
Subject: [PATCH] Faster redstone torch rapid clock removal
Only resize the the redstone torch list once, since resizing arrays / lists is costly
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 00911231201f84b781048d052495b60a47fb5277..c834428e04eab9639cfa9d07513d695dcb3bfce9 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -170,6 +170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
public CraftWorld getWorld() {
return this.world;
diff --git a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
index 9b6f8508d16bcecd9dc148f75598655e3585f175..da07fce0cf7c9fbdb57d2c59e431b59bf583bf50 100644
--- a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
@@ -21,7 +21,7 @@ import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit
public class RedstoneTorchBlock extends TorchBlock {
public static final BooleanProperty LIT = BlockStateProperties.LIT;
- private static final Map<BlockGetter, List<RedstoneTorchBlock.Toggle>> RECENT_TOGGLES = new WeakHashMap();
+ // Paper - Move the mapped list to World
public static final int RECENT_TOGGLE_TIMER = 60;
public static final int MAX_RECENT_TOGGLES = 8;
public static final int RESTART_DELAY = 160;
@@ -72,11 +72,15 @@ public class RedstoneTorchBlock extends TorchBlock {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
boolean flag = this.hasNeighborSignal(world, pos, state);
- List list = (List) RedstoneTorchBlock.RECENT_TOGGLES.get(world);
-
- while (list != null && !list.isEmpty() && world.getGameTime() - ((RedstoneTorchBlock.Toggle) list.get(0)).when > 60L) {
- list.remove(0);
+ // Paper start
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> redstoneUpdateInfos = world.redstoneUpdateInfos;
+ if (redstoneUpdateInfos != null) {
+ RedstoneTorchBlock.Toggle curr;
+ while ((curr = redstoneUpdateInfos.peek()) != null && world.getGameTime() - curr.when > 60L) {
+ redstoneUpdateInfos.poll();
+ }
}
+ // Paper end
// CraftBukkit start
org.bukkit.plugin.PluginManager manager = world.getCraftServer().getPluginManager();
@@ -152,9 +156,12 @@ public class RedstoneTorchBlock extends TorchBlock {
}
private static boolean isToggledTooFrequently(Level world, BlockPos pos, boolean addNew) {
- List<RedstoneTorchBlock.Toggle> list = (List) RedstoneTorchBlock.RECENT_TOGGLES.computeIfAbsent(world, (iblockaccess) -> {
- return Lists.newArrayList();
- });
+ // Paper start
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> list = world.redstoneUpdateInfos;
+ if (list == null) {
+ list = world.redstoneUpdateInfos = new java.util.ArrayDeque<>();
+ }
+
if (addNew) {
list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), world.getGameTime()));
@@ -162,9 +169,9 @@ public class RedstoneTorchBlock extends TorchBlock {
int i = 0;
- for (int j = 0; j < list.size(); ++j) {
- RedstoneTorchBlock.Toggle blockredstonetorch_redstoneupdateinfo = (RedstoneTorchBlock.Toggle) list.get(j);
-
+ for (java.util.Iterator<RedstoneTorchBlock.Toggle> iterator = list.iterator(); iterator.hasNext();) {
+ RedstoneTorchBlock.Toggle blockredstonetorch_redstoneupdateinfo = iterator.next();
+ // Paper end
if (blockredstonetorch_redstoneupdateinfo.pos.equals(pos)) {
++i;
if (i >= 8) {

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Panzer <postremus1996@googlemail.com>
Date: Sat, 28 May 2016 16:54:03 +0200
Subject: [PATCH] Add server-name parameter
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 49f6d20706e8fb94c41834f5addcd015d18acd7e..ef46dc1ed538b783213651f624326b2d49c786e0 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -156,6 +156,14 @@ public class Main {
.defaultsTo(new File[] {})
.describedAs("Jar file");
// Paper end
+
+ // Paper start
+ acceptsAll(asList("server-name"), "Name of the server")
+ .withRequiredArg()
+ .ofType(String.class)
+ .defaultsTo("Unknown Server")
+ .describedAs("Name");
+ // Paper end
}
};

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 31 May 2016 22:53:50 -0400
Subject: [PATCH] Only send global sounds to same world if limiting radius
Co-authored-by: Evan McCarthy <evanmccarthy@outlook.com>
Co-authored-by: lexikiq <noellekiq@gmail.com>
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
index fb26b6919acfb036affbe5519f5e4bd77955534f..89366ca29386fcbd03c3fc94d58451e714a1d779 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -654,7 +654,7 @@ public class EnderDragon extends Mob implements Enemy {
// CraftBukkit start - Use relative location for far away sounds
// this.world.b(1028, this.getChunkCoordinates(), 0);
int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16;
- for (net.minecraft.server.level.ServerPlayer player : this.level.getServer().getPlayerList().players) {
+ for (net.minecraft.server.level.ServerPlayer player : level.spigotConfig.dragonDeathSoundRadius > 0 ? ((ServerLevel) level).players() : level.getServer().getPlayerList().players) { // Paper
double deltaX = this.getX() - player.getX();
double deltaZ = this.getZ() - player.getZ();
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
index ae3931d65f6d8b91a654f3a7a4448d168eb526fc..807c8e18fdf5b0704638d7d084d6892556cc1525 100644
--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
@@ -270,7 +270,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
// CraftBukkit start - Use relative location for far away sounds
// this.world.globalLevelEvent(1023, new BlockPosition(this), 0);
int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16;
- for (ServerPlayer player : (List<ServerPlayer>) MinecraftServer.getServer().getPlayerList().players) {
+ for (ServerPlayer player : level.spigotConfig.witherSpawnSoundRadius > 0 ? ((ServerLevel) level).players() : level.getServer().getPlayerList().players) { // Paper
double deltaX = this.getX() - player.getX();
double deltaZ = this.getZ() - player.getZ();
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
diff --git a/src/main/java/net/minecraft/world/item/EnderEyeItem.java b/src/main/java/net/minecraft/world/item/EnderEyeItem.java
index a88ffff41481d346a99762352094cdb4e8dd6cc2..e0c3aa1285709a40ff0ea8c1d74d43d2b341aecc 100644
--- a/src/main/java/net/minecraft/world/item/EnderEyeItem.java
+++ b/src/main/java/net/minecraft/world/item/EnderEyeItem.java
@@ -64,7 +64,7 @@ public class EnderEyeItem extends Item {
// world.b(1038, blockposition1.c(1, 0, 1), 0);
int viewDistance = world.getCraftServer().getViewDistance() * 16;
BlockPos soundPos = blockposition1.offset(1, 0, 1);
- for (ServerPlayer player : world.getServer().getPlayerList().players) {
+ for (ServerPlayer player : world.spigotConfig.endPortalSoundRadius > 0 ? ((ServerLevel) world).players() : world.getServer().getPlayerList().players) { // Paper
double deltaX = soundPos.getX() - player.getX();
double deltaZ = soundPos.getZ() - player.getZ();
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 17 Jun 2016 20:50:11 -0400
Subject: [PATCH] Fix Old Sign Conversion
1) Sign loading code was trying to parse the JSON before the check for oldSign.
That code could then skip the old sign converting code if it triggers a JSON parse exception.
2) New Mojang Schematic system has Tile Entities in the new converted format, but missing the Bukkit.isConverted flag
This causes Igloos and such to render broken signs. We fix this by ignoring sign conversion for Defined Structures
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index 63acd109a79ed752a05df3d4f1b99309297c2055..b701a1344db066b9368841f2377ee493514bf282 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -32,6 +32,7 @@ public abstract class BlockEntity {
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
public CraftPersistentDataContainer persistentDataContainer;
// CraftBukkit end
+ public boolean isLoadingStructure = false; // Paper
private static final Logger LOGGER = LogUtils.getLogger();
private final BlockEntityType<?> type;
@Nullable
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
index 15695c9da294caf8531c59f72279aaeda6ceb23b..149728fa6371b4d8b0afaae769aacac27401ea03 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
@@ -112,7 +112,7 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C
s = "\"\"";
}
- if (oldSign) {
+ if (oldSign && !this.isLoadingStructure) { // Paper - saved structures will be in the new format, but will not have isConverted
this.messages[i] = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(s)[0];
continue;
}
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index 4f3a247a844844aa55d73089595d5f0b7ed49965..76666318690368bab672c2302c90dd3abb050299 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -286,7 +286,9 @@ public class StructureTemplate {
definedstructure_blockinfo.nbt.putLong("LootTableSeed", random.nextLong());
}
+ tileentity.isLoadingStructure = true; // Paper
tileentity.load(definedstructure_blockinfo.nbt);
+ tileentity.isLoadingStructure = false; // Paper
}
}

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 16 May 2016 23:19:16 -0400
Subject: [PATCH] Avoid blocking on Network Manager creation
Per Paper issue 294
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index a44520e8fb35d349d6481f369e39db1fdb475749..0e04532b8f1d48116eb46dcef7952bfcc0d11394 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -63,6 +63,15 @@ public class ServerConnectionListener {
public volatile boolean running;
private final List<ChannelFuture> channels = Collections.synchronizedList(Lists.newArrayList());
final List<Connection> connections = Collections.synchronizedList(Lists.newArrayList());
+ // Paper start - prevent blocking on adding a new network manager while the server is ticking
+ private final java.util.Queue<Connection> pending = new java.util.concurrent.ConcurrentLinkedQueue<>();
+ private final void addPending() {
+ Connection manager = null;
+ while ((manager = pending.poll()) != null) {
+ connections.add(manager);
+ }
+ }
+ // Paper end
public ServerConnectionListener(MinecraftServer server) {
this.server = server;
@@ -98,7 +107,8 @@ public class ServerConnectionListener {
int j = ServerConnectionListener.this.server.getRateLimitPacketsPerSecond();
Object object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND);
- ServerConnectionListener.this.connections.add((Connection) object); // CraftBukkit - decompile error
+ // ServerConnectionListener.this.connections.add((Connection) object); // CraftBukkit - decompile error
+ pending.add((Connection) object); // Paper
channel.pipeline().addLast("packet_handler", (ChannelHandler) object);
((Connection) object).setListener(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object));
}
@@ -157,6 +167,7 @@ public class ServerConnectionListener {
synchronized (this.connections) {
// Spigot Start
+ this.addPending(); // Paper
// 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 )
{

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sat, 16 Jul 2016 19:11:17 -0500
Subject: [PATCH] Don't lookup game profiles that have no UUID and no name
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index 225e15d686675e21969c4210fa38fef58d920355..5288aec173549a982e42aeeccf7f5f394080955d 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -98,6 +98,7 @@ public class GameProfileCache {
}
};
+ if (!org.apache.commons.lang3.StringUtils.isBlank(name)) // Paper - Don't lookup a profile with a blank name)
repository.findProfilesByNames(new String[]{name}, Agent.MINECRAFT, profilelookupcallback);
GameProfile gameprofile = (GameProfile) atomicreference.get();

View file

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gabriele C <sgdc3.mail@gmail.com>
Date: Fri, 5 Aug 2016 01:03:08 +0200
Subject: [PATCH] Add setting for proxy online mode status
TODO: Add isProxyOnlineMode check to Metrics
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index 5288aec173549a982e42aeeccf7f5f394080955d..58e923f4ef1980bc7fff1e3b3fcdaad8c4eded53 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -98,7 +98,8 @@ public class GameProfileCache {
}
};
- if (!org.apache.commons.lang3.StringUtils.isBlank(name)) // Paper - Don't lookup a profile with a blank name)
+ if (!org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name
+ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) // Paper - only run in online mode - 100 COL
repository.findProfilesByNames(new String[]{name}, Agent.MINECRAFT, profilelookupcallback);
GameProfile gameprofile = (GameProfile) atomicreference.get();
@@ -116,7 +117,7 @@ public class GameProfileCache {
}
private static boolean usesAuthentication() {
- return GameProfileCache.usesAuthentication;
+ return io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper
}
public void add(GameProfile profile) {
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
index da98f074ccd5a40c635824112c97fd174c393cb1..6599f874d9f97e9ef4862039ecad7277bbc5fd91 100644
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
@@ -66,7 +66,8 @@ public class OldUsersConverter {
return new String[i];
});
- if (server.usesAuthentication() || org.spigotmc.SpigotConfig.bungee) { // Spigot: bungee = online mode, for now.
+ if (server.usesAuthentication()
+ || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode())) { // Spigot: bungee = online mode, for now. // Paper - Handle via setting
server.getProfileRepository().findProfilesByNames(astring, Agent.MINECRAFT, callback);
} else {
String[] astring1 = astring;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 3a046d3eb6bca6f45f8018a3844c58ac8cba43ac..84a7c0b7826fba63adef2fe7a81fbe9b255d2ecf 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1715,7 +1715,7 @@ public final class CraftServer implements Server {
// Spigot Start
GameProfile profile = null;
// Only fetch an online UUID in online mode
- if ( this.getOnlineMode() || org.spigotmc.SpigotConfig.bungee )
+ if ( this.getOnlineMode() || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ) // Paper - Handle via setting
{
profile = this.console.getProfileCache().get(name).orElse(null);
}

View file

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alfie Cleveland <alfeh@me.com>
Date: Fri, 19 Aug 2016 01:52:56 +0100
Subject: [PATCH] Optimise BlockState's hashCode/equals
These are singleton "single instance" objects. We can rely on
object identity checks safely.
Use a simpler optimized hashcode
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
index 6cdb0716f2a4b29f7a5ecd109bf3c4700ebd22ad..ff1a0d125edd2ea10c870cbb62ae9aa23644b6dc 100644
--- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
@@ -30,8 +30,7 @@ public class BooleanProperty extends Property<Boolean> {
return value.toString();
}
- @Override
- public boolean equals(Object object) {
+ public boolean equals_unused(Object object) { // Paper
if (this == object) {
return true;
} else if (object instanceof BooleanProperty && super.equals(object)) {
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
index 4d6e7b5889ecb81195c7152225ae8e3343d3408c..0bca0f971dac994bd8b6ecd87e8b33e26c0f18f9 100644
--- a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
@@ -45,8 +45,7 @@ public class EnumProperty<T extends Enum<T> & StringRepresentable> extends Prope
return value.getSerializedName();
}
- @Override
- public boolean equals(Object object) {
+ public boolean equals_unused(Object object) { // Paper
if (this == object) {
return true;
} else if (object instanceof EnumProperty && super.equals(object)) {
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
index 59b5b22a567e4e2be499a2a35aedb10218a7432a..bdbe0362e49e73c05237f9f3143230e0b03e494e 100644
--- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
@@ -35,8 +35,7 @@ public class IntegerProperty extends Property<Integer> {
return this.values;
}
- @Override
- public boolean equals(Object object) {
+ public boolean equals_unused(Object object) { // Paper
if (this == object) {
return true;
} else if (object instanceof IntegerProperty && super.equals(object)) {
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
index 5a973c1536291e79aa8377ca5bda8ef84127e20a..a37424bbc6bee02354abaa793aa0865c556c6bbe 100644
--- a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
@@ -68,14 +68,7 @@ public abstract class Property<T extends Comparable<T>> {
@Override
public boolean equals(Object object) {
- if (this == object) {
- return true;
- } else if (!(object instanceof Property)) {
- return false;
- } else {
- Property<?> property = (Property)object;
- return this.clazz.equals(property.clazz) && this.name.equals(property.name);
- }
+ return this == object; // Paper
}
@Override

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sun, 11 Sep 2016 14:30:57 -0500
Subject: [PATCH] Configurable packet in spam threshold
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 050e8f545f5cc86985d3dbbe3192f632b64af66f..f0303267251e9f9b30897159b239db85d1170591 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1604,13 +1604,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
// Spigot start - limit place/interactions
private int limitedPackets;
private long lastLimitedPacket = -1;
+ private static final int THRESHOLD = io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.incomingPacketThreshold; // Paper - Configurable threshold
private boolean checkLimit(long timestamp) {
- if (this.lastLimitedPacket != -1 && timestamp - this.lastLimitedPacket < 30 && this.limitedPackets++ >= 4) {
+ if (this.lastLimitedPacket != -1 && timestamp - this.lastLimitedPacket < THRESHOLD && this.limitedPackets++ >= 8) { // Paper - Use threshold, raise packet limit to 8
return false;
}
- if (this.lastLimitedPacket == -1 || timestamp - this.lastLimitedPacket >= 30) {
+ if (this.lastLimitedPacket == -1 || timestamp - this.lastLimitedPacket >= THRESHOLD) { // Paper
this.lastLimitedPacket = timestamp;
this.limitedPackets = 0;
return true;

View file

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Tue, 20 Sep 2016 00:58:01 +0000
Subject: [PATCH] Configurable flying kick messages
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index f0303267251e9f9b30897159b239db85d1170591..534ae13641f36f94abb3a62538b072c7afc587fe 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -351,7 +351,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger()) {
if (++this.aboveGroundTickCount > 80) {
ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString());
- this.disconnect(Component.translatable("multiplayer.disconnect.flying"));
+ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer); // Paper - use configurable kick message
return;
}
} else {
@@ -370,7 +370,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
if (this.clientVehicleIsFloating && this.player.getRootVehicle().getControllingPassenger() == this.player) {
if (++this.aboveGroundVehicleTickCount > 80) {
ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString());
- this.disconnect(Component.translatable("multiplayer.disconnect.flying"));
+ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle); // Paper - use configurable kick message
return;
}
} else {

View file

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaBlend <whizkid3000@hotmail.com>
Date: Sun, 16 Oct 2016 23:19:30 -0700
Subject: [PATCH] Add EntityZapEvent
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 18ba4b9d9b68088afd48d1f12cec6b155ea84159..dfc67cd0ef52939be5e5a9952cfcdb4d87bf0d82 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -837,10 +837,17 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@Override
public void thunderHit(ServerLevel world, LightningBolt lightning) {
if (world.getDifficulty() != Difficulty.PEACEFUL) {
- Villager.LOGGER.info("Villager {} was struck by lightning {}.", this, lightning);
+ // Paper - move log down, event can cancel
Witch entitywitch = (Witch) EntityType.WITCH.create(world);
if (entitywitch != null) {
+ // Paper start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityZapEvent(this, lightning, entitywitch).isCancelled()) {
+ return;
+ }
+ if (org.spigotmc.SpigotConfig.logVillagerDeaths) Villager.LOGGER.info("Villager {} was struck by lightning {}.", this, lightning); // Move down
+ // Paper end
+
entitywitch.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
entitywitch.finalizeSpawn(world, world.getCurrentDifficultyAt(entitywitch.blockPosition()), MobSpawnType.CONVERSION, (SpawnGroupData) null, (CompoundTag) null);
entitywitch.setNoAi(this.isNoAi());
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 3b520b1301eb0225cdcbb271c8032726c59d3990..d8ebe20844136f2a5b395669dcfdd7f6bbc6fff3 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1158,6 +1158,14 @@ public class CraftEventFactory {
return event;
}
+ // Paper start
+ public static com.destroystokyo.paper.event.entity.EntityZapEvent callEntityZapEvent (Entity entity, Entity lightning, Entity changedEntity) {
+ com.destroystokyo.paper.event.entity.EntityZapEvent event = new com.destroystokyo.paper.event.entity.EntityZapEvent(entity.getBukkitEntity(), (LightningStrike) lightning.getBukkitEntity(), changedEntity.getBukkitEntity());
+ entity.getBukkitEntity().getServer().getPluginManager().callEvent(event);
+ return event;
+ }
+ // Paper end
+
public static HorseJumpEvent callHorseJumpEvent(Entity horse, float power) {
HorseJumpEvent event = new HorseJumpEvent((AbstractHorse) horse.getBukkitEntity(), power);
horse.getBukkitEntity().getServer().getPluginManager().callEvent(event);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sat, 12 Nov 2016 23:25:22 -0600
Subject: [PATCH] Filter bad tile entity nbt data from falling blocks
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 561b8d6fcf4d511fb026bcc2c02054e56589d0b7..97b2d12713d2245f1621d3ade5b5655b5897cbf4 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -331,7 +331,7 @@ public class FallingBlockEntity extends Entity {
this.dropItem = nbt.getBoolean("DropItem");
}
- if (nbt.contains("TileEntityData", 10)) {
+ if (nbt.contains("TileEntityData", 10) && !(this.level.paperConfig().entities.spawning.filterBadTileEntityNbtFromFallingBlocks && this.blockState.getBlock() instanceof net.minecraft.world.level.block.GameMasterBlock)) {
this.blockData = nbt.getCompound("TileEntityData");
}

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alfie Cleveland <alfeh@me.com>
Date: Fri, 25 Nov 2016 13:22:40 +0000
Subject: [PATCH] Cache user authenticator threads
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index a6e90e70730e106d1cac01abf7a41df8df787d89..453a9dd794c39be5e7221b05fabb71b802691003 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -112,6 +112,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
}
+ private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads
+
// Spigot start
public void initUUID()
{
@@ -208,8 +210,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge));
} else {
// Spigot start
- new Thread("User Authenticator #" + ServerLoginPacketListenerImpl.UNIQUE_THREAD_ID.incrementAndGet()) {
-
+ // Paper start - Cache authenticator threads
+ authenticatorPool.execute(new Runnable() {
@Override
public void run() {
try {
@@ -220,7 +222,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName(), ex);
}
}
- }.start();
+ });
+ // Paper end
// Spigot end
}
@@ -257,7 +260,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
throw new IllegalStateException("Protocol error", cryptographyexception);
}
- Thread thread = new Thread("User Authenticator #" + ServerLoginPacketListenerImpl.UNIQUE_THREAD_ID.incrementAndGet()) {
+ // Paper start - Cache authenticator threads
+ authenticatorPool.execute(new Runnable() {
public void run() {
GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
@@ -302,10 +306,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
return ServerLoginPacketListenerImpl.this.server.getPreventProxyConnections() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress) socketaddress).getAddress() : null;
}
- };
-
- thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(ServerLoginPacketListenerImpl.LOGGER));
- thread.start();
+ });
+ // Paper end
}
// Spigot start

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: willies952002 <admin@domnian.com>
Date: Mon, 28 Nov 2016 10:21:52 -0500
Subject: [PATCH] Allow Reloading of Command Aliases
Reload the aliases stored in commands.yml
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 84a7c0b7826fba63adef2fe7a81fbe9b255d2ecf..6396640956daf60bdd885face69425e8ca177d8f 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2572,5 +2572,24 @@ public final class CraftServer implements Server {
DefaultPermissions.registerCorePermissions();
CraftDefaultPermissions.registerCorePermissions();
}
+
+ @Override
+ public boolean reloadCommandAliases() {
+ Set<String> removals = getCommandAliases().keySet().stream()
+ .map(key -> key.toLowerCase(java.util.Locale.ENGLISH))
+ .collect(java.util.stream.Collectors.toSet());
+ getCommandMap().getKnownCommands().keySet().removeIf(removals::contains);
+ File file = getCommandsConfigFile();
+ try {
+ commandsConfiguration.load(file);
+ } catch (FileNotFoundException ex) {
+ return false;
+ } catch (IOException | org.bukkit.configuration.InvalidConfigurationException ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file, ex);
+ return false;
+ }
+ commandMap.registerServerAliases();
+ return true;
+ }
// Paper end
}

View file

@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaBlend <whizkid3000@hotmail.com>
Date: Thu, 8 Sep 2016 08:48:33 -0700
Subject: [PATCH] Add source to PlayerExpChangeEvent
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index baa5cc93ec210032fcbe493d473396964288933f..c12493cc369f632c4aa9535cde9b8629a0b2eb86 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -248,7 +248,7 @@ public class ExperienceOrb extends Entity {
int i = this.repairPlayerItems(player, this.value);
if (i > 0) {
- player.giveExperiencePoints(CraftEventFactory.callPlayerExpChangeEvent(player, i).getAmount()); // CraftBukkit - this.value -> event.getAmount()
+ player.giveExperiencePoints(CraftEventFactory.callPlayerExpChangeEvent(player, this).getAmount()); // CraftBukkit - this.value -> event.getAmount() // Paper - supply experience orb object
}
--this.count;
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index d8ebe20844136f2a5b395669dcfdd7f6bbc6fff3..71364663b577dedd62993808d764b4e4a91322d5 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1117,6 +1117,17 @@ public class CraftEventFactory {
return event;
}
+ // Paper start - Add orb
+ public static PlayerExpChangeEvent callPlayerExpChangeEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb entityOrb) {
+ Player player = (Player) entity.getBukkitEntity();
+ ExperienceOrb source = (ExperienceOrb) entityOrb.getBukkitEntity();
+ int expAmount = source.getExperience();
+ PlayerExpChangeEvent event = new PlayerExpChangeEvent(player, source, expAmount);
+ Bukkit.getPluginManager().callEvent(event);
+ return event;
+ }
+ // Paper end
+
public static boolean handleBlockGrowEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState block) {
return CraftEventFactory.handleBlockGrowEvent(world, pos, block, 3);
}

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Fri, 16 Dec 2016 21:25:39 -0600
Subject: [PATCH] Add ProjectileCollideEvent
Deprecated now and replaced with ProjectileHitEvent
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 71364663b577dedd62993808d764b4e4a91322d5..24814f91088b835e398d4d5fa1c895a3b1cdb086 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1261,6 +1261,17 @@ public class CraftEventFactory {
return CraftItemStack.asNMSCopy(bitem);
}
+ // Paper start
+ @Deprecated
+ public static com.destroystokyo.paper.event.entity.ProjectileCollideEvent callProjectileCollideEvent(Entity entity, EntityHitResult position) {
+ Projectile projectile = (Projectile) entity.getBukkitEntity();
+ org.bukkit.entity.Entity collided = position.getEntity().getBukkitEntity();
+ com.destroystokyo.paper.event.entity.ProjectileCollideEvent event = new com.destroystokyo.paper.event.entity.ProjectileCollideEvent(projectile, collided);
+ Bukkit.getPluginManager().callEvent(event);
+ return event;
+ }
+ // Paper end
+
public static ProjectileLaunchEvent callProjectileLaunchEvent(Entity entity) {
Projectile bukkitEntity = (Projectile) entity.getBukkitEntity();
ProjectileLaunchEvent event = new ProjectileLaunchEvent(bukkitEntity);
@@ -1285,8 +1296,15 @@ public class CraftEventFactory {
if (position.getType() == HitResult.Type.ENTITY) {
hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity();
}
+ // Paper start - legacy event
+ boolean cancelled = false;
+ if (hitEntity != null && position instanceof EntityHitResult entityHitResult) {
+ cancelled = callProjectileCollideEvent(entity, entityHitResult).isCancelled();
+ }
+ // Paper end
ProjectileHitEvent event = new ProjectileHitEvent((Projectile) entity.getBukkitEntity(), hitEntity, hitBlock, hitFace);
+ event.setCancelled(cancelled); // Paper - propagate legacy event cancellation to modern event
entity.level.getCraftServer().getPluginManager().callEvent(event);
return event;
}

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 19 Dec 2016 23:07:42 -0500
Subject: [PATCH] Prevent Pathfinding out of World Border
This prevents Entities from trying to run outside of the World Border
TODO: This doesn't prevent the pathfinder from using blocks outside the world border as nodes. We can fix this
by adding code to all overrides in:
NodeEvaluator:
public abstract BlockPathTypes getBlockPathType(BlockGetter world, int x, int y, int z);
to return BLOCKED if it is outside the world border.
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
index bd782c8935db6e0aa3489725d3c4ee401f9bf242..bf89b3a484334ec23f96426bdcf29e54725512c3 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -157,7 +157,7 @@ public abstract class PathNavigation {
// Paper start - Pathfind event
boolean copiedSet = false;
for (BlockPos possibleTarget : positions) {
- if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(),
+ if (!this.mob.getCommandSenderWorld().getWorldBorder().isWithinBounds(possibleTarget) || !new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), // Paper - don't path out of world border
io.papermc.paper.util.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) {
if (!copiedSet) {
copiedSet = true;

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 2 Dec 2016 00:11:43 -0500
Subject: [PATCH] Optimize World.isLoaded(BlockPosition)Z
Reduce method invocations for World.isLoaded(BlockPosition)Z
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index c834428e04eab9639cfa9d07513d695dcb3bfce9..64abe2a075c1b2ee18cb691599ef5223953108f3 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -338,6 +338,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return chunk == null ? null : chunk.getFluidState(blockposition);
}
+ @Override
+ public final boolean hasChunkAt(BlockPos pos) {
+ return getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4) != null; // Paper
+ }
+
public final boolean isLoadedAndInBounds(BlockPos blockposition) { // Paper - final for inline
return getWorldBorder().isWithinBounds(blockposition) && getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null;
}

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 20 Dec 2016 15:15:11 -0500
Subject: [PATCH] Bound Treasure Maps to World Border
Make it so a Treasure Map does not target a structure outside of the
World Border, where players are not even able to reach.
This also would help the case where a players close to the border, and one
that is outside happens to be closer, but unreachable, yet another reachable
one is in border that would of been missed.
diff --git a/src/main/java/net/minecraft/world/level/border/WorldBorder.java b/src/main/java/net/minecraft/world/level/border/WorldBorder.java
index 6ec5a1525d0b8ced8fe78d3eab29c5eb82996844..2442c287a7f26cfee10a19e9015558cdebdcf3ac 100644
--- a/src/main/java/net/minecraft/world/level/border/WorldBorder.java
+++ b/src/main/java/net/minecraft/world/level/border/WorldBorder.java
@@ -37,6 +37,18 @@ public class WorldBorder {
return (double) (pos.getX() + 1) > this.getMinX() && (double) pos.getX() < this.getMaxX() && (double) (pos.getZ() + 1) > this.getMinZ() && (double) pos.getZ() < this.getMaxZ();
}
+ // Paper start
+ private final BlockPos.MutableBlockPos mutPos = new BlockPos.MutableBlockPos();
+ public boolean isBlockInBounds(int chunkX, int chunkZ) {
+ this.mutPos.set(chunkX, 64, chunkZ);
+ return this.isWithinBounds(this.mutPos);
+ }
+ public boolean isChunkInBounds(int chunkX, int chunkZ) {
+ this.mutPos.set(((chunkX << 4) + 15), 64, (chunkZ << 4) + 15);
+ return this.isWithinBounds(this.mutPos);
+ }
+ // Paper end
+
public boolean isWithinBounds(ChunkPos pos) {
return (double) pos.getMaxBlockX() > this.getMinX() && (double) pos.getMinBlockX() < this.getMaxX() && (double) pos.getMaxBlockZ() > this.getMinZ() && (double) pos.getMinBlockZ() < this.getMaxZ();
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
index 2d89c415fe4e76bff51374d50f1a7efbaace134e..b6df6077107759963ee8205dddb90501d5ccb4d6 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -217,6 +217,7 @@ public abstract class ChunkGenerator {
while (iterator.hasNext()) {
ChunkPos chunkcoordintpair = (ChunkPos) iterator.next();
+ if (!world.getWorldBorder().isChunkInBounds(chunkcoordintpair.x, chunkcoordintpair.z)) { continue; } // Paper
blockposition_mutableblockposition.set(SectionPos.sectionToBlockCoord(chunkcoordintpair.x, 8), 32, SectionPos.sectionToBlockCoord(chunkcoordintpair.z, 8));
double d1 = blockposition_mutableblockposition.distSqr(center);

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 20 Dec 2016 15:26:27 -0500
Subject: [PATCH] Configurable Cartographer Treasure Maps
Allow configuring for cartographers to return the same map location
Also allow turning off treasure maps all together as they can eat up Map ID's
which are limited in quantity.
diff --git a/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java b/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java
index 155301c03e6553de8aed55e87ece40e8f5f3f495..44a237426739fad0096b2f5108f1d25bd388ea08 100644
--- a/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java
+++ b/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java
@@ -386,7 +386,8 @@ public class VillagerTrades {
return null;
} else {
ServerLevel serverLevel = (ServerLevel)entity.level;
- BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, entity.blockPosition(), 100, true);
+ if (!serverLevel.paperConfig().environment.treasureMaps.enabled) return null; // Paper
+ BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, entity.blockPosition(), 100, !serverLevel.paperConfig().environment.treasureMaps.findAlreadyDiscoveredVillager); // Paper
if (blockPos != null) {
ItemStack itemStack = MapItem.create(serverLevel, blockPos.getX(), blockPos.getZ(), (byte)2, true, true);
MapItem.renderBiomePreviewMap(serverLevel, itemStack);
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java b/src/main/java/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java
index 5762bb0725a0e206a24d3056d9330af45afea1bd..9d40469f92db025e760ed1603018fcb1f43dace5 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java
@@ -68,7 +68,16 @@ public class ExplorationMapFunction extends LootItemConditionalFunction {
Vec3 vec3 = context.getParamOrNull(LootContextParams.ORIGIN);
if (vec3 != null) {
ServerLevel serverLevel = context.getLevel();
- BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, new BlockPos(vec3), this.searchRadius, this.skipKnownStructures);
+ // Paper start
+ if (!serverLevel.paperConfig().environment.treasureMaps.enabled) {
+ /*
+ * NOTE: I fear users will just get a plain map as their "treasure"
+ * This is preferable to disrespecting the config.
+ */
+ return stack;
+ }
+ // Paper end
+ BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, new BlockPos(vec3), this.searchRadius, !serverLevel.paperConfig().environment.treasureMaps.findAlreadyDiscoveredLootTable.or(!this.skipKnownStructures)); // Paper
if (blockPos != null) {
ItemStack itemStack = MapItem.create(serverLevel, blockPos.getX(), blockPos.getZ(), this.zoom, true, true);
MapItem.renderBiomePreviewMap(serverLevel, itemStack);

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 21 Dec 2016 03:48:29 -0500
Subject: [PATCH] Optimize ItemStack.isEmpty()
Remove hashMap lookup every check, simplify code to remove ternary
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 87031aa69148118d9f5bf16cb8a55cf72f9d0a1d..cf47b0bed013b3242b516198ff7006aab5452d7e 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -249,7 +249,7 @@ public final class ItemStack {
}
public boolean isEmpty() {
- return this == ItemStack.EMPTY ? true : (this.getItem() != null && !this.is(Items.AIR) ? this.count <= 0 : true);
+ return this == ItemStack.EMPTY || this.item == null || this.item == Items.AIR || this.count <= 0; // Paper
}
public boolean isItemEnabled(FeatureFlagSet enabledFeatures) {

View file

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Wed, 21 Dec 2016 11:47:25 -0600
Subject: [PATCH] Add API methods to control if armour stands can move
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
index 3869aae0bcf3d4fb53009b314f8b869198e26ce5..58882569595a21b0499921dfddcbc9d01248cf1c 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -91,6 +91,7 @@ public class ArmorStand extends LivingEntity {
public Rotations rightArmPose;
public Rotations leftLegPose;
public Rotations rightLegPose;
+ public boolean canMove = true; // Paper
public ArmorStand(EntityType<? extends ArmorStand> type, Level world) {
super(type, world);
@@ -926,4 +927,13 @@ public class ArmorStand extends LivingEntity {
public boolean canBeSeenByAnyone() {
return !this.isInvisible() && !this.isMarker();
}
+
+ // Paper start
+ @Override
+ public void move(net.minecraft.world.entity.MoverType type, Vec3 movement) {
+ if (this.canMove) {
+ super.move(type, movement);
+ }
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java
index 47ca72e264950dd950f037a21bb0ad6cc1700751..06cedeea447f53d100e32a6eba6f83b4719cb231 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java
@@ -228,4 +228,15 @@ public class CraftArmorStand extends CraftLivingEntity implements ArmorStand {
public boolean hasEquipmentLock(EquipmentSlot equipmentSlot, LockType lockType) {
return (this.getHandle().disabledSlots & (1 << CraftEquipmentSlot.getNMS(equipmentSlot).getFilterFlag() + lockType.ordinal() * 8)) != 0;
}
+ // Paper start
+ @Override
+ public boolean canMove() {
+ return getHandle().canMove;
+ }
+
+ @Override
+ public void setCanMove(boolean move) {
+ getHandle().canMove = move;
+ }
+ // Paper end
}

View file

@ -1,58 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 27 Dec 2016 15:02:42 -0500
Subject: [PATCH] String based Action Bar API
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java
index 32ef3edebe94a2014168b7e438752a80b2687e5f..ab6c58eed6707ab7b0aa3e7549a871ad7dfad87f 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetActionBarTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetActionBarTextPacket(Component message) {
this.text = message;
@@ -21,6 +22,8 @@ public class ClientboundSetActionBarTextPacket implements Packet<ClientGamePacke
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index b08b72f8c029faae9b9d425e8ce77a1ff23addd7..aa81018c455629659df34802002105966bd89de3 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -357,6 +357,26 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
// Paper start
+ @Override
+ public void sendActionBar(BaseComponent[] message) {
+ if (getHandle().connection == null) return;
+ net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket packet = new net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = message;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void sendActionBar(String message) {
+ if (getHandle().connection == null || message == null || message.isEmpty()) return;
+ getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket(CraftChatMessage.fromStringOrNull(message)));
+ }
+
+ @Override
+ public void sendActionBar(char alternateChar, String message) {
+ if (message == null || message.isEmpty()) return;
+ sendActionBar(org.bukkit.ChatColor.translateAlternateColorCodes(alternateChar, message));
+ }
+
@Override
public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
if (header != null) {

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alfie Cleveland <alfeh@me.com>
Date: Tue, 27 Dec 2016 01:57:57 +0000
Subject: [PATCH] Properly fix item duplication bug
Credit to prplz for figuring out the real issue
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index cba9b5586048500d91081cc8ef2ad7ae2bb7a816..04912bd14a2b03ca123561a3e21a812b8f806366 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -2243,7 +2243,7 @@ public class ServerPlayer extends Player {
@Override
public boolean isImmobile() {
- return super.isImmobile() || !this.getBukkitEntity().isOnline();
+ return super.isImmobile() || (this.connection != null && this.connection.isDisconnected()); // Paper
}
@Override
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 534ae13641f36f94abb3a62538b072c7afc587fe..d0cef1be518aa788a6a2ce7788887afb66259b66 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3169,7 +3169,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
public final boolean isDisconnected() {
- return !this.player.joining && !this.connection.isConnected();
+ return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper
}
// CraftBukkit end

View file

@ -1,93 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 28 Dec 2016 07:18:33 +0100
Subject: [PATCH] Firework API's
== AT ==
public net.minecraft.world.entity.projectile.FireworkRocketEntity attachedToEntity
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
index 4abcdc515411372006ff5d33510bdd64092c186a..5406925cd66f46ab8744123c670d72cea7bfc3a1 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
@@ -39,6 +39,7 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
public int lifetime;
@Nullable
public LivingEntity attachedToEntity;
+ public java.util.UUID spawningEntity; // Paper
public FireworkRocketEntity(EntityType<? extends FireworkRocketEntity> type, Level world) {
super(type, world);
@@ -318,6 +319,11 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
}
nbt.putBoolean("ShotAtAngle", (Boolean) this.entityData.get(FireworkRocketEntity.DATA_SHOT_AT_ANGLE));
+ // Paper start
+ if (this.spawningEntity != null) {
+ nbt.putUUID("SpawningEntity", this.spawningEntity);
+ }
+ // Paper end
}
@Override
@@ -334,7 +340,11 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
if (nbt.contains("ShotAtAngle")) {
this.entityData.set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, nbt.getBoolean("ShotAtAngle"));
}
-
+ // Paper start
+ if (nbt.hasUUID("SpawningEntity")) {
+ this.spawningEntity = nbt.getUUID("SpawningEntity");
+ }
+ // Paper end
}
@Override
diff --git a/src/main/java/net/minecraft/world/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java
index 4b8ad27c8682f112c4964849d9bdfcf4c355701f..48626d564c9fb4630b51858edd124b56af2d7ca0 100644
--- a/src/main/java/net/minecraft/world/item/CrossbowItem.java
+++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java
@@ -220,6 +220,7 @@ public class CrossbowItem extends ProjectileWeaponItem implements Vanishable {
if (flag1) {
object = new FireworkRocketEntity(world, projectile, shooter, shooter.getX(), shooter.getEyeY() - 0.15000000596046448D, shooter.getZ(), true);
+ ((FireworkRocketEntity) object).spawningEntity = shooter.getUUID(); // Paper
} else {
object = CrossbowItem.getArrow(world, shooter, crossbow, projectile);
if (creative || simulated != 0.0F) {
diff --git a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
index 1d99d03c1ce0a647b053e8b7bd1e2da58805c4f8..854856ca742dff800ac5d7bf0af4f79cf631540b 100644
--- a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
+++ b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java
@@ -45,6 +45,7 @@ public class FireworkRocketItem extends Item {
Vec3 vec3 = context.getClickLocation();
Direction direction = context.getClickedFace();
FireworkRocketEntity fireworkRocketEntity = new FireworkRocketEntity(level, context.getPlayer(), vec3.x + (double)direction.getStepX() * 0.15D, vec3.y + (double)direction.getStepY() * 0.15D, vec3.z + (double)direction.getStepZ() * 0.15D, itemStack);
+ fireworkRocketEntity.spawningEntity = context.getPlayer() == null ? null : context.getPlayer().getUUID(); // Paper
level.addFreshEntity(fireworkRocketEntity);
itemStack.shrink(1);
}
@@ -58,6 +59,7 @@ public class FireworkRocketItem extends Item {
ItemStack itemStack = user.getItemInHand(hand);
if (!world.isClientSide) {
FireworkRocketEntity fireworkRocketEntity = new FireworkRocketEntity(world, itemStack, user);
+ fireworkRocketEntity.spawningEntity = user.getUUID(); // Paper
world.addFreshEntity(fireworkRocketEntity);
if (!user.getAbilities().instabuild) {
itemStack.shrink(1);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
index 59d5c314711b4ec239e5bcb4272b11ed72705c5a..c242f654c88ca1773429348939d3bb2ffae3768c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
@@ -135,4 +135,11 @@ public class CraftFirework extends CraftProjectile implements Firework {
public void setShotAtAngle(boolean shotAtAngle) {
this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, shotAtAngle);
}
+
+ // Paper start
+ @Override
+ public java.util.UUID getSpawningEntity() {
+ return getHandle().spawningEntity;
+ }
+ // Paper end
}

View file

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 31 Dec 2016 21:44:50 -0500
Subject: [PATCH] PlayerTeleportEndGatewayEvent
Allows you to access the Gateway being used in a teleport event
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
index 553f8314118adc64a6af9aee9351598b2991d18d..9c4469d46cb7a2cc781f6498d3e4ec6a9415d12e 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
@@ -12,6 +12,7 @@ import net.minecraft.data.worldgen.features.EndFeatures;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
+import io.papermc.paper.util.MCUtil;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
@@ -211,7 +212,7 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
location.setPitch(player.getLocation().getPitch());
location.setYaw(player.getLocation().getYaw());
- PlayerTeleportEvent teleEvent = new PlayerTeleportEvent(player, player.getLocation(), location, PlayerTeleportEvent.TeleportCause.END_GATEWAY);
+ PlayerTeleportEvent teleEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(player, player.getLocation(), location, new org.bukkit.craftbukkit.block.CraftEndGateway(worldserver.getWorld(), blockEntity)); // Paper
Bukkit.getPluginManager().callEvent(teleEvent);
if (teleEvent.isCancelled()) {
return;

View file

@ -1,82 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 7 Jan 2017 15:24:46 -0500
Subject: [PATCH] Provide E/TE/Chunk count stat methods
Provides counts without the ineffeciency of using .getEntities().size()
which creates copy of the collections.
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 64abe2a075c1b2ee18cb691599ef5223953108f3..94e527fa7db9822a15711c80107a2d99eacbaac5 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -115,7 +115,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public static final int TICKS_PER_DAY = 24000;
public static final int MAX_ENTITY_SPAWN_Y = 20000000;
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
- protected final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList();
+ protected final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList(); public final int getTotalTileEntityTickers() { return this.blockEntityTickers.size(); } // Paper
protected final NeighborUpdater neighborUpdater;
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
private boolean tickingBlockEntities;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 958c5faeddd3ee54ac2880eb3eb9e4ab2bba2540..3f6e5e4d36e8170def4ce50e29cdfcc7e25f4f4d 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -151,6 +151,56 @@ public class CraftWorld extends CraftRegionAccessor implements World {
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
+ // Paper start - Provide fast information methods
+ @Override
+ public int getEntityCount() {
+ int ret = 0;
+ for (net.minecraft.world.entity.Entity entity : world.getEntities().getAll()) {
+ if (entity.isChunkLoaded()) {
+ ++ret;
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public int getTileEntityCount() {
+ // We don't use the full world tile entity list, so we must iterate chunks
+ int size = 0;
+ for (ChunkHolder playerchunk : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world)) {
+ net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk();
+ if (chunk == null) {
+ continue;
+ }
+ size += chunk.blockEntities.size();
+ }
+ return size;
+ }
+
+ @Override
+ public int getTickableTileEntityCount() {
+ return world.getTotalTileEntityTickers();
+ }
+
+ @Override
+ public int getChunkCount() {
+ int ret = 0;
+
+ for (ChunkHolder chunkHolder : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world)) {
+ if (chunkHolder.getTickingChunk() != null) {
+ ++ret;
+ }
+ }
+
+ return ret;
+ }
+
+ @Override
+ public int getPlayerCount() {
+ return world.players().size();
+ }
+ // Paper end
+
private static final Random rand = new Random();
public CraftWorld(ServerLevel world, ChunkGenerator gen, BiomeProvider biomeProvider, Environment env) {

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 7 Jan 2017 15:41:58 -0500
Subject: [PATCH] Enforce Sync Player Saves
Saving players async is extremely dangerous. This will force it to main
the same way we handle async chunk loads.
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index e39619717f089162e2e3bf12cd00eb390a59c4bf..274f396d5bc01ac1cbeec4a1f2010b3e79fa1568 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1052,11 +1052,13 @@ public abstract class PlayerList {
}
public void saveAll() {
+ io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
MinecraftTimings.savePlayers.startTiming(); // Paper
for (int i = 0; i < this.players.size(); ++i) {
- this.save((ServerPlayer) this.players.get(i));
+ this.save(this.players.get(i));
}
MinecraftTimings.savePlayers.stopTiming(); // Paper
+ return null; }); // Paper - ensure main
}
public UserWhiteList getWhiteList() {

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alfie Cleveland <alfeh@me.com>
Date: Sun, 8 Jan 2017 04:31:36 +0000
Subject: [PATCH] Don't allow entities to ride themselves - #572
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0c0060cdc35e0d8d3098a0ade8080f91dbc81a2b..a28aa788f46dc944e174957fbed23dfeeff1eb72 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2404,6 +2404,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
protected boolean addPassenger(Entity entity) { // CraftBukkit
+ if (entity == this) throw new IllegalArgumentException("Entities cannot become a passenger of themselves"); // Paper - issue 572
if (entity.getVehicle() != this) {
throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
} else {

View file

@ -1,353 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 19 Dec 2017 16:31:46 -0500
Subject: [PATCH] ExperienceOrbs API for Reason/Source/Triggering player
Adds lots of information about why this orb exists.
Replaces isFromBottle() with logic that persists entity reloads too.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 7f87800a8371c80ef216f4ed0526639f43a20232..2775203a5bb7392428f1305730761e425300a8a9 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -419,7 +419,7 @@ public class ServerPlayerGameMode {
// Drop event experience
if (flag && event != null) {
- iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop());
+ iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper
}
return true;
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index c12493cc369f632c4aa9535cde9b8629a0b2eb86..2ba92563f95e2899db29bf9b017e1b385a5bda3c 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -38,13 +38,65 @@ public class ExperienceOrb extends Entity {
public int value;
private int count;
private Player followingPlayer;
+ // Paper start
+ public java.util.UUID sourceEntityId;
+ public java.util.UUID triggerEntityId;
+ public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
+
+ private void loadPaperNBT(CompoundTag nbttagcompound) {
+ if (!nbttagcompound.contains("Paper.ExpData", 10)) { // 10 = compound
+ return;
+ }
+ CompoundTag comp = nbttagcompound.getCompound("Paper.ExpData");
+ if (comp.hasUUID("source")) {
+ this.sourceEntityId = comp.getUUID("source");
+ }
+ if (comp.hasUUID("trigger")) {
+ this.triggerEntityId = comp.getUUID("trigger");
+ }
+ if (comp.contains("reason")) {
+ String reason = comp.getString("reason");
+ try {
+ this.spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.valueOf(reason);
+ } catch (Exception e) {
+ this.level.getCraftServer().getLogger().warning("Invalid spawnReason set for experience orb: " + e.getMessage() + " - " + reason);
+ }
+ }
+ }
+ private void savePaperNBT(CompoundTag nbttagcompound) {
+ CompoundTag comp = new CompoundTag();
+ if (this.sourceEntityId != null) {
+ comp.putUUID("source", this.sourceEntityId);
+ }
+ if (this.triggerEntityId != null) {
+ comp.putUUID("trigger", triggerEntityId);
+ }
+ if (this.spawnReason != null && this.spawnReason != org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN) {
+ comp.putString("reason", this.spawnReason.name());
+ }
+ nbttagcompound.put("Paper.ExpData", comp);
+ }
+ @io.papermc.paper.annotation.DoNotUse
+ @Deprecated
public ExperienceOrb(Level world, double x, double y, double z, int amount) {
+ this(world, x, y, z, amount, null, null);
+ }
+
+ public ExperienceOrb(Level world, double d0, double d1, double d2, int i, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId) {
+ this(world, d0, d1, d2, i, reason, triggerId, null);
+ }
+
+ public ExperienceOrb(Level world, double d0, double d1, double d2, int i, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) {
this(EntityType.EXPERIENCE_ORB, world);
- this.setPos(x, y, z);
+ this.sourceEntityId = sourceId != null ? sourceId.getUUID() : null;
+ this.triggerEntityId = triggerId != null ? triggerId.getUUID() : null;
+ this.spawnReason = reason != null ? reason : org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
+ // Paper end
+ this.setPos(d0, d1, d2);
this.setYRot((float) (this.random.nextDouble() * 360.0D));
this.setDeltaMovement((this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D, this.random.nextDouble() * 0.2D * 2.0D, (this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D);
- this.value = amount;
+ this.value = i;
}
public ExperienceOrb(EntityType<? extends ExperienceOrb> type, Level world) {
@@ -154,12 +206,20 @@ public class ExperienceOrb extends Entity {
}
public static void award(ServerLevel world, Vec3 pos, int amount) {
+ // Paper start - add reasons for orbs
+ award(world, pos, amount, null, null, null);
+ }
+ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId) {
+ award(world, pos, amount, reason, triggerId, null);
+ }
+ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) {
+ // Paper end - add reasons for orbs
while (amount > 0) {
int j = ExperienceOrb.getExperienceValue(amount);
amount -= j;
if (!ExperienceOrb.tryMergeToExisting(world, pos, j)) {
- world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j));
+ world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j, reason, triggerId, sourceId)); // Paper - add reason
}
}
@@ -229,6 +289,7 @@ public class ExperienceOrb extends Entity {
nbt.putShort("Age", (short) this.age);
nbt.putShort("Value", (short) this.value);
nbt.putInt("Count", this.count);
+ this.savePaperNBT(nbt); // Paper
}
@Override
@@ -237,6 +298,7 @@ public class ExperienceOrb extends Entity {
this.age = nbt.getShort("Age");
this.value = nbt.getShort("Value");
this.count = Math.max(nbt.getInt("Count"), 1);
+ this.loadPaperNBT(nbt); // Paper
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 16ec3763e6d13a2dd3e1cc8cd898c6d783ac070c..728370332d284fbe95fed57f4e5a88cabbe3f146 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1727,7 +1727,8 @@ public abstract class LivingEntity extends Entity {
protected void dropExperience() {
// CraftBukkit start - Update getExpReward() above if the removed if() changes!
if (true && !(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time
- ExperienceOrb.award((ServerLevel) this.level, this.position(), this.expToDrop);
+ LivingEntity attacker = this.lastHurtByPlayer != null ? this.lastHurtByPlayer : this.lastHurtByMob; // Paper
+ ExperienceOrb.award((ServerLevel) this.level, this.position(), this.expToDrop, this instanceof ServerPlayer ? org.bukkit.entity.ExperienceOrb.SpawnReason.PLAYER_DEATH : org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, attacker, this); // Paper
this.expToDrop = 0;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java
index 3cdd7180a41b87caa942d2b3436ba90726686ecb..6216513805add7c8f52e1ed6c77e2d26786b3ab5 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java
@@ -262,7 +262,7 @@ public abstract class Animal extends AgeableMob {
if (world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
// CraftBukkit start - use event experience
if (experience > 0) {
- world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), experience));
+ world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityageable)); // Paper
}
// CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java
index 125498c2cd1c3846e05a91774bb028e7a01fb238..dd124ccbdc7efe0e41b3a04abddcb328cac44948 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
@@ -897,7 +897,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Type> {
if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
// CraftBukkit start - use event experience
if (experience > 0) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience));
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityfox)); // Paper
}
// CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
index 721b6a5b4775877cc9f75d25379b4fb7c7cb3178..ab4e8ff5fe4f53bfda1d7b152aa89e6772bc3a16 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
@@ -450,7 +450,7 @@ public class Turtle extends Animal {
RandomSource randomsource = this.animal.getRandom();
if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1));
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper;
}
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
index 8852cc6253c8bc1a9f7591cd2b0beb95bb4f4d33..f2e84e832ad95df26fe3b9ba439ce38fc59b3585 100644
--- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
@@ -277,7 +277,7 @@ public class Frog extends Animal implements VariantHolder<FrogVariant> {
this.getBrain().setMemory(MemoryModuleType.IS_PREGNANT, Unit.INSTANCE);
world.broadcastEntityEvent(this, (byte)18);
if (world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1));
+ world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, serverPlayer)); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
index 89366ca29386fcbd03c3fc94d58451e714a1d779..a889be9dd2a94b531a227ff69a5e761e103067be 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -647,7 +647,7 @@ public class EnderDragon extends Mob implements Enemy {
if (this.level instanceof ServerLevel) {
if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
- ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.08F));
+ ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
}
if (this.dragonDeathTime == 1 && !this.isSilent()) {
@@ -677,7 +677,7 @@ public class EnderDragon extends Mob implements Enemy {
this.yBodyRot = this.getYRot();
if (this.dragonDeathTime == 200 && this.level instanceof ServerLevel) {
if (true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
- ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.2F));
+ ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
}
if (this.dragonFight != null) {
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index dfc67cd0ef52939be5e5a9952cfcdb4d87bf0d82..bbbb26550b0c5b36d9c7204f075aa90b79b85ff0 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -624,7 +624,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
if (offer.shouldRewardExp()) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5D, this.getZ(), i));
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
index 9bc9307966b77e34cb091fc895db3d3a66f7be82..e594cf4b8084b7448c29208a2070e766e391713d 100644
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
@@ -186,7 +186,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
if (offer.shouldRewardExp()) {
int i = 3 + this.random.nextInt(4);
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5D, this.getZ(), i));
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index 9d0df8d64a2cfd2458295a214829f277798030f0..75449d8575ac1b67aaa94d0f3fc08244728ec8a8 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -514,7 +514,7 @@ public class FishingHook extends Projectile {
this.level.addFreshEntity(entityitem);
// CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop()
if (playerFishEvent.getExpToDrop() > 0) {
- entityhuman.level.addFreshEntity(new ExperienceOrb(entityhuman.level, entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop()));
+ entityhuman.level.addFreshEntity(new ExperienceOrb(entityhuman.level, entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this)); // Paper
}
// CraftBukkit end
if (itemstack1.is(ItemTags.FISHES)) {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
index db6b1a9804a6d75dce22b780044beb04ca69cc94..dcbbff3a8dfcac869f07025e0e8e3d9c47956093 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
@@ -51,7 +51,7 @@ public class ThrownExperienceBottle extends ThrowableItemProjectile {
}
// CraftBukkit end
- ExperienceOrb.award((ServerLevel) this.level, this.position(), i);
+ ExperienceOrb.award((ServerLevel) this.level, this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper
this.discard();
}
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index 3a4808cd669d68e030de081ba17e028cbb652386..e3c3d202a9852adf32d5e94c9011c3799668419b 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -97,7 +97,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
context.execute((world, blockposition) -> {
if (world instanceof ServerLevel) {
- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world));
+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper
}
world.levelEvent(1042, blockposition, 0);
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
index 6b22de4b22aeec101076199f1e20376dd4b31f4d..11b0b1a217648496ccf08f09bb3aa53904ffa9cb 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -374,8 +374,13 @@ public class Block extends BlockBehaviour implements ItemLike {
}
public void popExperience(ServerLevel world, BlockPos pos, int size) {
+ // Paper start - add player parameter
+ popExperience(world, pos, size, null);
+ }
+ public void popExperience(ServerLevel world, BlockPos pos, int size, net.minecraft.server.level.ServerPlayer player) {
+ // Paper end - add player parameter
if (world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
- ExperienceOrb.award(world, Vec3.atCenterOf(pos), size);
+ ExperienceOrb.award(world, Vec3.atCenterOf(pos), size, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, player); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 04e7716f7a9b5d203aacd83b89b610760a19bb9e..8137682be60eb617738f7b257780a49182ef970c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -636,7 +636,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
j = event.getExpToDrop();
// CraftBukkit end
- ExperienceOrb.award(worldserver, vec3d, j);
+ ExperienceOrb.award(worldserver, vec3d, j, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, entityhuman); // Paper
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 6dbfd907766422258790f23a3279d2013db3de24..7e16cb08ca1ab2c0b6c0079ac7ffe00cfd758e18 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -915,7 +915,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
} else if (TNTPrimed.class.isAssignableFrom(clazz)) {
entity = new PrimedTnt(world, x, y, z, null);
} else if (ExperienceOrb.class.isAssignableFrom(clazz)) {
- entity = new net.minecraft.world.entity.ExperienceOrb(world, x, y, z, 0);
+ entity = new net.minecraft.world.entity.ExperienceOrb(world, x, y, z, 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null); // Paper
} else if (LightningStrike.class.isAssignableFrom(clazz)) {
entity = net.minecraft.world.entity.EntityType.LIGHTNING_BOLT.create(world);
entity.moveTo(location.getX(), location.getY(), location.getZ());
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
index 40713228b149b4532fcee3a54bbe63e161318258..84899284703baeb04bfc79251941265d52ac07e8 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
@@ -19,6 +19,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb {
this.getHandle().value = value;
}
+ // Paper start
+ public java.util.UUID getTriggerEntityId() {
+ return getHandle().triggerEntityId;
+ }
+ public java.util.UUID getSourceEntityId() {
+ return getHandle().sourceEntityId;
+ }
+ public SpawnReason getSpawnReason() {
+ return getHandle().spawnReason;
+ }
+ // Paper end
+
@Override
public net.minecraft.world.entity.ExperienceOrb getHandle() {
return (net.minecraft.world.entity.ExperienceOrb) entity;

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 22 Jan 2017 18:07:56 -0500
Subject: [PATCH] Cap Entity Collisions
Limit a single entity to colliding a max of configurable times per tick.
This will alleviate issues where living entities are hoarded in 1x1 pens
This is not tied to the maxEntityCramming rule. Cramming will still apply
just as it does in Vanilla, but entity pushing logic will be capped.
You can set this to 0 to disable collisions.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index a28aa788f46dc944e174957fbed23dfeeff1eb72..760596375e26b4cd73cc378758f4bf761c3352a5 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -379,6 +379,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
public void inactiveTick() { }
// Spigot end
// Paper start
+ protected int numCollisions = 0; // Paper
@javax.annotation.Nullable
private org.bukkit.util.Vector origin;
@javax.annotation.Nullable
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 728370332d284fbe95fed57f4e5a88cabbe3f146..b6aaebb5359c8162359b377b3485c3fcf91587e1 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3313,8 +3313,11 @@ public abstract class LivingEntity extends Entity {
}
}
- for (j = 0; j < list.size(); ++j) {
+ this.numCollisions = Math.max(0, this.numCollisions - this.level.paperConfig().collisions.maxEntityCollisions); // Paper
+ for (j = 0; j < list.size() && this.numCollisions < this.level.paperConfig().collisions.maxEntityCollisions; ++j) { // Paper
Entity entity = (Entity) list.get(j);
+ entity.numCollisions++; // Paper
+ this.numCollisions++; // Paper
this.doPush(entity);
}

View file

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 5 Feb 2017 00:04:04 -0500
Subject: [PATCH] Remove CraftScheduler Async Task Debugger
I have not once ever seen this system help debug a crash.
One report of a suspected memory leak with the system.
This adds additional overhead to asynchronous task dispatching
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index dfc2789009fcaa08baa8054bdac915590b8701d6..d96292052633941102c052894bef747817b2998f 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -445,7 +445,7 @@ public class CraftScheduler implements BukkitScheduler {
}
this.parsePending();
} else {
- this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
+ //this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper
this.executor.execute(new ServerSchedulerReportingWrapper(task)); // Paper
// We don't need to parse pending
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
@@ -462,7 +462,7 @@ public class CraftScheduler implements BukkitScheduler {
this.pending.addAll(temp);
temp.clear();
MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper
- this.debugHead = this.debugHead.getNextHead(currentTick);
+ //this.debugHead = this.debugHead.getNextHead(currentTick); // Paper
}
private void addTask(final CraftTask task) {
@@ -527,10 +527,15 @@ public class CraftScheduler implements BukkitScheduler {
@Override
public String toString() {
+ // Paper start
+ return "";
+ /*
int debugTick = this.currentTick;
StringBuilder string = new StringBuilder("Recent tasks from ").append(debugTick - CraftScheduler.RECENT_TICKS).append('-').append(debugTick).append('{');
this.debugHead.debugTo(string);
return string.append('}').toString();
+ */
+ // Paper end
}
@Deprecated

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sat, 18 Feb 2017 19:29:58 -0600
Subject: [PATCH] Do not let armorstands drown
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
index 58882569595a21b0499921dfddcbc9d01248cf1c..4398a33df4e0f0e9d28c51af3d48e41d957d7c9e 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -935,5 +935,12 @@ public class ArmorStand extends LivingEntity {
super.move(type, movement);
}
}
+
+ // Paper start
+ @Override
+ public boolean canBreatheUnderwater() { // Skips a bit of damage handling code, probably a micro-optimization
+ return true;
+ }
+ // Paper end
// Paper end
}

View file

@ -1,290 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Fri, 12 May 2017 23:34:11 -0500
Subject: [PATCH] Properly handle async calls to restart the server
The watchdog thread calls the server restart function asynchronously. Prior to
this change, it attempted to do several non-safe operations from the watchdog
thread, rather than the main. Specifically, because of a separate upstream change,
it causes player entities to be ticked asynchronously, among other things.
This is dangerous.
This patch moves the old handling into a synchronous variant, for calls from the
restart command, and adds separate handling for async calls, such as those from
the watchdog thread.
When calling from the watchdog thread, we cannot assume the main thread is in a
tickable state; it may be completely deadlocked. In order to handle this, we mark
the server as stopping, in order to account for situations where the server should
complete a tick reasonbly soon, i.e. 99% of cases.
Should the server not enter a state where it is stopping within 10 seconds, We
will assume that the server has in fact deadlocked and will proceed to force
kill the server.
This modification does not force restart the server should we actually enter a
deadlocked state where the server is stopping, whereas this will in most cases
exit within a reasonable amount of time, to put a fixed limit on a process that
will have plugins and worlds saving to the disk has a high potential to result
in corruption/dataloss.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0a419ec121bbddffa0424147c642f79d4e5eb817..ddc446e54b69c79fa0153478bb859bf981e9da5c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -233,6 +233,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private Map<ResourceKey<Level>, ServerLevel> levels;
private PlayerList playerList;
private volatile boolean running;
+ private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
private boolean stopped;
private int tickCount;
protected final Proxy proxy;
@@ -902,7 +903,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (this.playerList != null) {
MinecraftServer.LOGGER.info("Saving players");
this.playerList.saveAll();
- this.playerList.removeAll();
+ this.playerList.removeAll(this.isRestarting); // Paper
try { Thread.sleep(100); } catch (InterruptedException ex) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets
}
@@ -953,6 +954,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
public void halt(boolean waitForShutdown) {
+ // Paper start - allow passing of the intent to restart
+ this.safeShutdown(waitForShutdown, false);
+ }
+ public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
+ this.isRestarting = isRestarting;
+ // Paper end
this.running = false;
if (waitForShutdown) {
try {
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 274f396d5bc01ac1cbeec4a1f2010b3e79fa1568..8062488d8d9e830d07cd136465c5d9227ba1ac1d 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1164,8 +1164,15 @@ public abstract class PlayerList {
}
public void removeAll() {
+ // Paper start - Extract method to allow for restarting flag
+ this.removeAll(false);
+ }
+
+ public void removeAll(boolean isRestarting) {
+ // Paper end
// CraftBukkit start - disconnect safely
for (ServerPlayer player : this.players) {
+ if (isRestarting) player.connection.disconnect(org.spigotmc.SpigotConfig.restartMessage); else // Paper
player.connection.disconnect(this.server.server.shutdownMessage()); // CraftBukkit - add custom shutdown message // Paper - Adventure
}
// CraftBukkit end
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
index 94d8ba376cd1f024b244654cac9bb62bb19e3060..a142a56a920e153ed84c08cece993f10d76f7793 100644
--- a/src/main/java/org/spigotmc/RestartCommand.java
+++ b/src/main/java/org/spigotmc/RestartCommand.java
@@ -46,86 +46,134 @@ public class RestartCommand extends Command
org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
try
{
- String[] split = restartScript.split( " " );
- if ( split.length > 0 && new File( split[0] ).isFile() )
+ // Paper - extract method and cleanup
+ boolean isRestarting = addShutdownHook( restartScript );
+ if ( isRestarting )
{
- System.out.println( "Attempting to restart with " + restartScript );
+ System.out.println( "Attempting to restart with " + SpigotConfig.restartScript );
+ } else
+ {
+ System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
+ }
+ // Stop the watchdog
+ WatchdogThread.doStop();
- // Disable Watchdog
- WatchdogThread.doStop();
+ shutdownServer( isRestarting );
+ // Paper end
+ } catch ( Exception ex )
+ {
+ ex.printStackTrace();
+ }
+ }
- // Kick all players
- for ( ServerPlayer p : (List<ServerPlayer>) MinecraftServer.getServer().getPlayerList().players )
- {
- p.connection.disconnect(SpigotConfig.restartMessage);
- }
- // Give the socket a chance to send the packets
- try
- {
- Thread.sleep( 100 );
- } catch ( InterruptedException ex )
- {
- }
- // Close the socket so we can rebind with the new process
- MinecraftServer.getServer().getConnection().stop();
+ // Paper start - sync copied from above with minor changes, async added
+ private static void shutdownServer(boolean isRestarting)
+ {
+ if ( MinecraftServer.getServer().isSameThread() )
+ {
+ // Kick all players
+ for ( ServerPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) )
+ {
+ p.connection.disconnect(SpigotConfig.restartMessage);
+ }
+ // Give the socket a chance to send the packets
+ try
+ {
+ Thread.sleep( 100 );
+ } catch ( InterruptedException ex )
+ {
+ }
- // Give time for it to kick in
- try
- {
- Thread.sleep( 100 );
- } catch ( InterruptedException ex )
- {
- }
+ closeSocket();
- // Actually shutdown
- try
- {
- MinecraftServer.getServer().close();
- } catch ( Throwable t )
- {
- }
+ // Actually shutdown
+ try
+ {
+ MinecraftServer.getServer().close(); // calls stop()
+ } catch ( Throwable t )
+ {
+ }
+
+ // Actually stop the JVM
+ System.exit( 0 );
- // This will be done AFTER the server has completely halted
- Thread shutdownHook = new Thread()
+ } else
+ {
+ // Mark the server to shutdown at the end of the tick
+ MinecraftServer.getServer().safeShutdown( false, isRestarting );
+
+ // wait 10 seconds to see if we're actually going to try shutdown
+ try
+ {
+ Thread.sleep( 10000 );
+ }
+ catch (InterruptedException ignored)
+ {
+ }
+
+ // Check if we've actually hit a state where the server is going to safely shutdown
+ // if we have, let the server stop as usual
+ if (MinecraftServer.getServer().isStopped()) return;
+
+ // If the server hasn't stopped by now, assume worse case and kill
+ closeSocket();
+ System.exit( 0 );
+ }
+ }
+ // Paper end
+
+ // Paper - Split from moved code
+ private static void closeSocket()
+ {
+ // Close the socket so we can rebind with the new process
+ MinecraftServer.getServer().getConnection().stop();
+
+ // Give time for it to kick in
+ try
+ {
+ Thread.sleep( 100 );
+ } catch ( InterruptedException ex )
+ {
+ }
+ }
+ // Paper end
+
+ // Paper start - copied from above and modified to return if the hook registered
+ private static boolean addShutdownHook(String restartScript)
+ {
+ String[] split = restartScript.split( " " );
+ if ( split.length > 0 && new File( split[0] ).isFile() )
+ {
+ Thread shutdownHook = new Thread()
+ {
+ @Override
+ public void run()
{
- @Override
- public void run()
+ try
{
- try
+ String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH);
+ if ( os.contains( "win" ) )
{
- String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH);
- if ( os.contains( "win" ) )
- {
- Runtime.getRuntime().exec( "cmd /c start " + restartScript );
- } else
- {
- Runtime.getRuntime().exec( "sh " + restartScript );
- }
- } catch ( Exception e )
+ Runtime.getRuntime().exec( "cmd /c start " + restartScript );
+ } else
{
- e.printStackTrace();
+ Runtime.getRuntime().exec( "sh " + restartScript );
}
+ } catch ( Exception e )
+ {
+ e.printStackTrace();
}
- };
-
- shutdownHook.setDaemon( true );
- Runtime.getRuntime().addShutdownHook( shutdownHook );
- } else
- {
- System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
-
- // Actually shutdown
- try
- {
- MinecraftServer.getServer().close();
- } catch ( Throwable t )
- {
}
- }
- System.exit( 0 );
- } catch ( Exception ex )
+ };
+
+ shutdownHook.setDaemon( true );
+ Runtime.getRuntime().addShutdownHook( shutdownHook );
+ return true;
+ } else
{
- ex.printStackTrace();
+ return false;
}
}
+ // Paper end
+
}

Some files were not shown because too many files have changed in this diff Show more