moar patches
This commit is contained in:
parent
f371b4e374
commit
f04e64dfc6
14 changed files with 116 additions and 116 deletions
|
@ -1,119 +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/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 6e7699e5a725eac05de3e809ae9a45a45891892b..07a912cd9f7af3464ecd0de1d789fdcd8c56f86d 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -526,8 +526,18 @@ public class PaperWorldConfig {
|
||||
}
|
||||
|
||||
public boolean disablePillagerPatrols = false;
|
||||
+ public double patrolSpawnChance = 0.2;
|
||||
+ public boolean patrolPerPlayerDelay = false;
|
||||
+ public int patrolDelay = 12000;
|
||||
+ public boolean patrolPerPlayerStart = false;
|
||||
+ public int patrolStartDay = 5;
|
||||
private void pillagerSettings() {
|
||||
disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols);
|
||||
+ patrolSpawnChance = getDouble("game-mechanics.pillager-patrols.spawn-chance", patrolSpawnChance);
|
||||
+ patrolPerPlayerDelay = getBoolean("game-mechanics.pillager-patrols.spawn-delay.per-player", patrolPerPlayerDelay);
|
||||
+ patrolDelay = getInt("game-mechanics.pillager-patrols.spawn-delay.ticks", patrolDelay);
|
||||
+ patrolPerPlayerStart = getBoolean("game-mechanics.pillager-patrols.start.per-player", patrolPerPlayerStart);
|
||||
+ patrolStartDay = getInt("game-mechanics.pillager-patrols.start.day", patrolStartDay);
|
||||
}
|
||||
|
||||
public boolean generateFlatBedrock = false;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index ba8f8b222e8951e0eea8642ecbb843fbf5146f5d..600a774a0cdad4b2582afb3c603734209dac24f7 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -222,6 +222,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 d5a701b2d684bbe18f985adb6bd62e9218d3a0a6..babdbd9c78ff71a12d7bb369603f139cec1602ff 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
@@ -24,7 +24,7 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
|
||||
@Override
|
||||
public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
|
||||
- if (world.paperConfig.disablePillagerPatrols) return 0; // Paper
|
||||
+ if (world.paperConfig.disablePillagerPatrols || world.paperConfig.patrolSpawnChance == 0) return 0; // Paper
|
||||
if (!spawnMonsters) {
|
||||
return 0;
|
||||
} else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) {
|
||||
@@ -32,23 +32,51 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
} else {
|
||||
Random random = 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(random.nextInt(j));
|
||||
+ if (entityhuman.isSpectator()) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ int patrolSpawnDelay;
|
||||
+ if (world.paperConfig.patrolPerPlayerDelay) {
|
||||
+ --entityhuman.patrolSpawnDelay;
|
||||
+ patrolSpawnDelay = entityhuman.patrolSpawnDelay;
|
||||
} else {
|
||||
- this.nextTick += 12000 + random.nextInt(1200);
|
||||
- long i = world.getDayTime() / 24000L;
|
||||
+ this.nextTick--;
|
||||
+ patrolSpawnDelay = this.nextTick;
|
||||
+ }
|
||||
+
|
||||
+ if (patrolSpawnDelay > 0) {
|
||||
+ return 0;
|
||||
+ } else {
|
||||
+ long days;
|
||||
+ if (world.paperConfig.patrolPerPlayerStart) {
|
||||
+ 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.patrolPerPlayerDelay) {
|
||||
+ entityhuman.patrolSpawnDelay += world.paperConfig.patrolDelay + random.nextInt(1200);
|
||||
+ } else {
|
||||
+ this.nextTick += world.paperConfig.patrolDelay + random.nextInt(1200);
|
||||
+ }
|
||||
|
||||
- if (i >= 5L && world.isDay()) {
|
||||
- if (random.nextInt(5) != 0) {
|
||||
+ if (days >= world.paperConfig.patrolStartDay && world.isDay()) {
|
||||
+ if (random.nextDouble() >= world.paperConfig.patrolSpawnChance) {
|
||||
+ // Paper end
|
||||
return 0;
|
||||
} else {
|
||||
- int j = world.players().size();
|
||||
|
||||
if (j < 1) {
|
||||
return 0;
|
||||
} else {
|
||||
- Player entityhuman = (Player) world.players().get(random.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 4357d5c7c66d9490a34f2d591ddc3d58d36cadd1..ab26a26ac553071ecd943dc8a3b41debf8b797ef 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -434,11 +434,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 8e857d4ff6497d68e462418d75b8378ff7adbc97..c49e7ea3e2efc4459f5ed1d4ebd83c9d23420611 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -408,6 +408,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();
|
||||
@@ -441,6 +442,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;
|
||||
@@ -920,6 +922,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) {
|
||||
@@ -943,6 +946,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,48 +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 a0ffdeaad5c375539857d6a5a94832216d09f024..5346109670bedf88f13b4eff47c5292170fb47cc 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1600,6 +1600,14 @@ 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())) {
|
||||
+ new Throwable("[ERROR] Illegal PlayerChunkMap::addEntity for world " + this.level.getWorld().getName()
|
||||
+ + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""))
|
||||
+ .printStackTrace();
|
||||
+ 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 0a7dbafd938141b34dc66d0b4af26dba92a21c06..5009ad1a758e192eaf6ca59baab26d2ba58a6c66 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2210,7 +2210,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;
|
||||
|
||||
@@ -2243,6 +2243,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
|
||||
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 600a774a0cdad4b2582afb3c603734209dac24f7..ef222e90d1dd125c909f00bab98eeb501f547a50 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -643,7 +643,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 8a05690556f8f979d268cd7c6b5c14343ad33579..49648e258c6e72ac921f69114e1e36a926749d46 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1128,7 +1128,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 7b000de3fa232a75cc3737783e4a38025d0d8bde..52ce9718321b96ffb00b3a1b1b2b0071a91217b6 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -791,6 +791,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 32e93c0c9c56a00585ede420f488cfe4a1b37ffa..384f4eabb2ebacd459e0f21e268e3dd0cd4b4d20 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -174,6 +174,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// Paper end
|
||||
|
||||
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..a733c91700a38634806e9155c693b227e6aa16b6 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 && net.minecraft.server.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.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,46 +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.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index ef222e90d1dd125c909f00bab98eeb501f547a50..888e127e7e59a7ceb63f12ec69046916a0e29fc9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -313,7 +313,7 @@ public class ServerPlayer extends Player {
|
||||
this.stats = server.getPlayerList().getPlayerStats(this);
|
||||
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
||||
this.maxUpStep = 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
|
||||
|
||||
@@ -531,7 +531,7 @@ public class ServerPlayer extends Player {
|
||||
position = Vec3.atCenterOf(((ServerLevel) world).getSharedSpawnPos());
|
||||
}
|
||||
this.level = world;
|
||||
- this.setPos(position.x(), position.y(), position.z());
|
||||
+ 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 52ce9718321b96ffb00b3a1b1b2b0071a91217b6..332bc127230fcefcdab0087922536af8b6ff1e8c 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -210,6 +210,8 @@ public abstract class PlayerList {
|
||||
worldserver1 = worldserver;
|
||||
}
|
||||
|
||||
+ if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
|
||||
+
|
||||
player.setLevel(worldserver1);
|
||||
String s1 = "local";
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
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 19ee04dd92b39a775260f832ca8880335d24988b..a910189177da0c1134c954b3d81b9e9bc4bc1420 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
|
||||
@@ -29,10 +29,12 @@ public class GoalSelector {
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
public 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;
|
||||
@@ -62,26 +64,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;
|
||||
}
|
||||
@@ -95,7 +103,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();
|
||||
}
|
||||
}
|
||||
@@ -113,8 +121,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);
|
||||
@@ -154,11 +168,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,583 +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 e3b74dbdf8e14219a56fab939f3174e0c2f66de6..218f5bafeed8551b55b91c7fccaf6935c8b631ca 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 8cc4cb2163a93b9491550fe6d0f5d980fb216920..4dd14d73a37b32288a64fbd67ee22c435b6e6d57 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -228,6 +228,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 03ebc2a0476aef9297cbbc7f358915703a469b02..4ed65f1371013fb91fe60a0e1501e222a6e9c508 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -297,7 +297,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;
|
||||
@@ -307,6 +307,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Spigot end
|
||||
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 Thread(() -> {
|
||||
@@ -911,6 +914,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) {
|
||||
@@ -925,6 +929,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
|
||||
MinecraftServer.LOGGER.info("Stopping server");
|
||||
MinecraftTimings.stopServer(); // Paper
|
||||
@@ -1005,7 +1022,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");
|
||||
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
|
||||
+ 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() {
|
||||
@@ -1098,6 +1126,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void runServer() {
|
||||
try {
|
||||
+ long serverStartTime = Util.getNanos(); // Paper
|
||||
if (this.initServer()) {
|
||||
this.nextTickTime = Util.getMillis();
|
||||
this.status.setDescription(new TextComponent(this.motd));
|
||||
@@ -1105,6 +1134,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.updateStatusIcon(this.status);
|
||||
|
||||
// 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
|
||||
@@ -1162,6 +1203,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.onServerCrash((CrashReport) null);
|
||||
}
|
||||
} 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 )
|
||||
@@ -1195,14 +1242,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1266,6 +1313,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);
|
||||
}
|
||||
|
||||
@@ -1492,6 +1545,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
|
||||
@@ -1949,7 +2003,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.packRepository.setSelected(dataPacks);
|
||||
this.worldData.setDataPackConfig(MinecraftServer.getSelectedPacks(this.packRepository));
|
||||
this.resources.managers.updateRegistryTags(this.registryAccess());
|
||||
- this.getPlayerList().saveAll();
|
||||
+ if (Thread.currentThread() != this.serverThread) return; // Paper
|
||||
+ //this.getPlayerList().saveAll(); // Paper - we don't need to do this
|
||||
this.getPlayerList().reloadResources();
|
||||
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
|
||||
this.structureManager.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 ab26a26ac553071ecd943dc8a3b41debf8b797ef..d0d058287fc1e87e944e99d4fc2cbd38eafb82b3 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -284,7 +284,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);
|
||||
}
|
||||
@@ -441,7 +441,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
|
||||
@@ -767,7 +768,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/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 5346109670bedf88f13b4eff47c5292170fb47cc..7776c22744cdd31459e9634d1d549bdf2876e04f 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -571,6 +571,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
MutableBoolean mutableboolean = new MutableBoolean();
|
||||
|
||||
do {
|
||||
+ boolean isShuttingDown = level.getServer().hasStopped(); // Paper
|
||||
mutableboolean.setFalse();
|
||||
list.stream().map((playerchunk) -> {
|
||||
CompletableFuture completablefuture;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 332bc127230fcefcdab0087922536af8b6ff1e8c..936742383a6834bfd687ec48db308475f598d216 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -512,7 +512,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 6fefa619299d3202158490630d62c16aef71e831..7a4ade1a4190bf4fbb048919ae2be230f7b80fff 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 334fd625829c8e5e9c434b184f6d0084b2d6ccc8..e4c2bd0131a54495fbd1930ad046225118e33186 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -832,6 +832,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 f994d393929ca6813d4209fb9c93550e4f692228..0b049b267a1e1d6b48c035ed54ff24337863fb9e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1058,6 +1058,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/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 21a10a0dc98cb2c669a505d6185c2093855afae6..9e2adc414d43f0c91f222be5f082e74d9db173aa 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2067,7 +2067,7 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public boolean isPrimaryThread() {
|
||||
- return Thread.currentThread().equals(console.serverThread); // Paper - Fix issues with detecting main thread properly
|
||||
+ return Thread.currentThread().equals(console.serverThread) || Thread.currentThread().equals(net.minecraft.server.MinecraftServer.getServer().shutdownThread); // Paper - Fix issues with detecting main thread properly, the only time Watchdog will be used is during a crash shutdown which is a "try our best" scenario
|
||||
}
|
||||
|
||||
// Paper start
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 69b7a11d423b1cd8560cd726dd2b9a2b203e7dfd..7a5e7e8a680ead5128fbf5829bc47704715b94bd 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -12,6 +12,8 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
+import net.minecraft.util.ExceptionCollector;
|
||||
+import net.minecraft.world.level.lighting.LayerLightEventListener;
|
||||
import net.minecrell.terminalconsole.TerminalConsoleAppender; // Paper
|
||||
|
||||
public class Main {
|
||||
@@ -162,6 +164,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) {
|
||||
@@ -257,8 +289,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(LayerLightEventListener.DummyLightLayerEventListener.class.getName());
|
||||
+ tryPreloadClass(LayerLightEventListener.class.getName());
|
||||
+ tryPreloadClass(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..d752720f2f234b9dbd2117333fee1bfad663ec02 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
@@ -12,12 +12,27 @@ 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 {
|
||||
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 1ffb208094f521883ef0e23baf5fb29380b14273..4d271cae88c16ed2419f896c728fdff612540500 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -12,6 +12,7 @@ import org.bukkit.Bukkit;
|
||||
public class WatchdogThread extends Thread
|
||||
{
|
||||
|
||||
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper
|
||||
private static WatchdogThread instance;
|
||||
private long timeoutTime;
|
||||
private boolean restart;
|
||||
@@ -40,6 +41,7 @@ public class WatchdogThread extends Thread
|
||||
{
|
||||
if ( WatchdogThread.instance == null )
|
||||
{
|
||||
+ if (timeoutTime <= 0) timeoutTime = 300; // Paper
|
||||
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
|
||||
WatchdogThread.instance.start();
|
||||
} else
|
||||
@@ -71,12 +73,13 @@ public class WatchdogThread extends Thread
|
||||
// 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
|
||||
@@ -118,7 +121,7 @@ public class WatchdogThread extends Thread
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
|
||||
- WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
+ WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( server.serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
||||
// Paper start - Only print full dump on long timeouts
|
||||
@@ -138,9 +141,25 @@ public class WatchdogThread extends Thread
|
||||
|
||||
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 7991baa181d60ac037fd859278d00274ddb42be8..b47cd6d8ed02875bd9af54d27b7c1cda340e7f9f 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
|
||||
@@ -189,9 +189,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@spottedleaf.dev>
|
||||
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 a90adac7bd7ebd423f480e9ae0f44cb9d521fa4f..3f65fe71024928e35111fc6719a290aab9a6859e 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
|
Loading…
Add table
Add a link
Reference in a new issue