9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-24 01:09:29 +00:00

rewrite linear region

This commit is contained in:
NONPLAYT
2025-04-14 22:55:27 +03:00
parent b8342ec025
commit 9ecce7b5df
14 changed files with 771 additions and 408 deletions

View File

@@ -48,7 +48,7 @@
} }
} }
@@ -142,10 +_,22 @@ @@ -142,10 +_,23 @@
} }
dependencies { dependencies {
@@ -62,6 +62,7 @@
+ } + }
+ implementation("net.objecthunter:exp4j:0.4.8") + implementation("net.objecthunter:exp4j:0.4.8")
+ implementation("org.agrona:agrona:2.0.1") + implementation("org.agrona:agrona:2.0.1")
+ implementation("net.openhft:zero-allocation-hashing:0.16")
+ implementation("com.github.luben:zstd-jni:1.5.6-9") + implementation("com.github.luben:zstd-jni:1.5.6-9")
+ implementation("org.lz4:lz4-java:1.8.0") + implementation("org.lz4:lz4-java:1.8.0")
+ // DivineMC end + // DivineMC end

View File

@@ -1293,7 +1293,7 @@ index 6540b2d6a1062d883811ce240c49d30d1925b291..8055b8552b40160732953b15876dda79
} }
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a26a598f6e 100644 index eb6286d34a68bf6eb57877a9cfc2be09615c7e83..f4b1f45f1dc86bd077860f088cdd6da78ecc6020 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -77,8 +77,6 @@ import net.minecraft.util.ProgressListener; @@ -77,8 +77,6 @@ import net.minecraft.util.ProgressListener;
@@ -1437,7 +1437,7 @@ index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a2
} }
@VisibleForTesting @VisibleForTesting
@@ -1330,17 +1296,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1356,17 +1322,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} }
// Paper end - log detailed entity tick information // Paper end - log detailed entity tick information
entity.setOldPosAndRot(); entity.setOldPosAndRot();
@@ -1455,7 +1455,7 @@ index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a2
for (Entity entity1 : entity.getPassengers()) { for (Entity entity1 : entity.getPassengers()) {
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
@@ -1361,9 +1323,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1387,9 +1349,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
passengerEntity.setOldPosAndRot(); passengerEntity.setOldPosAndRot();
passengerEntity.tickCount++; passengerEntity.tickCount++;
passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities
@@ -1465,7 +1465,7 @@ index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a2
// Paper start - EAR 2 // Paper start - EAR 2
if (isActive) { if (isActive) {
passengerEntity.rideTick(); passengerEntity.rideTick();
@@ -1375,7 +1334,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1401,7 +1360,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
ridingEntity.positionRider(passengerEntity); ridingEntity.positionRider(passengerEntity);
} }
// Paper end - EAR 2 // Paper end - EAR 2

View File

@@ -208,10 +208,10 @@ index 0fb253aa55a24b56b17f524b3261c5b75c7d7e59..b6053158f5d9b6ad325ea075ab7c60f9
attributesToSync.clear(); attributesToSync.clear();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 9afd448ede87c9192dc576f66e08676a68b34d98..d4b44e0fdf113e66c45cc86221df20fe2d3bb9f0 100644 index c229d69ce3d007e4cb57e559611b3fca7a03562f..ba5ca5213fafd60b2257409f334a7c6b28fe918a 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -2471,7 +2471,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -2497,7 +2497,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override @Override
public LevelEntityGetter<Entity> getEntities() { public LevelEntityGetter<Entity> getEntities() {
@@ -220,7 +220,7 @@ index 9afd448ede87c9192dc576f66e08676a68b34d98..d4b44e0fdf113e66c45cc86221df20fe
return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system
} }
@@ -2698,7 +2698,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -2724,7 +2724,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} }
map.carriedByPlayers.remove(player); map.carriedByPlayers.remove(player);

View File

