mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-03 16:36:00 +00:00
cleanup regen
This commit is contained in:
parent
a56cd4c268
commit
21825c4d12
@ -46,18 +46,20 @@ import com.volmit.iris.util.interpolation.InterpolationMethod;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONArray;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.math.Spiraler;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.parallel.SyncExecutor;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.O;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.scheduling.jobs.QueueJob;
|
||||
import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
@ -76,8 +78,7 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ -161,54 +162,41 @@ public class CommandStudio implements DecreeExecutor {
|
||||
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
||||
int radius
|
||||
) {
|
||||
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
|
||||
World world = player().getWorld();
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
|
||||
}
|
||||
|
||||
VolmitSender sender = sender();
|
||||
var loc = player().getLocation().clone();
|
||||
|
||||
J.a(() -> {
|
||||
DecreeContext.touch(sender);
|
||||
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
|
||||
PlatformChunkGenerator plat = IrisToolbelt.access(world);
|
||||
Engine engine = plat.getEngine();
|
||||
try {
|
||||
Chunk cx = player().getLocation().getChunk();
|
||||
KList<Runnable> js = new KList<>();
|
||||
BurstExecutor b = MultiBurst.burst.burst();
|
||||
b.setMulticore(false);
|
||||
try (SyncExecutor executor = new SyncExecutor(20)) {
|
||||
int x = loc.getBlockX() >> 4;
|
||||
int z = loc.getBlockZ() >> 4;
|
||||
|
||||
int rad = engine.getMantle().getRadius();
|
||||
var mantle = engine.getMantle().getMantle();
|
||||
var chunkMap = new KMap<Position2, MantleChunk>();
|
||||
for (int i = -(radius + rad); i <= radius + rad; i++) {
|
||||
for (int j = -(radius + rad); j <= radius + rad; j++) {
|
||||
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
|
||||
int xx = i + x, zz = j + z;
|
||||
if (Math.abs(i) <= radius && Math.abs(j) <= radius) {
|
||||
mantle.deleteChunk(xx, zz);
|
||||
continue;
|
||||
}
|
||||
chunkMap.put(new Position2(xx, zz), mantle.getChunk(xx, zz));
|
||||
mantle.deleteChunk(xx, zz);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = -radius; i <= radius; i++) {
|
||||
for (int j = -radius; j <= radius; j++) {
|
||||
int finalJ = j;
|
||||
int finalI = i;
|
||||
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
|
||||
synchronized (js) {
|
||||
js.add(f);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
b.complete();
|
||||
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
|
||||
QueueJob<Runnable> r = new QueueJob<>() {
|
||||
final KList<Future<?>> futures = new KList<>();
|
||||
|
||||
ParallelQueueJob<Position2> job = new ParallelQueueJob<>() {
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
futures.add(J.sfut(runnable));
|
||||
|
||||
if (futures.size() > 64) {
|
||||
while (futures.isNotEmpty()) {
|
||||
try {
|
||||
futures.remove(0).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void execute(Position2 p) {
|
||||
plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -216,15 +204,35 @@ public class CommandStudio implements DecreeExecutor {
|
||||
return "Regenerating";
|
||||
}
|
||||
};
|
||||
r.queue(js);
|
||||
r.execute(sender());
|
||||
} catch (Throwable e) {
|
||||
sender().sendMessage("Unable to parse view-distance");
|
||||
for (int i = -radius; i <= radius; i++) {
|
||||
for (int j = -radius; j <= radius; j++) {
|
||||
job.queue(new Position2(i + x, j + z));
|
||||
}
|
||||
}
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
job.execute(sender(), latch::countDown);
|
||||
latch.await();
|
||||
|
||||
int sections = mantle.getWorldHeight() >> 4;
|
||||
chunkMap.forEach((pos, chunk) -> {
|
||||
var c = mantle.getChunk(pos.getX(), pos.getZ());
|
||||
for (MantleFlag flag : MantleFlag.values()) {
|
||||
c.flag(flag, chunk.isFlagged(flag));
|
||||
}
|
||||
c.clear();
|
||||
for (int y = 0; y < sections; y++) {
|
||||
var slice = chunk.get(y);
|
||||
if (slice == null) continue;
|
||||
var s = c.getOrCreate(y);
|
||||
slice.getSliceMap().forEach(s::putSlice);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
|
||||
} catch (Throwable e) {
|
||||
sender().sendMessage("Error while regenerating chunks");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Decree(description = "Convert objects in the \"convert\" folder")
|
||||
|
@ -61,15 +61,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@ -94,8 +91,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
@Setter
|
||||
private volatile StudioGenerator studioGenerator;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
|
||||
setup = new AtomicBoolean(false);
|
||||
studioGenerator = null;
|
||||
@ -114,10 +109,11 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldInit(WorldInitEvent event) {
|
||||
try {
|
||||
if (initialized || !world.name().equals(event.getWorld().getName()))
|
||||
return;
|
||||
if (!world.name().equals(event.getWorld().getName())) return;
|
||||
Iris.instance.unregisterListener(this);
|
||||
AutoClosing.closeContext();
|
||||
INMS.get().removeCustomDimensions(event.getWorld());
|
||||
|
||||
world.setRawWorldSeed(event.getWorld().getSeed());
|
||||
Engine engine = getEngine(event.getWorld());
|
||||
if (engine == null) {
|
||||
@ -128,7 +124,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
try {
|
||||
INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld());
|
||||
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
|
||||
initialized = true;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -138,7 +133,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld());
|
||||
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
|
||||
spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld()));
|
||||
initialized = true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@ -194,50 +188,57 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs) {
|
||||
public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) {
|
||||
try {
|
||||
loadLock.acquire();
|
||||
IrisBiomeStorage st = new IrisBiomeStorage();
|
||||
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
|
||||
Hunk<BlockData> blocks = Hunk.view(tc);
|
||||
Hunk<Biome> biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight());
|
||||
this.world.bind(world);
|
||||
getEngine().generate(x << 4, z << 4, blocks, biomes, true);
|
||||
Iris.debug("Regenerated " + x + " " + z);
|
||||
int t = 0;
|
||||
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
|
||||
if (!world.isChunkLoaded(x, z)) {
|
||||
continue;
|
||||
}
|
||||
getEngine().generate(x << 4, z << 4, tc, false);
|
||||
|
||||
Chunk c = world.getChunkAt(x, z);
|
||||
for (Entity ee : c.getEntities()) {
|
||||
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
|
||||
.thenApply(d -> {
|
||||
d.addPluginChunkTicket(Iris.instance);
|
||||
|
||||
for (Entity ee : d.getEntities()) {
|
||||
if (ee instanceof Player) {
|
||||
continue;
|
||||
}
|
||||
|
||||
J.s(ee::remove);
|
||||
ee.remove();
|
||||
}
|
||||
|
||||
J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
|
||||
engine.getWorldManager().onChunkLoad(d, false);
|
||||
return d;
|
||||
}).get();
|
||||
|
||||
int finalI = i;
|
||||
jobs.accept(() -> {
|
||||
|
||||
KList<CompletableFuture<?>> futures = new KList<>(1 + getEngine().getHeight() >> 4);
|
||||
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
|
||||
int finalI = i << 4;
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
for (int xx = 0; xx < 16; xx++) {
|
||||
for (int yy = 0; yy < 16; yy++) {
|
||||
for (int zz = 0; zz < 16; zz++) {
|
||||
if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) {
|
||||
if (yy + finalI >= engine.getHeight() || yy + finalI < 0) {
|
||||
continue;
|
||||
}
|
||||
c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz)
|
||||
.setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false);
|
||||
int y = yy + finalI + world.getMinHeight();
|
||||
c.getBlock(xx, y, zz).setBlockData(tc.getBlockData(xx, y, zz), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, syncExecutor));
|
||||
}
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.thenRunAsync(() -> {
|
||||
c.removePluginChunkTicket(Iris.instance);
|
||||
c.unload();
|
||||
}, syncExecutor)
|
||||
.get();
|
||||
Iris.debug("Regenerated " + x + " " + z);
|
||||
|
||||
loadLock.release();
|
||||
} catch (Throwable e) {
|
||||
loadLock.release();
|
||||
|
@ -26,7 +26,7 @@ import com.volmit.iris.util.data.DataProvider;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
||||
Engine getEngine();
|
||||
@ -40,7 +40,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
||||
return getEngine().getTarget();
|
||||
}
|
||||
|
||||
void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs);
|
||||
void injectChunkReplacement(World world, int x, int z, Executor syncExecutor);
|
||||
|
||||
void close();
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.volmit.iris.util.parallel;
|
||||
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.scheduling.SR;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class SyncExecutor implements Executor, AutoCloseable {
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
private final Queue<Runnable> queue = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
|
||||
public SyncExecutor(int msPerTick) {
|
||||
new SR() {
|
||||
@Override
|
||||
public void run() {
|
||||
var time = M.ms() + msPerTick;
|
||||
while (time > M.ms()) {
|
||||
Runnable r = queue.poll();
|
||||
if (r == null) break;
|
||||
r.run();
|
||||
}
|
||||
|
||||
if (closed.get() && queue.isEmpty()) {
|
||||
cancel();
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull Runnable command) {
|
||||
if (closed.get()) throw new IllegalStateException("Executor is closed!");
|
||||
queue.add(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
closed.set(true);
|
||||
latch.await();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user