use of com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent in project FastAsyncWorldEdit by IntellectualSites.
the class Regenerator method generate.
private boolean generate() throws Exception {
if (generateConcurrent) {
// Using concurrent chunk generation
executor = Executors.newFixedThreadPool(Settings.settings().QUEUE.PARALLEL_THREADS, new ThreadFactoryBuilder().setNameFormat("fawe-regen-%d").build());
}
// else using sequential chunk generation, concurrent not supported
// 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
// generate chunk coords lists with a certain radius
Int2ObjectOpenHashMap<List<Long>> chunkCoordsForRadius = new Int2ObjectOpenHashMap<>();
chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> {
if (radius == -1) {
// ignore ChunkStatus.EMPTY
return;
}
// 9 = 8 + 1, 8: max border radius used in chunk stages, 1: need 1 extra chunk for chunk
int border = 10 - radius;
// features to generate at the border of the region
chunkCoordsForRadius.put(radius, getChunkCoordsRegen(region, border));
});
// create chunks
for (Long xz : chunkCoordsForRadius.get(0)) {
ProtoChunk chunk = createProtoChunk(MathMan.unpairIntX(xz), MathMan.unpairIntY(xz));
protoChunks.put(xz, chunk);
}
// generate lists for RegionLimitedWorldAccess, need to be square with odd length (e.g. 17x17), 17 = 1 middle chunk + 8 border chunks * 2
Int2ObjectOpenHashMap<Long2ObjectOpenHashMap<List<IChunkAccess>>> worldlimits = new Int2ObjectOpenHashMap<>();
chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> {
if (radius == -1) {
// ignore ChunkStatus.EMPTY
return;
}
Long2ObjectOpenHashMap<List<IChunkAccess>> map = new Long2ObjectOpenHashMap<>();
for (Long xz : chunkCoordsForRadius.get(radius)) {
int x = MathMan.unpairIntX(xz);
int z = MathMan.unpairIntY(xz);
List<IChunkAccess> l = new ArrayList<>((radius + 1 + radius) * (radius + 1 + radius));
for (int zz = z - radius; zz <= z + radius; zz++) {
// order is important, first z then x
for (int xx = x - radius; xx <= x + radius; xx++) {
l.add(protoChunks.get(MathMan.pairInt(xx, zz)));
}
}
map.put(xz, l);
}
worldlimits.put(radius, map);
});
// run generation tasks excluding FULL chunk status
for (Map.Entry<ChunkStatus, Concurrency> entry : chunkStati.entrySet()) {
ChunkStatus chunkStatus = entry.getKey();
int radius = chunkStatus.requiredNeighborChunkRadius0();
List<Long> coords = chunkCoordsForRadius.get(radius);
if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) {
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks = getChunkStatusTaskRows(coords, radius);
for (ConcurrentTasks<SequentialTasks<Long>> para : tasks) {
List<Runnable> scheduled = new ArrayList<>(tasks.size());
for (SequentialTasks<Long> row : para) {
scheduled.add(() -> {
for (Long xz : row) {
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
}
});
}
try {
List<Future<?>> futures = new ArrayList<>();
scheduled.forEach(task -> futures.add(executor.submit(task)));
for (Future<?> future : futures) {
future.get();
}
} catch (Exception e) {
e.printStackTrace();
}
}
} else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) {
// every chunk can be processed individually
List<Runnable> scheduled = new ArrayList<>(coords.size());
for (long xz : coords) {
scheduled.add(() -> {
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
});
}
try {
List<Future<?>> futures = new ArrayList<>();
scheduled.forEach(task -> futures.add(executor.submit(task)));
for (Future<?> future : futures) {
future.get();
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
// run sequential
for (long xz : coords) {
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
}
}
}
// convert to proper chunks
for (Long xz : chunkCoordsForRadius.get(0)) {
ProtoChunk proto = protoChunks.get(xz);
chunks.put(xz, createChunk(proto));
}
// final chunkstatus
ChunkStatus FULL = getFullChunkStatus();
for (Long xz : chunkCoordsForRadius.get(0)) {
// FULL.requiredNeighbourChunkRadius() == 0!
Chunk chunk = chunks.get(xz);
FULL.processChunkSave(xz, Arrays.asList(chunk));
}
// populate
List<BlockPopulator> populators = getBlockPopulators();
for (Long xz : chunkCoordsForRadius.get(0)) {
int x = MathMan.unpairIntX(xz);
int z = MathMan.unpairIntY(xz);
// prepare chunk seed
Random random = getChunkRandom(seed, x, z);
// actually populate
Chunk c = chunks.get(xz);
populators.forEach(pop -> {
populate(c, random, pop);
});
}
source = new SingleThreadQueueExtent(BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMinHeight() : 0, BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMaxHeight() : 256);
source.init(target, initSourceQueueCache(), null);
return true;
}
Aggregations