more patches
This commit is contained in:
parent
0b8147f68e
commit
44e22b45a5
23 changed files with 132 additions and 132 deletions
|
@ -1,96 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sat, 1 Feb 2020 16:50:39 +0100
|
||||
Subject: [PATCH] Pillager patrol spawn settings and per player options
|
||||
|
||||
This adds config options for defining the spawn chance, spawn delay and
|
||||
spawn start day as well as toggles for handling the spawn delay and
|
||||
start day per player. (Based on the time played statistic)
|
||||
When not per player it will use the Vanilla mechanic of one delay per
|
||||
world and the world age for the start day.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index b014f1bd167bad3e1dc613dce5c929f201ef27cc..421be41fc09d53b50c08e74f9c32a198e90a2c7c 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -244,6 +244,7 @@ public class ServerPlayer extends Player {
|
||||
public boolean wonGame;
|
||||
private int containerUpdateDelay; // Paper
|
||||
public long loginTime; // Paper
|
||||
+ public int patrolSpawnDelay; // Paper - per player patrol spawns
|
||||
// Paper start - cancellable death event
|
||||
public boolean queueHealthUpdatePacket = false;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
index e5918fa3be107ac3a2fc8831fd78733a7506730a..a908652f1ebb426d265ef614746f70cd1e538268 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
@@ -25,7 +25,7 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
|
||||
@Override
|
||||
public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
|
||||
- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper
|
||||
if (!spawnMonsters) {
|
||||
return 0;
|
||||
} else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) {
|
||||
@@ -33,23 +33,51 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
} else {
|
||||
RandomSource randomsource = world.random;
|
||||
|
||||
- --this.nextTick;
|
||||
- if (this.nextTick > 0) {
|
||||
+ // Paper start - Patrol settings
|
||||
+ // Random player selection moved up for per player spawning and configuration
|
||||
+ int j = world.players().size();
|
||||
+ if (j < 1) {
|
||||
return 0;
|
||||
+ }
|
||||
+
|
||||
+ net.minecraft.server.level.ServerPlayer entityhuman = world.players().get(randomsource.nextInt(j));
|
||||
+ if (entityhuman.isSpectator()) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ int patrolSpawnDelay;
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) {
|
||||
+ --entityhuman.patrolSpawnDelay;
|
||||
+ patrolSpawnDelay = entityhuman.patrolSpawnDelay;
|
||||
} else {
|
||||
- this.nextTick += 12000 + randomsource.nextInt(1200);
|
||||
- long i = world.getDayTime() / 24000L;
|
||||
+ this.nextTick--;
|
||||
+ patrolSpawnDelay = this.nextTick;
|
||||
+ }
|
||||
+
|
||||
+ if (patrolSpawnDelay > 0) {
|
||||
+ return 0;
|
||||
+ } else {
|
||||
+ long days;
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) {
|
||||
+ days = entityhuman.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
|
||||
+ } else {
|
||||
+ days = world.getDayTime() / 24000L;
|
||||
+ }
|
||||
+ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) {
|
||||
+ entityhuman.patrolSpawnDelay += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200);
|
||||
+ } else {
|
||||
+ this.nextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200);
|
||||
+ }
|
||||
|
||||
- if (i >= 5L && world.isDay()) {
|
||||
- if (randomsource.nextInt(5) != 0) {
|
||||
+ if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) {
|
||||
+ if (randomsource.nextDouble() >= world.paperConfig().entities.behavior.pillagerPatrols.spawnChance) {
|
||||
+ // Paper end
|
||||
return 0;
|
||||
} else {
|
||||
- int j = world.players().size();
|
||||
|
||||
if (j < 1) {
|
||||
return 0;
|
||||
} else {
|
||||
- Player entityhuman = (Player) world.players().get(randomsource.nextInt(j));
|
||||
|
||||
if (entityhuman.isSpectator()) {
|
||||
return 0;
|
|
@ -1,25 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 31 Mar 2020 03:50:42 -0400
|
||||
Subject: [PATCH] Remote Connections shouldn't hold up shutdown
|
||||
|
||||
Bugs in the connection logic appears to leave stale connections even, preventing shutdown
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 338841804a92bea5ca074300eaea9374d1b77020..f22c50f0a2ef05e9f52550db7c40b5b99632650c 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -391,11 +391,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
|
||||
if (this.rconThread != null) {
|
||||
- this.rconThread.stop();
|
||||
+ //this.remoteControlListener.b(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
if (this.queryThreadGs4 != null) {
|
||||
- this.queryThreadGs4.stop();
|
||||
+ //this.remoteStatusListener.b(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
System.exit(0); // CraftBukkit
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: chickeneer <emcchickeneer@gmail.com>
|
||||
Date: Tue, 17 Mar 2020 14:18:50 -0500
|
||||
Subject: [PATCH] Do not allow bees to load chunks for beehives
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
index 5049d72f080bb82ca0e1fc5e2348b3605a0204f1..2a6dda97fcc761eb3e7109e032d3bb10c83908d7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -409,6 +409,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
if (this.hivePos == null) {
|
||||
return false;
|
||||
} else {
|
||||
+ if (!this.level.isLoadedAndInBounds(hivePos)) return false; // Paper
|
||||
BlockEntity tileentity = this.level.getBlockEntity(this.hivePos);
|
||||
|
||||
return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby();
|
||||
@@ -442,6 +443,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
}
|
||||
|
||||
private boolean doesHiveHaveSpace(BlockPos pos) {
|
||||
+ if (!this.level.isLoadedAndInBounds(pos)) return false; // Paper
|
||||
BlockEntity tileentity = this.level.getBlockEntity(pos);
|
||||
|
||||
return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false;
|
||||
@@ -919,6 +921,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
@Override
|
||||
public boolean canBeeUse() {
|
||||
if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerToCenterThan(Bee.this.position(), 2.0D)) {
|
||||
+ if (!Bee.this.level.isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper
|
||||
BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos);
|
||||
|
||||
if (tileentity instanceof BeehiveBlockEntity) {
|
||||
@@ -942,6 +945,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
+ if (!Bee.this.level.isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper
|
||||
BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos);
|
||||
|
||||
if (tileentity instanceof BeehiveBlockEntity) {
|
|
@ -1,47 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 01:42:39 -0400
|
||||
Subject: [PATCH] Prevent Double PlayerChunkMap adds crashing server
|
||||
|
||||
Suspected case would be around the technique used in .stopRiding
|
||||
Stack will identify any causer of this and warn instead of crashing.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 1c39d12a6e72954a24ad51d8d6346341dc1c5d22..9c5925bc6a0fb277970d46c34dd812cc765a537a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1033,6 +1033,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
public void addEntity(Entity entity) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
|
||||
+ // Paper start - ignore and warn about illegal addEntity calls instead of crashing server
|
||||
+ if (!entity.valid || entity.level != this.level || this.entityMap.containsKey(entity.getId())) {
|
||||
+ LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName()
|
||||
+ + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
int i = entitytypes.clientTrackingRange() * 16;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 67e59ac94c584a742bf5e6e2094459234603ef06..4bf38f9006be9e838c54783dafd40cf84553d627 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2324,7 +2324,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
public void onTrackingStart(Entity entity) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
|
||||
- ServerLevel.this.getChunkSource().addEntity(entity);
|
||||
+ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - moved down below valid=true
|
||||
if (entity instanceof ServerPlayer) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) entity;
|
||||
|
||||
@@ -2358,6 +2358,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
||||
entity.valid = true; // CraftBukkit
|
||||
+ ServerLevel.this.getChunkSource().addEntity(entity);
|
||||
// Paper start - Set origin location when the entity is being added to the world
|
||||
if (entity.getOriginVector() == null) {
|
||||
entity.setOrigin(entity.getBukkitEntity().getLocation());
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 17:16:48 -0400
|
||||
Subject: [PATCH] Don't tick dead players
|
||||
|
||||
Causes sync chunk loads and who knows what all else.
|
||||
This is safe because Spectators are skipped in unloaded chunks too in vanilla.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 421be41fc09d53b50c08e74f9c32a198e90a2c7c..e6945abd9337af07625793fb893718b00e67168a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -683,7 +683,7 @@ public class ServerPlayer extends Player {
|
||||
|
||||
public void doTick() {
|
||||
try {
|
||||
- if (!this.isSpectator() || !this.touchingUnloadedChunk()) {
|
||||
+ if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
|
||||
super.tick();
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 19:31:16 -0400
|
||||
Subject: [PATCH] Dead Player's shouldn't be able to move
|
||||
|
||||
This fixes a lot of game state issues where packets were delayed for processing
|
||||
due to 1.15's new queue but processed while dead.
|
||||
|
||||
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 a7e0203cc4bf7d98b65230fdbc4d873eeabdf9da..1ada0736ce35c0299e40d4ce8fbe49f170ea0c6f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1159,7 +1159,7 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
@Override
|
||||
protected boolean isImmobile() {
|
||||
- return super.isImmobile() || this.isSleeping();
|
||||
+ return super.isImmobile() || this.isSleeping() || this.isRemoved() || !valid; // Paper - player's who are dead or not in a world shouldn't move...
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,111 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 2 Apr 2020 02:37:57 -0400
|
||||
Subject: [PATCH] Optimize Collision to not load chunks
|
||||
|
||||
The collision code takes an AABB and generates a cuboid of checks rather
|
||||
than a cylinder, so at high velocity this can generate a lot of chunk checks.
|
||||
|
||||
Treat an unloaded chunk as a collision for entities, and also for players if
|
||||
the "prevent moving into unloaded chunks" setting is enabled.
|
||||
|
||||
If that serting is not enabled, collisions will be ignored for players, since
|
||||
movement will load only the chunk the player enters anyways and avoids loading
|
||||
massive amounts of surrounding chunks due to large AABB lookups.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 4efa85f9c18927248dc2397df0bd3cd0a9063347..635d803066fa34a13174935ba0b63a0c86c0b1f4 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -820,6 +820,7 @@ public abstract class PlayerList {
|
||||
entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
// CraftBukkit end
|
||||
|
||||
+ worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
|
||||
while (avoidSuffocation && !worldserver1.noCollision((Entity) entityplayer1) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) {
|
||||
entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 479586efacc17e418dd8d64d884efe67355e1844..33d37c7e1bd7e676d70ba942476def5c49a59176 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -237,6 +237,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper
|
||||
|
||||
public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
|
||||
+ public boolean collisionLoadChunks = false; // Paper
|
||||
private CraftEntity bukkitEntity;
|
||||
|
||||
public @org.jetbrains.annotations.Nullable net.minecraft.server.level.ChunkMap.TrackedEntity tracker; // Paper
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockCollisions.java b/src/main/java/net/minecraft/world/level/BlockCollisions.java
|
||||
index 8390ce194ccc692139c0e870c16a7fb76ac8ba68..be578f14146b0184d5419d5b961c5d681f9ba7a3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockCollisions.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockCollisions.java
|
||||
@@ -66,22 +66,41 @@ public class BlockCollisions extends AbstractIterator<VoxelShape> {
|
||||
protected VoxelShape computeNext() {
|
||||
while(true) {
|
||||
if (this.cursor.advance()) {
|
||||
- int i = this.cursor.nextX();
|
||||
- int j = this.cursor.nextY();
|
||||
- int k = this.cursor.nextZ();
|
||||
+ int i = this.cursor.nextX(); final int x = i; // Paper
|
||||
+ int j = this.cursor.nextY(); final int y = j; // Paper
|
||||
+ int k = this.cursor.nextZ(); final int z = k; // Paper
|
||||
int l = this.cursor.getNextType();
|
||||
if (l == 3) {
|
||||
continue;
|
||||
}
|
||||
+ // Paper start - ensure we don't load chunks
|
||||
+ final @Nullable Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null;
|
||||
+ boolean far = source != null && io.papermc.paper.util.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14;
|
||||
+ this.pos.set(x, y, z);
|
||||
|
||||
- BlockGetter blockGetter = this.getChunk(i, k);
|
||||
- if (blockGetter == null) {
|
||||
+ BlockState blockState;
|
||||
+ if (this.collisionGetter instanceof net.minecraft.server.level.WorldGenRegion) {
|
||||
+ BlockGetter blockGetter = this.getChunk(x, z);
|
||||
+ if (blockGetter == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ blockState = blockGetter.getBlockState(this.pos);
|
||||
+ } else if ((!far && source instanceof net.minecraft.server.level.ServerPlayer) || (source != null && source.collisionLoadChunks)) {
|
||||
+ blockState = this.collisionGetter.getBlockState(this.pos);
|
||||
+ } else {
|
||||
+ blockState = this.collisionGetter.getBlockStateIfLoaded(this.pos);
|
||||
+ }
|
||||
+
|
||||
+ if (blockState == null) {
|
||||
+ if (!(source instanceof net.minecraft.server.level.ServerPlayer) || source.level.paperConfig().chunks.preventMovingIntoUnloadedChunks) {
|
||||
+ return Shapes.create(far ? source.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
|
||||
+ }
|
||||
+ // Paper end
|
||||
continue;
|
||||
}
|
||||
|
||||
- this.pos.set(i, j, k);
|
||||
- BlockState blockState = blockGetter.getBlockState(this.pos);
|
||||
- if (this.onlySuffocatingBlocks && !blockState.isSuffocating(blockGetter, this.pos) || l == 1 && !blockState.hasLargeCollisionShape() || l == 2 && !blockState.is(Blocks.MOVING_PISTON)) {
|
||||
+ // Paper - moved up
|
||||
+ if (/*this.onlySuffocatingBlocks && (!blockState.isSuffocating(blockGetter, this.pos)) ||*/ l == 1 && !blockState.hasLargeCollisionShape() || l == 2 && !blockState.is(Blocks.MOVING_PISTON)) { // Paper - onlySuffocatingBlocks is only true on the client, so we don't care about it here
|
||||
continue;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
index 4c373d6c8ddd9f5db88888cd8dbbfc24eb5df793..56d94c94fb0d4dc468bb5d69be655ddd5c6b5360 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
@@ -44,11 +44,13 @@ public interface CollisionGetter extends BlockGetter {
|
||||
}
|
||||
|
||||
default boolean noCollision(@Nullable Entity entity, AABB box) {
|
||||
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
|
||||
for(VoxelShape voxelShape : this.getBlockCollisions(entity, box)) {
|
||||
if (!voxelShape.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
|
||||
|
||||
if (!this.getEntityCollisions(entity, box).isEmpty()) {
|
||||
return false;
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 9 Apr 2020 21:20:33 -0400
|
||||
Subject: [PATCH] Don't move existing players to world spawn
|
||||
|
||||
This can cause a nasty server lag the spawn chunks are not kept loaded
|
||||
or they aren't finished loading yet, or if the world spawn radius is
|
||||
larger than the keep loaded range.
|
||||
|
||||
By skipping this, we avoid potential for a large spike on server start.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.level.ServerPlayer fudgeSpawnLocation(Lnet/minecraft/server/level/ServerLevel;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index e6945abd9337af07625793fb893718b00e67168a..7dbf61d79db8a7f08e518c7858142bb0e0f469c4 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -336,7 +336,7 @@ public class ServerPlayer extends Player {
|
||||
this.stats = server.getPlayerList().getPlayerStats(this);
|
||||
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
||||
this.setMaxUpStep(1.0F);
|
||||
- this.fudgeSpawnLocation(world);
|
||||
+ //this.fudgeSpawnLocation(world); // Paper - don't move to spawn on login, only first join
|
||||
|
||||
this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
|
||||
|
||||
@@ -570,7 +570,7 @@ public class ServerPlayer extends Player {
|
||||
position = Vec3.atCenterOf(world.getSharedSpawnPos());
|
||||
}
|
||||
this.level = world;
|
||||
- this.setPos(position);
|
||||
+ this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet
|
||||
}
|
||||
this.gameMode.setLevel((ServerLevel) world);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 635d803066fa34a13174935ba0b63a0c86c0b1f4..3f5706d4b30b74ba54032ed48d37990ce6ddd715 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -229,6 +229,7 @@ public abstract class PlayerList {
|
||||
// Paper start
|
||||
if (nbttagcompound == null) {
|
||||
player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
|
||||
+ player.fudgeSpawnLocation(worldserver1); // only move to spawn on first login, otherwise, stay where you are....
|
||||
}
|
||||
// Paper end
|
||||
player.setLevel(worldserver1);
|
|
@ -1,169 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:53:29 -0700
|
||||
Subject: [PATCH] Optimize GoalSelector Goal.Flag Set operations
|
||||
|
||||
Optimise the stream.anyMatch statement to move to a bitset
|
||||
where we can replace the call with a single bitwise operation.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
index 6667ecc4b7eded4e20a415cef1e1b1179e6710b8..4379b9948f1eecfe6fd7dea98e298ad5f761019a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
@@ -4,7 +4,8 @@ import java.util.EnumSet;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public abstract class Goal {
|
||||
- private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
||||
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
|
||||
|
||||
public abstract boolean canUse();
|
||||
|
||||
@@ -30,8 +31,10 @@ public abstract class Goal {
|
||||
}
|
||||
|
||||
public void setFlags(EnumSet<Goal.Flag> controls) {
|
||||
- this.flags.clear();
|
||||
- this.flags.addAll(controls);
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ this.goalTypes.clear();
|
||||
+ this.goalTypes.addAllUnchecked(controls);
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,8 +42,10 @@ public abstract class Goal {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
- public EnumSet<Goal.Flag> getFlags() {
|
||||
- return this.flags;
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
|
||||
+ return this.goalTypes;
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
protected int adjustedTickDelay(int ticks) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index e5995d0db5dcfba59a873ff439601894fdacd556..b738ee2d3801fadfd09313f05ae24593e56b0ec6 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -30,10 +30,12 @@ public class GoalSelector {
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
|
||||
private final Supplier<ProfilerFiller> profiler;
|
||||
- private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
||||
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
|
||||
private int tickCount;
|
||||
private int newGoalRate = 3;
|
||||
private int curRate;
|
||||
+ private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
|
||||
|
||||
public GoalSelector(Supplier<ProfilerFiller> profiler) {
|
||||
this.profiler = profiler;
|
||||
@@ -65,26 +67,32 @@ public class GoalSelector {
|
||||
}
|
||||
// Paper end
|
||||
public void removeGoal(Goal goal) {
|
||||
- this.availableGoals.stream().filter((wrappedGoal) -> {
|
||||
- return wrappedGoal.getGoal() == goal;
|
||||
- }).filter(WrappedGoal::isRunning).forEach(WrappedGoal::stop);
|
||||
- this.availableGoals.removeIf((wrappedGoal) -> {
|
||||
- return wrappedGoal.getGoal() == goal;
|
||||
- });
|
||||
- }
|
||||
-
|
||||
- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet<Goal.Flag> controls) {
|
||||
- for(Goal.Flag flag : goal.getFlags()) {
|
||||
- if (controls.contains(flag)) {
|
||||
- return true;
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
|
||||
+ WrappedGoal goalWrapped = iterator.next();
|
||||
+ if (goalWrapped.getGoal() != goal) {
|
||||
+ continue;
|
||||
}
|
||||
+ if (goalWrapped.isRunning()) {
|
||||
+ goalWrapped.stop();
|
||||
+ }
|
||||
+ iterator.remove();
|
||||
}
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
+ }
|
||||
|
||||
- return false;
|
||||
+ private static boolean goalContainsAnyFlags(WrappedGoal goal, com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> controls) {
|
||||
+ return goal.getFlags().hasCommonElements(controls); // Paper
|
||||
}
|
||||
|
||||
private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map<Goal.Flag, WrappedGoal> goalsByControl) {
|
||||
- for(Goal.Flag flag : goal.getFlags()) {
|
||||
+ // Paper start
|
||||
+ long flagIterator = goal.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = goal.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= io.papermc.paper.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end
|
||||
if (!goalsByControl.getOrDefault(flag, NO_GOAL).canBeReplacedBy(goal)) {
|
||||
return false;
|
||||
}
|
||||
@@ -98,7 +106,7 @@ public class GoalSelector {
|
||||
profilerFiller.push("goalCleanup");
|
||||
|
||||
for(WrappedGoal wrappedGoal : this.availableGoals) {
|
||||
- if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.disabledFlags) || !wrappedGoal.canContinueToUse())) {
|
||||
+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) {
|
||||
wrappedGoal.stop();
|
||||
}
|
||||
}
|
||||
@@ -116,8 +124,14 @@ public class GoalSelector {
|
||||
profilerFiller.push("goalUpdate");
|
||||
|
||||
for(WrappedGoal wrappedGoal2 : this.availableGoals) {
|
||||
- if (!wrappedGoal2.isRunning() && !goalContainsAnyFlags(wrappedGoal2, this.disabledFlags) && goalCanBeReplacedForAllFlags(wrappedGoal2, this.lockedFlags) && wrappedGoal2.canUse()) {
|
||||
- for(Goal.Flag flag : wrappedGoal2.getFlags()) {
|
||||
+ // Paper start
|
||||
+ if (!wrappedGoal2.isRunning() && !goalContainsAnyFlags(wrappedGoal2, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoal2, this.lockedFlags) && wrappedGoal2.canUse()) {
|
||||
+ long flagIterator = wrappedGoal2.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = wrappedGoal2.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= io.papermc.paper.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end
|
||||
WrappedGoal wrappedGoal3 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
|
||||
wrappedGoal3.stop();
|
||||
this.lockedFlags.put(flag, wrappedGoal2);
|
||||
@@ -157,11 +171,11 @@ public class GoalSelector {
|
||||
}
|
||||
|
||||
public void disableControlFlag(Goal.Flag control) {
|
||||
- this.disabledFlags.add(control);
|
||||
+ this.goalTypes.addUnchecked(control); // Paper - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
public void enableControlFlag(Goal.Flag control) {
|
||||
- this.disabledFlags.remove(control);
|
||||
+ this.goalTypes.removeUnchecked(control); // Paper - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
public void setControlFlag(Goal.Flag control, boolean enabled) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
index 6665ce5f48316e626907e6937d5ef1bc398a7ebd..51deb4455cac055ffa455e4f34aa30858d2fb448 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
@@ -69,8 +69,10 @@ public class WrappedGoal extends Goal {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public EnumSet<Goal.Flag> getFlags() {
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
|
||||
return this.goal.getFlags();
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
|
@ -1,548 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 12 Apr 2020 15:50:48 -0400
|
||||
Subject: [PATCH] Improved Watchdog Support
|
||||
|
||||
Forced Watchdog Crash support and Improve Async Shutdown
|
||||
|
||||
If the request to shut down the server is received while we are in
|
||||
a watchdog hang, immediately treat it as a crash and begin the shutdown
|
||||
process. Shutdown process is now improved to also shutdown cleanly when
|
||||
not using restart scripts either.
|
||||
|
||||
If a server is deadlocked, a server owner can send SIGUP (or any other signal
|
||||
the JVM understands to shut down as it currently does) and the watchdog
|
||||
will no longer need to wait until the full timeout, allowing you to trigger
|
||||
a close process and try to shut the server down gracefully, saving player and
|
||||
world data.
|
||||
|
||||
Previously there was no way to trigger this outside of waiting for a full watchdog
|
||||
timeout, which may be set to a really long time...
|
||||
|
||||
Additionally, fix everything to do with shutting the server down asynchronously.
|
||||
|
||||
Previously, nearly everything about the process was fragile and unsafe. Main might
|
||||
not have actually been frozen, and might still be manipulating state.
|
||||
|
||||
Or, some reuest might ask main to do something in the shutdown but main is dead.
|
||||
|
||||
Or worse, other things might start closing down items such as the Console or Thread Pool
|
||||
before we are fully shutdown.
|
||||
|
||||
This change tries to resolve all of these issues by moving everything into the stop
|
||||
method and guaranteeing only one thread is stopping the server.
|
||||
|
||||
We then issue Thread Death to the main thread of another thread initiates the stop process.
|
||||
We have to ensure Thread Death propagates correctly though to stop main completely.
|
||||
|
||||
This is to ensure that if main isn't truely stuck, it's not manipulating state we are trying to save.
|
||||
|
||||
This also moves all plugins who register "delayed init" tasks to occur just before "Done" so they
|
||||
are properly accounted for and wont trip watchdog on init.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
index 6aaed8e8bf8c721fc834da5c76ac72a4c3e92458..4b002e8b75d117b726b0de274a76d3596fce015b 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
@@ -92,7 +92,12 @@ public class Metrics {
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
private void startSubmitting() {
|
||||
- final Runnable submitTask = this::submitData;
|
||||
+ final Runnable submitTask = () -> {
|
||||
+ if (MinecraftServer.getServer().hasStopped()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ submitData();
|
||||
+ };
|
||||
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay.
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 336795dff742b7c6957fbd3476aff31d25a5e659..30a58229aa6dac5039511d0c0df5f2912ea7de9f 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -230,6 +230,7 @@ public class CrashReport {
|
||||
}
|
||||
|
||||
public static CrashReport forThrowable(Throwable cause, String title) {
|
||||
+ if (cause instanceof ThreadDeath) com.destroystokyo.paper.util.SneakyThrow.sneaky(cause); // Paper
|
||||
while (cause instanceof CompletionException && cause.getCause() != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index d00545c31de383470bcb8e4d9c6edad2f39c864c..ebc8446631a4c4abccd2292ec52b69a0b6685199 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -299,7 +299,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||
public int autosavePeriod;
|
||||
public Commands vanillaCommandDispatcher;
|
||||
- private boolean forceTicks;
|
||||
+ public boolean forceTicks; // Paper
|
||||
// CraftBukkit end
|
||||
// Spigot start
|
||||
public static final int TPS = 20;
|
||||
@@ -310,6 +310,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations;
|
||||
public static long currentTickLong = 0L; // Paper
|
||||
|
||||
+ public volatile Thread shutdownThread; // Paper
|
||||
+ public volatile boolean abnormalExit = false; // Paper
|
||||
+
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
||||
AtomicReference<S> atomicreference = new AtomicReference();
|
||||
Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system
|
||||
@@ -888,6 +891,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean hasStopped = false;
|
||||
+ public volatile boolean hasFullyShutdown = false; // Paper
|
||||
private final Object stopLock = new Object();
|
||||
public final boolean hasStopped() {
|
||||
synchronized (this.stopLock) {
|
||||
@@ -902,6 +906,19 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (this.hasStopped) return;
|
||||
this.hasStopped = true;
|
||||
}
|
||||
+ // Paper start - kill main thread, and kill it hard
|
||||
+ shutdownThread = Thread.currentThread();
|
||||
+ org.spigotmc.WatchdogThread.doStop(); // Paper
|
||||
+ if (!isSameThread()) {
|
||||
+ MinecraftServer.LOGGER.info("Stopping main thread (Ignore any thread death message you see! - DO NOT REPORT THREAD DEATH TO PAPER)");
|
||||
+ while (this.getRunningThread().isAlive()) {
|
||||
+ this.getRunningThread().stop();
|
||||
+ try {
|
||||
+ Thread.sleep(1);
|
||||
+ } catch (InterruptedException e) {}
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
if (this.metricsRecorder.isRecording()) {
|
||||
this.cancelRecordingMetrics();
|
||||
@@ -958,7 +975,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.getProfileCache().save(false); // Paper
|
||||
}
|
||||
// Spigot end
|
||||
+ // Paper start - move final shutdown items here
|
||||
+ LOGGER.info("Flushing Chunk IO");
|
||||
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
|
||||
+ LOGGER.info("Closing Thread Pool");
|
||||
+ Util.shutdownExecutors(); // Paper
|
||||
+ LOGGER.info("Closing Server");
|
||||
+ try {
|
||||
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ } catch (Exception e) {
|
||||
+ }
|
||||
+ this.onServerExit();
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public String getLocalIp() {
|
||||
@@ -1053,6 +1081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void runServer() {
|
||||
try {
|
||||
+ long serverStartTime = Util.getNanos(); // Paper
|
||||
if (!this.initServer()) {
|
||||
throw new IllegalStateException("Failed to initialize server");
|
||||
}
|
||||
@@ -1062,6 +1091,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.status = this.buildServerStatus();
|
||||
|
||||
// Spigot start
|
||||
+ // Paper start - move done tracking
|
||||
+ LOGGER.info("Running delayed init tasks");
|
||||
+ this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // run all 1 tick delay tasks during init,
|
||||
+ // this is going to be the first thing the tick process does anyways, so move done and run it after
|
||||
+ // everything is init before watchdog tick.
|
||||
+ // anything at 3+ won't be caught here but also will trip watchdog....
|
||||
+ // tasks are default scheduled at -1 + delay, and first tick will tick at 1
|
||||
+ String doneTime = String.format(java.util.Locale.ROOT, "%.3fs", (double) (Util.getNanos() - serverStartTime) / 1.0E9D);
|
||||
+ LOGGER.info("Done ({})! For help, type \"help\"", doneTime);
|
||||
+ // Paper end
|
||||
+
|
||||
+ org.spigotmc.WatchdogThread.tick(); // Paper
|
||||
org.spigotmc.WatchdogThread.hasStarted = true; // Paper
|
||||
Arrays.fill( recentTps, 20 );
|
||||
long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
|
||||
@@ -1122,6 +1163,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
JvmProfiler.INSTANCE.onServerTick(this.averageTickTime);
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
+ // Paper start
|
||||
+ if (throwable instanceof ThreadDeath) {
|
||||
+ MinecraftServer.LOGGER.error("Main thread terminated by WatchDog due to hard crash", throwable);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
MinecraftServer.LOGGER.error("Encountered an unexpected exception", throwable);
|
||||
// Spigot Start
|
||||
if ( throwable.getCause() != null )
|
||||
@@ -1152,14 +1199,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.services.profileCache().clearExecutor();
|
||||
}
|
||||
|
||||
- org.spigotmc.WatchdogThread.doStop(); // Spigot
|
||||
+ //org.spigotmc.WatchdogThread.doStop(); // Spigot // Paper - move into stop
|
||||
// CraftBukkit start - Restore terminal to original settings
|
||||
try {
|
||||
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// CraftBukkit end
|
||||
- this.onServerExit();
|
||||
+ //this.onServerExit(); // Paper - moved into stop
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1228,6 +1275,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@Override
|
||||
public TickTask wrapRunnable(Runnable runnable) {
|
||||
+ // Paper start - anything that does try to post to main during watchdog crash, run on watchdog
|
||||
+ if (this.hasStopped && Thread.currentThread().equals(shutdownThread)) {
|
||||
+ runnable.run();
|
||||
+ runnable = () -> {};
|
||||
+ }
|
||||
+ // Paper end
|
||||
return new TickTask(this.tickCount, runnable);
|
||||
}
|
||||
|
||||
@@ -1463,6 +1516,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
try {
|
||||
crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
|
||||
} catch (Throwable t) {
|
||||
+ if (throwable instanceof ThreadDeath) { throw (ThreadDeath)throwable; } // Paper
|
||||
throw new RuntimeException("Error generating crash report", t);
|
||||
}
|
||||
// Spigot End
|
||||
@@ -1961,7 +2015,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
this.worldData.setDataConfiguration(worlddataconfiguration);
|
||||
this.resources.managers.updateRegistryTags(this.registryAccess());
|
||||
- this.getPlayerList().saveAll();
|
||||
+ // Paper start
|
||||
+ if (Thread.currentThread() != this.serverThread) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // this.getPlayerList().saveAll(); // Paper - we don't need to save everything, just advancements
|
||||
+ for (ServerPlayer player : this.getPlayerList().getPlayers()) {
|
||||
+ player.getAdvancements().save();
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.getPlayerList().reloadResources();
|
||||
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
|
||||
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index f22c50f0a2ef05e9f52550db7c40b5b99632650c..549ea8e0fe702615eefcbfd1cd6a30e05b7b3fd5 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -269,7 +269,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
long j = Util.getNanos() - i;
|
||||
String s = String.format(Locale.ROOT, "%.3fs", (double) j / 1.0E9D);
|
||||
|
||||
- DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s);
|
||||
+ //DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s); // Paper moved to after init
|
||||
if (dedicatedserverproperties.announcePlayerAchievements != null) {
|
||||
((GameRules.BooleanValue) this.getGameRules().getRule(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)).set(dedicatedserverproperties.announcePlayerAchievements, this);
|
||||
}
|
||||
@@ -398,7 +398,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
//this.remoteStatusListener.b(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
- System.exit(0); // CraftBukkit
|
||||
+ hasFullyShutdown = true; // Paper
|
||||
+ System.exit(this.abnormalExit ? 70 : 0); // CraftBukkit // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -761,7 +762,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@Override
|
||||
public void stopServer() {
|
||||
super.stopServer();
|
||||
- Util.shutdownExecutors();
|
||||
+ //Util.shutdownExecutors(); // Paper - moved into super
|
||||
SkullBlockEntity.clear();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 3f5706d4b30b74ba54032ed48d37990ce6ddd715..fd0b72abbbb237c640510aee65eafb9aa9fa0376 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -540,7 +540,7 @@ public abstract class PlayerList {
|
||||
this.cserver.getPluginManager().callEvent(playerQuitEvent);
|
||||
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
|
||||
|
||||
- entityplayer.doTick(); // SPIGOT-924
|
||||
+ if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
|
||||
// CraftBukkit end
|
||||
|
||||
// Paper start - Remove from collideRule team if needed
|
||||
diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
index f5829ae484d93b547a5437b85a9621346384a11b..83701fbfaa56a232593ee8f11a3afb8941238bfa 100644
|
||||
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
@@ -152,6 +152,7 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception var3) {
|
||||
+ if (var3.getCause() instanceof ThreadDeath) throw var3; // Paper
|
||||
LOGGER.error(LogUtils.FATAL_MARKER, "Error executing task on {}", this.name(), var3);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 637092303bbce94fd37f193367264d51b855847d..31edf8f2c683f56e53040e735d015ca6d6966d01 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -827,6 +827,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// 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);
|
||||
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 703830416a0483e960643bee269fe01e170112bd..ee1c9f2c8dd30b3f32a6d49aa1c43148f4e5ccac 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1225,6 +1225,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
|
||||
gameprofilerfiller.pop();
|
||||
} catch (Throwable throwable) {
|
||||
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// 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);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 77911e26af9ec468c8a0c1fe8161b79c67b2303c..be1fbe64a5145b25c111ba3b6bb35109e77deb9d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -178,6 +178,36 @@ public class Main {
|
||||
|
||||
OptionSet options = null;
|
||||
|
||||
+ // Paper start - preload logger classes to avoid plugins mixing versions
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Core");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.appender.AsyncAppender");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Appender");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.ContextDataInjector");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Filter");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.ErrorHandler");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.LogEvent");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.Logger");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.LoggerContext");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.LogEventListener");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.AbstractLogEvent");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.AsynchronouslyFormattable");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.FormattedMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.ParameterizedMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.Message");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.MessageFactory");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.TimestampMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.message.SimpleMessage");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLogger");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLoggerContext");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncQueueFullPolicy");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLoggerDisruptor");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.RingBufferLogEvent");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.DisruptorUtil");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.async.RingBufferLogEventHandler");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ThrowableProxy");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ExtendedClassInfo");
|
||||
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ExtendedStackTraceElement");
|
||||
+ // Paper end
|
||||
try {
|
||||
options = parser.parse(args);
|
||||
} catch (joptsimple.OptionException ex) {
|
||||
@@ -280,8 +310,64 @@ public class Main {
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
+ // Paper start
|
||||
+ // load some required classes to avoid errors during shutdown if jar is replaced
|
||||
+ // also to guarantee our version loads over plugins
|
||||
+ tryPreloadClass("com.destroystokyo.paper.util.SneakyThrow");
|
||||
+ tryPreloadClass("com.google.common.collect.Iterators$PeekingImpl");
|
||||
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$Values");
|
||||
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$ValueIterator");
|
||||
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$WriteThroughEntry");
|
||||
+ tryPreloadClass("com.google.common.collect.Iterables");
|
||||
+ for (int i = 1; i <= 15; i++) {
|
||||
+ tryPreloadClass("com.google.common.collect.Iterables$" + i, false);
|
||||
+ }
|
||||
+ tryPreloadClass("org.apache.commons.lang3.mutable.MutableBoolean");
|
||||
+ tryPreloadClass("org.apache.commons.lang3.mutable.MutableInt");
|
||||
+ tryPreloadClass("org.jline.terminal.impl.MouseSupport");
|
||||
+ tryPreloadClass("org.jline.terminal.impl.MouseSupport$1");
|
||||
+ tryPreloadClass("org.jline.terminal.Terminal$MouseTracking");
|
||||
+ tryPreloadClass("co.aikar.timings.TimingHistory");
|
||||
+ tryPreloadClass("co.aikar.timings.TimingHistory$MinuteReport");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext$11");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext$12");
|
||||
+ tryPreloadClass("io.netty.channel.AbstractChannel$AbstractUnsafe$8");
|
||||
+ tryPreloadClass("io.netty.util.concurrent.DefaultPromise");
|
||||
+ tryPreloadClass("io.netty.util.concurrent.DefaultPromise$1");
|
||||
+ tryPreloadClass("io.netty.util.internal.PromiseNotificationUtil");
|
||||
+ tryPreloadClass("io.netty.util.internal.SystemPropertyUtil");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$1");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$2");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$3");
|
||||
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$4");
|
||||
+ tryPreloadClass("org.slf4j.helpers.MessageFormatter");
|
||||
+ tryPreloadClass("org.slf4j.helpers.FormattingTuple");
|
||||
+ tryPreloadClass("org.slf4j.helpers.BasicMarker");
|
||||
+ tryPreloadClass("org.slf4j.helpers.Util");
|
||||
+ tryPreloadClass("com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent");
|
||||
+ tryPreloadClass("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent");
|
||||
+ // Minecraft, seen during saving
|
||||
+ tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.DummyLightLayerEventListener.class.getName());
|
||||
+ tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.class.getName());
|
||||
+ tryPreloadClass(net.minecraft.util.ExceptionCollector.class.getName());
|
||||
+ // Paper end
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Paper start
|
||||
+ private static void tryPreloadClass(String className) {
|
||||
+ tryPreloadClass(className, true);
|
||||
+ }
|
||||
+ private static void tryPreloadClass(String className, boolean printError) {
|
||||
+ try {
|
||||
+ Class.forName(className);
|
||||
+ } catch (ClassNotFoundException e) {
|
||||
+ if (printError) System.err.println("An expected class " + className + " was not found for preloading: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
private static List<String> asList(String... params) {
|
||||
return Arrays.asList(params);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
index b4a19d80bbf71591f25729fd0e98590350cb31d0..e948ec5a573b22645664eb53bc3e9932246544e4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
@@ -12,12 +12,28 @@ public class ServerShutdownThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
+ // Paper start - try to shutdown on main
|
||||
+ server.safeShutdown(false, false);
|
||||
+ for (int i = 1000; i > 0 && !server.hasStopped(); i -= 100) {
|
||||
+ Thread.sleep(100);
|
||||
+ }
|
||||
+ if (server.hasStopped()) {
|
||||
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Looks stalled, close async
|
||||
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
|
||||
org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
|
||||
+ server.forceTicks = true;
|
||||
this.server.close();
|
||||
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
|
||||
+ } catch (InterruptedException e) {
|
||||
+ e.printStackTrace();
|
||||
+ // Paper end
|
||||
} finally {
|
||||
+ org.apache.logging.log4j.LogManager.shutdown(); // Paper
|
||||
try {
|
||||
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
index a142a56a920e153ed84c08cece993f10d76f7793..92d97a5810a379b427a99b4c63fb9844d823a84f 100644
|
||||
--- a/src/main/java/org/spigotmc/RestartCommand.java
|
||||
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
@@ -139,7 +139,7 @@ public class RestartCommand extends Command
|
||||
// Paper end
|
||||
|
||||
// Paper start - copied from above and modified to return if the hook registered
|
||||
- private static boolean addShutdownHook(String restartScript)
|
||||
+ public static boolean addShutdownHook(String restartScript)
|
||||
{
|
||||
String[] split = restartScript.split( " " );
|
||||
if ( split.length > 0 && new File( split[0] ).isFile() )
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index b47d043144c499b1499f6b4be5a16a3f75c9fcb8..383c52c62f49b17db2fbf58009d6ea132d124bea 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -11,6 +11,7 @@ import org.bukkit.Bukkit;
|
||||
public final class WatchdogThread extends io.papermc.paper.util.TickThread // Paper - rewrite chunk system
|
||||
{
|
||||
|
||||
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper
|
||||
private static WatchdogThread instance;
|
||||
private long timeoutTime;
|
||||
private boolean restart;
|
||||
@@ -39,6 +40,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
{
|
||||
if ( WatchdogThread.instance == null )
|
||||
{
|
||||
+ if (timeoutTime <= 0) timeoutTime = 300; // Paper
|
||||
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
|
||||
WatchdogThread.instance.start();
|
||||
} else
|
||||
@@ -70,12 +72,13 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
// Paper start
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
long currentTime = WatchdogThread.monotonicMillis();
|
||||
- if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.hasStarted && (!server.isRunning() || (currentTime > this.lastTick + this.earlyWarningEvery && !DISABLE_WATCHDOG) )) // Paper - add property to disable
|
||||
{
|
||||
- boolean isLongTimeout = currentTime > lastTick + timeoutTime;
|
||||
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime || (!server.isRunning() && !server.hasStopped() && currentTime > lastTick + 1000);
|
||||
// Don't spam early warning dumps
|
||||
if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue;
|
||||
- if ( !isLongTimeout && MinecraftServer.getServer().hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
|
||||
+ if ( !isLongTimeout && server.hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
|
||||
lastEarlyWarning = currentTime;
|
||||
if (isLongTimeout) {
|
||||
// Paper end
|
||||
@@ -137,9 +140,25 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
|
||||
if ( isLongTimeout )
|
||||
{
|
||||
- if ( this.restart && !MinecraftServer.getServer().hasStopped() )
|
||||
+ if ( !server.hasStopped() )
|
||||
{
|
||||
- RestartCommand.restart();
|
||||
+ AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
|
||||
+ AsyncCatcher.shuttingDown = true;
|
||||
+ server.forceTicks = true;
|
||||
+ if (restart) {
|
||||
+ RestartCommand.addShutdownHook( SpigotConfig.restartScript );
|
||||
+ }
|
||||
+ // try one last chance to safe shutdown on main incase it 'comes back'
|
||||
+ server.abnormalExit = true;
|
||||
+ server.safeShutdown(false, restart);
|
||||
+ try {
|
||||
+ Thread.sleep(1000);
|
||||
+ } catch (InterruptedException e) {
|
||||
+ e.printStackTrace();
|
||||
+ }
|
||||
+ if (!server.hasStopped()) {
|
||||
+ server.close();
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
} // Paper end
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 3dc317e466e1b93dff030794dd7f29ca1b266778..d285dbec16272db6b8a71865e05924ad66087407 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
-<Configuration status="WARN" packages="com.mojang.util">
|
||||
+<Configuration status="WARN" packages="com.mojang.util" shutdownHook="disable">
|
||||
<Appenders>
|
||||
<Queue name="ServerGuiConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Mar 2016 02:02:07 -0600
|
||||
Subject: [PATCH] Optimize Pathfinding
|
||||
|
||||
Prevents pathfinding from spamming failures for things such as
|
||||
arrow attacks.
|
||||
|
||||
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 46c2885097ab768bb9d62187fe0ad2d61007d353..7ffe5bef3778d5971ea4ceadf3102725fd0d08cd 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
|
||||
@@ -192,9 +192,29 @@ public abstract class PathNavigation {
|
||||
return this.moveTo(this.createPath(x, y, z, 1), speed);
|
||||
}
|
||||
|
||||
+ // Paper start - optimise pathfinding
|
||||
+ private int lastFailure = 0;
|
||||
+ private int pathfindFailures = 0;
|
||||
+ // Paper end
|
||||
+
|
||||
public boolean moveTo(Entity entity, double speed) {
|
||||
+ // Paper start - Pathfinding optimizations
|
||||
+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
Path path = this.createPath(entity, 1);
|
||||
- return path != null && this.moveTo(path, speed);
|
||||
+ // Paper start - Pathfinding optimizations
|
||||
+ if (path != null && this.moveTo(path, speed)) {
|
||||
+ this.lastFailure = 0;
|
||||
+ this.pathfindFailures = 0;
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ this.pathfindFailures++;
|
||||
+ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public boolean moveTo(@Nullable Path path, double speed) {
|
|
@ -1,48 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 18:35:09 -0700
|
||||
Subject: [PATCH] Reduce Either Optional allocation
|
||||
|
||||
In order to get chunk values, we shouldn't need to create
|
||||
an optional each time.
|
||||
|
||||
diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
index de524d485fada3c3cca8c2fe6c63db0e0b33dad8..6eb0c94965a6e96ec8ae112125e98c6c4809805b 100644
|
||||
--- a/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
+++ b/src/main/java/com/mojang/datafixers/util/Either.java
|
||||
@@ -22,7 +22,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
}
|
||||
|
||||
private static final class Left<L, R> extends Either<L, R> {
|
||||
- private final L value;
|
||||
+ private final L value; private Optional<L> valueOptional; // Paper - reduce the optional allocation...
|
||||
|
||||
public Left(final L value) {
|
||||
this.value = value;
|
||||
@@ -51,7 +51,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
|
||||
@Override
|
||||
public Optional<L> left() {
|
||||
- return Optional.of(value);
|
||||
+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - reduce the optional allocation...
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,7 +83,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
}
|
||||
|
||||
private static final class Right<L, R> extends Either<L, R> {
|
||||
- private final R value;
|
||||
+ private final R value; private Optional<R> valueOptional; // Paper - reduce the optional allocation...
|
||||
|
||||
public Right(final R value) {
|
||||
this.value = value;
|
||||
@@ -117,7 +117,7 @@ public abstract class Either<L, R> implements App<Either.Mu<R>, L> {
|
||||
|
||||
@Override
|
||||
public Optional<R> right() {
|
||||
- return Optional.of(value);
|
||||
+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - reduce the optional allocation...
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:39:25 -0700
|
||||
Subject: [PATCH] Reduce memory footprint of NBTTagCompound
|
||||
|
||||
Fastutil maps are going to have a lower memory footprint - which
|
||||
is important because we clone chunk data after reading it for safety.
|
||||
So, reduce the impact of the clone on GC.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
index 64765dab6fed87ffdf4af197d8d5f28a04544db0..1d13bc15c56faa69699fb3ad39210233d6b6934d 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
@@ -36,7 +36,7 @@ public class CompoundTag implements Tag {
|
||||
if (i > 512) {
|
||||
throw new RuntimeException("Tried to read NBT tag with too high complexity, depth > 512");
|
||||
} else {
|
||||
- Map<String, Tag> map = Maps.newHashMap();
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - reduce memory footprint of NBTTagCompound
|
||||
|
||||
byte b;
|
||||
while((b = CompoundTag.readNamedTagType(dataInput, nbtAccounter)) != 0) {
|
||||
@@ -130,7 +130,7 @@ public class CompoundTag implements Tag {
|
||||
}
|
||||
|
||||
public CompoundTag() {
|
||||
- this(Maps.newHashMap());
|
||||
+ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - reduce memory footprint of NBTTagCompound
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -449,8 +449,16 @@ public class CompoundTag implements Tag {
|
||||
|
||||
@Override
|
||||
public CompoundTag copy() {
|
||||
- Map<String, Tag> map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy));
|
||||
- return new CompoundTag(map);
|
||||
+ // Paper start - reduce memory footprint of NBTTagCompound
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f);
|
||||
+ java.util.Iterator<java.util.Map.Entry<String, Tag>> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator();
|
||||
+ while (iterator.hasNext()) {
|
||||
+ Map.Entry<String, Tag> entry = iterator.next();
|
||||
+ ret.put(entry.getKey(), entry.getValue().copy());
|
||||
+ }
|
||||
+
|
||||
+ return new CompoundTag(ret);
|
||||
+ // Paper end - reduce memory footprint of NBTTagCompound
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,50 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Mon, 13 Apr 2020 07:31:44 +0100
|
||||
Subject: [PATCH] Prevent opening inventories when frozen
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 7dbf61d79db8a7f08e518c7858142bb0e0f469c4..fedd9727e9d73fdbced6431b313a080705b1d9a5 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -652,7 +652,7 @@ public class ServerPlayer extends Player {
|
||||
containerUpdateDelay = level.paperConfig().tickRates.containerUpdate;
|
||||
}
|
||||
// Paper end
|
||||
- if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
|
||||
+ if (!this.level.isClientSide && this.containerMenu != this.inventoryMenu && (isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - auto close while frozen
|
||||
this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
|
||||
this.containerMenu = this.inventoryMenu;
|
||||
}
|
||||
@@ -1501,7 +1501,7 @@ public class ServerPlayer extends Player {
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
this.containerMenu = container;
|
||||
- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle()));
|
||||
+ if (!isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper
|
||||
// CraftBukkit end
|
||||
this.initMenu(container);
|
||||
return OptionalInt.of(this.containerCounter);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index 77314674a1f66a514f8f5a0fef5ca188b5af0b6a..14984e791bd9309672b1fb404b8552849854d393 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -327,7 +327,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper
|
||||
|
||||
//player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment
|
||||
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
player.containerMenu = container;
|
||||
player.initMenu(container);
|
||||
}
|
||||
@@ -401,7 +401,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper
|
||||
if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper
|
||||
//player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment
|
||||
- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper
|
||||
player.containerMenu = container;
|
||||
player.initMenu(container);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Wed, 15 Apr 2020 17:56:07 -0700
|
||||
Subject: [PATCH] Don't run entity collision code if not needed
|
||||
|
||||
Will not run if:
|
||||
Max entity cramming is disabled and the max collisions per entity is less than or equal to 0.
|
||||
Entity#isPushable() returns false, meaning all entities will not be able to collide with this
|
||||
entity anyways.
|
||||
The entity's current team collision rule causes them to NEVER collide.
|
||||
|
||||
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index e6e4856db7d983460fdf898583915ff2e4a43d14..25e1dc97e3260e7f58b15a1759b8f9531c6a6f20 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3328,10 +3328,24 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
if (this.level.isClientSide()) {
|
||||
this.level.getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush);
|
||||
} else {
|
||||
+ // Paper start - don't run getEntities if we're not going to use its result
|
||||
+ if (!this.isPushable()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ net.minecraft.world.scores.Team team = this.getTeam();
|
||||
+ if (team != null && team.getCollisionRule() == net.minecraft.world.scores.Team.CollisionRule.NEVER) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
|
||||
+ if (i <= 0 && level.paperConfig().collisions.maxEntityCollisions <= 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - don't run getEntities if we're not going to use its result
|
||||
List<Entity> list = this.level.getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this));
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
- int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
|
||||
+ // Paper - moved up
|
||||
int j;
|
||||
|
||||
if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) {
|
|
@ -1,174 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Mon, 20 Jan 2020 21:38:15 +0100
|
||||
Subject: [PATCH] Implement Player Client Options API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabba57885e1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java
|
||||
@@ -0,0 +1,74 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+import com.google.common.base.Objects;
|
||||
+
|
||||
+import java.util.StringJoiner;
|
||||
+
|
||||
+public class PaperSkinParts implements SkinParts {
|
||||
+
|
||||
+ private final int raw;
|
||||
+
|
||||
+ public PaperSkinParts(int raw) {
|
||||
+ this.raw = raw;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasCapeEnabled() {
|
||||
+ return (raw & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasJacketEnabled() {
|
||||
+ return (raw >> 1 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasLeftSleeveEnabled() {
|
||||
+ return (raw >> 2 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasRightSleeveEnabled() {
|
||||
+ return (raw >> 3 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasLeftPantsEnabled() {
|
||||
+ return (raw >> 4 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasRightPantsEnabled() {
|
||||
+ return (raw >> 5 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasHatsEnabled() {
|
||||
+ return (raw >> 6 & 1) == 1;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getRaw() {
|
||||
+ return raw;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(Object o) {
|
||||
+ if (this == o) return true;
|
||||
+ if (o == null || getClass() != o.getClass()) return false;
|
||||
+ PaperSkinParts that = (PaperSkinParts) o;
|
||||
+ return raw == that.raw;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return Objects.hashCode(raw);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return new StringJoiner(", ", PaperSkinParts.class.getSimpleName() + "[", "]")
|
||||
+ .add("raw=" + raw)
|
||||
+ .add("cape=" + hasCapeEnabled())
|
||||
+ .add("jacket=" + hasJacketEnabled())
|
||||
+ .add("leftSleeve=" + hasLeftSleeveEnabled())
|
||||
+ .add("rightSleeve=" + hasRightSleeveEnabled())
|
||||
+ .add("leftPants=" + hasLeftPantsEnabled())
|
||||
+ .add("rightPants=" + hasRightPantsEnabled())
|
||||
+ .add("hats=" + hasHatsEnabled())
|
||||
+ .toString();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index fedd9727e9d73fdbced6431b313a080705b1d9a5..75350988934c6eb1cd39587fa1f53335bf05db17 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1904,9 +1904,24 @@ public class ServerPlayer extends Player {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Client option API
|
||||
+ private java.util.Map<com.destroystokyo.paper.ClientOption<?>, ?> getClientOptionMap(String locale, int viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility chatVisibility, boolean chatColors, com.destroystokyo.paper.PaperSkinParts skinParts, org.bukkit.inventory.MainHand mainHand, boolean allowsServerListing, boolean textFilteringEnabled) {
|
||||
+ java.util.Map<com.destroystokyo.paper.ClientOption<?>, Object> map = new java.util.HashMap<>();
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, locale);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, viewDistance);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, chatVisibility);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, chatColors);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, skinParts);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, mainHand);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, allowsServerListing);
|
||||
+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, textFilteringEnabled);
|
||||
+ return map;
|
||||
+ }
|
||||
+ // Paper end
|
||||
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) {
|
||||
+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(getBukkitEntity(), getClientOptionMap(packet.language, packet.viewDistance, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(packet.chatVisibility().name()), packet.chatColors(), new com.destroystokyo.paper.PaperSkinParts(packet.modelCustomisation()), packet.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT, packet.allowsListing(), packet.textFilteringEnabled())).callEvent(); // Paper - settings event
|
||||
// CraftBukkit start
|
||||
if (getMainArm() != packet.mainHand()) {
|
||||
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index fefe3dc1597d7449e0138be2f60918b06864108a..ef7078780b4829e61048233b60150b26f6a9b792 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -627,6 +627,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public <T> T getClientOption(com.destroystokyo.paper.ClientOption<T> type) {
|
||||
+ if (com.destroystokyo.paper.ClientOption.SKIN_PARTS == type) {
|
||||
+ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION)));
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED == type) {
|
||||
+ return type.getType().cast(getHandle().canChatInColor());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY == type) {
|
||||
+ return type.getType().cast(getHandle().getChatVisibility() == null ? com.destroystokyo.paper.ClientOption.ChatVisibility.UNKNOWN : com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(getHandle().getChatVisibility().name()));
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.LOCALE == type) {
|
||||
+ return type.getType().cast(getLocale());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.MAIN_HAND == type) {
|
||||
+ return type.getType().cast(getMainHand());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.VIEW_DISTANCE == type) {
|
||||
+ return type.getType().cast(getClientViewDistance());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) {
|
||||
+ return type.getType().cast(getHandle().allowsListing());
|
||||
+ } else if (com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED == type) {
|
||||
+ return type.getType().cast(getHandle().isTextFilteringEnabled());
|
||||
+ }
|
||||
+ throw new RuntimeException("Unknown settings type");
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fab3063fffa959ac7f0eb5937f2fae94d11b6591
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+package io.papermc.paper.world;
|
||||
+
|
||||
+import com.destroystokyo.paper.ClientOption;
|
||||
+import net.minecraft.world.entity.player.ChatVisiblity;
|
||||
+import org.bukkit.Difficulty;
|
||||
+import org.junit.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+public class TranslationKeyTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testChatVisibilityKeys() {
|
||||
+ for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) {
|
||||
+ if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue;
|
||||
+ Assert.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 18 Apr 2020 15:59:41 -0400
|
||||
Subject: [PATCH] Don't crash if player is attempted to be removed from
|
||||
untracked chunk.
|
||||
|
||||
I suspect it deals with teleporting as it uses players current x/y/z
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index ffa1e457decf8502c3283352bf5be94d419ff165..d3c3db919e9b0507e8543313d9028394e5163673 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -153,8 +153,8 @@ public abstract class DistanceManager {
|
||||
ObjectSet<ServerPlayer> objectset = (ObjectSet) this.playersPerChunk.get(i);
|
||||
if (objectset == null) return; // CraftBukkit - SPIGOT-6208
|
||||
|
||||
- objectset.remove(player);
|
||||
- if (objectset.isEmpty()) {
|
||||
+ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully.
|
||||
+ if (objectset == null || objectset.isEmpty()) { // Paper
|
||||
this.playersPerChunk.remove(i);
|
||||
this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
||||
//this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
|
@ -1,113 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 19 Apr 2020 00:05:46 -0400
|
||||
Subject: [PATCH] Fix Longstanding Broken behavior of PlayerJoinEvent
|
||||
|
||||
For years, plugin developers have had to delay many things they do
|
||||
inside of the PlayerJoinEvent by 1 tick to make it actually work.
|
||||
|
||||
This all boiled down to 1 reason why: The event fired before the
|
||||
player was fully ready and joined to the world!
|
||||
|
||||
Additionally, if that player logged out on a vehicle, the event
|
||||
fired before the vehicle was even loaded, so that plugins had no
|
||||
access to the vehicle during this event either.
|
||||
|
||||
This change finally fixes this issue, fully preparing the player
|
||||
into the world as a fully ready entity, vehicle included.
|
||||
|
||||
There should be no plugins that break because of this change, but might
|
||||
improve consistency with other plugins instead.
|
||||
|
||||
For example, if 2 plugins listens to this event, and the first one
|
||||
teleported the player in the event, then the 2nd plugin actually
|
||||
would be getting a valid player!
|
||||
|
||||
This was very non deterministic. This change will ensure every plugin
|
||||
receives a deterministic result, and should no longer require 1 tick
|
||||
delays anymore.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 9c5925bc6a0fb277970d46c34dd812cc765a537a..f2bdb647f137a1334789dc56e517844b74d70bd9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1039,6 +1039,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
+ ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
|
||||
return;
|
||||
}
|
||||
+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets
|
||||
// Paper end
|
||||
if (!(entity instanceof EnderDragonPart)) {
|
||||
EntityType<?> entitytypes = entity.getType();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 75350988934c6eb1cd39587fa1f53335bf05db17..35091999392e7c5e6763aee490020c675e19134b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -267,6 +267,7 @@ public class ServerPlayer extends Player {
|
||||
public double maxHealthCache;
|
||||
public boolean joining = true;
|
||||
public boolean sentListPacket = false;
|
||||
+ public boolean supressTrackerForLogin = false; // Paper
|
||||
public Integer clientViewDistance;
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index fd0b72abbbb237c640510aee65eafb9aa9fa0376..0e2a84148e721a8f799f0746e379c16a5f7f0dd3 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -304,6 +304,12 @@ public abstract class PlayerList {
|
||||
this.playersByUUID.put(player.getUUID(), player);
|
||||
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below
|
||||
|
||||
+ // Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
|
||||
+ player.supressTrackerForLogin = true;
|
||||
+ worldserver1.addNewPlayer(player);
|
||||
+ this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer);
|
||||
+ mountSavedVehicle(player, worldserver1, nbttagcompound);
|
||||
+ // Paper end
|
||||
// CraftBukkit start
|
||||
CraftPlayer bukkitPlayer = player.getBukkitEntity();
|
||||
|
||||
@@ -342,6 +348,8 @@ public abstract class PlayerList {
|
||||
player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1)));
|
||||
}
|
||||
player.sentListPacket = true;
|
||||
+ player.supressTrackerForLogin = false; // Paper
|
||||
+ ((ServerLevel)player.level).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now
|
||||
// CraftBukkit end
|
||||
|
||||
player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
|
||||
@@ -367,6 +375,11 @@ public abstract class PlayerList {
|
||||
playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect));
|
||||
}
|
||||
|
||||
+ // Paper start - move vehicle into method so it can be called above - short circuit around that code
|
||||
+ onPlayerJoinFinish(player, worldserver1, s1);
|
||||
+ }
|
||||
+ private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) {
|
||||
+ // Paper end
|
||||
if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) {
|
||||
CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
|
||||
// CraftBukkit start
|
||||
@@ -415,6 +428,10 @@ public abstract class PlayerList {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ }
|
||||
+ public void onPlayerJoinFinish(ServerPlayer player, ServerLevel worldserver1, String s1) {
|
||||
+ // Paper end
|
||||
player.initInventoryMenu();
|
||||
// CraftBukkit - Moved from above, added world
|
||||
// Paper start - Add to collideRule team if needed
|
||||
@@ -424,6 +441,7 @@ public abstract class PlayerList {
|
||||
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
|
||||
}
|
||||
// Paper end
|
||||
+ // CraftBukkit - Moved from above, added world
|
||||
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: 2277 <38501234+2277@users.noreply.github.com>
|
||||
Date: Tue, 31 Mar 2020 10:33:55 +0100
|
||||
Subject: [PATCH] Move player to spawn point if spawn in unloaded world
|
||||
|
||||
The code following this has better support for null worlds to move
|
||||
them back to the world spawn.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 33d37c7e1bd7e676d70ba942476def5c49a59176..ecff22945c0a4cbc5cd26c04bb8e6416ba07fffd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2200,9 +2200,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
bworld = server.getWorld(worldName);
|
||||
}
|
||||
|
||||
- if (bworld == null) {
|
||||
- bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld();
|
||||
- }
|
||||
+ // Paper start - Move player to spawn point if spawn in unloaded world
|
||||
+// if (bworld == null) {
|
||||
+// bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(World.OVERWORLD).getWorld();
|
||||
+// }
|
||||
+ // Paper end - Move player to spawn point if spawn in unloaded world
|
||||
|
||||
((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: nossr50 <nossr50@gmail.com>
|
||||
Date: Thu, 26 Mar 2020 19:44:50 -0700
|
||||
Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 25e1dc97e3260e7f58b15a1759b8f9531c6a6f20..6541caa4a574271fa940d1dceef434655ffd8aa9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2126,7 +2126,16 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption);
|
||||
if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) {
|
||||
- ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired
|
||||
+ // Paper start - PlayerAttackEntityCooldownResetEvent
|
||||
+ if (damagesource.getEntity() instanceof ServerPlayer) {
|
||||
+ ServerPlayer player = (ServerPlayer) damagesource.getEntity();
|
||||
+ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) {
|
||||
+ player.resetAttackStrengthTicker();
|
||||
+ }
|
||||
+ } else {
|
||||
+ ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
|
@ -1,28 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 23 Apr 2020 01:36:39 -0400
|
||||
Subject: [PATCH] Don't fire BlockFade on worldgen threads
|
||||
|
||||
Caused a deadlock
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
index 33ece83c6d41c65042356c44eee2c76934c07d0b..9576f581bb61e6c71de427c52dcc3e56dc3ed81e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java
|
||||
@@ -101,6 +101,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||
// CraftBukkit start
|
||||
+ if (!(world instanceof ServerLevel)) return this.canSurvive(state, world, pos) ? (BlockState) this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation
|
||||
if (!this.canSurvive(state, world, pos)) {
|
||||
// Suppress during worldgen
|
||||
if (!(world instanceof Level)) {
|
||||
@@ -116,7 +117,7 @@ public class FireBlock extends BaseFireBlock {
|
||||
return blockState.getHandle();
|
||||
}
|
||||
}
|
||||
- return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE));
|
||||
+ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - diff on change, see "don't fire events in world generation"
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sat, 25 Apr 2020 15:13:41 -0500
|
||||
Subject: [PATCH] Add phantom creative and insomniac controls
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
index 6fd874a83a248e6a7d427d18d11fc608544662c5..302676ef78ed5b3b7fc1b04851447ca72eed10c0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
||||
@@ -27,6 +27,7 @@ public final class EntitySelector {
|
||||
return !entity.isSpectator();
|
||||
};
|
||||
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
|
||||
+ public static Predicate<Player> isInsomniac = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
|
||||
|
||||
private EntitySelector() {}
|
||||
// Paper start
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
index a3663ea031f3a243f670bf1c98272a49daed71b0..0ada1ba6774e3d0514afb946fd0f104004cc020d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
||||
@@ -563,6 +563,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
||||
Player entityhuman = (Player) iterator.next();
|
||||
|
||||
if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) {
|
||||
+ if (!level.paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.isInsomniac.test(entityhuman)) // Paper
|
||||
Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason
|
||||
return true;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
index df7f23bb039a61ed26e117df934aad9ec5df3f58..66ac41d8fce4176feecf9a7e89e15244f47d261d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
@@ -51,7 +51,7 @@ public class PhantomSpawner implements CustomSpawner {
|
||||
while (iterator.hasNext()) {
|
||||
Player entityhuman = (Player) iterator.next();
|
||||
|
||||
- if (!entityhuman.isSpectator()) {
|
||||
+ if (!entityhuman.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityhuman.isCreative())) { // Paper
|
||||
BlockPos blockposition = entityhuman.blockPosition();
|
||||
|
||||
if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) {
|
|
@ -1,167 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 25 Apr 2020 06:46:35 -0400
|
||||
Subject: [PATCH] Fix numerous item duplication issues and teleport issues
|
||||
|
||||
This notably fixes the newest "Donkey Dupe", but also fixes a lot
|
||||
of dupe bugs in general around nether portals and entity world transfer
|
||||
|
||||
We also fix item duplication generically by anytime we clone an item
|
||||
to drop it on the ground, destroy the source item.
|
||||
|
||||
This avoid an itemstack ever existing twice in the world state pre
|
||||
clean up stage.
|
||||
|
||||
So even if something NEW comes up, it would be impossible to drop the
|
||||
same item twice because the source was destroyed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index ecff22945c0a4cbc5cd26c04bb8e6416ba07fffd..04a388bd3a89a27f0b75134ef781b5e22da633de 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2330,11 +2330,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
} else {
|
||||
// CraftBukkit start - Capture drops for death event
|
||||
if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) {
|
||||
- ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack));
|
||||
+ ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later
|
||||
return null;
|
||||
}
|
||||
// CraftBukkit end
|
||||
- ItemEntity entityitem = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack);
|
||||
+ ItemEntity entityitem = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - clone so we can destroy original
|
||||
+ stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe
|
||||
|
||||
entityitem.setDefaultPickUpDelay();
|
||||
// CraftBukkit start
|
||||
@@ -3115,6 +3116,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@Nullable
|
||||
public Entity teleportTo(ServerLevel worldserver, PositionImpl location) {
|
||||
// CraftBukkit end
|
||||
+ // Paper start - fix bad state entities causing dupes
|
||||
+ if (!isAlive() || !valid) {
|
||||
+ LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable());
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (this.level instanceof ServerLevel && !this.isRemoved()) {
|
||||
this.level.getProfiler().push("changeDimension");
|
||||
// CraftBukkit start
|
||||
@@ -3141,6 +3148,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// CraftBukkit end
|
||||
|
||||
this.level.getProfiler().popPush("reloading");
|
||||
+ // Paper start - Change lead drop timing to prevent dupe
|
||||
+ if (this instanceof Mob) {
|
||||
+ ((Mob) this).dropLeash(true, true); // Paper drop lead
|
||||
+ }
|
||||
+ // Paper end
|
||||
Entity entity = this.getType().create(worldserver);
|
||||
|
||||
if (entity != null) {
|
||||
@@ -3154,10 +3166,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// CraftBukkit start - Forward the CraftEntity to the new entity
|
||||
this.getBukkitEntity().setHandle(entity);
|
||||
entity.bukkitEntity = this.getBukkitEntity();
|
||||
-
|
||||
- if (this instanceof Mob) {
|
||||
- ((Mob) this).dropLeash(true, false); // Unleash to prevent duping of leads.
|
||||
- }
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
@@ -3278,7 +3286,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public boolean canChangeDimensions() {
|
||||
- return !this.isPassenger() && !this.isVehicle();
|
||||
+ return !this.isPassenger() && !this.isVehicle() && isAlive() && valid; // Paper
|
||||
}
|
||||
|
||||
public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index f7ae0c52313f4d8c64849605148f8293e0e96141..65f5381c3362b16fa709728458f87b9283b73291 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1636,9 +1636,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
// Paper start
|
||||
org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(damageSource);
|
||||
if (deathEvent == null || !deathEvent.isCancelled()) {
|
||||
- if (this.deathScore >= 0 && entityliving != null) {
|
||||
- entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
- }
|
||||
+ // if (this.deathScore >= 0 && entityliving != null) { // Paper moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent
|
||||
+ // entityliving.awardKillScore(this, this.deathScore, damageSource);
|
||||
+ // }
|
||||
// Paper start - clear equipment if event is not cancelled
|
||||
if (this instanceof Mob) {
|
||||
for (EquipmentSlot slot : this.clearedEquipmentSlots) {
|
||||
@@ -1736,8 +1736,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.dropCustomDeathLoot(source, i, flag);
|
||||
this.clearEquipmentSlots = prev; // Paper
|
||||
}
|
||||
- // CraftBukkit start - Call death event
|
||||
- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper
|
||||
+ // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment
|
||||
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops, () -> {
|
||||
+ final LivingEntity entityliving = this.getKillCredit();
|
||||
+ if (this.deathScore >= 0 && entityliving != null) {
|
||||
+ entityliving.awardKillScore(this, this.deathScore, source);
|
||||
+ }
|
||||
+ }); // Paper end
|
||||
this.postDeathDropItems(deathEvent); // Paper
|
||||
this.drops = new ArrayList<>();
|
||||
// CraftBukkit end
|
||||
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 dbb4bfb3d1f1ce2e435ca531be36ea448c0e3212..3be5ea477cb3dd3ce75f3feced8daf7cce7075cd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -627,7 +627,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.handItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.handItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
|
||||
this.handItems.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
@@ -635,7 +635,7 @@ public class ArmorStand extends LivingEntity {
|
||||
for (i = 0; i < this.armorItems.size(); ++i) {
|
||||
itemstack = (ItemStack) this.armorItems.get(i);
|
||||
if (!itemstack.isEmpty()) {
|
||||
- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
|
||||
+ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
|
||||
this.armorItems.set(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index cdf93e8751fa2520881290b2a7385f99ec4d0dc2..195f5ef5fcabcf021e429b2a51aa274e929c7322 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -827,6 +827,11 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops) {
|
||||
+ // Paper start
|
||||
+ return CraftEventFactory.callEntityDeathEvent(victim, drops, com.google.common.util.concurrent.Runnables.doNothing());
|
||||
+ }
|
||||
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops, Runnable lootCheck) {
|
||||
+ // Paper end
|
||||
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
|
||||
EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
|
||||
populateFields(victim, event); // Paper - make cancellable
|
||||
@@ -840,11 +845,13 @@ public class CraftEventFactory {
|
||||
playDeathSound(victim, event);
|
||||
// Paper end
|
||||
victim.expToDrop = event.getDroppedExp();
|
||||
+ lootCheck.run(); // Paper - advancement triggers before destroying items
|
||||
|
||||
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
|
||||
if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue;
|
||||
|
||||
- world.dropItem(entity.getLocation(), stack);
|
||||
+ world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS
|
||||
+ if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items
|
||||
}
|
||||
|
||||
return event;
|
Loading…
Add table
Add a link
Reference in a new issue