geforkt von Mirrors/Paper
Update remaining feature patches
Dieser Commit ist enthalten in:
Ursprung
b0cef6818d
Commit
c45286cb08
@ -7,22 +7,23 @@ Subject: [PATCH] Only write chunk data to disk if it serializes without
|
|||||||
This ensures at least a valid version of the chunk exists
|
This ensures at least a valid version of the chunk exists
|
||||||
on disk, even if outdated
|
on disk, even if outdated
|
||||||
|
|
||||||
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
|
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
|
||||||
|
|
||||||
}
|
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
// Paper end
|
index 7da388ffab162c282cad0f297bb7304f3c2abbaf..ff4fc280409f680f3879a495e37cf1925b1a38f1 100644
|
||||||
|
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
|
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
|
||||||
|
|
||||||
|
public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
|
+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
|
||||||
private class ChunkBuffer extends ByteArrayOutputStream implements ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkBuffer { // Paper - rewrite chunk system
|
private static final int SECTOR_BYTES = 4096;
|
||||||
|
@VisibleForTesting
|
||||||
private final ChunkPos pos;
|
protected static final int SECTOR_INTS = 1024;
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
@@ -455,6 +456,24 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
super.write(RegionFile.this.version.getId());
|
this.pos = pos;
|
||||||
this.pos = chunkcoordintpair;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public void write(final int b) {
|
+ public void write(final int b) {
|
||||||
@ -40,23 +41,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ super.write(b, off, len);
|
+ super.write(b, off, len);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||||
|
+
|
||||||
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf, 0, this.count);
|
||||||
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
|
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index e35bb5534e2fbd2e30154a15ff6d39baa121608f..d263f78fa610ce6f6fb5a0f5e064e3d8335c2199 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.ChunkPos;
|
@@ -15,6 +15,7 @@ import net.minecraft.util.ExceptionCollector;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
|
||||||
public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system
|
public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system
|
||||||
|
|
||||||
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
||||||
+
|
|
||||||
public static final String ANVIL_EXTENSION = ".mca";
|
public static final String ANVIL_EXTENSION = ".mca";
|
||||||
private static final int MAX_CACHE_SIZE = 256;
|
private static final int MAX_CACHE_SIZE = 256;
|
||||||
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap();
|
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
@@ -119,11 +120,24 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||||
// (and, the regionfile parameter is unused for writing until the write call)
|
// (and, the regionfile parameter is unused for writing until the write call)
|
||||||
final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos);
|
final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos);
|
||||||
|
|
||||||
@ -81,39 +82,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
|
|
||||||
return writeData;
|
return writeData;
|
||||||
}
|
}
|
||||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
@@ -326,9 +340,17 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||||
try {
|
if (chunkData == null) {
|
||||||
NbtIo.write(nbt, (DataOutput) dataoutputstream);
|
regionFile.clear(chunkPos);
|
||||||
regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
} else {
|
||||||
|
- try (DataOutputStream chunkDataOutputStream = regionFile.getChunkDataOutputStream(chunkPos)) {
|
||||||
|
+ DataOutputStream chunkDataOutputStream = regionFile.getChunkDataOutputStream(chunkPos); // Paper - Only write if successful
|
||||||
|
+ try { // Paper - Only write if successful
|
||||||
|
NbtIo.write(chunkData, chunkDataOutputStream);
|
||||||
|
regionFile.setOversized(chunkPos.x, chunkPos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||||
+ dataoutputstream.close(); // Only write if successful
|
+ chunkDataOutputStream.close();
|
||||||
+ } catch (final RegionFileSizeException ex) {
|
+ } catch (final RegionFileSizeException ex) {
|
||||||
+ regionfile.clear(pos);
|
+ regionFile.clear(chunkPos);
|
||||||
+ final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024);
|
+ final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024);
|
||||||
+ LOGGER.error("Chunk at (" + pos.x + "," + pos.z + ") in regionfile '" + regionfile.getPath().toString() + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
|
+ LOGGER.error("Chunk at (" + chunkPos.x + "," + chunkPos.z + ") in regionfile '" + regionFile.getPath().toString() + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
|
||||||
+ return;
|
|
||||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||||
} catch (Throwable throwable) {
|
|
||||||
if (dataoutputstream != null) {
|
|
||||||
try {
|
|
||||||
- dataoutputstream.close();
|
|
||||||
+ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails
|
|
||||||
} catch (Throwable throwable1) {
|
|
||||||
throwable.addSuppressed(throwable1);
|
|
||||||
}
|
|
||||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
||||||
|
|
||||||
throw throwable;
|
|
||||||
}
|
}
|
||||||
-
|
|
||||||
- if (dataoutputstream != null) {
|
|
||||||
- dataoutputstream.close();
|
|
||||||
- }
|
|
||||||
+ // Paper - don't write garbage data to disk if writing serialization fails; move into try block to only write if successfully serialized
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
@@ -370,4 +392,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||||
public RegionStorageInfo info() {
|
public RegionStorageInfo info() {
|
||||||
return this.info;
|
return this.info;
|
||||||
}
|
}
|
||||||
@ -121,7 +109,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||||
+ public static final class RegionFileSizeException extends RuntimeException {
|
+ public static final class RegionFileSizeException extends RuntimeException {
|
||||||
+
|
+
|
||||||
+ public RegionFileSizeException(String message) {
|
+ public RegionFileSizeException(final String message) {
|
||||||
+ super(message);
|
+ super(message);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
@ -8,11 +8,12 @@ to a chunk. The default values of -1 disable the limit. Although
|
|||||||
defaults are only included for certain entites, this allows setting
|
defaults are only included for certain entites, this allows setting
|
||||||
limits for any entity type.
|
limits for any entity type.
|
||||||
|
|
||||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
index 7aea4e343581b977d11af90f9f65eac3532eade1..d21ce54ebb5724c04eadf56a2cde701d5eeb5db2 100644
|
||||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||||
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
|
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||||
|
@@ -104,7 +104,18 @@ public final class ChunkEntitySlices {
|
||||||
}
|
}
|
||||||
|
|
||||||
final ListTag entitiesTag = new ListTag();
|
final ListTag entitiesTag = new ListTag();
|
||||||
@ -31,21 +32,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
CompoundTag compoundTag = new CompoundTag();
|
CompoundTag compoundTag = new CompoundTag();
|
||||||
if (entity.save(compoundTag)) {
|
if (entity.save(compoundTag)) {
|
||||||
entitiesTag.add(compoundTag);
|
entitiesTag.add(compoundTag);
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 73cdfa5a315ed259b38dfa946a0b7955d9ac9f50..49201d6664656ebe34c84c1c84b5ea4878729062 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
--- a/net/minecraft/world/entity/EntityType.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
+++ b/net/minecraft/world/entity/EntityType.java
|
||||||
@@ -0,0 +0,0 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
@@ -1420,9 +1420,20 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
||||||
final Spliterator<? extends Tag> spliterator = entityNbtList.spliterator();
|
public static Stream<Entity> loadEntitiesRecursive(final List<? extends Tag> entityTags, final Level level, final EntitySpawnReason spawnReason) {
|
||||||
|
final Spliterator<? extends Tag> spliterator = entityTags.spliterator();
|
||||||
return StreamSupport.stream(new Spliterator<Entity>() {
|
return StreamSupport.stream(new Spliterator<Entity>() {
|
||||||
+ final java.util.Map<EntityType<?>, Integer> loadedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
|
+ final java.util.Map<EntityType<?>, Integer> loadedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
|
||||||
|
@Override
|
||||||
public boolean tryAdvance(Consumer<? super Entity> consumer) {
|
public boolean tryAdvance(Consumer<? super Entity> consumer) {
|
||||||
return spliterator.tryAdvance((nbtbase) -> {
|
return spliterator.tryAdvance(tag -> EntityType.loadEntityRecursive((CompoundTag)tag, level, spawnReason, entity -> {
|
||||||
EntityType.loadEntityRecursive((CompoundTag) nbtbase, world, reason, (entity) -> {
|
|
||||||
+ // Paper start - Entity load/save limit per chunk
|
+ // Paper start - Entity load/save limit per chunk
|
||||||
+ final EntityType<?> entityType = entity.getType();
|
+ final EntityType<?> entityType = entity.getType();
|
||||||
+ final int saveLimit = world.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
+ final int saveLimit = level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||||
+ if (saveLimit > -1) {
|
+ if (saveLimit > -1) {
|
||||||
+ if (this.loadedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) {
|
+ if (this.loadedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) {
|
||||||
+ return null;
|
+ return null;
|
||||||
@ -53,19 +54,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ this.loadedEntityCounts.merge(entityType, 1, Integer::sum);
|
+ this.loadedEntityCounts.merge(entityType, 1, Integer::sum);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - Entity load/save limit per chunk
|
+ // Paper end - Entity load/save limit per chunk
|
||||||
consumer.accept(entity);
|
consumer.accept(entity);
|
||||||
return entity;
|
return entity;
|
||||||
});
|
}));
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
diff --git a/net/minecraft/world/level/chunk/storage/EntityStorage.java b/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index da05fb780c55381a7a08ced51d01764a645740b2..2856206eafddfcbcc1b65408deda40357f43a6f8 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
--- a/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
+++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||||
@@ -0,0 +0,0 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
@@ -93,7 +93,18 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ListTag listTag = new ListTag();
|
ListTag listTag = new ListTag();
|
||||||
+ final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
|
+ final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
|
||||||
dataList.getEntities().forEach(entity -> {
|
entities.getEntities().forEach(entity -> {
|
||||||
+ // Paper start - Entity load/save limit per chunk
|
+ // Paper start - Entity load/save limit per chunk
|
||||||
+ final EntityType<?> entityType = entity.getType();
|
+ final EntityType<?> entityType = entity.getType();
|
||||||
+ final int saveLimit = this.level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
+ final int saveLimit = this.level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||||
@ -76,6 +77,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ savedEntityCounts.merge(entityType, 1, Integer::sum);
|
+ savedEntityCounts.merge(entityType, 1, Integer::sum);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - Entity load/save limit per chunk
|
+ // Paper end - Entity load/save limit per chunk
|
||||||
CompoundTag compoundTagx = new CompoundTag();
|
CompoundTag compoundTag1 = new CompoundTag();
|
||||||
if (entity.save(compoundTagx)) {
|
if (entity.save(compoundTag1)) {
|
||||||
listTag.add(compoundTagx);
|
listTag.add(compoundTag1);
|
||||||
|
@ -9,11 +9,12 @@ we instead drop the current regionfile header and recalculate -
|
|||||||
hoping that at least then we don't swap chunks, and maybe recover
|
hoping that at least then we don't swap chunks, and maybe recover
|
||||||
them all.
|
them all.
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
diff --git a/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
index 64a718c98f799c62a5bb28e1e8e5f66cc96c915d..666f2e967c99f78422c83fb20e1a3bf3efa7845e 100644
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
--- a/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||||
@@ -0,0 +0,0 @@ import java.util.BitSet;
|
+++ b/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||||
|
@@ -9,6 +9,27 @@ import java.util.BitSet;
|
||||||
public class RegionBitmap {
|
public class RegionBitmap {
|
||||||
private final BitSet used = new BitSet();
|
private final BitSet used = new BitSet();
|
||||||
|
|
||||||
@ -38,17 +39,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ }
|
+ }
|
||||||
+ // Paper end - Attempt to recalculate regionfile header if it is corrupt
|
+ // Paper end - Attempt to recalculate regionfile header if it is corrupt
|
||||||
+
|
+
|
||||||
public void force(int start, int size) {
|
public void force(int sectorOffset, int sectorCount) {
|
||||||
this.used.set(start, start + size);
|
this.used.set(sectorOffset, sectorOffset + sectorCount);
|
||||||
}
|
}
|
||||||
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
|
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index ff4fc280409f680f3879a495e37cf1925b1a38f1..a4621c96fd456c5cdd1b6847931806e677b26b30 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
@@ -46,6 +46,355 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
private final IntBuffer timestamps;
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected final RegionBitmap usedSectors;
|
protected final RegionBitmap usedSectors = new RegionBitmap();
|
||||||
|
|
||||||
+ // Paper start - Attempt to recalculate regionfile header if it is corrupt
|
+ // Paper start - Attempt to recalculate regionfile header if it is corrupt
|
||||||
+ private static long roundToSectors(long bytes) {
|
+ private static long roundToSectors(long bytes) {
|
||||||
+ long sectors = bytes >>> 12; // 4096 = 2^12
|
+ long sectors = bytes >>> 12; // 4096 = 2^12
|
||||||
@ -57,9 +58,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ return sectors + (sign >>> 63);
|
+ return sectors + (sign >>> 63);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private static final CompoundTag OVERSIZED_COMPOUND = new CompoundTag();
|
+ private static final net.minecraft.nbt.CompoundTag OVERSIZED_COMPOUND = new net.minecraft.nbt.CompoundTag();
|
||||||
+
|
+
|
||||||
+ private CompoundTag attemptRead(long sector, int chunkDataLength, long fileLength) throws IOException {
|
+ private @Nullable net.minecraft.nbt.CompoundTag attemptRead(long sector, int chunkDataLength, long fileLength) throws IOException {
|
||||||
+ try {
|
+ try {
|
||||||
+ if (chunkDataLength < 0) {
|
+ if (chunkDataLength < 0) {
|
||||||
+ return null;
|
+ return null;
|
||||||
@ -91,7 +92,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+
|
+
|
||||||
+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position()));
|
+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position()));
|
||||||
+
|
+
|
||||||
+ return NbtIo.read(new DataInputStream(input));
|
+ return net.minecraft.nbt.NbtIo.read(new DataInputStream(input));
|
||||||
+ } catch (Exception ex) {
|
+ } catch (Exception ex) {
|
||||||
+ return null;
|
+ return null;
|
||||||
+ }
|
+ }
|
||||||
@ -142,7 +143,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ // try to backup file so maybe it could be sent to us for further investigation
|
+ // try to backup file so maybe it could be sent to us for further investigation
|
||||||
+
|
+
|
||||||
+ this.backupRegionFile();
|
+ this.backupRegionFile();
|
||||||
+ CompoundTag[] compounds = new CompoundTag[32 * 32]; // only in the regionfile (i.e exclude mojang/aikar oversized data)
|
+ net.minecraft.nbt.CompoundTag[] compounds = new net.minecraft.nbt.CompoundTag[32 * 32]; // only in the regionfile (i.e exclude mojang/aikar oversized data)
|
||||||
+ int[] rawLengths = new int[32 * 32]; // length of chunk data including 4 byte length field, bytes
|
+ int[] rawLengths = new int[32 * 32]; // length of chunk data including 4 byte length field, bytes
|
||||||
+ int[] sectorOffsets = new int[32 * 32]; // in sectors
|
+ int[] sectorOffsets = new int[32 * 32]; // in sectors
|
||||||
+ boolean[] hasAikarOversized = new boolean[32 * 32];
|
+ boolean[] hasAikarOversized = new boolean[32 * 32];
|
||||||
@ -154,7 +155,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+
|
+
|
||||||
+ for (long i = 2, maxSector = Math.min((long)(Integer.MAX_VALUE >>> 8), totalSectors); i < maxSector; ++i) { // first two sectors are header, skip
|
+ for (long i = 2, maxSector = Math.min((long)(Integer.MAX_VALUE >>> 8), totalSectors); i < maxSector; ++i) { // first two sectors are header, skip
|
||||||
+ int chunkDataLength = this.getLength(i);
|
+ int chunkDataLength = this.getLength(i);
|
||||||
+ CompoundTag compound = this.attemptRead(i, chunkDataLength, fileLength);
|
+ net.minecraft.nbt.CompoundTag compound = this.attemptRead(i, chunkDataLength, fileLength);
|
||||||
+ if (compound == null || compound == OVERSIZED_COMPOUND) {
|
+ if (compound == null || compound == OVERSIZED_COMPOUND) {
|
||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
@ -166,7 +167,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ }
|
+ }
|
||||||
+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5);
|
+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5);
|
||||||
+
|
+
|
||||||
+ CompoundTag otherCompound = compounds[location];
|
+ net.minecraft.nbt.CompoundTag otherCompound = compounds[location];
|
||||||
+
|
+
|
||||||
+ if (otherCompound != null && SerializableChunkData.getLastWorldSaveTime(otherCompound) > SerializableChunkData.getLastWorldSaveTime(compound)) {
|
+ if (otherCompound != null && SerializableChunkData.getLastWorldSaveTime(otherCompound) > SerializableChunkData.getLastWorldSaveTime(compound)) {
|
||||||
+ continue; // don't overwrite newer data.
|
+ continue; // don't overwrite newer data.
|
||||||
@ -177,7 +178,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ boolean isAikarOversized = false;
|
+ boolean isAikarOversized = false;
|
||||||
+ if (Files.exists(aikarOversizedFile)) {
|
+ if (Files.exists(aikarOversizedFile)) {
|
||||||
+ try {
|
+ try {
|
||||||
+ CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
|
+ net.minecraft.nbt.CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
|
||||||
+ if (SerializableChunkData.getLastWorldSaveTime(compound) == SerializableChunkData.getLastWorldSaveTime(aikarOversizedCompound)) {
|
+ if (SerializableChunkData.getLastWorldSaveTime(compound) == SerializableChunkData.getLastWorldSaveTime(aikarOversizedCompound)) {
|
||||||
+ // best we got for an id. hope it's good enough
|
+ // best we got for an id. hope it's good enough
|
||||||
+ isAikarOversized = true;
|
+ isAikarOversized = true;
|
||||||
@ -236,14 +237,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ CompoundTag compound = null;
|
+ net.minecraft.nbt.CompoundTag compound = null;
|
||||||
+
|
+
|
||||||
+ // We do not know the compression type, as it's stored in the regionfile. So we need to try all of them
|
+ // We do not know the compression type, as it's stored in the regionfile. So we need to try all of them
|
||||||
+ RegionFileVersion compression = null;
|
+ RegionFileVersion compression = null;
|
||||||
+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) {
|
+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) {
|
||||||
+ try {
|
+ try {
|
||||||
+ DataInputStream in = new DataInputStream(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);
|
+ compound = net.minecraft.nbt.NbtIo.read((java.io.DataInput)in);
|
||||||
+ compression = compressionType;
|
+ compression = compressionType;
|
||||||
+ break; // reaches here iff readNBT does not throw
|
+ break; // reaches here iff readNBT does not throw
|
||||||
+ } catch (Exception ex) {
|
+ } catch (Exception ex) {
|
||||||
@ -397,63 +398,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+
|
+
|
||||||
+ final boolean canRecalcHeader; // final forces compile fail on new constructor
|
+ final boolean canRecalcHeader; // final forces compile fail on new constructor
|
||||||
+ // Paper end - Attempt to recalculate regionfile header if it is corrupt
|
+ // Paper end - Attempt to recalculate regionfile header if it is corrupt
|
||||||
|
+
|
||||||
// Paper start - rewrite chunk system
|
// Paper start - rewrite chunk system
|
||||||
@Override
|
@Override
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final net.minecraft.nbt.CompoundTag data, final ChunkPos pos) throws IOException {
|
||||||
throw new IllegalArgumentException("Expected directory, got " + String.valueOf(directory.toAbsolutePath()));
|
@@ -74,6 +423,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
|
throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath());
|
||||||
} else {
|
} else {
|
||||||
this.externalFileDir = directory;
|
this.externalFileDir = externalFileDir;
|
||||||
+ this.canRecalcHeader = RegionFileStorage.isChunkDataFolder(this.externalFileDir); // Paper - add can recalc flag
|
+ this.canRecalcHeader = RegionFileStorage.isChunkDataFolder(this.externalFileDir); // Paper - add can recalc flag
|
||||||
this.offsets = this.header.asIntBuffer();
|
this.offsets = this.header.asIntBuffer();
|
||||||
((java.nio.Buffer) this.offsets).limit(1024); // CraftBukkit - decompile error
|
this.offsets.limit(1024);
|
||||||
((java.nio.Buffer) this.header).position(4096); // CraftBukkit - decompile error
|
this.header.position(4096);
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
@@ -94,11 +444,13 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
RegionFile.LOGGER.warn("Region file {} has truncated header: {}", path, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
- long j = Files.size(path);
|
long size = Files.size(path);
|
||||||
+ final long j = Files.size(path); final long regionFileSize = j; // Paper - recalculate header on header corruption
|
|
||||||
|
|
||||||
- for (int k = 0; k < 1024; ++k) {
|
- for (int i1 = 0; i1 < 1024; i1++) {
|
||||||
- int l = this.offsets.get(k);
|
|
||||||
+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption
|
+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption
|
||||||
+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption
|
+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption
|
||||||
+ for (int k = 0; k < 1024; ++k) { final int headerLocation = k; // Paper - we expect this to be the header location
|
+ for (int i1 = 0; i1 < 1024; i1++) { final int headerLocation = i1; // Paper - we expect this to be the header location
|
||||||
+ final int l = this.offsets.get(k);
|
int i2 = this.offsets.get(i1);
|
||||||
|
if (i2 != 0) {
|
||||||
if (l != 0) {
|
- int sectorNumber = getSectorNumber(i2);
|
||||||
- int i1 = RegionFile.getSectorNumber(l);
|
- int numSectors = getNumSectors(i2);
|
||||||
- int j1 = RegionFile.getNumSectors(l);
|
+ final int sectorNumber = getSectorNumber(i2); // Paper - we expect this to be offset in file in sectors
|
||||||
+ final int i1 = RegionFile.getSectorNumber(l); final int offset = i1; // Paper - we expect this to be offset in file in sectors
|
+ int numSectors = getNumSectors(i2); // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
||||||
+ int j1 = RegionFile.getNumSectors(l); final int sectorLength; // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
|
||||||
// Spigot start
|
// Spigot start
|
||||||
if (j1 == 255) {
|
if (numSectors == 255) {
|
||||||
// We're maxed out, so we need to read the proper length from the section
|
// We're maxed out, so we need to read the proper length from the section
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
@@ -109,18 +461,62 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
j1 = (realLen.getInt(0) + 4) / 4096 + 1;
|
|
||||||
}
|
|
||||||
// Spigot end
|
// Spigot end
|
||||||
+ sectorLength = j1; // Paper - diff on change, we expect this to be sector length of region
|
if (sectorNumber < 2) {
|
||||||
|
LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i1, sectorNumber);
|
||||||
if (i1 < 2) {
|
- this.offsets.put(i1, 0);
|
||||||
RegionFile.LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", new Object[]{path, k, i1});
|
+ //this.offsets.put(i1, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||||
- this.offsets.put(k, 0);
|
} else if (numSectors == 0) {
|
||||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, i1);
|
||||||
} else if (j1 == 0) {
|
- this.offsets.put(i1, 0);
|
||||||
RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, k);
|
+ //this.offsets.put(i1, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||||
- this.offsets.put(k, 0);
|
} else if (sectorNumber * 4096L > size) {
|
||||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", path, i1, sectorNumber);
|
||||||
} else if ((long) i1 * 4096L > j) {
|
- this.offsets.put(i1, 0);
|
||||||
RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", new Object[]{path, k, i1});
|
+ //this.offsets.put(i1, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||||
- this.offsets.put(k, 0);
|
|
||||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
|
||||||
} else {
|
} else {
|
||||||
- this.usedSectors.force(i1, j1);
|
- this.usedSectors.force(sectorNumber, numSectors);
|
||||||
+ //this.usedSectors.force(i1, j1); // Paper - move this down so we can check if it fails to allocate
|
+ //this.usedSectors.force(sectorNumber, numSectors); // Paper - move this down so we can check if it fails to allocate
|
||||||
+ }
|
+ }
|
||||||
+ // Paper start - recalculate header on header corruption
|
+ // Paper start - recalculate header on header corruption
|
||||||
+ if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) {
|
+ if (sectorNumber < 2 || numSectors <= 0 || ((long)sectorNumber * 4096L) > size) {
|
||||||
+ if (canRecalcHeader) {
|
+ if (canRecalcHeader) {
|
||||||
+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + "! Recalculating header...");
|
+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + "! Recalculating header...");
|
||||||
+ needsHeaderRecalc = true;
|
+ needsHeaderRecalc = true;
|
||||||
@ -471,7 +464,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength);
|
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(sectorNumber, numSectors);
|
||||||
+ if (failedToAllocate) {
|
+ if (failedToAllocate) {
|
||||||
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.path.toAbsolutePath());
|
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.path.toAbsolutePath());
|
||||||
}
|
}
|
||||||
@ -499,20 +492,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ }
|
+ }
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
}
|
||||||
|
@@ -130,10 +526,35 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path getExternalChunkPath(ChunkPos chunkPos) {
|
private Path getExternalChunkPath(ChunkPos chunkPos) {
|
||||||
- String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc";
|
- String string = "c." + chunkPos.x + "." + chunkPos.z + ".mcc";
|
||||||
+ String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; // Paper - diff on change
|
+ String string = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; // Paper - diff on change
|
||||||
|
return this.externalFileDir.resolve(string);
|
||||||
return this.externalFileDir.resolve(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // Paper start
|
+ // Paper start
|
||||||
+ private static ChunkPos getOversizedChunkPair(Path file) {
|
+ private static @Nullable ChunkPos getOversizedChunkPair(Path file) {
|
||||||
+ String fileName = file.getFileName().toString();
|
+ String fileName = file.getFileName().toString();
|
||||||
+
|
+
|
||||||
+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) {
|
+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) {
|
||||||
@ -537,81 +529,79 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ // Paper end
|
+ // Paper end
|
||||||
+
|
+
|
||||||
@Nullable
|
@Nullable
|
||||||
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException {
|
public synchronized DataInputStream getChunkDataInputStream(ChunkPos chunkPos) throws IOException {
|
||||||
int i = this.getOffset(pos);
|
int offset = this.getOffset(chunkPos);
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
@@ -155,30 +576,67 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
|
byteBuffer.flip();
|
||||||
if (bytebuffer.remaining() < 5) {
|
if (byteBuffer.remaining() < 5) {
|
||||||
RegionFile.LOGGER.error("Chunk {} header is truncated: expected {} but read {}", new Object[]{pos, l, bytebuffer.remaining()});
|
LOGGER.error("Chunk {} header is truncated: expected {} but read {}", chunkPos, i, byteBuffer.remaining());
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
int i1 = bytebuffer.getInt();
|
int _int = byteBuffer.getInt();
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
byte b = byteBuffer.get();
|
||||||
|
if (_int == 0) {
|
||||||
if (i1 == 0) {
|
LOGGER.warn("Chunk {} is allocated, but stream is missing", chunkPos);
|
||||||
RegionFile.LOGGER.warn("Chunk {} is allocated, but stream is missing", pos);
|
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
int j1 = i1 - 1;
|
int i1 = _int - 1;
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
if (isExternalStreamChunk(b)) {
|
||||||
if (RegionFile.isExternalStreamChunk(b0)) {
|
if (i1 != 0) {
|
||||||
if (j1 != 0) {
|
LOGGER.warn("Chunk has both internal and external streams");
|
||||||
RegionFile.LOGGER.warn("Chunk has both internal and external streams");
|
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
}
|
}
|
||||||
|
|
||||||
- return this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0));
|
- return this.createExternalChunkInputStream(chunkPos, getExternalChunkVersion(b));
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ final DataInputStream ret = this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0));
|
+ final DataInputStream ret = this.createExternalChunkInputStream(chunkPos, getExternalChunkVersion(b));
|
||||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
} else if (j1 > bytebuffer.remaining()) {
|
} else if (i1 > byteBuffer.remaining()) {
|
||||||
RegionFile.LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", new Object[]{pos, j1, bytebuffer.remaining()});
|
LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", chunkPos, i1, byteBuffer.remaining());
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
return null;
|
return null;
|
||||||
} else if (j1 < 0) {
|
} else if (i1 < 0) {
|
||||||
RegionFile.LOGGER.error("Declared size {} of chunk {} is negative", i1, pos);
|
LOGGER.error("Declared size {} of chunk {} is negative", _int, chunkPos);
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, j1);
|
JvmProfiler.INSTANCE.onRegionFileRead(this.info, chunkPos, this.version, i1);
|
||||||
- return this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
|
- return this.createChunkInputStream(chunkPos, b, createStream(byteBuffer, i1));
|
||||||
+ // Paper start - recalculate header on regionfile corruption
|
+ // Paper start - recalculate header on regionfile corruption
|
||||||
+ final DataInputStream ret = this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
|
+ final DataInputStream ret = this.createChunkInputStream(chunkPos, b, createStream(byteBuffer, i1));
|
||||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||||
+ return this.getChunkDataInputStream(pos);
|
+ return this.getChunkDataInputStream(chunkPos);
|
||||||
+ }
|
+ }
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+ // Paper end - recalculate header on regionfile corruption
|
+ // Paper end - recalculate header on regionfile corruption
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
@@ -361,9 +819,14 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuffer createExternalStub() {
|
private ByteBuffer createExternalStub() {
|
||||||
@ -620,22 +610,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ }
|
+ }
|
||||||
+ private ByteBuffer createExternalStub(RegionFileVersion version) {
|
+ private ByteBuffer createExternalStub(RegionFileVersion version) {
|
||||||
+ // Paper end - add version param
|
+ // Paper end - add version param
|
||||||
ByteBuffer bytebuffer = ByteBuffer.allocate(5);
|
ByteBuffer byteBuffer = ByteBuffer.allocate(5);
|
||||||
|
byteBuffer.putInt(1);
|
||||||
|
- byteBuffer.put((byte)(this.version.getId() | 128));
|
||||||
|
+ byteBuffer.put((byte)(version.getId() | 128));
|
||||||
|
byteBuffer.flip();
|
||||||
|
return byteBuffer;
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||||
|
index d263f78fa610ce6f6fb5a0f5e064e3d8335c2199..dad7f94b611cf0fc68b1a3878c458233f6bb6d61 100644
|
||||||
|
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||||
|
@@ -23,6 +23,36 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||||
|
private final Path folder;
|
||||||
|
private final boolean sync;
|
||||||
|
|
||||||
bytebuffer.putInt(1);
|
|
||||||
- bytebuffer.put((byte) (this.version.getId() | 128));
|
|
||||||
+ bytebuffer.put((byte) (version.getId() | 128)); // Paper - replace with version param
|
|
||||||
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
|
|
||||||
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
|
|
||||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Paper end - rewrite chunk system
|
|
||||||
+ // Paper start - recalculate region file headers
|
+ // Paper start - recalculate region file headers
|
||||||
+ private final boolean isChunkData;
|
+ private final boolean isChunkData;
|
||||||
+
|
+
|
||||||
@ -666,40 +655,42 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
|
// Paper start - rewrite chunk system
|
||||||
protected RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { // Paper - protected
|
private static final int REGION_SHIFT = 5;
|
||||||
this.folder = directory;
|
private static final int MAX_NON_EXISTING_CACHE = 1024 * 4;
|
||||||
this.sync = dsync;
|
@@ -216,6 +246,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||||
this.info = storageKey;
|
this.folder = folder;
|
||||||
|
this.sync = sync;
|
||||||
|
this.info = info;
|
||||||
+ this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
|
+ this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paper start - rewrite chunk system
|
@org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit
|
||||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
@@ -309,6 +340,19 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||||
try {
|
}
|
||||||
if (datainputstream != null) {
|
|
||||||
nbttagcompound = NbtIo.read((DataInput) datainputstream);
|
|
||||||
+ // Paper start - recover from corrupt regionfile header
|
|
||||||
+ if (this.isChunkData) {
|
|
||||||
+ ChunkPos chunkPos = SerializableChunkData.getChunkCoordinate(nbttagcompound);
|
|
||||||
+ if (!chunkPos.equals(pos)) {
|
|
||||||
+ 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.getPath().toAbsolutePath());
|
|
||||||
+ if (regionfile.recalculateHeader()) {
|
|
||||||
+ return this.read(pos);
|
|
||||||
+ }
|
|
||||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.getPath().toAbsolutePath());
|
|
||||||
+ return null;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end - recover from corrupt regionfile header
|
|
||||||
break label43;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
var4 = NbtIo.read(chunkDataInputStream);
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
+ // Paper start - recover from corrupt regionfile header
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
+ if (this.isChunkData) {
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
+ ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(var4);
|
||||||
@@ -0,0 +0,0 @@ import org.slf4j.Logger;
|
+ if (!headerChunkPos.equals(chunkPos)) {
|
||||||
|
+ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + chunkPos + " but got chunk data for " + headerChunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionFile.getPath().toAbsolutePath());
|
||||||
|
+ if (regionFile.recalculateHeader()) {
|
||||||
|
+ return this.read(chunkPos);
|
||||||
|
+ }
|
||||||
|
+ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + chunkPos + " for " + regionFile.getPath().toAbsolutePath());
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end - recover from corrupt regionfile header
|
||||||
|
}
|
||||||
|
|
||||||
|
return var4;
|
||||||
|
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||||
|
index 0c739ca5b01ac0ec35a11fd01c5fc65de97c2852..de7deee4b79c969a7797bd57b657a16404c15303 100644
|
||||||
|
--- a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||||
|
@@ -21,7 +21,7 @@ import org.slf4j.Logger;
|
||||||
|
|
||||||
public class RegionFileVersion {
|
public class RegionFileVersion {
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
@ -708,11 +699,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
private static final Object2ObjectMap<String, RegionFileVersion> VERSIONS_BY_NAME = new Object2ObjectOpenHashMap<>();
|
private static final Object2ObjectMap<String, RegionFileVersion> VERSIONS_BY_NAME = new Object2ObjectOpenHashMap<>();
|
||||||
public static final RegionFileVersion VERSION_GZIP = register(
|
public static final RegionFileVersion VERSION_GZIP = register(
|
||||||
new RegionFileVersion(
|
new RegionFileVersion(
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 70a9972252576e039ac126f6057a6ed66b80cdfc..d783c3580ea274a0a9cb07449eb8037bc5a04d76 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||||
@@ -0,0 +0,0 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun
|
@@ -120,6 +120,18 @@ public record SerializableChunkData(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Paper end - guard against serializing mismatching coordinates
|
// Paper end - guard against serializing mismatching coordinates
|
||||||
@ -731,12 +722,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
|
|
||||||
// Paper start - Do not let the server load chunks from newer versions
|
// Paper start - Do not let the server load chunks from newer versions
|
||||||
private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
||||||
@@ -0,0 +0,0 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun
|
@@ -604,7 +616,7 @@ public record SerializableChunkData(
|
||||||
nbttagcompound.putInt("xPos", this.chunkPos.x);
|
compoundTag.putInt("xPos", this.chunkPos.x);
|
||||||
nbttagcompound.putInt("yPos", this.minSectionY);
|
compoundTag.putInt("yPos", this.minSectionY);
|
||||||
nbttagcompound.putInt("zPos", this.chunkPos.z);
|
compoundTag.putInt("zPos", this.chunkPos.z);
|
||||||
- nbttagcompound.putLong("LastUpdate", this.lastUpdateTime);
|
- compoundTag.putLong("LastUpdate", this.lastUpdateTime);
|
||||||
+ nbttagcompound.putLong("LastUpdate", this.lastUpdateTime); // Paper - Diff on change
|
+ compoundTag.putLong("LastUpdate", this.lastUpdateTime); // Paper - Diff on change
|
||||||
nbttagcompound.putLong("InhabitedTime", this.inhabitedTime);
|
compoundTag.putLong("InhabitedTime", this.inhabitedTime);
|
||||||
nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
|
compoundTag.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
|
||||||
DataResult<Tag> dataresult; // CraftBukkit - decompile error
|
if (this.blendingData != null) {
|
||||||
|
@ -30,12 +30,13 @@ This patch also specifically optimises other areas of code to
|
|||||||
use PoiAccess. For example, some villager AI and portaling code
|
use PoiAccess. For example, some villager AI and portaling code
|
||||||
had to be specifically modified.
|
had to be specifically modified.
|
||||||
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/util/PoiAccess.java b/src/main/java/io/papermc/paper/util/PoiAccess.java
|
|
||||||
|
diff --git a/io/papermc/paper/util/PoiAccess.java b/io/papermc/paper/util/PoiAccess.java
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
index 0000000000000000000000000000000000000000..f39294b1f83c4022be5ced4da781103a1eee2daf
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/main/java/io/papermc/paper/util/PoiAccess.java
|
+++ b/io/papermc/paper/util/PoiAccess.java
|
||||||
@@ -0,0 +0,0 @@
|
@@ -0,0 +1,806 @@
|
||||||
+package io.papermc.paper.util;
|
+package io.papermc.paper.util;
|
||||||
+
|
+
|
||||||
+import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
+import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
@ -842,38 +843,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ throw new RuntimeException();
|
+ throw new RuntimeException();
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
diff --git a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 9de13a78b2a8be181c02ab330bfa9abb936a83db..b9174ae7e3a3e2de2d570b95ab5012ac3c3a2eda 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
+++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||||
@@ -0,0 +0,0 @@ public class AcquirePoi {
|
@@ -84,12 +84,16 @@ public class AcquirePoi {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
- Set<Pair<Holder<PoiType>, BlockPos>> set = poiManager.findAllClosestFirstWithType(
|
- Set<Pair<Holder<PoiType>, BlockPos>> set = poiManager.findAllClosestFirstWithType(
|
||||||
- poiPredicate, predicate2, entity.blockPosition(), 48, PoiManager.Occupancy.HAS_SPACE
|
- acquirablePois, predicate1, mob.blockPosition(), 48, PoiManager.Occupancy.HAS_SPACE
|
||||||
- )
|
- )
|
||||||
- .limit(5L)
|
- .limit(5L)
|
||||||
- .filter(pairx -> worldPosBiPredicate.test(world, (BlockPos)pairx.getSecond()))
|
- .filter(pair1 -> predicate.test(level, pair1.getSecond()))
|
||||||
- .collect(Collectors.toSet());
|
- .collect(Collectors.toSet());
|
||||||
+ // Paper start - optimise POI access
|
+ // Paper start - optimise POI access
|
||||||
+ final java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
+ final java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
||||||
+ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes);
|
+ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, acquirablePois, predicate1, mob.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes);
|
||||||
+ final Set<Pair<Holder<PoiType>, BlockPos>> set = new java.util.HashSet<>(poiposes.size());
|
+ final Set<Pair<Holder<PoiType>, BlockPos>> set = new java.util.HashSet<>(poiposes.size());
|
||||||
+ for (final Pair<Holder<PoiType>, BlockPos> poiPose : poiposes) {
|
+ for (final Pair<Holder<PoiType>, BlockPos> poiPose : poiposes) {
|
||||||
+ if (worldPosBiPredicate.test(world, poiPose.getSecond())) {
|
+ if (predicate.test(level, poiPose.getSecond())) {
|
||||||
+ set.add(poiPose);
|
+ set.add(poiPose);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - optimise POI access
|
+ // Paper end - optimise POI access
|
||||||
Path path = findPathToPois(entity, set);
|
Path path = findPathToPois(mob, set);
|
||||||
if (path != null && path.canReach()) {
|
if (path != null && path.canReach()) {
|
||||||
BlockPos blockPos = path.getTarget();
|
BlockPos target = 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
|
diff --git a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 6e9325f0800a35637fdec5edb8a514ea03741762..066faa704338c573472381e1ebd063e0d52aaaa4 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
--- a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
+++ b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||||
@@ -0,0 +0,0 @@ public class NearestBedSensor extends Sensor<Mob> {
|
@@ -53,11 +53,12 @@ public class NearestBedSensor extends Sensor<Mob> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -889,82 +890,82 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
+ Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||||
+ // Paper end - optimise POI access
|
+ // Paper end - optimise POI access
|
||||||
if (path != null && path.canReach()) {
|
if (path != null && path.canReach()) {
|
||||||
BlockPos blockPos = path.getTarget();
|
BlockPos target = path.getTarget();
|
||||||
Optional<Holder<PoiType>> optional = poiManager.getType(blockPos);
|
Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||||
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
|
diff --git a/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 5c5724f5e3ad640f55aecbc1d8f71d1f59ecdc62..618fc0eb4fe70e46e55f3aa28e8eac1d2d01b6d9 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
--- a/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
+++ b/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
@@ -254,36 +254,47 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
||||||
public Optional<BlockPos> find(
|
public Optional<BlockPos> find(
|
||||||
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus
|
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int distance, PoiManager.Occupancy status
|
||||||
) {
|
) {
|
||||||
- return this.findAll(typePredicate, posPredicate, pos, radius, occupationStatus).findFirst();
|
- return this.findAll(typePredicate, posPredicate, pos, distance, status).findFirst();
|
||||||
+ // Paper start - re-route to faster logic
|
+ // Paper start - re-route to faster logic
|
||||||
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findAnyPoiPosition(this, typePredicate, posPredicate, pos, radius, occupationStatus, false);
|
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findAnyPoiPosition(this, typePredicate, posPredicate, pos, distance, status, false);
|
||||||
+ return Optional.ofNullable(ret);
|
+ return Optional.ofNullable(ret);
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<BlockPos> findClosest(Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) {
|
public Optional<BlockPos> findClosest(Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int distance, PoiManager.Occupancy status) {
|
||||||
- return this.getInRange(typePredicate, pos, radius, occupationStatus)
|
- return this.getInRange(typePredicate, pos, distance, status).map(PoiRecord::getPos).min(Comparator.comparingDouble(blockPos -> blockPos.distSqr(pos)));
|
||||||
- .map(PoiRecord::getPos)
|
|
||||||
- .min(Comparator.comparingDouble(poiPos -> poiPos.distSqr(pos)));
|
|
||||||
+ // Paper start - re-route to faster logic
|
+ // Paper start - re-route to faster logic
|
||||||
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, radius, radius * radius, occupationStatus, false);
|
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, distance, distance * distance, status, false);
|
||||||
+ return Optional.ofNullable(closestPos);
|
+ return Optional.ofNullable(closestPos);
|
||||||
+ // Paper end - re-route to faster logic
|
+ // Paper end - re-route to faster logic
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Pair<Holder<PoiType>, BlockPos>> findClosestWithType(
|
public Optional<Pair<Holder<PoiType>, BlockPos>> findClosestWithType(
|
||||||
Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus
|
Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int distance, PoiManager.Occupancy status
|
||||||
) {
|
) {
|
||||||
- return this.getInRange(typePredicate, pos, radius, occupationStatus)
|
- return this.getInRange(typePredicate, pos, distance, status)
|
||||||
- .min(Comparator.comparingDouble(poi -> poi.getPos().distSqr(pos)))
|
- .min(Comparator.comparingDouble(poiRecord -> poiRecord.getPos().distSqr(pos)))
|
||||||
- .map(poi -> Pair.of(poi.getPoiType(), poi.getPos()));
|
- .map(poiRecord -> Pair.of(poiRecord.getPoiType(), poiRecord.getPos()));
|
||||||
+ // Paper start - re-route to faster logic
|
+ // Paper start - re-route to faster logic
|
||||||
+ return Optional.ofNullable(io.papermc.paper.util.PoiAccess.findClosestPoiDataTypeAndPosition(
|
+ return Optional.ofNullable(io.papermc.paper.util.PoiAccess.findClosestPoiDataTypeAndPosition(
|
||||||
+ this, typePredicate, null, pos, radius, radius * radius, occupationStatus, false
|
+ this, typePredicate, null, pos, distance, distance * distance, status, false
|
||||||
+ ));
|
+ ));
|
||||||
+ // Paper end - re-route to faster logic
|
+ // Paper end - re-route to faster logic
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<BlockPos> findClosest(
|
public Optional<BlockPos> findClosest(
|
||||||
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus
|
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int distance, PoiManager.Occupancy status
|
||||||
) {
|
) {
|
||||||
- return this.getInRange(typePredicate, pos, radius, occupationStatus)
|
- return this.getInRange(typePredicate, pos, distance, status)
|
||||||
- .map(PoiRecord::getPos)
|
- .map(PoiRecord::getPos)
|
||||||
- .filter(posPredicate)
|
- .filter(posPredicate)
|
||||||
- .min(Comparator.comparingDouble(poiPos -> poiPos.distSqr(pos)));
|
- .min(Comparator.comparingDouble(blockPos -> blockPos.distSqr(pos)));
|
||||||
+ // Paper start - re-route to faster logic
|
+ // Paper start - re-route to faster logic
|
||||||
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, radius, radius * radius, occupationStatus, false);
|
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, distance, distance * distance, status, false);
|
||||||
+ return Optional.ofNullable(closestPos);
|
+ return Optional.ofNullable(closestPos);
|
||||||
+ // Paper end - re-route to faster logic
|
+ // Paper end - re-route to faster logic
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<BlockPos> take(Predicate<Holder<PoiType>> typePredicate, BiPredicate<Holder<PoiType>, BlockPos> posPredicate, BlockPos pos, int radius) {
|
public Optional<BlockPos> take(
|
||||||
- return this.getInRange(typePredicate, pos, radius, PoiManager.Occupancy.HAS_SPACE)
|
Predicate<Holder<PoiType>> typePredicate, BiPredicate<Holder<PoiType>, BlockPos> combinedTypePosPredicate, BlockPos pos, int distance
|
||||||
- .filter(poi -> posPredicate.test(poi.getPoiType(), poi.getPos()))
|
) {
|
||||||
|
- return this.getInRange(typePredicate, pos, distance, PoiManager.Occupancy.HAS_SPACE)
|
||||||
|
- .filter(poiRecord -> combinedTypePosPredicate.test(poiRecord.getPoiType(), poiRecord.getPos()))
|
||||||
- .findFirst()
|
- .findFirst()
|
||||||
+ // Paper start - re-route to faster logic
|
+ // Paper start - re-route to faster logic
|
||||||
+ final @javax.annotation.Nullable PoiRecord closest = io.papermc.paper.util.PoiAccess.findClosestPoiDataRecord(
|
+ final @javax.annotation.Nullable PoiRecord closest = io.papermc.paper.util.PoiAccess.findClosestPoiDataRecord(
|
||||||
+ this, typePredicate, posPredicate, pos, radius, radius * radius, Occupancy.HAS_SPACE, false
|
+ this, typePredicate, combinedTypePosPredicate, pos, distance, distance * distance, Occupancy.HAS_SPACE, false
|
||||||
+ );
|
+ );
|
||||||
+ return Optional.ofNullable(closest)
|
+ return Optional.ofNullable(closest)
|
||||||
+ // Paper end - re-route to faster logic
|
+ // Paper end - re-route to faster logic
|
||||||
.map(poi -> {
|
.map(poiRecord -> {
|
||||||
poi.acquireTicket();
|
poiRecord.acquireTicket();
|
||||||
return poi.getPos();
|
return poiRecord.getPos();
|
||||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
@@ -298,8 +309,21 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
||||||
int radius,
|
int distance,
|
||||||
RandomSource random
|
RandomSource random
|
||||||
) {
|
) {
|
||||||
- List<PoiRecord> list = Util.toShuffledList(this.getInRange(typePredicate, pos, radius, occupationStatus), random);
|
- List<PoiRecord> list = Util.toShuffledList(this.getInRange(typePredicate, pos, distance, status), random);
|
||||||
- return list.stream().filter(poi -> positionPredicate.test(poi.getPos())).findFirst().map(PoiRecord::getPos);
|
- return list.stream().filter(poiRecord -> posPredicate.test(poiRecord.getPos())).findFirst().map(PoiRecord::getPos);
|
||||||
+ // Paper start - re-route to faster logic
|
+ // Paper start - re-route to faster logic
|
||||||
+ List<PoiRecord> list = new java.util.ArrayList<>();
|
+ List<PoiRecord> list = new java.util.ArrayList<>();
|
||||||
+ io.papermc.paper.util.PoiAccess.findAnyPoiRecords(
|
+ io.papermc.paper.util.PoiAccess.findAnyPoiRecords(
|
||||||
+ this, typePredicate, positionPredicate, pos, radius, occupationStatus, false, Integer.MAX_VALUE, list
|
+ this, typePredicate, posPredicate, pos, distance, status, false, Integer.MAX_VALUE, list
|
||||||
+ );
|
+ );
|
||||||
+
|
+
|
||||||
+ // the old method shuffled the list and then tried to find the first element in it that
|
+ // the old method shuffled the list and then tried to find the first element in it that
|
||||||
@ -979,11 +980,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean release(BlockPos pos) {
|
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
|
diff --git a/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 39cd1e3d8192d7077d6b7864d33933097cc6b986..b92ba4d194fd3af94c7af5d8e150fc4297c73ab8 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
--- a/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
+++ b/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||||
@@ -0,0 +0,0 @@ import org.slf4j.Logger;
|
@@ -26,7 +26,7 @@ import org.slf4j.Logger;
|
||||||
public class PoiSection implements ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiSection { // Paper - rewrite chunk system
|
public class PoiSection implements ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiSection { // Paper - rewrite chunk system
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
private final Short2ObjectMap<PoiRecord> records = new Short2ObjectOpenHashMap<>();
|
private final Short2ObjectMap<PoiRecord> records = new Short2ObjectOpenHashMap<>();
|
||||||
@ -992,48 +993,43 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
private final Runnable setDirty;
|
private final Runnable setDirty;
|
||||||
private boolean isValid;
|
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
|
diff --git a/net/minecraft/world/level/chunk/storage/SectionStorage.java b/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 778bd73a938c94ecb85ca0f8b686ff4e1baee040..79d4ce7712f16995b0de3be86477fb43ab3961d7 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
--- a/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
+++ b/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||||
@@ -0,0 +0,0 @@ public class SectionStorage<R, P> implements AutoCloseable, ca.spottedleaf.moonr
|
@@ -131,11 +131,11 @@ public class SectionStorage<R, P> implements AutoCloseable, ca.spottedleaf.moonr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
- protected Optional<R> get(long pos) {
|
- protected Optional<R> get(long sectionKey) {
|
||||||
+ public Optional<R> get(long pos) { // Paper - public
|
+ public Optional<R> get(long sectionKey) { // Paper - public
|
||||||
return this.storage.get(pos);
|
return this.storage.get(sectionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
- protected Optional<R> getOrLoad(long pos) {
|
- protected Optional<R> getOrLoad(long sectionKey) {
|
||||||
+ public Optional<R> getOrLoad(long pos) { // Paper - public
|
+ public Optional<R> getOrLoad(long sectionKey) { // Paper - public
|
||||||
if (this.outsideStoredRange(pos)) {
|
if (this.outsideStoredRange(sectionKey)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else {
|
} 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
|
diff --git a/net/minecraft/world/level/portal/PortalForcer.java b/net/minecraft/world/level/portal/PortalForcer.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index ada2da62d3a40d67e64f5f8d7299f78b5c6f53cb..90ae71eb8cc7f925eb212f39731d70f3bff5ef0a 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
--- a/net/minecraft/world/level/portal/PortalForcer.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
+++ b/net/minecraft/world/level/portal/PortalForcer.java
|
||||||
@@ -0,0 +0,0 @@ public class PortalForcer {
|
@@ -48,13 +48,38 @@ public class PortalForcer {
|
||||||
// int i = flag ? 16 : 128;
|
PoiManager poiManager = this.level.getPoiManager();
|
||||||
|
// int i = isNether ? 16 : 128;
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
- poiManager.ensureLoadedAndValid(this.level, exitPos, i);
|
||||||
- villageplace.ensureLoadedAndValid(this.level, blockposition, i);
|
- return poiManager.getInSquare(holder -> holder.is(PoiTypes.NETHER_PORTAL), exitPos, i, PoiManager.Occupancy.ANY)
|
||||||
- Stream<BlockPos> stream = villageplace.getInSquare((holder) -> { // CraftBukkit - decompile error
|
- .map(PoiRecord::getPos)
|
||||||
- return holder.is(PoiTypes.NETHER_PORTAL);
|
- .filter(worldBorder::isWithinBounds)
|
||||||
- }, blockposition, i, PoiManager.Occupancy.ANY).map(PoiRecord::getPos);
|
- .filter(pos -> !(this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) // Paper - Configurable nether ceiling damage
|
||||||
-
|
- .filter(blockPos -> this.level.getBlockState(blockPos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS))
|
||||||
- Objects.requireNonNull(worldborder);
|
- .min(Comparator.<BlockPos>comparingDouble(blockPos -> blockPos.distSqr(exitPos)).thenComparingInt(Vec3i::getY));
|
||||||
- return stream.filter(worldborder::isWithinBounds).filter(pos -> !(this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))).filter((blockposition1) -> { // Paper - Configurable nether ceiling damage
|
|
||||||
- return this.level.getBlockState(blockposition1).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
|
|
||||||
- }).min(Comparator.comparingDouble((BlockPos blockposition1) -> { // CraftBukkit - decompile error
|
|
||||||
- return blockposition1.distSqr(blockposition);
|
|
||||||
- }).thenComparingInt(Vec3i::getY));
|
|
||||||
+ // Paper start - optimise portals
|
+ // Paper start - optimise portals
|
||||||
+ Optional<PoiRecord> optional;
|
|
||||||
+ java.util.List<PoiRecord> records = new java.util.ArrayList<>();
|
+ java.util.List<PoiRecord> records = new java.util.ArrayList<>();
|
||||||
+ io.papermc.paper.util.PoiAccess.findClosestPoiDataRecords(
|
+ io.papermc.paper.util.PoiAccess.findClosestPoiDataRecords(
|
||||||
+ villageplace,
|
+ poiManager,
|
||||||
+ type -> type.is(PoiTypes.NETHER_PORTAL),
|
+ type -> type.is(PoiTypes.NETHER_PORTAL),
|
||||||
+ (BlockPos pos) -> {
|
+ (BlockPos pos) -> {
|
||||||
+ net.minecraft.world.level.chunk.ChunkAccess lowest = this.level.getChunk(pos.getX() >> 4, pos.getZ() >> 4, net.minecraft.world.level.chunk.status.ChunkStatus.EMPTY);
|
+ net.minecraft.world.level.chunk.ChunkAccess lowest = this.level.getChunk(pos.getX() >> 4, pos.getZ() >> 4, net.minecraft.world.level.chunk.status.ChunkStatus.EMPTY);
|
||||||
@ -1042,12 +1038,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ // why would we generate the chunk?
|
+ // why would we generate the chunk?
|
||||||
+ return false;
|
+ return false;
|
||||||
+ }
|
+ }
|
||||||
+ if (!worldborder.isWithinBounds(pos) || (this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) { // Paper - Configurable nether ceiling damage
|
+ if (!worldBorder.isWithinBounds(pos) || (this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) { // Paper - Configurable nether ceiling damage
|
||||||
+ return false;
|
+ return false;
|
||||||
+ }
|
+ }
|
||||||
+ return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
|
+ return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
|
||||||
+ },
|
+ },
|
||||||
+ blockposition, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records
|
+ exitPos, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records
|
||||||
+ );
|
+ );
|
||||||
+
|
+
|
||||||
+ // this gets us most of the way there, but we bias towards lower y values.
|
+ // this gets us most of the way there, but we bias towards lower y values.
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren