2020-06-30 18:07:47 +02:00
|
|
|
package net.minestom.server.instance;
|
|
|
|
|
2020-10-24 09:34:19 +02:00
|
|
|
import net.minestom.server.MinecraftServer;
|
2021-07-11 03:35:17 +02:00
|
|
|
import net.minestom.server.utils.async.AsyncUtils;
|
2020-10-24 10:46:23 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import org.jetbrains.annotations.Nullable;
|
2020-10-24 09:34:19 +02:00
|
|
|
|
|
|
|
import java.util.Collection;
|
2021-07-11 02:54:02 +02:00
|
|
|
import java.util.concurrent.CompletableFuture;
|
2020-10-24 09:34:19 +02:00
|
|
|
import java.util.concurrent.ExecutorService;
|
2021-12-17 20:57:21 +01:00
|
|
|
import java.util.concurrent.ForkJoinPool;
|
2020-10-24 09:34:19 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
2020-06-30 18:07:47 +02:00
|
|
|
|
2020-07-21 18:48:15 +02:00
|
|
|
/**
|
2020-10-12 02:56:30 +02:00
|
|
|
* Interface implemented to change the way chunks are loaded/saved.
|
2020-10-15 08:21:13 +02:00
|
|
|
* <p>
|
2021-06-20 20:46:57 +02:00
|
|
|
* See {@link AnvilLoader} for the default implementation used in {@link InstanceContainer}.
|
2020-07-21 18:48:15 +02:00
|
|
|
*/
|
2020-06-30 18:07:47 +02:00
|
|
|
public interface IChunkLoader {
|
2020-07-21 18:48:15 +02:00
|
|
|
|
2021-08-09 01:16:51 +02:00
|
|
|
/**
|
|
|
|
* Loads instance data from the loader.
|
|
|
|
*
|
|
|
|
* @param instance the instance to retrieve the data from
|
|
|
|
*/
|
|
|
|
default void loadInstance(@NotNull Instance instance) {
|
|
|
|
}
|
|
|
|
|
2020-07-21 18:48:15 +02:00
|
|
|
/**
|
2020-10-24 09:34:19 +02:00
|
|
|
* Loads a {@link Chunk}, all blocks should be set since the {@link ChunkGenerator} is not applied.
|
2020-07-21 18:48:15 +02:00
|
|
|
*
|
2020-10-12 03:18:02 +02:00
|
|
|
* @param instance the {@link Instance} where the {@link Chunk} belong
|
2020-07-21 18:48:15 +02:00
|
|
|
* @param chunkX the chunk X
|
|
|
|
* @param chunkZ the chunk Z
|
2021-07-11 02:54:02 +02:00
|
|
|
* @return a {@link CompletableFuture} containing the chunk, or null if not present
|
2020-07-21 18:48:15 +02:00
|
|
|
*/
|
2021-07-11 02:54:02 +02:00
|
|
|
@NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ);
|
2020-07-21 18:48:15 +02:00
|
|
|
|
2021-08-09 01:16:51 +02:00
|
|
|
default @NotNull CompletableFuture<Void> saveInstance(@NotNull Instance instance) {
|
|
|
|
return AsyncUtils.VOID_FUTURE;
|
|
|
|
}
|
|
|
|
|
2020-07-21 18:48:15 +02:00
|
|
|
/**
|
2020-10-24 09:34:19 +02:00
|
|
|
* Saves a {@link Chunk} with an optional callback for when it is done.
|
2020-07-21 18:48:15 +02:00
|
|
|
*
|
2021-07-11 02:54:02 +02:00
|
|
|
* @param chunk the {@link Chunk} to save
|
|
|
|
* @return a {@link CompletableFuture} executed when the {@link Chunk} is done saving,
|
2021-07-11 03:14:17 +02:00
|
|
|
* should be called even if the saving failed (you can throw an exception).
|
2020-07-21 18:48:15 +02:00
|
|
|
*/
|
2021-07-11 02:54:02 +02:00
|
|
|
@NotNull CompletableFuture<Void> saveChunk(@NotNull Chunk chunk);
|
2020-07-07 13:41:55 +02:00
|
|
|
|
2020-10-24 09:34:19 +02:00
|
|
|
/**
|
|
|
|
* Saves multiple chunks with an optional callback for when it is done.
|
|
|
|
* <p>
|
|
|
|
* Implementations need to check {@link #supportsParallelSaving()} to support the feature if possible.
|
|
|
|
*
|
2021-07-11 02:54:02 +02:00
|
|
|
* @param chunks the chunks to save
|
|
|
|
* @return a {@link CompletableFuture} executed when the {@link Chunk} is done saving,
|
2021-07-11 03:14:17 +02:00
|
|
|
* should be called even if the saving failed (you can throw an exception).
|
2020-10-24 09:34:19 +02:00
|
|
|
*/
|
2021-07-11 02:54:02 +02:00
|
|
|
default @NotNull CompletableFuture<Void> saveChunks(@NotNull Collection<Chunk> chunks) {
|
2020-10-24 09:34:19 +02:00
|
|
|
if (supportsParallelSaving()) {
|
2021-12-17 20:57:21 +01:00
|
|
|
ExecutorService parallelSavingThreadPool = ForkJoinPool.commonPool();
|
2021-07-11 02:54:02 +02:00
|
|
|
chunks.forEach(c -> parallelSavingThreadPool.execute(() -> saveChunk(c)));
|
2020-10-24 09:34:19 +02:00
|
|
|
try {
|
|
|
|
parallelSavingThreadPool.shutdown();
|
|
|
|
parallelSavingThreadPool.awaitTermination(1L, java.util.concurrent.TimeUnit.DAYS);
|
|
|
|
} catch (InterruptedException e) {
|
2021-01-19 18:25:54 +01:00
|
|
|
MinecraftServer.getExceptionManager().handleException(e);
|
2020-10-24 09:34:19 +02:00
|
|
|
}
|
2021-07-28 17:28:36 +02:00
|
|
|
return AsyncUtils.VOID_FUTURE;
|
2020-10-24 09:34:19 +02:00
|
|
|
} else {
|
2021-07-11 02:54:02 +02:00
|
|
|
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
|
2020-10-24 09:34:19 +02:00
|
|
|
AtomicInteger counter = new AtomicInteger();
|
|
|
|
for (Chunk chunk : chunks) {
|
2021-07-11 02:54:02 +02:00
|
|
|
saveChunk(chunk).whenComplete((unused, throwable) -> {
|
2020-10-24 09:34:19 +02:00
|
|
|
final boolean isLast = counter.incrementAndGet() == chunks.size();
|
|
|
|
if (isLast) {
|
2021-07-11 02:54:02 +02:00
|
|
|
completableFuture.complete(null);
|
2020-10-24 09:34:19 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-07-11 02:54:02 +02:00
|
|
|
return completableFuture;
|
2020-10-24 09:34:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-07 13:41:55 +02:00
|
|
|
/**
|
2020-10-12 02:56:30 +02:00
|
|
|
* Does this {@link IChunkLoader} allow for multi-threaded saving of {@link Chunk}?
|
2020-07-21 18:48:15 +02:00
|
|
|
*
|
2020-08-07 09:14:50 +02:00
|
|
|
* @return true if the chunk loader supports parallel saving
|
2020-07-07 13:41:55 +02:00
|
|
|
*/
|
|
|
|
default boolean supportsParallelSaving() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-12 02:56:30 +02:00
|
|
|
* Does this {@link IChunkLoader} allow for multi-threaded loading of {@link Chunk}?
|
2020-07-21 18:48:15 +02:00
|
|
|
*
|
2020-08-07 09:14:50 +02:00
|
|
|
* @return true if the chunk loader supports parallel loading
|
2020-07-07 13:41:55 +02:00
|
|
|
*/
|
|
|
|
default boolean supportsParallelLoading() {
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-30 18:07:47 +02:00
|
|
|
}
|