|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: MrHua269 <wangxyper@163.com>
|
|
|
|
|
Date: Sun, 15 Dec 2024 12:53:33 +0800
|
|
|
|
|
Subject: [PATCH] Add configurable region format framework & linear v2 region
|
|
|
|
|
Subject: [PATCH] Add configurable region format framework & linear v2 region
|
|
|
|
|
format support
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -68,24 +68,19 @@ index 0000000000000000000000000000000000000000..d92f1d549c7e01daa6b5bba7d405e462
|
|
|
|
|
+}
|
|
|
|
|
diff --git a/src/main/java/abomination/LinearRegionFile.java b/src/main/java/abomination/LinearRegionFile.java
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c96f6173e
|
|
|
|
|
index 0000000000000000000000000000000000000000..bb0fcf5f47b5ae3d86e1d0572f951236afdcd017
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/src/main/java/abomination/LinearRegionFile.java
|
|
|
|
|
@@ -0,0 +1,666 @@
|
|
|
|
|
@@ -0,0 +1,622 @@
|
|
|
|
|
+package abomination;
|
|
|
|
|
+
|
|
|
|
|
+import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
|
|
|
|
|
+import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool;
|
|
|
|
|
+import ca.spottedleaf.concurrentutil.util.Priority;
|
|
|
|
|
+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 me.earthme.luminol.config.modules.misc.RegionFormatConfig;
|
|
|
|
|
+import net.jpountz.lz4.LZ4Compressor;
|
|
|
|
|
+import net.jpountz.lz4.LZ4Factory;
|
|
|
|
|
+import net.jpountz.lz4.LZ4FastDecompressor;
|
|
|
|
|
+import net.minecraft.server.MinecraftServer;
|
|
|
|
|
+import net.openhft.hashing.LongHashFunction;
|
|
|
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
|
|
|
+import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
|
|
|
|
@@ -99,12 +94,12 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+import java.nio.file.Files;
|
|
|
|
|
+import java.nio.file.Path;
|
|
|
|
|
+import java.nio.file.StandardCopyOption;
|
|
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
|
|
+import java.util.concurrent.Executor;
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Arrays;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
+import java.util.concurrent.locks.LockSupport;
|
|
|
|
|
+import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
|
+import java.util.stream.IntStream;
|
|
|
|
|
+
|
|
|
|
|
+// LinearRegionFile_implementation_version_0_5byXymb
|
|
|
|
|
+// Just gonna use this string to inform other forks about updates ;-)
|
|
|
|
|
@@ -134,9 +129,7 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ private final int compressionLevel;
|
|
|
|
|
+ private int gridSize = 8;
|
|
|
|
|
+ private int bucketSize = 4;
|
|
|
|
|
+
|
|
|
|
|
+ private final AtomicInteger modifiedChunkCount = new AtomicInteger(0);
|
|
|
|
|
+ private PrioritisedExecutor.PrioritisedTask ioTask = null;
|
|
|
|
|
+ private final Thread bindThread;
|
|
|
|
|
+
|
|
|
|
|
+ public Path getRegionFile() {
|
|
|
|
|
+ return this.regionFile;
|
|
|
|
|
@@ -206,7 +199,7 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ File regionFile = new File(this.regionFile.toString());
|
|
|
|
|
+
|
|
|
|
|
+ if(!regionFile.canRead()) {
|
|
|
|
|
+ //this.start();
|
|
|
|
|
+ this.bindThread.start();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
@@ -227,7 +220,7 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ throw new RuntimeException("Invalid version: " + version + " file " + this.regionFile);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //this.start();
|
|
|
|
|
+ this.bindThread.start();
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ throw new RuntimeException("Failed to open region file " + this.regionFile, e);
|
|
|
|
|
+ }
|
|
|
|
|
@@ -331,6 +324,35 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public LinearRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, int compressionLevel) throws IOException {
|
|
|
|
|
+ Runnable flushCheck = () -> {
|
|
|
|
|
+ while (!close) {
|
|
|
|
|
+ synchronized (saveLock) {
|
|
|
|
|
+ if (markedToSave && activeSaveThreads < SAVE_THREAD_MAX_COUNT) {
|
|
|
|
|
+ activeSaveThreads++;
|
|
|
|
|
+ Runnable flushOperation = () -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ flush();
|
|
|
|
|
+ } catch (IOException ex) {
|
|
|
|
|
+ LOGGER.error("Region file {} flush failed", this.regionFile.toAbsolutePath(), ex);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ synchronized (saveLock) {
|
|
|
|
|
+ activeSaveThreads--;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ Thread saveThread = USE_VIRTUAL_THREAD ?
|
|
|
|
|
+ Thread.ofVirtual().name("Linear IO - " + LinearRegionFile.this.hashCode()).unstarted(flushOperation) :
|
|
|
|
|
+ Thread.ofPlatform().name("Linear IO - " + LinearRegionFile.this.hashCode()).unstarted(flushOperation);
|
|
|
|
|
+ saveThread.setPriority(Thread.NORM_PRIORITY - 3);
|
|
|
|
|
+ saveThread.start();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(SAVE_DELAY_MS));
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ this.bindThread = USE_VIRTUAL_THREAD ? Thread.ofVirtual().unstarted(flushCheck) : Thread.ofPlatform().unstarted(flushCheck);
|
|
|
|
|
+ this.bindThread.setName("Linear IO Schedule - " + this.hashCode());
|
|
|
|
|
+ this.regionFile = path;
|
|
|
|
|
+ this.compressionLevel = compressionLevel;
|
|
|
|
|
+
|
|
|
|
|
@@ -354,52 +376,34 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static final AtomicInteger ioThreadId = new AtomicInteger();
|
|
|
|
|
+ private static final PrioritisedThreadPool linearIOThreadPool = new PrioritisedThreadPool(thread -> {
|
|
|
|
|
+ thread.setName("Linear RegionFile IO Thread- " + ioThreadId.getAndIncrement());
|
|
|
|
|
+ thread.setContextClassLoader(MinecraftServer.class.getClassLoader());
|
|
|
|
|
+ });
|
|
|
|
|
+ public static final long WORKER_QUEUE_HOLD_TIME = (long)(20.0e6); // 20ms
|
|
|
|
|
+ private static PrioritisedExecutor linearIOExecutor;
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ private static final int SAVE_THREAD_MAX_COUNT = 6;
|
|
|
|
|
+ public static int SAVE_THREAD_MAX_COUNT = 6;
|
|
|
|
|
+ public static int SAVE_DELAY_MS = 100;
|
|
|
|
|
+ public static boolean USE_VIRTUAL_THREAD = true;
|
|
|
|
|
+ private static final Object saveLock = new Object();
|
|
|
|
|
+ private static int activeSaveThreads = 0;
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ public static void initIOExecutor() {
|
|
|
|
|
+ linearIOExecutor = linearIOThreadPool.createExecutorGroup(1, 0).createExecutor(RegionFormatConfig.linearIoThreadCount, WORKER_QUEUE_HOLD_TIME, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static void shutdownIOExecutor() {
|
|
|
|
|
+ linearIOThreadPool.shutdown(true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /*public void run() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ while (!close) {
|
|
|
|
|
+ synchronized (saveLock) {
|
|
|
|
|
+ if (markedToSave && activeSaveThreads < SAVE_THREAD_MAX_COUNT) {
|
|
|
|
|
+ activeSaveThreads++;
|
|
|
|
|
+ Thread saveThread = new Thread(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ flush();
|
|
|
|
|
+ } catch (IOException ex) {
|
|
|
|
|
+ LOGGER.error("Region file " + this.regionFile.toAbsolutePath() + " flush failed", ex);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ synchronized (saveLock) {
|
|
|
|
|
+ activeSaveThreads--;
|
|
|
|
|
+ }
|
|
|
|
|
+ while (!close) {
|
|
|
|
|
+ synchronized (saveLock) {
|
|
|
|
|
+ if (markedToSave && activeSaveThreads < SAVE_THREAD_MAX_COUNT) {
|
|
|
|
|
+ activeSaveThreads++;
|
|
|
|
|
+ Thread saveThread = new Thread(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ flush();
|
|
|
|
|
+ } catch (IOException ex) {
|
|
|
|
|
+ LOGGER.error("Region file " + this.regionFile.toAbsolutePath() + " flush failed", ex);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ synchronized (saveLock) {
|
|
|
|
|
+ activeSaveThreads--;
|
|
|
|
|
+ }
|
|
|
|
|
+ }, "RegionFileFlush");
|
|
|
|
|
+ saveThread.setPriority(Thread.NORM_PRIORITY - 3);
|
|
|
|
|
+ saveThread.start();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, "RegionFileFlush");
|
|
|
|
|
+ saveThread.setPriority(Thread.NORM_PRIORITY - 3);
|
|
|
|
|
+ saveThread.start();
|
|
|
|
|
+ }
|
|
|
|
|
+ Thread.sleep(100);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch(InterruptedException ignored) {}
|
|
|
|
|
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(SAVE_DELAY_MS));
|
|
|
|
|
+ }
|
|
|
|
|
+ }*/
|
|
|
|
|
+
|
|
|
|
|
+ public synchronized boolean doesChunkExist(ChunkPos pos) throws Exception {
|
|
|
|
|
@@ -414,7 +418,7 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+
|
|
|
|
|
+ long timestamp = getTimestamp();
|
|
|
|
|
+
|
|
|
|
|
+ long writeStart = System.nanoTime();
|
|
|
|
|
+long writeStart = System.nanoTime();
|
|
|
|
|
+ File tempFile = new File(regionFile.toString() + ".tmp");
|
|
|
|
|
+ FileOutputStream fileStream = new FileOutputStream(tempFile);
|
|
|
|
|
+ DataOutputStream dataStream = new DataOutputStream(fileStream);
|
|
|
|
|
@@ -515,7 +519,6 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ fileStream.close();
|
|
|
|
|
+ Files.move(tempFile.toPath(), this.regionFile, StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
|
+//System.out.println("writeStart REGION FILE FLUSH " + (System.nanoTime() - writeStart) + " misses: " + bucketMisses);
|
|
|
|
|
+ this.modifiedChunkCount.set(0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void writeNBTFeatures(DataOutputStream dataStream) throws IOException {
|
|
|
|
|
@@ -558,53 +561,6 @@ index 0000000000000000000000000000000000000000..4a8a71686dddfc6b0c27882d1f73b92c
|
|
|
|
|
+ LOGGER.error("Chunk write IOException " + e + " " + this.regionFile);
|
|
|
|
|
+ }
|
|
|
|
|
+ markToSave();
|
|
|
|
|
+ this.modifiedChunkCount.getAndIncrement();
|
|
|
|
|
+
|
|
|
|
|
+ if (ioTask == null) {
|
|
|
|
|
+ this.scheduleSave();
|
|
|
|
|
+ }else {
|
|
|
|
|
+ if (this.ioTask.getPriority() == Priority.COMPLETING) {
|
|
|
|
|
+ this.scheduleSave();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.ioTask.raisePriority(this.computeSavePriority());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Priority computeSavePriority() {
|
|
|
|
|
+ final int currentModifiedChunkCount = this.modifiedChunkCount.get();
|
|
|
|
|
+
|
|
|
|
|
+ final int[] ordinals = new int[]{2, 3, 4, 5, 6};
|
|
|
|
|
+ final int[] thresholds = new int[]{20, 40, 60, 80, 100};
|
|
|
|
|
+ final int coverPercent = (currentModifiedChunkCount / 1024) * 100;
|
|
|
|
|
+
|
|
|
|
|
+ int actualOrdinal = 6;
|
|
|
|
|
+ for (int i = 0; i < thresholds.length; i++) {
|
|
|
|
|
+ if (coverPercent >= thresholds[i]) {
|
|
|
|
|
+ actualOrdinal = ordinals[i];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Priority.values()[actualOrdinal];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void scheduleSave() {
|
|
|
|
|
+ final PrioritisedExecutor.PrioritisedTask created = linearIOExecutor.createTask(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ synchronized (this) {
|
|
|
|
|
+ if (!this.close) {
|
|
|
|
|
+ this.flush();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, this.computeSavePriority());
|
|
|
|
|
+
|
|
|
|
|
+ created.queue();
|
|
|
|
|
+
|
|
|
|
|
+ this.ioTask = created;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
|
|
|
|
|
@@ -780,28 +736,34 @@ index 51c126735ace8fdde89ad97b5cab62f244212db0..c7d4d944eb198ac53a3eeae717a25c7d
|
|
|
|
|
}
|
|
|
|
|
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000000000000000000000000000000000000..60546260cd1d535cc596485de2ced48b7e045b3a
|
|
|
|
|
index 0000000000000000000000000000000000000000..eb689b6b79143ffaf1eadcba84feca0c632d1407
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java
|
|
|
|
|
@@ -0,0 +1,48 @@
|
|
|
|
|
@@ -0,0 +1,59 @@
|
|
|
|
|
+package me.earthme.luminol.config.modules.misc;
|
|
|
|
|
+
|
|
|
|
|
+import abomination.LinearRegionFile;
|
|
|
|
|
+import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
|
|
|
|
+import me.earthme.luminol.config.ConfigInfo;
|
|
|
|
|
+import me.earthme.luminol.config.DoNotLoad;
|
|
|
|
|
+import me.earthme.luminol.config.EnumConfigCategory;
|
|
|
|
|
+import me.earthme.luminol.config.IConfigModule;
|
|
|
|
|
+import me.earthme.luminol.config.*;
|
|
|
|
|
+import me.earthme.luminol.utils.EnumRegionFormat;
|
|
|
|
|
+import net.minecraft.server.MinecraftServer;
|
|
|
|
|
+
|
|
|
|
|
+public class RegionFormatConfig implements IConfigModule {
|
|
|
|
|
+ @HotReloadUnsupported
|
|
|
|
|
+ @ConfigInfo(baseName = "format")
|
|
|
|
|
+ public static String format = "MCA";
|
|
|
|
|
+ @HotReloadUnsupported
|
|
|
|
|
+ @ConfigInfo(baseName = "linear_compression_level")
|
|
|
|
|
+ public static int linearCompressionLevel = 1;
|
|
|
|
|
+ @HotReloadUnsupported
|
|
|
|
|
+ @ConfigInfo(baseName = "linear_io_thread_count")
|
|
|
|
|
+ public static int linearIoThreadCount = 6;
|
|
|
|
|
+ @HotReloadUnsupported
|
|
|
|
|
+ @ConfigInfo(baseName = "linear_io_flush_delay_ms")
|
|
|
|
|
+ public static int linearIoFlushDelayMs = 100;
|
|
|
|
|
+ @HotReloadUnsupported
|
|
|
|
|
+ @ConfigInfo(baseName = "linear_use_virtual_thread")
|
|
|
|
|
+ public static boolean linearUseVirtualThread = true;
|
|
|
|
|
+
|
|
|
|
|
+ @DoNotLoad
|
|
|
|
|
+ public static EnumRegionFormat regionFormat;
|
|
|
|
|
@@ -818,17 +780,22 @@ index 0000000000000000000000000000000000000000..60546260cd1d535cc596485de2ced48b
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void onLoaded(CommentedFileConfig configInstance) {
|
|
|
|
|
+ LinearRegionFile.initIOExecutor();
|
|
|
|
|
+ regionFormat = EnumRegionFormat.fromString(format.toUpperCase());
|
|
|
|
|
+
|
|
|
|
|
+ if (regionFormat == null) {
|
|
|
|
|
+ throw new RuntimeException("Invalid region format: " + format);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (RegionFormatConfig.linearCompressionLevel > 23 || RegionFormatConfig.linearCompressionLevel < 1) {
|
|
|
|
|
+ MinecraftServer.LOGGER.error("Linear region compression level should be between 1 and 22 in config: {}", RegionFormatConfig.linearCompressionLevel);
|
|
|
|
|
+ MinecraftServer.LOGGER.error("Falling back to compression level 1.");
|
|
|
|
|
+ RegionFormatConfig.linearCompressionLevel = 1;
|
|
|
|
|
+ if (regionFormat == EnumRegionFormat.LINEAR_V2) {
|
|
|
|
|
+ if (RegionFormatConfig.linearCompressionLevel > 23 || RegionFormatConfig.linearCompressionLevel < 1) {
|
|
|
|
|
+ MinecraftServer.LOGGER.error("Linear region compression level should be between 1 and 22 in config: {}", RegionFormatConfig.linearCompressionLevel);
|
|
|
|
|
+ MinecraftServer.LOGGER.error("Falling back to compression level 1.");
|
|
|
|
|
+ RegionFormatConfig.linearCompressionLevel = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LinearRegionFile.SAVE_DELAY_MS = linearIoFlushDelayMs;
|
|
|
|
|
+ LinearRegionFile.SAVE_THREAD_MAX_COUNT = linearIoThreadCount;
|
|
|
|
|
+ LinearRegionFile.USE_VIRTUAL_THREAD = linearUseVirtualThread;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
@@ -907,17 +874,22 @@ index 0000000000000000000000000000000000000000..5af068489646ed70330d8c6242ec88f5
|
|
|
|
|
+
|
|
|
|
|
+public record RegionCreatorInfo (RegionStorageInfo info, Path filePath, Path folder, boolean sync) {}
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
|
|
|
index 8cc0c01a19fc71753d7c3ed4fa7e9992aaf93b5a..88be8a6232bc3311cc0bdb7c697f7a78ce33e38d 100644
|
|
|
|
|
index 8cc0c01a19fc71753d7c3ed4fa7e9992aaf93b5a..04f68856cb3d982f1644d26f5ae57587b6e36ff2 100644
|
|
|
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
|
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
|
|
|
@@ -1180,6 +1180,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
|
|
|
this.saveAllChunks(false, true, true, true); // Paper - rewrite chunk system
|
|
|
|
|
@@ -1036,10 +1036,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
|
|
|
while (iterator1.hasNext()) {
|
|
|
|
|
ServerLevel worldserver2 = (ServerLevel) iterator1.next();
|
|
|
|
|
|
|
|
|
|
this.isSaving = false;
|
|
|
|
|
+ abomination.LinearRegionFile.shutdownIOExecutor(); // Luminol - Linear region file format
|
|
|
|
|
// Folia start - region threading
|
|
|
|
|
this.stopPart2();
|
|
|
|
|
}
|
|
|
|
|
- MinecraftServer.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", worldserver2.getChunkSource().chunkMap.getStorageName());
|
|
|
|
|
+ MinecraftServer.LOGGER.info("ThreadedChunkStorage ({}): All chunks are saved", worldserver2.getChunkSource().chunkMap.getStorageName()); // Luminol - configurable region format
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- MinecraftServer.LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved");
|
|
|
|
|
+ MinecraftServer.LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // Luminol - configurable region format
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag3;
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
|
|
|
index 622d0cbe023774d92d212f242b60b96317720835..9b4b01a741e8779f4ea06b0fd801ce243e179910 100644
|
|
|
|
|
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
|
|
|
@@ -1030,7 +1002,7 @@ index 16f07007a0f73ec0c6f421c9b082518e87e8cc7b..fc69834e18e0860750d878e1361722fc
|
|
|
|
|
}
|
|
|
|
|
// Paper end - rewrite chunk system
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
|
|
|
index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe28b6027c2 100644
|
|
|
|
|
index e40665cead218502b44dd49051a53326ed94f061..a25e1bfd74b7ec9d6fcc3fe7c4369bc20b33a0da 100644
|
|
|
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
|
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
|
|
|
@@ -23,7 +23,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -1042,7 +1014,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
private final RegionStorageInfo info;
|
|
|
|
|
private final Path folder;
|
|
|
|
|
private final boolean sync;
|
|
|
|
|
@@ -33,8 +33,33 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -33,8 +33,27 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
private static final int MAX_NON_EXISTING_CACHE = 1024 * 4;
|
|
|
|
|
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) {
|
|
|
|
|
@@ -1053,31 +1025,25 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
+ public static abomination.IRegionFile createNew(RegionStorageInfo info, Path filePath, Path folder, boolean sync) throws IOException{
|
|
|
|
|
+ final me.earthme.luminol.utils.EnumRegionFormat regionFormat = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormat;
|
|
|
|
|
+ final String fullFileName = filePath.getFileName().toString();
|
|
|
|
|
+ final String argument;
|
|
|
|
|
+ final String[] fullNameSplit = fullFileName.split("\\.");
|
|
|
|
|
+ final String extensionName = fullNameSplit[fullNameSplit.length - 1];
|
|
|
|
|
+
|
|
|
|
|
+ int lastDotIndex = fullFileName.lastIndexOf(".");
|
|
|
|
|
+ if (lastDotIndex != -1 && lastDotIndex < fullFileName.length() - 1) {
|
|
|
|
|
+ argument = fullFileName.substring(lastDotIndex + 1);
|
|
|
|
|
+ }else {
|
|
|
|
|
+ throw new IOException("Invalid region file name: " + fullFileName);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!regionFormat.getArgument().equalsIgnoreCase(argument)) {
|
|
|
|
|
+ net.minecraft.server.MinecraftServer.setFatalException(new RuntimeException("Invalid region file format: " + argument + " expected " + regionFormat.getArgument()));
|
|
|
|
|
+ throw new IOException("Invalid region file format: ." + argument + " expected " + regionFormat.getArgument());
|
|
|
|
|
+ if (!regionFormat.getArgument().equalsIgnoreCase(extensionName)) {
|
|
|
|
|
+ net.minecraft.server.MinecraftServer.setFatalException(new RuntimeException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument()));
|
|
|
|
|
+ throw new IOException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return regionFormat.getCreator().create(new me.earthme.luminol.utils.RegionCreatorInfo(info, filePath, folder, sync));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static String getExtensionName() {
|
|
|
|
|
+ return me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormat.getArgument();
|
|
|
|
|
+ return "." + me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormat.getArgument();
|
|
|
|
|
+ }
|
|
|
|
|
+ // Luminol end
|
|
|
|
|
|
|
|
|
|
private boolean doesRegionFilePossiblyExist(final long position) {
|
|
|
|
|
synchronized (this.nonExistingRegionFiles) {
|
|
|
|
|
@@ -68,15 +93,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -68,15 +87,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@@ -1096,7 +1062,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
if (ret != null) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
@@ -100,7 +125,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -100,7 +119,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
|
|
|
|
|
FileUtil.createDirectoriesSafe(this.folder);
|
|
|
|
|
|
|
|
|
|
@@ -1105,7 +1071,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
|
|
|
|
|
this.regionCache.putAndMoveToFirst(key, ret);
|
|
|
|
|
|
|
|
|
|
@@ -119,7 +144,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -119,7 +138,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
|
|
|
|
@@ -1114,7 +1080,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
@@ -153,7 +178,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -153,7 +172,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
) throws IOException {
|
|
|
|
|
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
|
|
|
|
if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) {
|
|
|
|
|
@@ -1123,7 +1089,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
if (regionFile != null) {
|
|
|
|
|
regionFile.clear(pos);
|
|
|
|
|
} // else: didn't exist
|
|
|
|
|
@@ -168,7 +193,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -168,7 +187,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.ReadData moonrise$readData(
|
|
|
|
|
final int chunkX, final int chunkZ
|
|
|
|
|
) throws IOException {
|
|
|
|
|
@@ -1132,7 +1098,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
|
|
|
|
|
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
|
|
|
|
|
|
|
|
|
|
@@ -221,7 +246,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -221,7 +240,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@Nullable
|
|
|
|
|
public static ChunkPos getRegionFileCoordinates(Path file) {
|
|
|
|
|
String fileName = file.getFileName().toString();
|
|
|
|
|
@@ -1141,7 +1107,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -250,12 +275,12 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -250,12 +269,12 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Paper start - rewrite chunk system
|
|
|
|
|
@@ -1156,7 +1122,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
// Paper start - rewrite chunk system
|
|
|
|
|
if (existingOnly) {
|
|
|
|
|
return this.moonrise$getRegionFileIfExists(chunkcoordintpair.x, chunkcoordintpair.z);
|
|
|
|
|
@@ -263,7 +288,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -263,7 +282,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
final long key = ChunkPos.asLong(chunkcoordintpair.x >> REGION_SHIFT, chunkcoordintpair.z >> REGION_SHIFT);
|
|
|
|
|
|
|
|
|
|
@@ -1165,7 +1131,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
if (ret != null) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
@@ -278,7 +303,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -278,7 +297,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
|
|
|
|
|
FileUtil.createDirectoriesSafe(this.folder);
|
|
|
|
|
|
|
|
|
|
@@ -1174,7 +1140,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
|
|
|
|
|
this.regionCache.putAndMoveToFirst(key, ret);
|
|
|
|
|
|
|
|
|
|
@@ -292,7 +317,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -292,7 +311,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1183,7 +1149,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
synchronized (regionfile) {
|
|
|
|
|
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
|
|
|
|
|
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
|
|
|
|
|
@@ -327,7 +352,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -327,7 +346,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@Nullable
|
|
|
|
|
public CompoundTag read(ChunkPos pos) throws IOException {
|
|
|
|
|
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
|
|
|
|
@@ -1192,7 +1158,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
if (regionfile == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
@@ -391,7 +416,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -391,7 +410,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
|
|
|
|
|
public void scanChunk(ChunkPos chunkPos, StreamTagVisitor scanner) throws IOException {
|
|
|
|
|
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
|
|
|
|
@@ -1201,7 +1167,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
if (regionfile == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -421,7 +446,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -421,7 +440,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { // Paper - rewrite chunk system - public
|
|
|
|
|
@@ -1210,7 +1176,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
// Paper start - rewrite chunk system
|
|
|
|
|
if (regionfile == null) {
|
|
|
|
|
// if the RegionFile doesn't exist, no point in deleting from it
|
|
|
|
|
@@ -465,7 +490,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -465,7 +484,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
// Paper start - rewrite chunk system
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
|
|
|
|
|
@@ -1219,7 +1185,7 @@ index e40665cead218502b44dd49051a53326ed94f061..d16d0c0ec4cd32688b436bc73d152fe2
|
|
|
|
|
try {
|
|
|
|
|
regionFile.close();
|
|
|
|
|
} catch (final IOException ex) {
|
|
|
|
|
@@ -482,7 +507,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
@@ -482,7 +501,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
|
|
|
|
// Paper start - rewrite chunk system
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
|
|
|
|
|
|