mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 17:27:38 +00:00
Slightly improve regen workflow, update adapters to a9c745a600
This commit is contained in:
parent
e4cbd85197
commit
4182d7473c
@ -27,7 +27,7 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -52,11 +52,10 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
|
|
||||||
//runtime
|
//runtime
|
||||||
protected final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
|
protected final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
|
||||||
protected boolean generateConcurrent = true;
|
|
||||||
protected long seed;
|
|
||||||
|
|
||||||
private final Long2ObjectLinkedOpenHashMap<ProtoChunk> protoChunks = new Long2ObjectLinkedOpenHashMap<>();
|
private final Long2ObjectLinkedOpenHashMap<ProtoChunk> protoChunks = new Long2ObjectLinkedOpenHashMap<>();
|
||||||
private final Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
|
private final Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
|
||||||
|
protected boolean generateConcurrent = true;
|
||||||
|
protected long seed;
|
||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
private SingleThreadQueueExtent source;
|
private SingleThreadQueueExtent source;
|
||||||
|
|
||||||
@ -75,6 +74,15 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Random getChunkRandom(long worldseed, int x, int z) {
|
||||||
|
Random random = new Random();
|
||||||
|
random.setSeed(worldseed);
|
||||||
|
long xRand = random.nextLong() / 2L * 2L + 1L;
|
||||||
|
long zRand = random.nextLong() / 2L * 2L + 1L;
|
||||||
|
random.setSeed((long) x * xRand + (long) z * zRand ^ worldseed);
|
||||||
|
return random;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerates the selected {@code Region}.
|
* Regenerates the selected {@code Region}.
|
||||||
*
|
*
|
||||||
@ -145,7 +153,7 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
executor = Executors.newFixedThreadPool(Settings.IMP.QUEUE.PARALLEL_THREADS);
|
executor = Executors.newFixedThreadPool(Settings.IMP.QUEUE.PARALLEL_THREADS);
|
||||||
} // else using sequential chunk generation, concurrent not supported
|
} // else using sequential chunk generation, concurrent not supported
|
||||||
|
|
||||||
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
|
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
|
||||||
//for now it is working well and fast, if we are bored in the future we could do the research (a lot of it) to reduce the border radius
|
//for now it is working well and fast, if we are bored in the future we could do the research (a lot of it) to reduce the border radius
|
||||||
|
|
||||||
//generate chunk coords lists with a certain radius
|
//generate chunk coords lists with a certain radius
|
||||||
@ -154,7 +162,8 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
if (radius == -1) { //ignore ChunkStatus.EMPTY
|
if (radius == -1) { //ignore ChunkStatus.EMPTY
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int border = 16 - radius; //9 = 8 + 1, 8: max border radius used in chunk stages, 1: need 1 extra chunk for chunk features to generate at the border of the region
|
int border = 10 - radius; //9 = 8 + 1, 8: max border radius used in chunk stages, 1: need 1 extra chunk for chunk
|
||||||
|
// features to generate at the border of the region
|
||||||
chunkCoordsForRadius.put(radius, getChunkCoordsRegen(region, border));
|
chunkCoordsForRadius.put(radius, getChunkCoordsRegen(region, border));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -185,7 +194,7 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
worldlimits.put(radius, map);
|
worldlimits.put(radius, map);
|
||||||
});
|
});
|
||||||
|
|
||||||
//run generation tasks exluding FULL chunk status
|
//run generation tasks excluding FULL chunk status
|
||||||
for (Map.Entry<ChunkStatus, Concurrency> entry : chunkStati.entrySet()) {
|
for (Map.Entry<ChunkStatus, Concurrency> entry : chunkStati.entrySet()) {
|
||||||
ChunkStatus chunkStatus = entry.getKey();
|
ChunkStatus chunkStatus = entry.getKey();
|
||||||
int radius = chunkStatus.requiredNeigborChunkRadius0();
|
int radius = chunkStatus.requiredNeigborChunkRadius0();
|
||||||
@ -194,18 +203,18 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) {
|
if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) {
|
||||||
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks = getChunkStatusTaskRows(coords, radius);
|
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks = getChunkStatusTaskRows(coords, radius);
|
||||||
for (ConcurrentTasks<SequentialTasks<Long>> para : tasks) {
|
for (ConcurrentTasks<SequentialTasks<Long>> para : tasks) {
|
||||||
List scheduled = new ArrayList<>(tasks.size());
|
List<Runnable> scheduled = new ArrayList<>(tasks.size());
|
||||||
for (SequentialTasks<Long> row : para) {
|
for (SequentialTasks<Long> row : para) {
|
||||||
scheduled.add((Callable) () -> {
|
scheduled.add(() -> {
|
||||||
for (Long xz : row) {
|
for (Long xz : row) {
|
||||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
List<Future> futures = executor.invokeAll(scheduled);
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
for (Future future : futures) {
|
scheduled.forEach(task -> futures.add(executor.submit(task)));
|
||||||
|
for (Future<?> future : futures) {
|
||||||
future.get();
|
future.get();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -214,16 +223,16 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
}
|
}
|
||||||
} else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) {
|
} else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) {
|
||||||
// every chunk can be processed individually
|
// every chunk can be processed individually
|
||||||
List scheduled = new ArrayList(coords.size());
|
List<Runnable> scheduled = new ArrayList<>(coords.size());
|
||||||
for (long xz : coords) {
|
for (long xz : coords) {
|
||||||
scheduled.add((Callable) () -> {
|
scheduled.add(() -> {
|
||||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
List<Future> futures = executor.invokeAll(scheduled);
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
for (Future future : futures) {
|
scheduled.forEach(task -> futures.add(executor.submit(task)));
|
||||||
|
for (Future<?> future : futures) {
|
||||||
future.get();
|
future.get();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -318,13 +327,13 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
*/
|
*/
|
||||||
protected abstract boolean initNewWorld() throws Exception;
|
protected abstract boolean initNewWorld() throws Exception;
|
||||||
|
|
||||||
|
//functions to implement by sub class - regenate related
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement the cleanup of all the mess that is created during the regeneration process (initNewWorld() and generate()).This function must not throw any exceptions.
|
* Implement the cleanup of all the mess that is created during the regeneration process (initNewWorld() and generate()).This function must not throw any exceptions.
|
||||||
*/
|
*/
|
||||||
protected abstract void cleanup();
|
protected abstract void cleanup();
|
||||||
|
|
||||||
//functions to implement by sub class - regenate related
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement the initialization of a {@code ProtoChunk} here.
|
* Implement the initialization of a {@code ProtoChunk} here.
|
||||||
*
|
*
|
||||||
@ -391,8 +400,8 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
return adjustedRegion.getChunks().stream()
|
return adjustedRegion.getChunks().stream()
|
||||||
.map(c -> BlockVector2.at(c.getX(), c.getZ()))
|
.map(c -> BlockVector2.at(c.getX(), c.getZ()))
|
||||||
.sorted(Comparator
|
.sorted(Comparator
|
||||||
.<BlockVector2>comparingInt(c -> c.getZ())
|
.comparingInt(BlockVector2::getZ)
|
||||||
.thenComparingInt(c -> c.getX())) //needed for RegionLimitedWorldAccess
|
.thenComparingInt(BlockVector2::getX)) //needed for RegionLimitedWorldAccess
|
||||||
.map(c -> MathMan.pairInt(c.getX(), c.getZ()))
|
.map(c -> MathMan.pairInt(c.getX(), c.getZ()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@ -401,7 +410,8 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
* Creates a list of chunkcoord rows that may be executed concurrently
|
* Creates a list of chunkcoord rows that may be executed concurrently
|
||||||
*
|
*
|
||||||
* @param allcoords the coords that should be sorted into rows, must be sorted by z and x
|
* @param allcoords the coords that should be sorted into rows, must be sorted by z and x
|
||||||
* @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to conccurently (ChunkStatus.requiredNeighborRadius)
|
* @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to concurrently (ChunkStatus
|
||||||
|
* .requiredNeighborRadius)
|
||||||
* @return a list of chunkcoords rows that may be executed concurrently
|
* @return a list of chunkcoords rows that may be executed concurrently
|
||||||
*/
|
*/
|
||||||
private SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> getChunkStatusTaskRows(
|
private SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> getChunkStatusTaskRows(
|
||||||
@ -470,17 +480,14 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Random getChunkRandom(long worldseed, int x, int z) {
|
|
||||||
Random random = new Random();
|
|
||||||
random.setSeed(worldseed);
|
|
||||||
long xRand = random.nextLong() / 2L * 2L + 1L;
|
|
||||||
long zRand = random.nextLong() / 2L * 2L + 1L;
|
|
||||||
random.setSeed((long) x * xRand + (long) z * zRand ^ worldseed);
|
|
||||||
return random;
|
|
||||||
}
|
|
||||||
|
|
||||||
//classes
|
//classes
|
||||||
|
|
||||||
|
public enum Concurrency {
|
||||||
|
FULL,
|
||||||
|
RADIUS,
|
||||||
|
NONE
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to wrap the ChunkStatus of the current Minecraft implementation and as the implementation to execute a chunk generation step.
|
* This class is used to wrap the ChunkStatus of the current Minecraft implementation and as the implementation to execute a chunk generation step.
|
||||||
*
|
*
|
||||||
@ -513,11 +520,11 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
* @param accessibleChunks a list of chunks that will be used during the execution of the wrapped {@code ChunkStatus}.
|
* @param accessibleChunks a list of chunks that will be used during the execution of the wrapped {@code ChunkStatus}.
|
||||||
* This list is order in the correct order required by the {@code ChunkStatus}, unless Mojang suddenly decides to do things differently.
|
* This list is order in the correct order required by the {@code ChunkStatus}, unless Mojang suddenly decides to do things differently.
|
||||||
*/
|
*/
|
||||||
public abstract void processChunk(Long xz, List<IChunkAccess> accessibleChunks);
|
public abstract CompletableFuture<?> processChunk(Long xz, List<IChunkAccess> accessibleChunks);
|
||||||
|
|
||||||
void processChunkSave(Long xz, List<IChunkAccess> accessibleChunks) {
|
void processChunkSave(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||||
try {
|
try {
|
||||||
processChunk(xz, accessibleChunks);
|
processChunk(xz, accessibleChunks).get();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
"Error while running " + name() + " on chunk " + MathMan.unpairIntX(xz) + "/" + MathMan.unpairIntY(xz),
|
"Error while running " + name() + " on chunk " + MathMan.unpairIntX(xz) + "/" + MathMan.unpairIntY(xz),
|
||||||
@ -528,12 +535,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Concurrency {
|
|
||||||
FULL,
|
|
||||||
RADIUS,
|
|
||||||
NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SequentialTasks<T> extends Tasks<T> {
|
public static class SequentialTasks<T> extends Tasks<T> {
|
||||||
|
|
||||||
public SequentialTasks(int expectedsize) {
|
public SequentialTasks(int expectedsize) {
|
||||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.util.WorldUnloadedException;
|
import com.fastasyncworldedit.bukkit.util.WorldUnloadedException;
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
|
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
@ -235,6 +236,8 @@ public class BukkitWorld extends AbstractWorld {
|
|||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("Missing BukkitImplAdapter for this version.");
|
throw new UnsupportedOperationException("Missing BukkitImplAdapter for this version.");
|
||||||
}
|
}
|
||||||
|
} catch (FaweException e) {
|
||||||
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warn("Regeneration via adapter failed.", e);
|
LOGGER.warn("Regeneration via adapter failed.", e);
|
||||||
return false;
|
return false;
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user