mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-29 04:28:21 +01:00
Added IChunkLoader#saveChunks with a default implementation
This commit is contained in:
parent
4ddfc88d43
commit
3e59c9d396
@ -1,6 +1,13 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.utils.callback.OptionalCallback;
|
||||
import net.minestom.server.utils.chunk.ChunkCallback;
|
||||
import net.minestom.server.utils.thread.MinestomThread;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Interface implemented to change the way chunks are loaded/saved.
|
||||
@ -10,26 +17,61 @@ import net.minestom.server.utils.chunk.ChunkCallback;
|
||||
public interface IChunkLoader {
|
||||
|
||||
/**
|
||||
* Load a {@link Chunk}, all blocks should be set since the {@link ChunkGenerator} is not applied
|
||||
* Loads a {@link Chunk}, all blocks should be set since the {@link ChunkGenerator} is not applied.
|
||||
*
|
||||
* @param instance the {@link Instance} where the {@link Chunk} belong
|
||||
* @param chunkX the chunk X
|
||||
* @param chunkZ the chunk Z
|
||||
* @param callback the callback executed when the {@link Chunk} is done loading,
|
||||
* never called if the method returns false.
|
||||
* never called if the method returns false. Can be null.
|
||||
* @return true if the chunk loaded successfully, false otherwise
|
||||
*/
|
||||
boolean loadChunk(Instance instance, int chunkX, int chunkZ, ChunkCallback callback);
|
||||
|
||||
/**
|
||||
* Save a {@link Chunk} with a callback for when it is done
|
||||
* Saves a {@link Chunk} with an optional callback for when it is done.
|
||||
*
|
||||
* @param chunk the {@link Chunk} to save
|
||||
* @param callback the callback executed when the {@link Chunk} is done saving,
|
||||
* should be called even if the saving failed (you can throw an exception)
|
||||
* should be called even if the saving failed (you can throw an exception).
|
||||
* Can be null.
|
||||
*/
|
||||
void saveChunk(Chunk chunk, Runnable callback);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param chunks the chunks to save
|
||||
* @param callback the callback executed when the {@link Chunk} is done saving,
|
||||
* should be called even if the saving failed (you can throw an exception).
|
||||
* Can be null.
|
||||
*/
|
||||
default void saveChunks(Collection<Chunk> chunks, Runnable callback) {
|
||||
if (supportsParallelSaving()) {
|
||||
ExecutorService parallelSavingThreadPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PARALLEL_CHUNK_SAVING, MinecraftServer.THREAD_NAME_PARALLEL_CHUNK_SAVING, true);
|
||||
chunks.forEach(c -> parallelSavingThreadPool.execute(() -> saveChunk(c, null)));
|
||||
try {
|
||||
parallelSavingThreadPool.shutdown();
|
||||
parallelSavingThreadPool.awaitTermination(1L, java.util.concurrent.TimeUnit.DAYS);
|
||||
OptionalCallback.execute(callback);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
for (Chunk chunk : chunks) {
|
||||
saveChunk(chunk, () -> {
|
||||
final boolean isLast = counter.incrementAndGet() == chunks.size();
|
||||
if (isLast) {
|
||||
OptionalCallback.execute(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this {@link IChunkLoader} allow for multi-threaded saving of {@link Chunk}?
|
||||
*
|
||||
|
@ -142,7 +142,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
*
|
||||
* @param chunkX the chunk X
|
||||
* @param chunkZ the chunk Z
|
||||
* @param callback consumer called after the chunk has been generated,
|
||||
* @param callback optional consumer called after the chunk has been generated,
|
||||
* the returned chunk will never be null
|
||||
*/
|
||||
public abstract void loadChunk(int chunkX, int chunkZ, ChunkCallback callback);
|
||||
@ -153,7 +153,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
*
|
||||
* @param chunkX the chunk X
|
||||
* @param chunkZ the chunk Z
|
||||
* @param callback consumer called after the chunk has tried to be loaded,
|
||||
* @param callback optional consumer called after the chunk has tried to be loaded,
|
||||
* contains a chunk if it is successful, null otherwise
|
||||
*/
|
||||
public abstract void loadOptionalChunk(int chunkX, int chunkZ, ChunkCallback callback);
|
||||
@ -184,14 +184,14 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
* Saves a {@link Chunk} to permanent storage.
|
||||
*
|
||||
* @param chunk the {@link Chunk} to save
|
||||
* @param callback called when the {@link Chunk} is done saving
|
||||
* @param callback optional callback called when the {@link Chunk} is done saving
|
||||
*/
|
||||
public abstract void saveChunkToStorage(Chunk chunk, Runnable callback);
|
||||
|
||||
/**
|
||||
* Saves multiple chunks to permanent storage.
|
||||
*
|
||||
* @param callback called when the chunks are done saving
|
||||
* @param callback optional callback called when the chunks are done saving
|
||||
*/
|
||||
public abstract void saveChunksToStorage(Runnable callback);
|
||||
|
||||
@ -254,7 +254,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
*
|
||||
* @param chunkX the chunk X
|
||||
* @param chunkZ the chunk X
|
||||
* @param callback the callback executed once the {@link Chunk} has been retrieved
|
||||
* @param callback the optional callback executed once the {@link Chunk} has been retrieved
|
||||
*/
|
||||
protected abstract void retrieveChunk(int chunkX, int chunkZ, ChunkCallback callback);
|
||||
|
||||
@ -265,7 +265,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
*
|
||||
* @param chunkX the chunk X
|
||||
* @param chunkZ the chunk Z
|
||||
* @param callback the callback executed with the newly created {@link Chunk}
|
||||
* @param callback the optional callback executed with the newly created {@link Chunk}
|
||||
*/
|
||||
protected abstract void createChunk(int chunkX, int chunkZ, ChunkCallback callback);
|
||||
|
||||
@ -541,7 +541,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
* Loads the chunk at the given {@link Position} with a callback.
|
||||
*
|
||||
* @param position the chunk position
|
||||
* @param callback the callback to run when the chunk is loaded
|
||||
* @param callback the optional callback to run when the chunk is loaded
|
||||
*/
|
||||
public void loadChunk(Position position, ChunkCallback callback) {
|
||||
final int chunkX = ChunkUtils.getChunkCoordinate((int) position.getX());
|
||||
@ -554,7 +554,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
* at the given {@link Position} with a callback.
|
||||
*
|
||||
* @param position the chunk position
|
||||
* @param callback the callback executed when the chunk is loaded (or with a null chunk if not)
|
||||
* @param callback the optional callback executed when the chunk is loaded (or with a null chunk if not)
|
||||
*/
|
||||
public void loadOptionalChunk(Position position, ChunkCallback callback) {
|
||||
final int chunkX = ChunkUtils.getChunkCoordinate((int) position.getX());
|
||||
@ -933,7 +933,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
* Schedules a block update at a given {@link BlockPosition}.
|
||||
* Does nothing if no {@link CustomBlock} is present at 'position'.
|
||||
* <p>
|
||||
* Cancelled if the block changes between this call and the actual update
|
||||
* Cancelled if the block changes between this call and the actual update.
|
||||
*
|
||||
* @param time in how long this update must be performed?
|
||||
* @param unit in what unit is the time expressed
|
||||
@ -946,7 +946,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
|
||||
* <p>
|
||||
* Warning: this does not update chunks and entities.
|
||||
*
|
||||
* @param time the current time
|
||||
* @param time the tick time in milliseconds
|
||||
*/
|
||||
public void tick(long time) {
|
||||
// scheduled tasks
|
||||
|
@ -25,7 +25,6 @@ import net.minestom.server.utils.callback.OptionalCallback;
|
||||
import net.minestom.server.utils.chunk.ChunkCallback;
|
||||
import net.minestom.server.utils.chunk.ChunkSupplier;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.thread.MinestomThread;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
@ -34,7 +33,6 @@ import net.minestom.server.world.biomes.Biome;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@ -221,11 +219,12 @@ public class InstanceContainer extends Instance {
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this block already changed since last update? Prevents StackOverflow with blocks trying to modify their position in onDestroy or onPlace.
|
||||
* Has this block already changed since last update?
|
||||
* Prevents StackOverflow with blocks trying to modify their position in onDestroy or onPlace.
|
||||
*
|
||||
* @param blockPosition the block position
|
||||
* @param blockStateId the block state id
|
||||
* @return
|
||||
* @return true if the block changed since the last update
|
||||
*/
|
||||
private boolean isAlreadyChanged(BlockPosition blockPosition, short blockStateId) {
|
||||
final Block changedBlock = currentlyChangingBlocks.get(blockPosition);
|
||||
@ -248,7 +247,7 @@ public class InstanceContainer extends Instance {
|
||||
/**
|
||||
* Calls {@link CustomBlock#onDestroy(Instance, BlockPosition, Data)} for {@code previousBlock}.
|
||||
* <p>
|
||||
* WARNING {@code chunk} needs to be synchronized
|
||||
* WARNING {@code chunk} needs to be synchronized.
|
||||
*
|
||||
* @param chunk the chunk where the block is
|
||||
* @param index the index of the block
|
||||
@ -263,7 +262,7 @@ public class InstanceContainer extends Instance {
|
||||
/**
|
||||
* Calls {@link CustomBlock#onPlace(Instance, BlockPosition, Data)} for the current custom block at the position.
|
||||
* <p>
|
||||
* WARNING {@code chunk} needs to be synchronized
|
||||
* WARNING {@code chunk} needs to be synchronized.
|
||||
*
|
||||
* @param chunk the chunk where the block is
|
||||
* @param index the block index
|
||||
@ -444,9 +443,9 @@ public class InstanceContainer extends Instance {
|
||||
/**
|
||||
* Saves the instance ({@link #getUniqueId()} {@link #getData()}) and call {@link #saveChunksToStorage(Runnable)}.
|
||||
* <p>
|
||||
* WARNING: {@link #getData()} needs to be a {@link SerializableData} in order to be saved
|
||||
* WARNING: {@link #getData()} needs to be a {@link SerializableData} in order to be saved.
|
||||
*
|
||||
* @param callback the callback once the saving is done
|
||||
* @param callback the callback once the saving is done. Can be null.
|
||||
*/
|
||||
public void saveInstance(Runnable callback) {
|
||||
Check.notNull(getStorageLocation(), "You cannot save the instance if no StorageLocation has been defined");
|
||||
@ -464,7 +463,7 @@ public class InstanceContainer extends Instance {
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the instance without callback
|
||||
* Save the instance without callback.
|
||||
*
|
||||
* @see #saveInstance(Runnable)
|
||||
*/
|
||||
@ -474,29 +473,12 @@ public class InstanceContainer extends Instance {
|
||||
|
||||
@Override
|
||||
public void saveChunkToStorage(Chunk chunk, Runnable callback) {
|
||||
chunkLoader.saveChunk(chunk, callback);
|
||||
this.chunkLoader.saveChunk(chunk, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChunksToStorage(Runnable callback) {
|
||||
if (chunkLoader.supportsParallelSaving()) {
|
||||
ExecutorService parallelSavingThreadPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PARALLEL_CHUNK_SAVING, MinecraftServer.THREAD_NAME_PARALLEL_CHUNK_SAVING, true);
|
||||
getChunks().forEach(c -> parallelSavingThreadPool.execute(() -> saveChunkToStorage(c, null)));
|
||||
try {
|
||||
parallelSavingThreadPool.shutdown();
|
||||
parallelSavingThreadPool.awaitTermination(1L, java.util.concurrent.TimeUnit.DAYS);
|
||||
OptionalCallback.execute(callback);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
final Iterator<Chunk> chunkIterator = chunks.values().iterator();
|
||||
while (chunkIterator.hasNext()) {
|
||||
final Chunk chunk = chunkIterator.next();
|
||||
final boolean isLast = !chunkIterator.hasNext();
|
||||
saveChunkToStorage(chunk, isLast ? callback : null);
|
||||
}
|
||||
}
|
||||
this.chunkLoader.saveChunks(chunks.values(), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -579,7 +561,7 @@ public class InstanceContainer extends Instance {
|
||||
* <p>
|
||||
* WARNING: if you need to save this instance's chunks later,
|
||||
* the code needs to be predictable for {@link IChunkLoader#loadChunk(Instance, int, int, ChunkCallback)}
|
||||
* to create the correct type of {@link Chunk}. tl;dr: Need chunk save = no random
|
||||
* to create the correct type of {@link Chunk}. tl;dr: Need chunk save = no random type.
|
||||
*
|
||||
* @param chunkSupplier the new {@link ChunkSupplier} of this instance, chunks need to be non-null
|
||||
* @throws NullPointerException if {@code chunkSupplier} is null
|
||||
|
Loading…
Reference in New Issue
Block a user