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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.bxteam.divinemc.region;
|
||||||
|
|
||||||
|
public enum LinearImplementation {
|
||||||
|
V1,
|
||||||
|
V2
|
||||||
|
}
|
||||||
@@ -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};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 -> {
|
||||||
@@ -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" -> {
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user