even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even more patches

This commit is contained in:
Jason Penilla 2021-11-24 21:13:29 -08:00 committed by MiniDigger | Martin
parent fdde23eecf
commit dc58f85df2
14 changed files with 227 additions and 267 deletions

View file

@ -15,6 +15,8 @@ CraftBukkit breaks legacy world conversion in three ways:
This patch fixes all of these issues, and also threads the
McRegionUpgrader to improve performance.
1.18 update note: legacy region conversion has been entirely removed from the vanilla server
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
index 8703f97dc2f392b136c6851aa09b607cbfdfa5de..ade010fe3b62a4624b009c6d665e9909b2d314ac 100644
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java

View file

@ -8,10 +8,10 @@ This WILL cause state corruption if it happens. So, don't
allow it.
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index d4ea81824acdc1220616b24ea0f465db97f4a343..b0a6eb7846580489e0476e69565676e77fd224cd 100644
index be8e63fb3e5c65157ea4ed9c0e3910aaba8c3d45..7418245d5d08706ca2a1378e769abfb0de1076ed 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -599,7 +599,13 @@ public class ChunkHolder {
@@ -385,7 +385,13 @@ public class ChunkHolder {
CompletableFuture<Void> completablefuture1 = new CompletableFuture();
completablefuture1.thenRunAsync(() -> {
@ -25,7 +25,7 @@ index d4ea81824acdc1220616b24ea0f465db97f4a343..b0a6eb7846580489e0476e69565676e7
}, executor);
this.pendingFullStateConfirmation = completablefuture1;
completablefuture.thenAccept((either) -> {
@@ -616,7 +622,12 @@ public class ChunkHolder {
@@ -397,7 +403,12 @@ public class ChunkHolder {
private void demoteFullChunk(ChunkMap playerchunkmap, ChunkHolder.FullChunkStatus playerchunk_state) {
this.pendingFullStateConfirmation.cancel(false);

View file

@ -10,10 +10,10 @@ out due to a sync load, as the worldgen threads will be
stalling on profile lookups.
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 59437f04911662f06596ef61b91017caa6427eec..69faebb95924946f648cf9f86ff777d3274e3f28 100644
index 6288ffdaad147a10f25cce00c13820903b4cc7d7..f4b8dca0a3cbccb55b23b2408e9a17185fd2896f 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -67,6 +67,22 @@ public class Util {
@@ -70,6 +70,22 @@ public class Util {
private static final AtomicInteger WORKER_COUNT = new AtomicInteger(1);
private static final ExecutorService BOOTSTRAP_EXECUTOR = makeExecutor("Bootstrap", -2); // Paper - add -2 priority
private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main", -1); // Paper - add -1 priority
@ -37,7 +37,7 @@ index 59437f04911662f06596ef61b91017caa6427eec..69faebb95924946f648cf9f86ff777d3
public static LongSupplier timeSource = System::nanoTime;
public static final UUID NIL_UUID = new UUID(0L, 0L);
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index 66dfa8c844963091b63e1f2f85d0da6dd2cd083c..f5b8ff3032e46173c0e8920efb336b9901331259 100644
index a157f71cf55b9e97fac56c7c55b552da86000fd5..4e2833dc941863cc54416c81f09c688b5616d7a4 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -200,7 +200,7 @@ public class GameProfileCache {
@ -50,10 +50,10 @@ index 66dfa8c844963091b63e1f2f85d0da6dd2cd083c..f5b8ff3032e46173c0e8920efb336b99
}, this.executor).whenCompleteAsync((optional, throwable) -> {
consumer.accept(optional);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
index 6381544b0038de9a09c01238638e4e127e4eddc6..f61c313195c3d16d996721b2f8cd0d9a10ce1aaf 100644
index e3efea8623c7d34915069a6b9b7da9f2b1694c28..118472b83a21a250f398c088c91ac4560c19c749 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
@@ -150,7 +150,7 @@ public class SkullBlockEntity extends BlockEntity {
@@ -148,7 +148,7 @@ public class SkullBlockEntity extends BlockEntity {
public static void updateGameprofile(@Nullable GameProfile owner, Consumer<GameProfile> callback) {
if (owner != null && !StringUtil.isNullOrEmpty(owner.getName()) && (!owner.isComplete() || !owner.getProperties().containsKey("textures")) && profileCache != null && sessionService != null) {
profileCache.getAsync(owner.getName(), (profile) -> {

View file

@ -802,7 +802,7 @@ index 84a0ee595bebcc1947c602c4c06e7437706ce37c..afbb2acd27416c801af3d718850b82a1
if (path != null && path.canReach()) {
BlockPos blockPos = path.getTarget();
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
index e41b2fa1db6fb77a26cdb498904021b430e35be0..488d1e24b3e8f0fd8dc973d450215e4216720db3 100644
index 0eea3e39616e40e15d1662b973c097cda3b2cee7..3ccc1421f4a5a08dadb9fe3c9fa3ac3131e6ba1e 100644
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
@@ -49,8 +49,12 @@ public class NearestBedSensor extends Sensor<Mob> {
@ -821,7 +821,7 @@ index e41b2fa1db6fb77a26cdb498904021b430e35be0..488d1e24b3e8f0fd8dc973d450215e42
BlockPos blockPos = path.getTarget();
Optional<PoiType> optional = poiManager.getType(blockPos);
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
index 7b1d2748328ffc1447bcacd1316f2c6fdbaf92b0..2b79ace854461b216dc4970d1cc4a3953a51dd50 100644
index 4a972b26242cf4c9d7e8f655cb1264cddad5f143..8a569e3300543cb171c3befae59969628adc424c 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
@@ -37,7 +37,7 @@ public class PoiManager extends SectionStorage<PoiSection> {
@ -831,8 +831,8 @@ index 7b1d2748328ffc1447bcacd1316f2c6fdbaf92b0..2b79ace854461b216dc4970d1cc4a395
- private final net.minecraft.server.level.ServerLevel world; // Paper
+ public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public
public PoiManager(File directory, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) {
super(directory, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world);
public PoiManager(Path path, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) {
super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world);
@@ -100,36 +100,55 @@ public class PoiManager extends SectionStorage<PoiSection> {
}
@ -854,12 +854,12 @@ index 7b1d2748328ffc1447bcacd1316f2c6fdbaf92b0..2b79ace854461b216dc4970d1cc4a395
+ // Paper end - re-route to faster logic
}
public Optional<BlockPos> findClosest(Predicate<PoiType> predicate, Predicate<BlockPos> predicate2, BlockPos blockPos, int i, PoiManager.Occupancy occupancy) {
- return this.getInRange(predicate, blockPos, i, occupancy).map(PoiRecord::getPos).filter(predicate2).min(Comparator.comparingDouble((blockPos2) -> {
- return blockPos2.distSqr(blockPos);
public Optional<BlockPos> findClosest(Predicate<PoiType> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) {
- return this.getInRange(typePredicate, pos, radius, occupationStatus).map(PoiRecord::getPos).filter(posPredicate).min(Comparator.comparingDouble((blockPos2) -> {
- return blockPos2.distSqr(pos);
- }));
+ // Paper start - re-route to faster logic
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, predicate, predicate2, blockPos, i, i*i, occupancy, false);
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, radius, radius * radius, occupationStatus, false);
+ return Optional.ofNullable(ret);
+ // Paper end - re-route to faster logic
}
@ -886,8 +886,8 @@ index 7b1d2748328ffc1447bcacd1316f2c6fdbaf92b0..2b79ace854461b216dc4970d1cc4a395
public Optional<BlockPos> getRandom(Predicate<PoiType> typePredicate, Predicate<BlockPos> positionPredicate, PoiManager.Occupancy occupationStatus, BlockPos pos, int radius, Random random) {
- List<PoiRecord> list = this.getInRange(typePredicate, pos, radius, occupationStatus).collect(Collectors.toList());
- Collections.shuffle(list, random);
- return list.stream().filter((poiRecord) -> {
- return positionPredicate.test(poiRecord.getPos());
- return list.stream().filter((poi) -> {
- return positionPredicate.test(poi.getPos());
- }).findFirst().map(PoiRecord::getPos);
+ // Paper start - re-route to faster logic
+ List<PoiRecord> list = new java.util.ArrayList<>();
@ -908,7 +908,7 @@ index 7b1d2748328ffc1447bcacd1316f2c6fdbaf92b0..2b79ace854461b216dc4970d1cc4a395
public boolean release(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
index 5a86bc6f552913e2978c61233148db22e3a240f1..16f9796adcb83350e97220ba0e96bfee998f1ff4 100644
index 63f283f32bdad02299d4a16c305a28c3bfbce9a8..de94f25792261c6c89986ad3dee3255c2a89357b 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
@@ -25,7 +25,7 @@ import org.apache.logging.log4j.Logger;
@ -921,7 +921,7 @@ index 5a86bc6f552913e2978c61233148db22e3a240f1..16f9796adcb83350e97220ba0e96bfee
private boolean isValid;
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
index 90f7b06bd2c558be35c4577044fa033e1fb5cc22..e2d1149cbe75b0689c9f816b87ebb7ba0d6f56c8 100644
index ff6cadec530dedf9efc5d6226e48a096a1073ad6..d73b99d7fde724da4503b5176c3ad7b013197c6a 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
@@ -61,11 +61,11 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
@ -939,17 +939,19 @@ index 90f7b06bd2c558be35c4577044fa033e1fb5cc22..e2d1149cbe75b0689c9f816b87ebb7ba
return Optional.empty();
} else {
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
index ca3e143e641933fa6b9499bbaaa1836877d90c52..4e3987e6233e84647d019e41ba6afe7c5d09ea80 100644
index ed79058696eb26a89b9d4116821840dbad9ea449..d990d1652b71205816d678618bf360a60f309ad2 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -52,16 +52,37 @@ public class PortalForcer {
@@ -51,18 +51,40 @@ public class PortalForcer {
// int i = flag ? 16 : 128;
// CraftBukkit end
- villageplace.ensureLoadedAndValid(this.level, blockposition, i);
- Optional<PoiRecord> optional = villageplace.getInSquare((villageplacetype) -> {
- return villageplacetype == PoiType.NETHER_PORTAL;
- }, blockposition, i, PoiManager.Occupancy.ANY).sorted(Comparator.comparingDouble((PoiRecord villageplacerecord) -> { // CraftBukkit - decompile error
- }, blockposition, i, PoiManager.Occupancy.ANY).filter((villageplacerecord) -> {
- return worldborder.isWithinBounds(villageplacerecord.getPos());
- }).sorted(Comparator.comparingDouble((PoiRecord villageplacerecord) -> { // CraftBukkit - decompile error
- return villageplacerecord.getPos().distSqr(blockposition);
- }).thenComparingInt((villageplacerecord) -> {
- return villageplacerecord.getPos().getY();
@ -970,6 +972,9 @@ index ca3e143e641933fa6b9499bbaaa1836877d90c52..4e3987e6233e84647d019e41ba6afe7c
+ // why would we generate the chunk?
+ return false;
+ }
+ if (!worldborder.isWithinBounds(pos)) {
+ return false;
+ }
+ return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
+ },
+ blockposition, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records

View file

@ -9,7 +9,7 @@ This patch will be used to optimise out flush calls in later
patches.
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 3eff1c97dcdc6bd8a0c4b7c5bbead2bd68490a4b..032d65a489d65e9b5b5066dff80c65d2e1b28c82 100644
index 16954170ffeeedf18d8f8079b5e75915e0c682ba..a6b438543a12f5ecf05fb631ef53b18d4d253dff 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -94,6 +94,39 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@ -91,14 +91,14 @@ index 3eff1c97dcdc6bd8a0c4b7c5bbead2bd68490a4b..032d65a489d65e9b5b5066dff80c65d2
}
private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol enumprotocol, ConnectionProtocol enumprotocol1) {
private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol packetState, ConnectionProtocol currentState) {
+ // Paper start - add flush parameter
+ this.doSendPacket(packet, callback, enumprotocol, enumprotocol1, true);
+ this.doSendPacket(packet, callback, packetState, currentState, true);
+ }
+ private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol enumprotocol, ConnectionProtocol enumprotocol1, boolean flush) {
+ private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol packetState, ConnectionProtocol currentState, boolean flush) {
+ // Paper end - add flush parameter
if (enumprotocol != enumprotocol1) {
this.setProtocol(enumprotocol);
if (packetState != currentState) {
this.setProtocol(packetState);
}
@@ -312,7 +358,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {

View file

@ -31,7 +31,7 @@ index f01182a0ac8a14bcd5b1deb778306e7bf1bf70ed..b27c8db914cca3ff0ea8a24acddb9cb9
throw new UnsupportedOperationException("Only one concurrent iteration supported");
} else {
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
index 573e5ba276d270b8f67727dc1fbe6bfd7f2a28b1..e89396ea1d06f9e4a0a58d86cb7f9d857d50dc0a 100644
index e19f5b2c8f485d596a64d5d96e75fa1f4a8255b5..14487f7b1f684ae17fd77aa0632fc61829ee691b 100644
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
@@ -166,6 +166,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A

View file

@ -914,26 +914,27 @@ index 0000000000000000000000000000000000000000..3ba094e640d7fe7803e2bbdab8ff3beb
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index ac3ef76f0db5a2d0f02b5e48a8bf511d9b0104d4..5c588c39de11bbabdc2f50ef4204007c622fdc6a 100644
index 82ae5094025c7d86ba6fdbf4334b2575e7b6afa1..0ffd53590c883c0090c913356665058b6c5d3f3f 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -437,7 +437,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
@@ -425,7 +425,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
DataFixer datafixer = minecraftserver.getFixerUpper();
EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, new File(convertable_conversionsession.getDimensionPath(resourcekey), "entities"), datafixer, flag2, minecraftserver);
EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver);
- this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage);
+ this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper
StructureManager definedstructuremanager = minecraftserver.getStructureManager();
int j = this.spigotConfig.viewDistance; // Spigot
PersistentEntitySectionManager persistententitysectionmanager = this.entityManager;
int k = this.spigotConfig.simulationDistance; // Spigot
diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
index 0f6b534a4c789a2f09f6c4624e5d58b99c7ed0e6..21d1e0c9c471e9e556b5bd70166a769b46105c7a 100644
index 5d189257f494eb12b5fd98b12da6dd09ca14f972..913b56361dece6c699ed7fad7e580d408a407bb5 100644
--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java
+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
@@ -77,6 +77,23 @@ public class WorldGenRegion implements WorldGenLevel {
@Nullable
private Supplier<String> currentlyGenerating;
@@ -496,4 +496,21 @@ public class WorldGenRegion implements WorldGenLevel {
public long nextSubTickCount() {
return this.subTickCount.getAndIncrement();
}
+
+ // Paper start
+ // No-op, this class doesn't provide entity access
+ @Override
@ -950,15 +951,12 @@ index 0f6b534a4c789a2f09f6c4624e5d58b99c7ed0e6..21d1e0c9c471e9e556b5bd70166a769b
+ @Override
+ public <T> void getEntitiesByClass(Class<? extends T> clazz, Entity except, AABB box, List<? super T> into, Predicate<? super T> predicate) {}
+ // Paper end
+
public WorldGenRegion(ServerLevel world, List<ChunkAccess> list, ChunkStatus chunkstatus, int i) {
this.generatingStatus = chunkstatus;
this.writeRadiusCutoff = i;
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index e9eacba3816ff3b76c51e9d3011c739b24864355..b7b802053c48c740161747c89cc55ade80094cb7 100644
index dcfc726ab96dccc05848219e824ad7612dbfbdab..db6c11694e6316c50a3f0a138e09542fdae45718 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -417,6 +417,56 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
@@ -386,6 +386,56 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
}
// Paper end - make end portalling safe
@ -1015,7 +1013,7 @@ index e9eacba3816ff3b76c51e9d3011c739b24864355..b7b802053c48c740161747c89cc55ade
public Entity(EntityType<?> type, Level world) {
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
this.passengers = ImmutableList.of();
@@ -2280,11 +2330,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
@@ -2233,11 +2283,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
return InteractionResult.PASS;
}
@ -1030,10 +1028,10 @@ index e9eacba3816ff3b76c51e9d3011c739b24864355..b7b802053c48c740161747c89cc55ade
}
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
index 325e244c46ec208a2e7e18d71ccbbfcc25fc1bce..94130509e3a7980c378cc95c46821cf0fc753ce6 100644
index bc3bfe8d3c2f87e2e9f167b9ff34d9ca8a696391..30276959c0119813c27ee3f98e237c93236e5b39 100644
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
@@ -18,6 +18,18 @@ import net.minecraft.world.phys.shapes.Shapes;
@@ -19,6 +19,18 @@ import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public interface EntityGetter {
@ -1052,42 +1050,17 @@ index 325e244c46ec208a2e7e18d71ccbbfcc25fc1bce..94130509e3a7980c378cc95c46821cf0
List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate);
<T extends Entity> List<T> getEntities(EntityTypeTest<Entity, T> filter, AABB box, Predicate<? super T> predicate);
@@ -55,8 +67,8 @@ public interface EntityGetter {
return Stream.empty();
} else {
AABB aABB = box.inflate(1.0E-7D);
- return this.getEntities(entity, aABB, predicate.and((entityx) -> {
- if (entityx.getBoundingBox().intersects(aABB)) {
+ Predicate<Entity> hardCollides = (entityx) -> { // Paper - optimise entity hard collisions
+ if (true || entityx.getBoundingBox().intersects(aABB)) { // Paper - always true
if (entity == null) {
if (entityx.canBeCollidedWith()) {
return true;
@@ -67,7 +79,11 @@ public interface EntityGetter {
}
return false;
- })).stream().map(Entity::getBoundingBox).map(Shapes::create);
+ }; // Paper start - optimise entity hard collisions
+ predicate = predicate == null ? hardCollides : hardCollides.and(predicate);
+ return (entity != null && entity.hardCollides() ? this.getEntities(entity, aABB, predicate) : this.getHardCollidingEntities(entity, aABB, predicate))
+ .stream().map(Entity::getBoundingBox).map(Shapes::create);
+ // Paper end - optimise entity hard collisions
}
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index d0cfa782498eca8a13ce7d7f28d5e55ae4e402fa..1dd2e968bde16da2d2da63ca3c30515e1fd5b620 100644
index e5cb991543c695bc90256ef250a1d695ac5bc17d..4484c455f4be73763f5aa1112be5969e18c092bc 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -204,6 +204,50 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return this.typeKey;
}
@@ -202,6 +202,48 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public abstract ResourceKey<LevelStem> getTypeKey();
+ // Paper start
+ protected final io.papermc.paper.world.EntitySliceManager entitySliceManager;
+
+ // Paper start - optimise CraftChunk#getEntities
+ public org.bukkit.entity.Entity[] getChunkEntities(int chunkX, int chunkZ) {
+ io.papermc.paper.world.ChunkEntitySlices slices = this.entitySliceManager.getChunk(chunkX, chunkZ);
+ if (slices == null) {
@ -1095,7 +1068,6 @@ index d0cfa782498eca8a13ce7d7f28d5e55ae4e402fa..1dd2e968bde16da2d2da63ca3c30515e
+ }
+ return slices.getChunkEntities();
+ }
+ // Paper end - optimise CraftChunk#getEntities
+
+ @Override
+ public List<Entity> getHardCollidingEntities(Entity except, AABB box, Predicate<? super Entity> predicate) {
@ -1128,18 +1100,18 @@ index d0cfa782498eca8a13ce7d7f28d5e55ae4e402fa..1dd2e968bde16da2d2da63ca3c30515e
+ }
+ // Paper end
+
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) {
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
@@ -281,6 +325,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.chunkPacketBlockController = this.paperConfig.antiXray ?
new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor)
: com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
@@ -278,6 +320,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
+ this.entitySliceManager = new io.papermc.paper.world.EntitySliceManager((ServerLevel)this); // Paper
}
// Paper start
@@ -987,26 +1032,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -987,26 +1030,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate) {
this.getProfiler().incrementCounter("getEntities");
List<Entity> list = Lists.newArrayList();
@ -1167,7 +1139,7 @@ index d0cfa782498eca8a13ce7d7f28d5e55ae4e402fa..1dd2e968bde16da2d2da63ca3c30515e
return list;
}
@@ -1015,26 +1041,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -1015,27 +1039,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.getProfiler().incrementCounter("getEntities");
List<T> list = Lists.newArrayList();
@ -1177,12 +1149,13 @@ index d0cfa782498eca8a13ce7d7f28d5e55ae4e402fa..1dd2e968bde16da2d2da63ca3c30515e
- }
-
- if (entity instanceof EnderDragon) {
- EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity).getSubEntities();
- EnderDragon entityenderdragon = (EnderDragon) entity;
- EnderDragonPart[] aentitycomplexpart = entityenderdragon.getSubEntities();
- int i = aentitycomplexpart.length;
-
- for (int j = 0; j < i; ++j) {
- EnderDragonPart entitycomplexpart = aentitycomplexpart[j];
- T t0 = filter.tryCast(entitycomplexpart);
- T t0 = filter.tryCast(entitycomplexpart); // CraftBukkit - decompile error
-
- if (t0 != null && predicate.test(t0)) {
- list.add(t0);
@ -1210,7 +1183,7 @@ index d0cfa782498eca8a13ce7d7f28d5e55ae4e402fa..1dd2e968bde16da2d2da63ca3c30515e
}
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
index e89396ea1d06f9e4a0a58d86cb7f9d857d50dc0a..976d206a17add01a31ae38b966913368cf386cb1 100644
index 14487f7b1f684ae17fd77aa0632fc61829ee691b..1d61807768dd883cb82bda5d529055bc50e4d1a9 100644
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
@@ -49,8 +49,10 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
@ -1228,7 +1201,7 @@ index e89396ea1d06f9e4a0a58d86cb7f9d857d50dc0a..976d206a17add01a31ae38b966913368
@@ -112,6 +114,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
EntitySection<T> entitysection = this.sectionStorage.getOrCreateSection(i);
entitysection.add(entity); // CraftBukkit - decompile error
entitysection.add(entity);
+ this.entitySliceManager.addEntity((Entity)entity); // Paper
entity.setLevelCallback(new PersistentEntitySectionManager.Callback(entity, i, entitysection));
if (!existing) {
@ -1241,7 +1214,7 @@ index e89396ea1d06f9e4a0a58d86cb7f9d857d50dc0a..976d206a17add01a31ae38b966913368
this.updateChunkStatus(chunkPos, visibility);
}
@@ -461,6 +465,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
@@ -450,6 +454,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
long i = SectionPos.asLong(blockposition);
if (i != this.currentSectionKey) {
@ -1249,7 +1222,7 @@ index e89396ea1d06f9e4a0a58d86cb7f9d857d50dc0a..976d206a17add01a31ae38b966913368
Visibility visibility = this.currentSection.getStatus();
if (!this.currentSection.remove(this.entity)) {
@@ -509,6 +514,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
@@ -498,6 +503,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
if (!this.currentSection.remove(this.entity)) {
PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", this.entity, SectionPos.of(this.currentSectionKey), reason);
}
@ -1258,13 +1231,13 @@ index e89396ea1d06f9e4a0a58d86cb7f9d857d50dc0a..976d206a17add01a31ae38b966913368
Visibility visibility = PersistentEntitySectionManager.getEffectiveStatus(this.entity, this.currentSection.getStatus());
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index 5088c84f6518cb686241b1db54faa8d813cb3eaa..07dfe575dea0f41a75bb9dad0ee2d541e983f6d7 100644
index 187366c33c86b220581c3deac9168d6b6a2c5a3e..fa1b3762ce94290f3a162f7b9628779cf8a2849c 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -131,9 +131,7 @@ public class CraftChunk implements Chunk {
@@ -132,9 +132,7 @@ public class CraftChunk implements Chunk {
long pair = ChunkPos.asLong(x, z);
if (entityManager.areEntitiesLoaded(pair)) { // PAIL rename isEntitiesLoaded
if (entityManager.areEntitiesLoaded(pair)) {
- return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream()
- .map(net.minecraft.world.entity.Entity::getBukkitEntity)
- .filter(Objects::nonNull).toArray(Entity[]::new);
@ -1272,7 +1245,7 @@ index 5088c84f6518cb686241b1db54faa8d813cb3eaa..07dfe575dea0f41a75bb9dad0ee2d541
}
entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading
@@ -169,9 +167,7 @@ public class CraftChunk implements Chunk {
@@ -170,9 +168,7 @@ public class CraftChunk implements Chunk {
}
}
@ -1284,12 +1257,12 @@ index 5088c84f6518cb686241b1db54faa8d813cb3eaa..07dfe575dea0f41a75bb9dad0ee2d541
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
index c5d132dcf70a55de041c0187ff8fb889248bdfee..950d4381459d31d02acf55c4aef4f5e33367748b 100644
index aff1a282516119e0f6026f1b35d6ee72859e8670..80948afdb8c40d9930706e299ca359596ef41189 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
@@ -254,4 +254,20 @@ public class DummyGeneratorAccess implements WorldGenLevel {
public Stream<? extends StructureStart<?>> startsForFeature(SectionPos pos, StructureFeature<?> feature) {
throw new UnsupportedOperationException("Not supported yet.");
@@ -258,4 +258,20 @@ public class DummyGeneratorAccess implements WorldGenLevel {
public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) {
return false; // SPIGOT-6515
}
+
+ // Paper start
@ -1309,7 +1282,7 @@ index c5d132dcf70a55de041c0187ff8fb889248bdfee..950d4381459d31d02acf55c4aef4f5e3
+ // Paper end
}
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 85449fc6d19974622588e7f13e1dc78c8dffbeee..9c456cce42ef9d1654df9047d6fc1e0da13dc1c9 100644
index e0302f82356e8cba848aa8cec1e821e02abbd6f6..72400204fbeea41e4af8d3a0d5eef6f2e75e7518 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -205,7 +205,13 @@ public class ActivationRange

View file

@ -18,23 +18,11 @@ index b27021a42cbed3f0648a8d0903d00d03922ae221..eada966d7f108a6081be7a848f5c1dfc
private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
private MinecraftTimings() {}
diff --git a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
index 5fdaefc128956581be4bb9b34199fd6410563991..b7edc1121797bc1c57e25f540ed0124fa8b36b7a 100644
--- a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
+++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
@@ -312,6 +312,7 @@ public final class PaperTickList<T> extends ServerTickList<T> { // extend to avo
toTick.tickState = STATE_SCHEDULED;
this.addToNotTickingReady(toTick);
}
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick
} catch (final Throwable thr) {
// start copy from TickListServer // TODO check on update
CrashReport crashreport = CrashReport.forThrowable(thr, "Exception while ticking");
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 98eb8318413014f0650dc5c80125aa84b51cfc93..57cb2722e973cfc8edc845bc7154b8b8bbb11e12 100644
index 983bc6b8600489696899b5aaa09e7f7b674d2e42..86b57776a42261053237d62f3b666793457c5e2f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -330,6 +330,76 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -331,6 +331,76 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return s0;
}
@ -111,7 +99,7 @@ index 98eb8318413014f0650dc5c80125aa84b51cfc93..57cb2722e973cfc8edc845bc7154b8b8
public MinecraftServer(OptionSet options, DataPackConfig datapackconfiguration, Thread thread, RegistryAccess.RegistryHolder iregistrycustom_dimension, LevelStorageSource.LevelStorageAccess convertable_conversionsession, WorldData savedata, PackRepository resourcepackrepository, Proxy proxy, DataFixer datafixer, ServerResources datapackresources, @Nullable MinecraftSessionService minecraftsessionservice, @Nullable GameProfileRepository gameprofilerepository, @Nullable GameProfileCache usercache, ChunkProgressListenerFactory worldloadlistenerfactory) {
super("Server");
SERVER = this; // Paper - better singleton
@@ -1325,6 +1395,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1311,6 +1381,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private boolean pollTaskInternal() {
if (super.pollTask()) {
@ -119,33 +107,13 @@ index 98eb8318413014f0650dc5c80125aa84b51cfc93..57cb2722e973cfc8edc845bc7154b8b8
return true;
} else {
if (this.haveTime()) {
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index d6981bbcf480c5856b51960013d144beba2361b3..39840403da99252c5d634e99e1da19f6066dee7c 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -1023,6 +1023,7 @@ public class ServerChunkCache extends ChunkSource {
Collections.shuffle(shuffled);
iterator = shuffled.iterator();
}
+ int chunksTicked = 0; // Paper
try { while (iterator.hasNext()) {
LevelChunk chunk = iterator.next();
ChunkHolder playerchunk = chunk.playerChunk;
@@ -1045,6 +1046,7 @@ public class ServerChunkCache extends ChunkSource {
this.level.tickChunk(chunk, k);
// this.level.timings.doTickTiles.stopTiming(); // Spigot // Paper
}
+ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
}
} // Paper start - optimise chunk tick iteration
} finally {
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 5c588c39de11bbabdc2f50ef4204007c622fdc6a..e219e385df356531639cb1b4bf993dca9034aa1d 100644
index 0ffd53590c883c0090c913356665058b6c5d3f3f..5d4f20a31ad99b4e808bb9a7aaa2153666af493f 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -190,7 +190,9 @@ public class ServerLevel extends Level implements WorldGenLevel {
final Int2ObjectMap<EnderDragonPart> dragonParts;
@@ -198,7 +198,9 @@ public class ServerLevel extends Level implements WorldGenLevel {
private final StructureFeatureManager structureFeatureManager;
private final StructureCheck structureCheck;
private final boolean tickTime;
-
+ // Paper start - execute chunk tasks mid tick
@ -155,10 +123,10 @@ index 5c588c39de11bbabdc2f50ef4204007c622fdc6a..e219e385df356531639cb1b4bf993dca
// CraftBukkit start
private int tickPosition;
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 1dd2e968bde16da2d2da63ca3c30515e1fd5b620..3a6f79233cec7aee87be20787b6deae4b313f0ac 100644
index 4484c455f4be73763f5aa1112be5969e18c092bc..9cc34ff8ec5db5a87faf0afb574543f01c8381c2 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -903,6 +903,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -893,6 +893,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) {
try {
tickConsumer.accept(entity);

View file

@ -9,7 +9,7 @@ the function. I saw approximately 1/3rd of the function
on the copy.
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
index 807bbe54f6516f794bdcb735bb7b8d6812e3ef01..2ef4b4c2ff81d0fa33d4630593266066d8e6a6f3 100644
index f436ab35798c9b6e6cb2eb60d2c02cbf9b742e69..85beb460aa59313cf2ace2d6a6bf24938e3e2b80 100644
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -277,7 +277,7 @@ public class PaperCommand extends Command {
@ -22,7 +22,7 @@ index 807bbe54f6516f794bdcb735bb7b8d6812e3ef01..2ef4b4c2ff81d0fa33d4630593266066
continue;
}
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
index 436ea61d284120a43123709f0213ec56870147dc..d2ea11d35ea111c349df5aa375d7ee8831658262 100644
index 2fe519d4059fac06781c30e140895b604e13104f..7082c61b2dbe524c334efa56a73b24565b996b42 100644
--- a/src/main/java/net/minecraft/server/MCUtil.java
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -619,7 +619,7 @@ public final class MCUtil {
@ -35,10 +35,10 @@ index 436ea61d284120a43123709f0213ec56870147dc..d2ea11d35ea111c349df5aa375d7ee88
List<ChunkHolder> allChunks = new ArrayList<>(visibleChunks.values());
List<ServerPlayer> players = world.players;
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686a280ae50 100644
index 0a3aa9808c7308917b990b8aee3740ada23a4b24..b244713d4a5bc6eb3d9536a56fdc9d688ca0d756 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -114,9 +114,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -117,9 +117,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private static final int MIN_VIEW_DISTANCE = 3;
public static final int MAX_VIEW_DISTANCE = 33;
public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance();
@ -52,16 +52,16 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads;
public final LongSet entitiesInLevel;
public final ServerLevel level;
@@ -344,7 +346,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -238,7 +240,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
super(new File(session.getDimensionPath(world.dimension()), "region"), dataFixer, dsync);
super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
- this.visibleChunkMap = this.updatingChunkMap.clone();
+ // Paper - don't copy
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
this.entitiesInLevel = new LongOpenHashSet();
this.toDrop = new LongOpenHashSet();
@@ -676,12 +678,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -382,12 +384,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@Nullable
public ChunkHolder getUpdatingChunkIfPresent(long pos) {
@ -81,7 +81,7 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
}
protected IntSupplier getChunkQueueLevel(long pos) {
@@ -833,7 +840,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -529,7 +536,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end
}
@ -90,7 +90,7 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
this.modified = true;
}
@@ -913,7 +920,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -551,7 +558,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
protected void saveAllChunks(boolean flush) {
if (flush) {
@ -99,16 +99,16 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
MutableBoolean mutableboolean = new MutableBoolean();
do {
@@ -944,7 +951,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -582,7 +589,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
//this.flushWorker(); // Paper - nuke IOWorker
this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour
// this.i(); // Paper - nuke IOWorker
} else {
- this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> {
+ this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> { // Paper
ChunkAccess ichunkaccess = (ChunkAccess) playerchunk.getChunkToSave().getNow(null); // CraftBukkit - decompile error
- this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded);
+ this.updatingChunks.getVisibleValuesCopy().forEach(this::saveChunkIfNeeded); // Paper
}
if (ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk) {
@@ -986,7 +993,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
@@ -616,7 +623,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
while (longiterator.hasNext()) { // Spigot
long j = longiterator.nextLong();
longiterator.remove(); // Spigot
@ -117,7 +117,16 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
if (playerchunk != null) {
this.pendingUnloads.put(j, playerchunk);
@@ -1121,7 +1128,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -642,7 +649,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
int l = 0;
- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator();
+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper
while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) {
if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) {
@@ -720,7 +727,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
if (!this.modified) {
return false;
} else {
@ -131,7 +140,16 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
this.modified = false;
return true;
}
@@ -1587,7 +1599,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1174,7 +1186,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.viewDistance = j;
this.distanceManager.updatePlayerTickets(this.viewDistance);
- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator();
+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper
while (objectiterator.hasNext()) {
ChunkHolder playerchunk = (ChunkHolder) objectiterator.next();
@@ -1216,7 +1228,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public int size() {
@ -139,8 +157,8 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
+ return this.updatingChunks.getVisibleMap().size(); // Paper - Don't copy
}
protected DistanceManager getDistanceManager() {
@@ -1595,12 +1607,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
public DistanceManager getDistanceManager() {
@@ -1224,13 +1236,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
protected Iterable<ChunkHolder> getChunks() {
@ -149,14 +167,15 @@ index aae8dca773686bec3f867b79aa11d668032b9244..2f5ab00d26dcf027ec0e152a8bf17686
}
void dumpChunks(Writer writer) throws IOException {
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").build(writer);
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer);
TickingTracker tickingtracker = this.distanceManager.tickingTracker();
- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
+ ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper
while (objectbidirectionaliterator.hasNext()) {
Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next();
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 4430385a758906239b8573c59b18d19470339ec5..b4cf0d44bda13625cfa8264043a49c1a0daf1054 100644
index 69a4572c0eb4019491e099cf75049728a9aa4f99..a4188556cc6e657d9b288f2a410c716ca7b100db 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -149,7 +149,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {

View file

@ -10,46 +10,36 @@ hoping that at least then we don't swap chunks, and maybe recover
them all.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
index c81392f5b4a6dcef9c1864c1b2c268914b904561..ad4081efec9c7eaf315ddb660f813f6ef3cfbb5b 100644
index f58050eaa1354ace7b3558d528ab8effdd1432aa..23b3203d04cf1dd2fc3c42e2c7b287a949c81699 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
@@ -70,6 +70,13 @@ public class ChunkSerializer {
private static final String SKYLIGHT_STATE_TAG = "starlight.skylight_state";
private static final String STARLIGHT_VERSION_TAG = "starlight.light_version";
// Paper end - replace light engine impl
@@ -66,6 +66,12 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ChunkSerializer {
+ // Paper start
+ // TODO: Check on update
+ public static long getLastWorldSaveTime(CompoundTag chunkData) {
+ CompoundTag levelData = chunkData.getCompound("Level");
+ return levelData.getLong("LastUpdate");
+ return chunkData.getLong("LastUpdate");
+ }
+ // Paper end
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
private static final Logger LOGGER = LogManager.getLogger();
public static final String TAG_UPGRADE_DATA = "UpgradeData";
@@ -124,7 +131,7 @@ public class ChunkSerializer {
}
// Paper end
BiomeSource worldchunkmanager = chunkgenerator.getBiomeSource();
- CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate
+ CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate // Paper - diff on change
ChunkPos chunkcoordintpair1 = new ChunkPos(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate
if (!Objects.equals(pos, chunkcoordintpair1)) {
@@ -495,7 +502,7 @@ public class ChunkSerializer {
nbttagcompound.put("Level", nbttagcompound1);
nbttagcompound1.putInt("xPos", chunkcoordintpair.x);
nbttagcompound1.putInt("zPos", chunkcoordintpair.z);
- nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading
+ nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading // Paper - diff on change
nbttagcompound1.putLong("InhabitedTime", chunk.getInhabitedTime());
nbttagcompound1.putString("Status", chunk.getStatus().getName());
UpgradeData chunkconverter = chunk.getUpgradeData();
@@ -437,7 +443,7 @@ public class ChunkSerializer {
nbttagcompound.putInt("xPos", chunkcoordintpair.x);
nbttagcompound.putInt("yPos", chunk.getMinSection());
nbttagcompound.putInt("zPos", chunkcoordintpair.z);
- nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading
+ nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading // Paper - diff on change
nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime());
nbttagcompound.putString("Status", chunk.getStatus().getName());
BlendingData blendingdata = chunk.getBlendingData();
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
index 037bbd562e2f35e17c324cd200c55c5e6cb5d768..b889dbad607b6508fb4987d21d3be691a5b37072 100644
index a750b40be3ba5ba258ca2540ab0398deac5a6c5e..3c1724a86cccd3d66459f6c21ed358b47d2d0eac 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
@@ -34,7 +34,7 @@ public class ChunkStorage implements AutoCloseable {
@@ -38,7 +38,7 @@ public class ChunkStorage implements AutoCloseable {
this.fixerUpper = dataFixer;
// Paper start - async chunk io
// remove IO worker
@ -91,12 +81,12 @@ index c8298a597818227de33a4afce4698ec0666cf758..6baceb6ce9021c489be6e79d338a9704
this.used.set(start, start + size);
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66338ae27d 100644
index 293cce2c80fbdc18480977f5f6b24d6b4fa8dcf3..834fa7048e3affb4fcc734d56526b9fba5fa69ca 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -55,6 +55,355 @@ public class RegionFile implements AutoCloseable {
@@ -52,6 +52,355 @@ public class RegionFile implements AutoCloseable {
public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper
public final File regionFile; // Paper
public final Path regionFile; // Paper
+ // Paper start - try to recover from RegionFile header corruption
+ private static long roundToSectors(long bytes) {
@ -140,7 +130,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+
+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position()));
+
+ return NbtIo.read((java.io.DataInput)new DataInputStream(new BufferedInputStream(input)));
+ return NbtIo.read(new DataInputStream(input));
+ } catch (Exception ex) {
+ return null;
+ }
@ -156,18 +146,18 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ }
+
+ private void backupRegionFile() {
+ File backup = new File(this.regionFile.getParent(), this.regionFile.getName() + "." + new java.util.Random().nextLong() + ".backup");
+ Path backup = this.regionFile.getParent().resolve(this.regionFile.getFileName() + "." + new java.util.Random().nextLong() + ".backup");
+ this.backupRegionFile(backup);
+ }
+
+ private void backupRegionFile(File to) {
+ private void backupRegionFile(Path to) {
+ try {
+ this.file.force(true);
+ LOGGER.warn("Backing up regionfile \"" + this.regionFile.getAbsolutePath() + "\" to " + to.getAbsolutePath());
+ java.nio.file.Files.copy(this.regionFile.toPath(), to.toPath());
+ LOGGER.warn("Backed up the regionfile to " + to.getAbsolutePath());
+ LOGGER.warn("Backing up regionfile \"" + this.regionFile.toAbsolutePath() + "\" to " + to.toAbsolutePath());
+ java.nio.file.Files.copy(this.regionFile, to);
+ LOGGER.warn("Backed up the regionfile to " + to.toAbsolutePath());
+ } catch (IOException ex) {
+ LOGGER.error("Failed to backup to " + to.getAbsolutePath(), ex);
+ LOGGER.error("Failed to backup to " + to.toAbsolutePath(), ex);
+ }
+ }
+
@ -182,11 +172,11 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ }
+ ChunkPos ourLowerLeftPosition = RegionFileStorage.getRegionFileCoordinates(this.regionFile);
+ if (ourLowerLeftPosition == null) {
+ LOGGER.fatal("Unable to get chunk location of regionfile " + this.regionFile.getAbsolutePath() + ", cannot recover header");
+ LOGGER.fatal("Unable to get chunk location of regionfile " + this.regionFile.toAbsolutePath() + ", cannot recover header");
+ return false;
+ }
+ synchronized (this) {
+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.regionFile.getAbsolutePath(), new Throwable());
+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.regionFile.toAbsolutePath(), new Throwable());
+
+ // try to backup file so maybe it could be sent to us for further investigation
+
@ -210,7 +200,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+
+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(compound);
+ if (!inSameRegionfile(ourLowerLeftPosition, chunkPos)) {
+ LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.regionFile.getAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x >> 5) + "," + (chunkPos.z >> 5) + ")");
+ LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.regionFile.toAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x >> 5) + "," + (chunkPos.z >> 5) + ")");
+ continue;
+ }
+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5);
@ -222,9 +212,9 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ }
+
+ // aikar oversized?
+ File aikarOversizedFile = this.getOversizedFile(chunkPos.x, chunkPos.z);
+ Path aikarOversizedFile = this.getOversizedFile(chunkPos.x, chunkPos.z);
+ boolean isAikarOversized = false;
+ if (aikarOversizedFile.exists()) {
+ if (Files.exists(aikarOversizedFile)) {
+ try {
+ CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
+ if (ChunkSerializer.getLastWorldSaveTime(compound) == ChunkSerializer.getLastWorldSaveTime(aikarOversizedCompound)) {
@ -232,7 +222,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ isAikarOversized = true;
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x + "," + chunkPos.z + ") in regionfile " + this.regionFile.getAbsolutePath() + ", oversized data for this chunk will be lost", ex);
+ LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x + "," + chunkPos.z + ") in regionfile " + this.regionFile.toAbsolutePath() + ", oversized data for this chunk will be lost", ex);
+ // fall through, if we can't read aikar oversized we can't risk corrupting chunk data
+ }
+ }
@ -252,7 +242,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ // local data compound
+
+ java.nio.file.Path containingFolder = this.externalFileDir;
+ File[] regionFiles = containingFolder.toFile().listFiles();
+ Path[] regionFiles = Files.list(containingFolder).toArray(Path[]::new);
+ boolean[] oversized = new boolean[32 * 32];
+ RegionFileVersion[] oversizedCompressionTypes = new RegionFileVersion[32 * 32];
+
@ -263,7 +253,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ int upperZBound = lowerZBound + 32 - 1; // inclusive
+
+ // read mojang oversized data
+ for (File regionFile : regionFiles) {
+ for (Path regionFile : regionFiles) {
+ ChunkPos oversizedCoords = getOversizedChunkPair(regionFile);
+ if (oversizedCoords == null) {
+ continue;
@ -279,9 +269,9 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+
+ byte[] chunkData;
+ try {
+ chunkData = Files.readAllBytes(regionFile.toPath());
+ chunkData = Files.readAllBytes(regionFile);
+ } catch (Exception ex) {
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.getAbsolutePath() + ", data will be lost", ex);
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", data will be lost", ex);
+ continue;
+ }
+
@ -291,7 +281,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ RegionFileVersion compression = null;
+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) {
+ try {
+ DataInputStream in = new DataInputStream(new BufferedInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData)))); // typical java
+ DataInputStream in = new DataInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData))); // typical java
+ compound = NbtIo.read((java.io.DataInput)in);
+ compression = compressionType;
+ break; // reaches here iff readNBT does not throw
@ -301,12 +291,12 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ }
+
+ if (compound == null) {
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.getAbsolutePath() + ", it's corrupt. Its data will be lost");
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", it's corrupt. Its data will be lost");
+ continue;
+ }
+
+ if (!ChunkSerializer.getChunkCoordinate(compound).equals(oversizedCoords)) {
+ LOGGER.error("Can't use oversized chunk stored in " + regionFile.getAbsolutePath() + ", got absolute chunkpos: " + ChunkSerializer.getChunkCoordinate(compound) + ", expected " + oversizedCoords);
+ LOGGER.error("Can't use oversized chunk stored in " + regionFile.toAbsolutePath() + ", got absolute chunkpos: " + ChunkSerializer.getChunkCoordinate(compound) + ", expected " + oversizedCoords);
+ continue;
+ }
+
@ -340,7 +330,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ if (newSectorAllocations.tryAllocate(sectorOffset, sectorLength)) {
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
+ } else {
+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath() + ", chunk will be regenerated");
+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath() + ", chunk will be regenerated");
+ }
+ }
+ }
@ -364,7 +354,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
+ } catch (IOException ex) {
+ newSectorAllocations.free(sectorOffset, sectorLength);
+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath() + " will be regenerated");
+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath() + " will be regenerated");
+ }
+ }
+ }
@ -386,18 +376,18 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ try {
+ this.writeOversizedMeta();
+ } catch (Exception ex) {
+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.regionFile.getAbsolutePath(), ex);
+ this.getOversizedMetaFile().delete();
+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.regionFile.toAbsolutePath(), ex);
+ Files.deleteIfExists(this.getOversizedMetaFile());
+ }
+ } else {
+ this.getOversizedMetaFile().delete();
+ Files.deleteIfExists(this.getOversizedMetaFile());
+ }
+
+ this.usedSectors.copyFrom(newSectorAllocations);
+
+ // before we overwrite the old sectors, print a summary of the chunks that got changed.
+
+ LOGGER.info("Starting summary of changes for regionfile " + this.regionFile.getAbsolutePath());
+ LOGGER.info("Starting summary of changes for regionfile " + this.regionFile.toAbsolutePath());
+
+ for (int chunkX = 0; chunkX < 32; ++chunkX) {
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
@ -414,16 +404,16 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+
+ if (oldOffset == 0) {
+ // found lost data
+ LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath());
+ LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath());
+ } else if (newOffset == 0) {
+ LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.regionFile.getAbsolutePath() + ", it will be regenerated");
+ LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.regionFile.toAbsolutePath() + ", it will be regenerated");
+ } else {
+ LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.regionFile.getAbsolutePath());
+ LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.regionFile.toAbsolutePath());
+ }
+ }
+ }
+
+ LOGGER.info("End of change summary for regionfile " + this.regionFile.getAbsolutePath());
+ LOGGER.info("End of change summary for regionfile " + this.regionFile.toAbsolutePath());
+
+ // simply destroy the timestamp header, it's not used
+
@ -435,9 +425,9 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ try {
+ this.flush();
+ this.file.force(true); // try to ensure it goes through...
+ LOGGER.info("Successfully wrote new header to disk for regionfile " + this.regionFile.getAbsolutePath());
+ LOGGER.info("Successfully wrote new header to disk for regionfile " + this.regionFile.toAbsolutePath());
+ } catch (IOException ex) {
+ LOGGER.fatal("Failed to write new header to disk for regionfile " + this.regionFile.getAbsolutePath(), ex);
+ LOGGER.fatal("Failed to write new header to disk for regionfile " + this.regionFile.toAbsolutePath(), ex);
+ }
+ }
+
@ -450,13 +440,13 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
// Paper start - Cache chunk status
private final ChunkStatus[] statuses = new ChunkStatus[32 * 32];
@@ -82,8 +431,19 @@ public class RegionFile implements AutoCloseable {
public RegionFile(File file, File directory, boolean dsync) throws IOException {
this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync);
@@ -79,8 +428,19 @@ public class RegionFile implements AutoCloseable {
public RegionFile(Path file, Path directory, boolean dsync) throws IOException {
this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync);
}
+ // Paper start - add can recalc flag
+ public RegionFile(File file, File directory, boolean dsync, boolean canRecalcHeader) throws IOException {
+ this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader);
+ public RegionFile(Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException {
+ this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader);
+ }
+ // Paper end - add can recalc flag
@ -468,9 +458,9 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ this.canRecalcHeader = canRecalcHeader;
+ // Paper end - add can recalc flag
this.header = ByteBuffer.allocateDirect(8192);
this.regionFile = file.toFile(); // Paper
this.regionFile = file; // Paper
initOversizedState(); // Paper
@@ -112,14 +472,16 @@ public class RegionFile implements AutoCloseable {
@@ -109,14 +469,16 @@ public class RegionFile implements AutoCloseable {
RegionFile.LOGGER.warn("Region file {} has truncated header: {}", file, i);
}
@ -491,7 +481,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
// Spigot start
if (j1 == 255) {
// We're maxed out, so we need to read the proper length from the section
@@ -128,32 +490,102 @@ public class RegionFile implements AutoCloseable {
@@ -125,32 +487,102 @@ public class RegionFile implements AutoCloseable {
j1 = (realLen.getInt(0) + 4) / 4096 + 1;
}
// Spigot end
@ -516,12 +506,12 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ // Paper start - recalculate header on header corruption
+ if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) {
+ if (canRecalcHeader) {
+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + "! Recalculating header...");
+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() + "! Recalculating header...");
+ needsHeaderRecalc = true;
+ break;
+ } else {
+ // location = chunkX | (chunkZ << 5);
+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() +
+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() +
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
+ if (!hasBackedUp) {
+ hasBackedUp = true;
@ -534,11 +524,11 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ }
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength);
+ if (failedToAllocate) {
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.getAbsolutePath());
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.toAbsolutePath());
}
+ if (failedToAllocate & !canRecalcHeader) {
+ // location = chunkX | (chunkZ << 5);
+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() +
+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() +
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
+ if (!hasBackedUp) {
+ hasBackedUp = true;
@ -555,7 +545,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
+ // Paper start - recalculate header on header corruption
+ // we move the recalc here so comparison to old header is correct when logging to console
+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues
+ LOGGER.error("Recalculating regionfile " + this.regionFile.getAbsolutePath() + ", header gave erroneous offsets & locations");
+ LOGGER.error("Recalculating regionfile " + this.regionFile.toAbsolutePath() + ", header gave erroneous offsets & locations");
+ this.recalculateHeader();
+ }
+ // Paper end
@ -572,8 +562,8 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
}
+ // Paper start
+ private static ChunkPos getOversizedChunkPair(File file) {
+ String fileName = file.getName();
+ private static ChunkPos getOversizedChunkPair(Path file) {
+ String fileName = file.getFileName().toString();
+
+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) {
+ return null;
@ -599,7 +589,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
@Nullable
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException {
int i = this.getOffset(pos);
@@ -177,6 +609,11 @@ public class RegionFile implements AutoCloseable {
@@ -174,6 +606,11 @@ public class RegionFile implements AutoCloseable {
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
if (bytebuffer.remaining() < 5) {
RegionFile.LOGGER.error("Chunk {} header is truncated: expected {} but read {}", pos, l, bytebuffer.remaining());
@ -611,7 +601,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
return null;
} else {
int i1 = bytebuffer.getInt();
@@ -184,6 +621,11 @@ public class RegionFile implements AutoCloseable {
@@ -181,6 +618,11 @@ public class RegionFile implements AutoCloseable {
if (i1 == 0) {
RegionFile.LOGGER.warn("Chunk {} is allocated, but stream is missing", pos);
@ -623,7 +613,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
return null;
} else {
int j1 = i1 - 1;
@@ -191,17 +633,44 @@ public class RegionFile implements AutoCloseable {
@@ -188,17 +630,44 @@ public class RegionFile implements AutoCloseable {
if (RegionFile.isExternalStreamChunk(b0)) {
if (j1 != 0) {
RegionFile.LOGGER.warn("Chunk has both internal and external streams");
@ -670,7 +660,7 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
}
}
}
@@ -376,10 +845,15 @@ public class RegionFile implements AutoCloseable {
@@ -373,10 +842,15 @@ public class RegionFile implements AutoCloseable {
}
private ByteBuffer createExternalStub() {
@ -688,38 +678,38 @@ index c22391a0d4b7db49bd3994b0887939a7d8019391..d1a4f9979f209a1afb2bf4bfa3d70c66
return bytebuffer;
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 6496108953effae82391b5c1ea6fdec8482731cd..e360ff62d3be252d6b9746b00dbdb4a2aae95405 100644
index 0c5f5b2960f1a0d4bbd41c3c3baf101b4c388c43..cf555bd67599441ce53ae8559c1ffd4bb681ac71 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -25,7 +25,15 @@ public class RegionFileStorage implements AutoCloseable {
private final File folder;
@@ -26,7 +26,15 @@ public class RegionFileStorage implements AutoCloseable {
private final Path folder;
private final boolean sync;
+ private final boolean isChunkData; // Paper
+
RegionFileStorage(File directory, boolean dsync) {
RegionFileStorage(Path directory, boolean dsync) {
+ // Paper start - add isChunkData param
+ this(directory, dsync, false);
+ }
+ RegionFileStorage(File directory, boolean dsync, boolean isChunkData) {
+ RegionFileStorage(Path directory, boolean dsync, boolean isChunkData) {
+ this.isChunkData = isChunkData;
+ // Paper end - add isChunkData param
this.folder = directory;
this.sync = dsync;
}
@@ -90,9 +98,9 @@ public class RegionFileStorage implements AutoCloseable {
File file = this.folder;
@@ -88,9 +96,9 @@ public class RegionFileStorage implements AutoCloseable {
Files.createDirectories(this.folder);
Path path = this.folder;
int j = chunkcoordintpair.getRegionX();
- File file1 = new File(file, "r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
+ File file1 = new File(file, "r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change
if (existingOnly && !file1.exists()) return null; // CraftBukkit
- RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync);
+ RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
- Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
+ Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change
if (existingOnly && !Files.exists(path1)) return null; // CraftBukkit
- RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
+ RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
this.regionCache.putAndMoveToFirst(i, regionfile1);
// Paper start
@@ -180,6 +188,13 @@ public class RegionFileStorage implements AutoCloseable {
@@ -178,6 +186,13 @@ public class RegionFileStorage implements AutoCloseable {
if (regionfile == null) {
return null;
}
@ -733,7 +723,7 @@ index 6496108953effae82391b5c1ea6fdec8482731cd..e360ff62d3be252d6b9746b00dbdb4a2
// CraftBukkit end
try { // Paper
DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos);
@@ -196,6 +211,20 @@ public class RegionFileStorage implements AutoCloseable {
@@ -194,6 +209,20 @@ public class RegionFileStorage implements AutoCloseable {
try {
if (datainputstream != null) {
nbttagcompound = NbtIo.read((DataInput) datainputstream);
@ -741,12 +731,12 @@ index 6496108953effae82391b5c1ea6fdec8482731cd..e360ff62d3be252d6b9746b00dbdb4a2
+ if (this.isChunkData) {
+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound);
+ if (!chunkPos.equals(pos)) {
+ MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos.toString() + " but got chunk data for " + chunkPos.toString() + " instead! Attempting regionfile recalculation for regionfile " + regionfile.regionFile.getAbsolutePath());
+ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + chunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionfile.regionFile.toAbsolutePath());
+ if (regionfile.recalculateHeader()) {
+ regionfile.fileLock.lock(); // otherwise we will unlock twice and only lock once.
+ return this.read(pos, regionfile);
+ }
+ MinecraftServer.LOGGER.fatal("Can't recalculate regionfile header, regenerating chunk " + pos.toString() + " for " + regionfile.regionFile.getAbsolutePath());
+ net.minecraft.server.MinecraftServer.LOGGER.fatal("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.regionFile.toAbsolutePath());
+ return null;
+ }
+ }
@ -755,15 +745,15 @@ index 6496108953effae82391b5c1ea6fdec8482731cd..e360ff62d3be252d6b9746b00dbdb4a2
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
index b7835b9b904e7d4bff64f7189049e334f5ab4d6f..492bba91e0e61c678e5067a6f855674d42d7f4ea 100644
index 95070af5e5bb7013ce7126ba9f725b43e3c4c749..97d4ae5619dcc0922e0381b1bb45a135f514e3af 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
@@ -12,7 +12,7 @@ import java.util.zip.InflaterInputStream;
import javax.annotation.Nullable;
@@ -14,7 +14,7 @@ import javax.annotation.Nullable;
import net.minecraft.util.FastBufferedInputStream;
public class RegionFileVersion {
- private static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>();
+ public static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); // Paper - public
public static final RegionFileVersion VERSION_GZIP = register(new RegionFileVersion(1, GZIPInputStream::new, GZIPOutputStream::new));
public static final RegionFileVersion VERSION_DEFLATE = register(new RegionFileVersion(2, InflaterInputStream::new, DeflaterOutputStream::new));
public static final RegionFileVersion VERSION_NONE = register(new RegionFileVersion(3, (inputStream) -> {
public static final RegionFileVersion VERSION_GZIP = register(new RegionFileVersion(1, (inputStream) -> {
return new FastBufferedInputStream(new GZIPInputStream(inputStream));
}, (outputStream) -> {

View file

@ -26,3 +26,6 @@ index 48812329969b7192acd948db974bb77bb546f979..5b1e0ea40dea6c7d787699ed25160c8b
check ChunkHolder#updateFutures async catcher
leaf: check mid tick chunk task diff in ServerChunkCache