@@ -435,7 +435,7 @@ index 0d889730641fd88d4da0c9116226a4dae385e846..f7a061ad623fa909389c60c1d5b4be84
try { try {
org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings")); org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings"));
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index d4b44e0fdf113e66c45cc86221df20fe2d3bb9f0..50ea7f4a0428cbc49fb13a31b1fa643e00ef9434 100644 index ba5ca5213fafd60b2257409f334a7c6b28fe918a..52ba052fc1ff2a35786570c282a7de4e9dff99f5 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -182,7 +182,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -182,7 +182,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -463,7 +463,7 @@ index d4b44e0fdf113e66c45cc86221df20fe2d3bb9f0..50ea7f4a0428cbc49fb13a31b1fa643e
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
} }
@@ -1255,12 +1257,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1281,12 +1283,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
if (fluidState.is(fluid)) { if (fluidState.is(fluid)) {
fluidState.tick(this, pos, blockState); fluidState.tick(this, pos, blockState);
} }
@@ -481,7 +481,7 @@ index d4b44e0fdf113e66c45cc86221df20fe2d3bb9f0..50ea7f4a0428cbc49fb13a31b1fa643e
} }
private void tickBlock(BlockPos pos, Block block) { private void tickBlock(BlockPos pos, Block block) {
@@ -1268,12 +1270,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1294,12 +1296,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
if (blockState.is(block)) { if (blockState.is(block)) {
blockState.tick(this, pos, this.random); blockState.tick(this, pos, this.random);
} }
@@ -499,7 +499,7 @@ index d4b44e0fdf113e66c45cc86221df20fe2d3bb9f0..50ea7f4a0428cbc49fb13a31b1fa643e
} }
// Paper start - log detailed entity tick information // Paper start - log detailed entity tick information
@@ -1522,6 +1524,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1548,6 +1550,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} }
private void addPlayer(ServerPlayer player) { private void addPlayer(ServerPlayer player) {
@@ -507,7 +507,7 @@ index d4b44e0fdf113e66c45cc86221df20fe2d3bb9f0..50ea7f4a0428cbc49fb13a31b1fa643e
Entity entity = this.getEntities().get(player.getUUID()); Entity entity = this.getEntities().get(player.getUUID());
if (entity != null) { if (entity != null) {
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID()); LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
@@ -1534,7 +1537,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1560,7 +1563,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// CraftBukkit start // CraftBukkit start
private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {

View File

@@ -1092,7 +1092,7 @@ index ab30af9cd58ff7310e05be87b08f42bacf69e11e..ae0e36d198ad8243920c8e8a55c0be49
} }
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 50ea7f4a0428cbc49fb13a31b1fa643e00ef9434..a70007d324e2169d1b2a1a11046500196b8b5660 100644 index 52ba052fc1ff2a35786570c282a7de4e9dff99f5..9298bdca9a653622f3625190e875e7b6c5e40023 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -181,6 +181,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -181,6 +181,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1199,7 +1199,7 @@ index 50ea7f4a0428cbc49fb13a31b1fa643e00ef9434..a70007d324e2169d1b2a1a1104650019
} }
// Paper end - optimise random ticking // Paper end - optimise random ticking
@@ -2531,30 +2533,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -2557,30 +2559,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) { private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) {
// Paper start - rewrite chunk system // Paper start - rewrite chunk system

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Linear region file format
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
index a814512fcfb85312474ae2c2c21443843bf57831..c21e04c1d43797db221e4712fcc987a44eaa983c 100644 index a814512fcfb85312474ae2c2c21443843bf57831..fdccc27c528b01b16a72e614ffd96523aa6f50d2 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
@@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage { @@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage {
@@ -13,15 +13,15 @@ index a814512fcfb85312474ae2c2c21443843bf57831..c21e04c1d43797db221e4712fcc987a4
public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ); public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ);
- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); - public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ);
+ public org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Linear region file format + public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Linear region file format
- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; - public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException;
+ public org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Linear region file format + public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Linear region file format
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite( public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(
final int chunkX, final int chunkZ, final CompoundTag compound final int chunkX, final int chunkZ, final CompoundTag compound
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..57ae23fdd5a95e7670eb4dfaca0d290edfc1d25c 100644 index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..34682217252cb98a70511a8cb25f077ec9f872b8 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
@@ -1260,7 +1260,7 @@ public final class MoonriseRegionFileIO { @@ -1260,7 +1260,7 @@ public final class MoonriseRegionFileIO {
@@ -29,7 +29,7 @@ index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..57ae23fdd5a95e7670eb4dfaca0d290e
// Paper start - flush regionfiles on save // Paper start - flush regionfiles on save
if (this.world.paperConfig().chunks.flushRegionsOnSave) { if (this.world.paperConfig().chunks.flushRegionsOnSave) {
- final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); - final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Linear region file format
if (regionFile != null) { if (regionFile != null) {
regionFile.flush(); regionFile.flush();
} // else: evicted from cache, which should have called flush } // else: evicted from cache, which should have called flush
@@ -38,12 +38,12 @@ index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..57ae23fdd5a95e7670eb4dfaca0d290e
public static interface IORunnable { public static interface IORunnable {
- public void run(final RegionFile regionFile) throws IOException; - public void run(final RegionFile regionFile) throws IOException;
+ public void run(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format + public void run(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format
} }
} }
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
index 51c126735ace8fdde89ad97b5cab62f244212db0..c466ce5c669e4b5ed835b13584a5ae5afe08fa11 100644 index 51c126735ace8fdde89ad97b5cab62f244212db0..8713d00d767c9225a0823d2fdbb0b479005738d7 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer { @@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer {
@@ -51,10 +51,10 @@ index 51c126735ace8fdde89ad97b5cab62f244212db0..c466ce5c669e4b5ed835b13584a5ae5a
public void moonrise$setWriteOnClose(final boolean value); public void moonrise$setWriteOnClose(final boolean value);
- public void moonrise$write(final RegionFile regionFile) throws IOException; - public void moonrise$write(final RegionFile regionFile) throws IOException;
+ public void moonrise$write(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format + public void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format
} }
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 9d6fa3bced0ba5ab3443bdf4ce306598a8e4a31f..34bc5d54de26608e64170bd902baa87da137dab6 100644 index 26a4a279122bb03a83dd4a34e780d6a4567ba3a8..51b79f614417f231951e9ba05b29ff0044e081e7 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -947,10 +947,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -947,10 +947,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -71,7 +71,7 @@ index 9d6fa3bced0ba5ab3443bdf4ce306598a8e4a31f..34bc5d54de26608e64170bd902baa87d
return flag; return flag;
diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java
index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d05ce3afb3 100644 index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..e99f3c3567f9e6fb5a328bf9b59d40c72522f922 100644
--- a/net/minecraft/util/worldupdate/WorldUpgrader.java --- a/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/net/minecraft/util/worldupdate/WorldUpgrader.java +++ b/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -72,7 +72,7 @@ public class WorldUpgrader implements AutoCloseable { @@ -72,7 +72,7 @@ public class WorldUpgrader implements AutoCloseable {
@@ -97,7 +97,7 @@ index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d0
List<ChunkPos> list1 = Lists.newArrayList(); List<ChunkPos> list1 = Lists.newArrayList();
- try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) { - try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) {
+ try (org.stupidcraft.linearpaper.region.IRegionFile regionFile = org.stupidcraft.linearpaper.region.IRegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Linear region file format + try (org.bxteam.divinemc.region.IRegionFile regionFile = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Linear region file format
for (int i2 = 0; i2 < 32; i2++) { for (int i2 = 0; i2 < 32; i2++) {
for (int i3 = 0; i3 < 32; i3++) { for (int i3 = 0; i3 < 32; i3++) {
ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1); ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1);
@@ -106,7 +106,7 @@ index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d0
protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey<Level> dimension); protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey<Level> dimension);
- private void onFileFinished(RegionFile regionFile) { - private void onFileFinished(RegionFile regionFile) {
+ private void onFileFinished(org.stupidcraft.linearpaper.region.IRegionFile regionFile) { // DivineMC - Linear region file format + private void onFileFinished(org.bxteam.divinemc.region.IRegionFile regionFile) { // DivineMC - Linear region file format
if (WorldUpgrader.this.recreateRegionFiles) { if (WorldUpgrader.this.recreateRegionFiles) {
if (this.previousWriteFuture != null) { if (this.previousWriteFuture != null) {
this.previousWriteFuture.join(); this.previousWriteFuture.join();
@@ -115,12 +115,12 @@ index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d0
} }
- record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) { - record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) {
+ record FileToUpgrade(org.stupidcraft.linearpaper.region.IRegionFile file, List<ChunkPos> chunksToUpgrade) { // DivineMC - Linear region file format + record FileToUpgrade(org.bxteam.divinemc.region.IRegionFile file, List<ChunkPos> chunksToUpgrade) { // DivineMC - Linear region file format
} }
class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader { class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader {
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/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 c72494e757a9dc50e053dbc873f7b30e83d5cb8c..5d29e3046485dcdda9356f6bfe6f6463e9b9bef4 100644 index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..2988084cf2d72557dd304dcb904d09441e79863d 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java --- a/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; @@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler;
@@ -128,7 +128,7 @@ index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..5d29e3046485dcdda9356f6bfe6f6463
import org.slf4j.Logger; import org.slf4j.Logger;
-public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system -public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.stupidcraft.linearpaper.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Linear region file format +public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.bxteam.divinemc.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Linear region file format
private static final Logger LOGGER = LogUtils.getLogger(); 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 static final int SECTOR_BYTES = 4096; private static final int SECTOR_BYTES = 4096;
@@ -137,12 +137,12 @@ index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..5d29e3046485dcdda9356f6bfe6f6463
@Override @Override
- public final void moonrise$write(final RegionFile regionFile) throws IOException { - public final void moonrise$write(final RegionFile regionFile) throws IOException {
+ public final void moonrise$write(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException { // DivineMC - Linear region file format + public final void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException { // DivineMC - Linear region file format
regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count)); regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count));
} }
// Paper end - rewrite chunk system // Paper end - rewrite chunk system
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/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 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b4196cf25588 100644 index 16cd10ab8de69ca3d29c84cf93715645322fd72a..9fd987078625bee796b381108ae7dbfb1f14d256 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -18,7 +18,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @@ -18,7 +18,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
@@ -150,7 +150,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
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<>();
+ public final Long2ObjectLinkedOpenHashMap<org.stupidcraft.linearpaper.region.IRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Linear region file format + public final Long2ObjectLinkedOpenHashMap<org.bxteam.divinemc.region.IRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Linear region file format
private final RegionStorageInfo info; private final RegionStorageInfo info;
private final Path folder; private final Path folder;
private final boolean sync; private final boolean sync;
@@ -168,7 +168,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet();
private static String getRegionFileName(final int chunkX, final int chunkZ) { private static String getRegionFileName(final int chunkX, final int chunkZ) {
+ // DivineMC start - Linear region file format + // DivineMC start - Linear region file format
+ if (org.bxteam.divinemc.DivineConfig.regionFormatTypeName == org.stupidcraft.linearpaper.region.EnumRegionFileExtension.LINEAR) { + if (org.bxteam.divinemc.DivineConfig.regionFormatTypeName == org.bxteam.divinemc.region.RegionFileFormat.LINEAR) {
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear"; + return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear";
+ } + }
+ // DivineMC end - Linear region file format + // DivineMC end - Linear region file format
@@ -181,17 +181,17 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
@Override @Override
- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { - public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) {
+ public synchronized final org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Linear region file format + public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Linear region file format
return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT)); return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT));
} }
@Override @Override
- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { - public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException {
+ public synchronized final org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Linear region file format + public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Linear region file format
final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT);
- RegionFile ret = this.regionCache.getAndMoveToFirst(key); - RegionFile ret = this.regionCache.getAndMoveToFirst(key);
+ org.stupidcraft.linearpaper.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format
if (ret != null) { if (ret != null) {
return ret; return ret;
} }
@@ -200,7 +200,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
FileUtil.createDirectoriesSafe(this.folder); FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync); - ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = org.stupidcraft.linearpaper.region.IRegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format + ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format
this.regionCache.putAndMoveToFirst(key, ret); this.regionCache.putAndMoveToFirst(key, ret);
@@ -209,7 +209,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final ChunkPos pos = new ChunkPos(chunkX, chunkZ); final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
- final RegionFile regionFile = this.getRegionFile(pos); - final RegionFile regionFile = this.getRegionFile(pos);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Linear region file format
// note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input // note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input
// (and, the regionfile parameter is unused for writing until the write call) // (and, the regionfile parameter is unused for writing until the write call)
@@ -223,7 +223,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final ChunkPos pos = new ChunkPos(chunkX, chunkZ); final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) { if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) {
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); - final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format
if (regionFile != null) { if (regionFile != null) {
regionFile.clear(pos); regionFile.clear(pos);
} // else: didn't exist } // else: didn't exist
@@ -232,7 +232,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final int chunkX, final int chunkZ final int chunkX, final int chunkZ
) throws IOException { ) throws IOException {
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); - final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ)); final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
@@ -241,7 +241,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
// Paper end - rewrite chunk system // Paper end - rewrite chunk system
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
- public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { - public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException {
+ public org.stupidcraft.linearpaper.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Linear region file format + public org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Linear region file format
return this.getRegionFile(chunkcoordintpair, false); return this.getRegionFile(chunkcoordintpair, false);
} }
// Paper end - rewrite chunk system // Paper end - rewrite chunk system
@@ -250,7 +250,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
} }
- @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit - @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit
+ @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.stupidcraft.linearpaper.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Linear region file format + @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Linear region file format
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
if (existingOnly) { if (existingOnly) {
return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z); return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z);
@@ -259,7 +259,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT); final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT);
- RegionFile ret = this.regionCache.getAndMoveToFirst(key); - RegionFile ret = this.regionCache.getAndMoveToFirst(key);
+ org.stupidcraft.linearpaper.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format
if (ret != null) { if (ret != null) {
return ret; return ret;
} }
@@ -268,7 +268,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
FileUtil.createDirectoriesSafe(this.folder); FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync); - ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = org.stupidcraft.linearpaper.region.IRegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format + ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format
this.regionCache.putAndMoveToFirst(key, ret); this.regionCache.putAndMoveToFirst(key, ret);
@@ -277,7 +277,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
} }
- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { - private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
+ private static CompoundTag readOversizedChunk(org.stupidcraft.linearpaper.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Linear region file format + private static CompoundTag readOversizedChunk(org.bxteam.divinemc.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Linear region file format
synchronized (regionfile) { synchronized (regionfile) {
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
@@ -286,7 +286,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public CompoundTag read(ChunkPos chunkPos) throws IOException { public CompoundTag read(ChunkPos chunkPos) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
- RegionFile regionFile = this.getRegionFile(chunkPos, true); - RegionFile regionFile = this.getRegionFile(chunkPos, true);
+ org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format
if (regionFile == null) { if (regionFile == null) {
return null; return null;
} }
@@ -295,7 +295,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException { public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
- RegionFile regionFile = this.getRegionFile(chunkPos, true); - RegionFile regionFile = this.getRegionFile(chunkPos, true);
+ org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format
if (regionFile == null) { if (regionFile == null) {
return; return;
} }
@@ -304,7 +304,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public
- RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system - RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system
+ org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Linear region file format
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
if (regionFile == null) { if (regionFile == null) {
// if the RegionFile doesn't exist, no point in deleting from it // if the RegionFile doesn't exist, no point in deleting from it
@@ -313,7 +313,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
synchronized (this) { synchronized (this) {
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
- for (final RegionFile regionFile : this.regionCache.values()) { - for (final RegionFile regionFile : this.regionCache.values()) {
+ for (final org.stupidcraft.linearpaper.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format + for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format
try { try {
regionFile.close(); regionFile.close();
} catch (final IOException ex) { } catch (final IOException ex) {
@@ -322,7 +322,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
synchronized (this) { synchronized (this) {
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
- for (final RegionFile regionFile : this.regionCache.values()) { - for (final RegionFile regionFile : this.regionCache.values()) {
+ for (final org.stupidcraft.linearpaper.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format + for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format
try { try {
regionFile.flush(); regionFile.flush();
} catch (final IOException ex) { } catch (final IOException ex) {

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Add missing purpur config options
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 168361632d4af27c2144864ade539ce7ea217217..48248e1a7eb9f63220dd619c1868dcca3150c345 100644 index 554ae05a1a7f7dbe91455cb14b1d9a02f3b7d288..2c32f98e4f3ac2705ae6e95a8e8965b4b9d9a0d5 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -327,6 +327,7 @@ public class PurpurConfig { @@ -327,6 +327,7 @@ public class PurpurConfig {
@@ -16,7 +16,7 @@ index 168361632d4af27c2144864ade539ce7ea217217..48248e1a7eb9f63220dd619c1868dcca
public static boolean enderChestSixRows = false; public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false; public static boolean enderChestPermissionRows = false;
public static boolean cryingObsidianValidForPortalFrame = false; public static boolean cryingObsidianValidForPortalFrame = false;
@@ -369,6 +370,7 @@ public class PurpurConfig { @@ -370,6 +371,7 @@ public class PurpurConfig {
case 1 -> 9; case 1 -> 9;
default -> 27; default -> 27;
}); });

View File

@@ -10,13 +10,14 @@ import org.apache.logging.log4j.Logger;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.configuration.MemoryConfiguration;
import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy;
import org.bxteam.divinemc.region.LinearImplementation;
import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms; import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms;
import org.bxteam.divinemc.server.chunk.ChunkTaskPriority; import org.bxteam.divinemc.server.chunk.ChunkTaskPriority;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.simpleyaml.configuration.comments.CommentType; import org.simpleyaml.configuration.comments.CommentType;
import org.simpleyaml.configuration.file.YamlFile; import org.simpleyaml.configuration.file.YamlFile;
import org.simpleyaml.exceptions.InvalidConfigurationException; import org.simpleyaml.exceptions.InvalidConfigurationException;
import org.stupidcraft.linearpaper.region.EnumRegionFileExtension; import org.bxteam.divinemc.region.RegionFileFormat;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -526,32 +527,50 @@ public class DivineConfig {
if (asyncEntityTrackerQueueSize <= 0) asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384; if (asyncEntityTrackerQueueSize <= 0) asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
} }
public static EnumRegionFileExtension regionFormatTypeName = EnumRegionFileExtension.MCA; public static RegionFileFormat regionFormatTypeName = RegionFileFormat.ANVIL;
public static LinearImplementation linearImplementation = LinearImplementation.V2;
public static int linearFlushMaxThreads = 4;
public static int linearFlushDelay = 100;
public static boolean linearUseVirtualThread = false;
public static int linearCompressionLevel = 1; public static int linearCompressionLevel = 1;
public static int linearFlushFrequency = 5;
private static void linearRegionFormat() { private static void linearRegionFormat() {
regionFormatTypeName = EnumRegionFileExtension.fromName(getString("settings.linear-region-format.type", regionFormatTypeName.name(), regionFormatTypeName = RegionFileFormat.fromName(getString("settings.linear-region-format.type", regionFormatTypeName.name(),
"The type of region file format to use for storing chunk data.", "The type of region file format to use for storing chunk data.",
"Valid values:", "Valid values:",
" - LINEAR: Linear region file format", " - LINEAR: Linear region file format",
" - MCA: Anvil region file format (default)")); " - ANVIL: Anvil region file format (default)"));
linearImplementation = LinearImplementation.valueOf(getString("settings.linear-region-format.implementation", linearImplementation.name(),
"The implementation of the linear region file format to use.",
"Valid values:",
" - V1: Basic and default linear implementation",
" - V2: Introduces a grid-based compression scheme for better data management and flexibility (default)"));
linearFlushMaxThreads = getInt("settings.linear-region-format.flush-max-threads", linearFlushMaxThreads,
"The maximum number of threads to use for flushing linear region files.",
"If this value is less than or equal to 0, it will be set to the number of available processors + this value.");
linearFlushDelay = getInt("settings.linear-region-format.flush-delay", linearFlushDelay,
"The delay in milliseconds to wait before flushing next files.");
linearUseVirtualThread = getBoolean("settings.linear-region-format.use-virtual-thread", linearUseVirtualThread,
"Whether to use virtual threads for flushing.");
linearCompressionLevel = getInt("settings.linear-region-format.compression-level", linearCompressionLevel, linearCompressionLevel = getInt("settings.linear-region-format.compression-level", linearCompressionLevel,
"The compression level to use for the linear region file format."); "The compression level to use for the linear region file format.");
linearFlushFrequency = getInt("settings.linear-region-format.flush-frequency", linearFlushFrequency,
"The frequency in seconds to flush the linear region file format.");
setComment("settings.linear-region-format", setComment("settings.linear-region-format",
"The linear region file format is a custom region file format that is designed to be more efficient than the MCA format.", "The linear region file format is a custom region file format that is designed to be more efficient than the ANVIL format.",
"It uses uses ZSTD compression instead of ZLIB. This format saves about 50% of disk space.", "It uses uses ZSTD compression instead of ZLIB. This format saves about 50% of disk space.",
"Read more information about linear region format at https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools", "Read more information about linear region format at https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools",
"WARNING: If you are want to use this format, make sure to create backup of your world before switching to it, there is potential risk to lose chunk data."); "WARNING: If you are want to use this format, make sure to create backup of your world before switching to it, there is potential risk to lose chunk data.");
if (regionFormatTypeName == EnumRegionFileExtension.UNKNOWN) { if (regionFormatTypeName == RegionFileFormat.UNKNOWN) {
LOGGER.error("Unknown region file type: {}, falling back to MCA format.", regionFormatTypeName); LOGGER.error("Unknown region file type: {}, falling back to ANVIL format.", regionFormatTypeName);
regionFormatTypeName = EnumRegionFileExtension.MCA; regionFormatTypeName = RegionFileFormat.ANVIL;
} }
if (linearCompressionLevel > 23 || linearCompressionLevel < 1) { if (linearFlushMaxThreads <= 0) {
linearFlushMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + linearFlushMaxThreads, 1);
}
if (linearCompressionLevel > 22 || linearCompressionLevel < 1) {
LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", playerNearChunkDetectionRange); LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", playerNearChunkDetectionRange);
linearCompressionLevel = 1; linearCompressionLevel = 1;
} }

View File

@@ -1,4 +1,4 @@
package org.stupidcraft.linearpaper.region; package org.bxteam.divinemc.region;
import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile; import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;

View File

@@ -0,0 +1,6 @@
package org.bxteam.divinemc.region;
public enum LinearImplementation {
V1,
V2
}

View File

@@ -0,0 +1,659 @@
package org.bxteam.divinemc.region;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import com.github.luben.zstd.ZstdInputStream;
import com.github.luben.zstd.ZstdOutputStream;
import com.mojang.logging.LogUtils;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import net.openhft.hashing.LongHashFunction;
import org.bxteam.divinemc.DivineConfig;
import org.bxteam.divinemc.spark.ThreadDumperRegistry;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LinearRegionFile implements IRegionFile {
public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024;
private static final Object SAVE_LOCK = new Object();
private static final long SUPERBLOCK = 0xc3ff13183cca9d9aL;
private static final Logger LOGGER = LogUtils.getLogger();
private static final byte V1_VERSION = 2;
private static final byte V2_VERSION = 3;
private byte[][] bucketBuffers;
private final byte[][] chunkCompressedBuffers = new byte[1024][];
private final int[] chunkUncompressedSizes = new int[1024];
private final long[] chunkTimestamps = new long[1024];
private final Object markedToSaveLock = new Object();
private boolean markedToSave = false;
private final LZ4Compressor compressor;
private final LZ4FastDecompressor decompressor;
private volatile boolean regionFileOpen = false;
private volatile boolean close = false;
private final Path regionFilePath;
private final int gridSizeDefault = 8;
private int gridSize = gridSizeDefault;
private int bucketSize = 4;
private final int compressionLevel;
private final LinearImplementation linearImpl;
private final Thread schedulingThread;
private static int activeSaveThreads = 0;
public LinearRegionFile(Path path, LinearImplementation linearImplementation, int compressionLevel) {
this.regionFilePath = path;
this.linearImpl = linearImplementation;
this.compressionLevel = compressionLevel;
this.compressor = LZ4Factory.fastestInstance().fastCompressor();
this.decompressor = LZ4Factory.fastestInstance().fastDecompressor();
Runnable flushCheck = () -> {
while (!close) {
synchronized (SAVE_LOCK) {
if (markedToSave && activeSaveThreads < DivineConfig.linearFlushMaxThreads) {
activeSaveThreads++;
Runnable flushOperation = () -> {
try {
flush();
} catch (IOException ex) {
LOGGER.error("Region file {} flush failed", regionFilePath.toAbsolutePath(), ex);
} finally {
synchronized (SAVE_LOCK) {
activeSaveThreads--;
}
}
};
Thread saveThread = DivineConfig.linearUseVirtualThread
? Thread.ofVirtual().name("Linear IO - " + this.hashCode()).unstarted(flushOperation)
: Thread.ofPlatform().name("Linear IO - " + this.hashCode()).unstarted(flushOperation);
saveThread.setPriority(Thread.NORM_PRIORITY - 3);
saveThread.start();
ThreadDumperRegistry.REGISTRY.add(saveThread.getName());
}
}
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(DivineConfig.linearFlushDelay));
}
};
this.schedulingThread = DivineConfig.linearUseVirtualThread
? Thread.ofVirtual().unstarted(flushCheck)
: Thread.ofPlatform().unstarted(flushCheck);
this.schedulingThread.setName("Linear IO Schedule - " + this.hashCode());
ThreadDumperRegistry.REGISTRY.add(this.schedulingThread.getName());
}
private synchronized void openRegionFile() {
if (regionFileOpen) return;
regionFileOpen = true;
File file = regionFilePath.toFile();
if (!file.canRead()) {
schedulingThread.start();
return;
}
try {
byte[] fileContent = Files.readAllBytes(regionFilePath);
ByteBuffer byteBuffer = ByteBuffer.wrap(fileContent);
long superBlock = byteBuffer.getLong();
if (superBlock != SUPERBLOCK) {
throw new RuntimeException("Invalid superblock: " + superBlock + " file " + regionFilePath);
}
byte version = byteBuffer.get();
if (version == V1_VERSION) {
parseLinearV1(byteBuffer);
} else if (version == V2_VERSION) {
parseLinearV2(byteBuffer);
} else {
throw new RuntimeException("Invalid version: " + version + " file " + regionFilePath);
}
schedulingThread.start();
} catch (IOException e) {
throw new RuntimeException("Failed to open region file " + regionFilePath, e);
}
}
private void parseLinearV1(ByteBuffer buffer) throws IOException {
final int HEADER_SIZE = 32;
final int FOOTER_SIZE = 8;
buffer.position(buffer.position() + 11);
int dataCount = buffer.getInt();
long fileLength = regionFilePath.toFile().length();
if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) {
throw new IOException("Invalid file length: " + regionFilePath + " " + fileLength + " expected " + (HEADER_SIZE + dataCount + FOOTER_SIZE));
}
buffer.position(buffer.position() + 8);
byte[] rawCompressed = new byte[dataCount];
buffer.get(rawCompressed);
try (ByteArrayInputStream bais = new ByteArrayInputStream(rawCompressed);
ZstdInputStream zstdIn = new ZstdInputStream(bais)) {
ByteBuffer decompressedBuffer = ByteBuffer.wrap(zstdIn.readAllBytes());
int[] starts = new int[1024];
for (int i = 0; i < 1024; i++) {
starts[i] = decompressedBuffer.getInt();
decompressedBuffer.getInt();
}
for (int i = 0; i < 1024; i++) {
if (starts[i] > 0) {
int size = starts[i];
byte[] chunkData = new byte[size];
decompressedBuffer.get(chunkData);
int maxCompressedLength = compressor.maxCompressedLength(size);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(chunkData, 0, size, compressed, 0, maxCompressedLength);
byte[] finalCompressed = new byte[compressedLength];
System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength);
chunkCompressedBuffers[i] = finalCompressed;
chunkUncompressedSizes[i] = size;
chunkTimestamps[i] = currentTimestamp();
}
}
}
}
private void parseLinearV2(ByteBuffer buffer) throws IOException {
buffer.getLong();
gridSize = buffer.get();
if (!(gridSize == 1 || gridSize == 2 || gridSize == 4 || gridSize == 8 || gridSize == 16 || gridSize == 32)) {
throw new RuntimeException("Invalid grid size: " + gridSize + " file " + regionFilePath);
}
bucketSize = 32 / gridSize;
buffer.getInt();
buffer.getInt();
boolean[] chunkExistenceBitmap = deserializeExistenceBitmap(buffer);
while (true) {
byte featureNameLength = buffer.get();
if (featureNameLength == 0) break;
byte[] featureNameBytes = new byte[featureNameLength];
buffer.get(featureNameBytes);
String featureName = new String(featureNameBytes);
int featureValue = buffer.getInt();
}
int bucketCount = gridSize * gridSize;
int[] bucketSizes = new int[bucketCount];
byte[] bucketCompressionLevels = new byte[bucketCount];
long[] bucketHashes = new long[bucketCount];
for (int i = 0; i < bucketCount; i++) {
bucketSizes[i] = buffer.getInt();
bucketCompressionLevels[i] = buffer.get();
bucketHashes[i] = buffer.getLong();
}
bucketBuffers = new byte[bucketCount][];
for (int i = 0; i < bucketCount; i++) {
if (bucketSizes[i] > 0) {
bucketBuffers[i] = new byte[bucketSizes[i]];
buffer.get(bucketBuffers[i]);
long rawHash = LongHashFunction.xx().hashBytes(bucketBuffers[i]);
if (rawHash != bucketHashes[i]) {
throw new IOException("Region file hash incorrect " + regionFilePath);
}
}
}
long footerSuperBlock = buffer.getLong();
if (footerSuperBlock != SUPERBLOCK) {
throw new IOException("Footer superblock invalid " + regionFilePath);
}
}
private synchronized void markToSave() {
synchronized (markedToSaveLock) {
markedToSave = true;
}
}
private synchronized boolean isMarkedToSave() {
synchronized (markedToSaveLock) {
if (markedToSave) {
markedToSave = false;
return true;
}
return false;
}
}
@Override
public synchronized boolean doesChunkExist(ChunkPos pos) {
openRegionFile();
return hasChunk(pos);
}
@Override
public synchronized boolean hasChunk(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
int index = getChunkIndex(pos.x, pos.z);
return chunkUncompressedSizes[index] > 0;
}
@Override
public synchronized void flush() throws IOException {
if (!isMarkedToSave()) return;
openRegionFile();
if (linearImpl == LinearImplementation.V1) {
flushLinearV1();
} else if (linearImpl == LinearImplementation.V2) {
flushLinearV2();
}
}
private void flushLinearV1() throws IOException {
long timestamp = currentTimestamp();
short chunkCount = 0;
File tempFile = new File(regionFilePath.toString() + ".tmp");
try (FileOutputStream fos = new FileOutputStream(tempFile);
ByteArrayOutputStream zstdBAOS = new ByteArrayOutputStream();
ZstdOutputStream zstdOut = new ZstdOutputStream(zstdBAOS, compressionLevel);
DataOutputStream zstdDataOut = new DataOutputStream(zstdOut);
DataOutputStream fileDataOut = new DataOutputStream(fos)) {
fileDataOut.writeLong(SUPERBLOCK);
fileDataOut.writeByte(V1_VERSION);
fileDataOut.writeLong(timestamp);
fileDataOut.writeByte(compressionLevel);
ArrayList<byte[]> decompressedChunks = new ArrayList<>(1024);
for (int i = 0; i < 1024; i++) {
if (chunkUncompressedSizes[i] != 0) {
chunkCount++;
byte[] decompressed = new byte[chunkUncompressedSizes[i]];
decompressor.decompress(chunkCompressedBuffers[i], 0, decompressed, 0, chunkUncompressedSizes[i]);
decompressedChunks.add(decompressed);
} else {
decompressedChunks.add(null);
}
}
for (int i = 0; i < 1024; i++) {
zstdDataOut.writeInt(chunkUncompressedSizes[i]);
zstdDataOut.writeInt((int) chunkTimestamps[i]);
}
for (int i = 0; i < 1024; i++) {
if (decompressedChunks.get(i) != null) {
zstdDataOut.write(decompressedChunks.get(i));
}
}
zstdDataOut.close();
fileDataOut.writeShort(chunkCount);
byte[] compressedZstdData = zstdBAOS.toByteArray();
fileDataOut.writeInt(compressedZstdData.length);
fileDataOut.writeLong(0);
fileDataOut.write(compressedZstdData);
fileDataOut.writeLong(SUPERBLOCK);
fileDataOut.flush();
fos.getFD().sync();
fos.getChannel().force(true);
}
Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING);
}
private void flushLinearV2() throws IOException {
long timestamp = currentTimestamp();
File tempFile = new File(regionFilePath.toString() + ".tmp");
try (FileOutputStream fos = new FileOutputStream(tempFile);
DataOutputStream dataOut = new DataOutputStream(fos)) {
dataOut.writeLong(SUPERBLOCK);
dataOut.writeByte(V2_VERSION);
dataOut.writeLong(timestamp);
dataOut.writeByte(gridSize);
int[] regionCoords = parseRegionCoordinates(regionFilePath.getFileName().toString());
dataOut.writeInt(regionCoords[0]);
dataOut.writeInt(regionCoords[1]);
boolean[] chunkExistence = new boolean[1024];
for (int i = 0; i < 1024; i++) {
chunkExistence[i] = (chunkUncompressedSizes[i] > 0);
}
writeExistenceBitmap(dataOut, chunkExistence);
writeNBTFeatures(dataOut);
byte[][] buckets = buildBuckets();
int bucketCount = gridSize * gridSize;
for (int i = 0; i < bucketCount; i++) {
dataOut.writeInt(buckets[i] != null ? buckets[i].length : 0);
dataOut.writeByte(compressionLevel);
long bucketHash = buckets[i] != null ? LongHashFunction.xx().hashBytes(buckets[i]) : 0;
dataOut.writeLong(bucketHash);
}
for (int i = 0; i < bucketCount; i++) {
if (buckets[i] != null) {
dataOut.write(buckets[i]);
}
}
dataOut.writeLong(SUPERBLOCK);
dataOut.flush();
fos.getFD().sync();
fos.getChannel().force(true);
}
Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING);
}
private void writeNBTFeatures(DataOutputStream dataOut) throws IOException {
dataOut.writeByte(0);
}
private byte[][] buildBuckets() throws IOException {
int bucketCount = gridSize * gridSize;
byte[][] buckets = new byte[bucketCount][];
for (int bx = 0; bx < gridSize; bx++) {
for (int bz = 0; bz < gridSize; bz++) {
int bucketIdx = bx * gridSize + bz;
if (bucketBuffers != null && bucketBuffers[bucketIdx] != null) {
buckets[bucketIdx] = bucketBuffers[bucketIdx];
continue;
}
try (ByteArrayOutputStream bucketBAOS = new ByteArrayOutputStream();
ZstdOutputStream bucketZstdOut = new ZstdOutputStream(bucketBAOS, compressionLevel);
DataOutputStream bucketDataOut = new DataOutputStream(bucketZstdOut)) {
boolean hasData = false;
int cellCount = 32 / gridSize;
for (int cx = 0; cx < cellCount; cx++) {
for (int cz = 0; cz < cellCount; cz++) {
int chunkIndex = (bx * cellCount + cx) + (bz * cellCount + cz) * 32;
if (chunkUncompressedSizes[chunkIndex] > 0) {
hasData = true;
byte[] chunkData = new byte[chunkUncompressedSizes[chunkIndex]];
decompressor.decompress(chunkCompressedBuffers[chunkIndex], 0, chunkData, 0, chunkUncompressedSizes[chunkIndex]);
bucketDataOut.writeInt(chunkData.length + 8);
bucketDataOut.writeLong(chunkTimestamps[chunkIndex]);
bucketDataOut.write(chunkData);
} else {
bucketDataOut.writeInt(0);
bucketDataOut.writeLong(chunkTimestamps[chunkIndex]);
}
}
}
bucketDataOut.close();
if (hasData) {
buckets[bucketIdx] = bucketBAOS.toByteArray();
}
}
}
}
return buckets;
}
private void openBucketForChunk(int chunkX, int chunkZ) {
int modX = Math.floorMod(chunkX, 32);
int modZ = Math.floorMod(chunkZ, 32);
int bucketIdx = chunkToBucketIndex(modX, modZ);
if (bucketBuffers == null || bucketBuffers[bucketIdx] == null) {
return;
}
try (ByteArrayInputStream bucketBAIS = new ByteArrayInputStream(bucketBuffers[bucketIdx]);
ZstdInputStream bucketZstdIn = new ZstdInputStream(bucketBAIS)) {
ByteBuffer bucketBuffer = ByteBuffer.wrap(bucketZstdIn.readAllBytes());
int cellsPerBucket = 32 / gridSize;
int bx = modX / bucketSize, bz = modZ / bucketSize;
for (int cx = 0; cx < cellsPerBucket; cx++) {
for (int cz = 0; cz < cellsPerBucket; cz++) {
int chunkIndex = (bx * cellsPerBucket + cx) + (bz * cellsPerBucket + cz) * 32;
int chunkSize = bucketBuffer.getInt();
long timestamp = bucketBuffer.getLong();
chunkTimestamps[chunkIndex] = timestamp;
if (chunkSize > 0) {
byte[] chunkData = new byte[chunkSize - 8];
bucketBuffer.get(chunkData);
int maxCompressedLength = compressor.maxCompressedLength(chunkData.length);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(chunkData, 0, chunkData.length, compressed, 0, maxCompressedLength);
byte[] finalCompressed = new byte[compressedLength];
System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength);
chunkCompressedBuffers[chunkIndex] = finalCompressed;
chunkUncompressedSizes[chunkIndex] = chunkData.length;
}
}
}
} catch (IOException ex) {
throw new RuntimeException("Region file corrupted: " + regionFilePath + " bucket: " + bucketIdx, ex);
}
bucketBuffers[bucketIdx] = null;
}
@Override
public synchronized void write(ChunkPos pos, ByteBuffer buffer) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
try {
byte[] rawData = toByteArray(new ByteArrayInputStream(buffer.array()));
int uncompressedSize = rawData.length;
if (uncompressedSize > MAX_CHUNK_SIZE) {
LOGGER.error("Chunk dupe attempt {}", regionFilePath);
clear(pos);
} else {
int maxCompressedLength = compressor.maxCompressedLength(uncompressedSize);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(rawData, 0, uncompressedSize, compressed, 0, maxCompressedLength);
byte[] finalCompressed = new byte[compressedLength];
System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength);
int index = getChunkIndex(pos.x, pos.z);
chunkCompressedBuffers[index] = finalCompressed;
chunkTimestamps[index] = currentTimestamp();
chunkUncompressedSizes[index] = uncompressedSize;
}
} catch (IOException e) {
LOGGER.error("Chunk write IOException {} {}", e, regionFilePath);
}
markToSave();
}
@Override
public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos)));
}
@Override
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) {
DataOutputStream out = getChunkDataOutputStream(pos);
return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData(
data,
ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
out,
regionFile -> {
try {
out.close();
} catch (IOException e) {
LOGGER.error("Failed to close region file stream", e);
}
}
);
}
private class ChunkBuffer extends ByteArrayOutputStream {
private final ChunkPos pos;
public ChunkBuffer(ChunkPos pos) {
super();
this.pos = pos;
}
@Override
public void close() {
ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf, 0, this.count);
LinearRegionFile.this.write(this.pos, byteBuffer);
}
}
private byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] tempBuffer = new byte[4096];
int length;
while ((length = in.read(tempBuffer)) >= 0) {
out.write(tempBuffer, 0, length);
}
return out.toByteArray();
}
@Nullable
@Override
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
int index = getChunkIndex(pos.x, pos.z);
if (chunkUncompressedSizes[index] != 0) {
byte[] decompressed = new byte[chunkUncompressedSizes[index]];
decompressor.decompress(chunkCompressedBuffers[index], 0, decompressed, 0, chunkUncompressedSizes[index]);
return new DataInputStream(new ByteArrayInputStream(decompressed));
}
return null;
}
@Override
public synchronized void clear(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
int index = getChunkIndex(pos.x, pos.z);
chunkCompressedBuffers[index] = null;
chunkUncompressedSizes[index] = 0;
chunkTimestamps[index] = 0;
markToSave();
}
@Override
public synchronized void close() throws IOException {
openRegionFile();
close = true;
try {
flush();
} catch (IOException e) {
throw new IOException("Region flush IOException " + e + " " + regionFilePath, e);
}
}
private static int getChunkIndex(int x, int z) {
return (x & 31) + ((z & 31) << 5);
}
private static int currentTimestamp() {
return (int) (System.currentTimeMillis() / 1000L);
}
@Override
public boolean recalculateHeader() {
return false;
}
@Override
public void setOversized(int x, int z, boolean something) {
// stub
}
@Override
public CompoundTag getOversizedData(int x, int z) throws IOException {
throw new IOException("getOversizedData is a stub " + regionFilePath);
}
@Override
public boolean isOversized(int x, int z) {
return false;
}
@Override
public Path getPath() {
return regionFilePath;
}
private boolean[] deserializeExistenceBitmap(ByteBuffer buffer) {
boolean[] result = new boolean[1024];
for (int i = 0; i < 128; i++) {
byte b = buffer.get();
for (int j = 0; j < 8; j++) {
result[i * 8 + j] = ((b >> (7 - j)) & 1) == 1;
}
}
return result;
}
private void writeExistenceBitmap(DataOutputStream out, boolean[] bitmap) throws IOException {
for (int i = 0; i < 128; i++) {
byte b = 0;
for (int j = 0; j < 8; j++) {
if (bitmap[i * 8 + j]) {
b |= (1 << (7 - j));
}
}
out.writeByte(b);
}
}
private int chunkToBucketIndex(int chunkX, int chunkZ) {
int bx = chunkX / bucketSize, bz = chunkZ / bucketSize;
return bx * gridSize + bz;
}
private int[] parseRegionCoordinates(String fileName) {
int regionX = 0;
int regionZ = 0;
String[] parts = fileName.split("\\.");
if (parts.length >= 4) {
try {
regionX = Integer.parseInt(parts[1]);
regionZ = Integer.parseInt(parts[2]);
} catch (NumberFormatException e) {
LOGGER.error("Failed to parse region coordinates from file name: {}", fileName, e);
}
} else {
LOGGER.warn("Unexpected file name format: {}", fileName);
}
return new int[]{regionX, regionZ};
}
}

View File

@@ -1,4 +1,4 @@
package org.stupidcraft.linearpaper.region; package org.bxteam.divinemc.region;
import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionFile;
import net.minecraft.world.level.chunk.storage.RegionFileVersion; import net.minecraft.world.level.chunk.storage.RegionFileVersion;
@@ -10,34 +10,20 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
public class IRegionFileFactory { public class RegionFileFactory {
@Contract("_, _, _, _ -> new") @Contract("_, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException {
return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync);
} }
@Contract("_, _, _, _, _ -> new") @Contract("_, _, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, boolean canRecalcHeader) throws IOException { public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException {
return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader);
}
@Contract("_, _, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException {
return getAbstractRegionFile(storageKey, path, directory, compressionFormat, dsync, true);
}
@Contract("_, _, _, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, boolean canRecalcHeader) throws IOException {
final String fullFileName = path.getFileName().toString(); final String fullFileName = path.getFileName().toString();
final String[] fullNameSplit = fullFileName.split("\\."); final String[] fullNameSplit = fullFileName.split("\\.");
final String extensionName = fullNameSplit[fullNameSplit.length - 1]; final String extensionName = fullNameSplit[fullNameSplit.length - 1];
switch (EnumRegionFileExtension.fromExtension(extensionName)) { switch (RegionFileFormat.fromExtension(extensionName)) {
case UNKNOWN -> {
return new RegionFile(storageKey, path, directory, compressionFormat, dsync);
}
case LINEAR -> { case LINEAR -> {
return new LinearRegionFile(path, DivineConfig.linearCompressionLevel); return new LinearRegionFile(path, DivineConfig.linearImplementation, DivineConfig.linearCompressionLevel);
} }
default -> { default -> {

View File

@@ -1,46 +1,46 @@
package org.stupidcraft.linearpaper.region; package org.bxteam.divinemc.region;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Locale; import java.util.Locale;
public enum EnumRegionFileExtension { public enum RegionFileFormat {
LINEAR(".linear"), LINEAR(".linear"),
MCA(".mca"), ANVIL(".mca"),
UNKNOWN(null); UNKNOWN(null);
private final String extensionName; private final String extension;
EnumRegionFileExtension(String extensionName) { RegionFileFormat(String extension) {
this.extensionName = extensionName; this.extension = extension;
} }
public String getExtensionName() { public String getExtensionName() {
return this.extensionName; return this.extension;
} }
@Contract(pure = true) @Contract(pure = true)
public static EnumRegionFileExtension fromName(@NotNull String name) { public static RegionFileFormat fromName(@NotNull String name) {
switch (name.toUpperCase(Locale.ROOT)) { switch (name.toUpperCase(Locale.ROOT)) {
case "MCA" -> { case "MCA", "ANVIL" -> {
return MCA; return ANVIL;
} }
case "LINEAR" -> { case "LINEAR" -> {
return LINEAR; return LINEAR;
} }
default -> { default -> {
return UNKNOWN; throw new IllegalArgumentException("Unknown region file format: " + name);
} }
} }
} }
@Contract(pure = true) @Contract(pure = true)
public static EnumRegionFileExtension fromExtension(@NotNull String name) { public static RegionFileFormat fromExtension(@NotNull String name) {
switch (name.toLowerCase()) { switch (name.toLowerCase()) {
case "mca" -> { case "mca", "anvil" -> {
return MCA; return ANVIL;
} }
case "linear" -> { case "linear" -> {

View File

@@ -1,308 +0,0 @@
package org.stupidcraft.linearpaper.region;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import com.github.luben.zstd.ZstdInputStream;
import com.github.luben.zstd.ZstdOutputStream;
import com.mojang.logging.LogUtils;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import org.bxteam.divinemc.DivineConfig;
import org.slf4j.Logger;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
public class LinearRegionFile implements IRegionFile {
private static final long SUPERBLOCK = -4323716122432332390L;
private static final byte VERSION = 2;
private static final int HEADER_SIZE = 32;
private static final int FOOTER_SIZE = 8;
private static final Logger LOGGER = LogUtils.getLogger();
private static final List<Byte> SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2);
private final byte[][] buffer = new byte[1024][];
private final int[] bufferUncompressedSize = new int[1024];
private final int[] chunkTimestamps = new int[1024];
private final LZ4Compressor compressor;
private final LZ4FastDecompressor decompressor;
private final int compressionLevel;
public boolean closed = false;
public Path path;
private volatile long lastFlushed = System.nanoTime();
public LinearRegionFile(Path file, int compression) throws IOException {
this.path = file;
this.compressionLevel = compression;
this.compressor = LZ4Factory.fastestInstance().fastCompressor();
this.decompressor = LZ4Factory.fastestInstance().fastDecompressor();
File regionFile = new File(this.path.toString());
Arrays.fill(this.bufferUncompressedSize, 0);
if (!regionFile.canRead()) return;
try (FileInputStream fileStream = new FileInputStream(regionFile);
DataInputStream rawDataStream = new DataInputStream(fileStream)) {
long superBlock = rawDataStream.readLong();
if (superBlock != SUPERBLOCK)
throw new RuntimeException("Invalid superblock: " + superBlock + " in " + file);
byte version = rawDataStream.readByte();
if (!SUPPORTED_VERSIONS.contains(version))
throw new RuntimeException("Invalid version: " + version + " in " + file);
rawDataStream.skipBytes(11);
int dataCount = rawDataStream.readInt();
long fileLength = file.toFile().length();
if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE)
throw new IOException("Invalid file length: " + this.path + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE));
rawDataStream.skipBytes(8);
byte[] rawCompressed = new byte[dataCount];
rawDataStream.readFully(rawCompressed, 0, dataCount);
superBlock = rawDataStream.readLong();
if (superBlock != SUPERBLOCK)
throw new IOException("Footer superblock invalid " + this.path);
try (DataInputStream dataStream = new DataInputStream(new ZstdInputStream(new ByteArrayInputStream(rawCompressed)))) {
int[] starts = new int[1024];
for (int i = 0; i < 1024; i++) {
starts[i] = dataStream.readInt();
dataStream.skipBytes(4);
}
for (int i = 0; i < 1024; i++) {
if (starts[i] > 0) {
int size = starts[i];
byte[] b = new byte[size];
dataStream.readFully(b, 0, size);
int maxCompressedLength = this.compressor.maxCompressedLength(size);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = this.compressor.compress(b, 0, size, compressed, 0, maxCompressedLength);
b = new byte[compressedLength];
System.arraycopy(compressed, 0, b, 0, compressedLength);
this.buffer[i] = b;
this.bufferUncompressedSize[i] = size;
}
}
}
}
}
private static int getChunkIndex(int x, int z) {
return (x & 31) + ((z & 31) << 5);
}
private static int getTimestamp() {
return (int) (System.currentTimeMillis() / 1000L);
}
public void flush() throws IOException {
flushWrapper();
}
public void flushWrapper() {
try {
save();
} catch (IOException e) {
LOGGER.error("Failed to flush region file {}", path.toAbsolutePath(), e);
}
}
public boolean doesChunkExist(ChunkPos pos) throws Exception {
throw new Exception("doesChunkExist is a stub");
}
private synchronized void save() throws IOException {
long timestamp = getTimestamp();
short chunkCount = 0;
File tempFile = new File(path.toString() + ".tmp");
try (FileOutputStream fileStream = new FileOutputStream(tempFile);
ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream();
ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel);
DataOutputStream zstdDataStream = new DataOutputStream(zstdStream);
DataOutputStream dataStream = new DataOutputStream(fileStream)) {
dataStream.writeLong(SUPERBLOCK);
dataStream.writeByte(VERSION);
dataStream.writeLong(timestamp);
dataStream.writeByte(this.compressionLevel);
ArrayList<byte[]> byteBuffers = new ArrayList<>();
for (int i = 0; i < 1024; i++) {
if (this.bufferUncompressedSize[i] != 0) {
chunkCount += 1;
byte[] content = new byte[bufferUncompressedSize[i]];
this.decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]);
byteBuffers.add(content);
} else byteBuffers.add(null);
}
for (int i = 0; i < 1024; i++) {
zstdDataStream.writeInt(this.bufferUncompressedSize[i]);
zstdDataStream.writeInt(this.chunkTimestamps[i]);
}
for (int i = 0; i < 1024; i++) {
if (byteBuffers.get(i) != null)
zstdDataStream.write(byteBuffers.get(i), 0, byteBuffers.get(i).length);
}
zstdDataStream.close();
dataStream.writeShort(chunkCount);
byte[] compressed = zstdByteArray.toByteArray();
dataStream.writeInt(compressed.length);
dataStream.writeLong(0);
dataStream.write(compressed, 0, compressed.length);
dataStream.writeLong(SUPERBLOCK);
dataStream.flush();
fileStream.getFD().sync();
fileStream.getChannel().force(true);
}
Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING);
this.lastFlushed = System.nanoTime();
}
public synchronized void write(ChunkPos pos, ByteBuffer buffer) {
try {
byte[] b = toByteArray(new ByteArrayInputStream(buffer.array()));
int uncompressedSize = b.length;
int maxCompressedLength = this.compressor.maxCompressedLength(b.length);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength);
b = new byte[compressedLength];
System.arraycopy(compressed, 0, b, 0, compressedLength);
int index = getChunkIndex(pos.x, pos.z);
this.buffer[index] = b;
this.chunkTimestamps[index] = getTimestamp();
this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize;
} catch (IOException e) {
LOGGER.error("Chunk write IOException {} {}", e, this.path);
}
if ((System.nanoTime() - this.lastFlushed) >= TimeUnit.NANOSECONDS.toSeconds(DivineConfig.linearFlushFrequency)) {
this.flushWrapper();
}
}
public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos)));
}
@Override
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) {
final DataOutputStream out = this.getChunkDataOutputStream(pos);
return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData(
data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
out, regionFile -> out.close()
);
}
private byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] tempBuffer = new byte[4096];
int length;
while ((length = in.read(tempBuffer)) >= 0) {
out.write(tempBuffer, 0, length);
}
return out.toByteArray();
}
@Nullable
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) {
byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]];
this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]);
return new DataInputStream(new ByteArrayInputStream(content));
}
return null;
}
public void clear(ChunkPos pos) {
int i = getChunkIndex(pos.x, pos.z);
this.buffer[i] = null;
this.bufferUncompressedSize[i] = 0;
this.chunkTimestamps[i] = getTimestamp();
this.flushWrapper();
}
public Path getPath() {
return this.path;
}
public boolean hasChunk(ChunkPos pos) {
return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0;
}
public void close() throws IOException {
if (closed) return;
closed = true;
flush();
}
public boolean recalculateHeader() {
return false;
}
public void setOversized(int x, int z, boolean something) {
}
public CompoundTag getOversizedData(int x, int z) throws IOException {
throw new IOException("getOversizedData is a stub " + this.path);
}
public boolean isOversized(int x, int z) {
return false;
}
private class ChunkBuffer extends ByteArrayOutputStream {
private final ChunkPos pos;
public ChunkBuffer(ChunkPos chunkcoordintpair) {
super();
this.pos = chunkcoordintpair;
}
public void close() {
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
LinearRegionFile.this.write(this.pos, bytebuffer);
}
}
}