mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-04 00:46:08 +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.io.IO;
|
||||||
import com.volmit.iris.util.json.JSONArray;
|
import com.volmit.iris.util.json.JSONArray;
|
||||||
import com.volmit.iris.util.json.JSONObject;
|
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.M;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
import com.volmit.iris.util.math.Spiraler;
|
import com.volmit.iris.util.math.Spiraler;
|
||||||
import com.volmit.iris.util.noise.CNG;
|
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.MultiBurst;
|
||||||
|
import com.volmit.iris.util.parallel.SyncExecutor;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import com.volmit.iris.util.scheduling.O;
|
import com.volmit.iris.util.scheduling.O;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
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 io.papermc.lib.PaperLib;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
@ -76,8 +78,7 @@ import java.time.temporal.ChronoUnit;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -161,70 +162,77 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
||||||
int radius
|
int radius
|
||||||
) {
|
) {
|
||||||
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
|
World world = player().getWorld();
|
||||||
VolmitSender sender = sender();
|
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||||
J.a(() -> {
|
|
||||||
DecreeContext.touch(sender);
|
|
||||||
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
|
|
||||||
Engine engine = plat.getEngine();
|
|
||||||
try {
|
|
||||||
Chunk cx = player().getLocation().getChunk();
|
|
||||||
KList<Runnable> js = new KList<>();
|
|
||||||
BurstExecutor b = MultiBurst.burst.burst();
|
|
||||||
b.setMulticore(false);
|
|
||||||
int rad = engine.getMantle().getRadius();
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<>();
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Regenerating";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
r.queue(js);
|
|
||||||
r.execute(sender());
|
|
||||||
} catch (Throwable e) {
|
|
||||||
sender().sendMessage("Unable to parse view-distance");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
|
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(world);
|
||||||
|
Engine engine = plat.getEngine();
|
||||||
|
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++) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelQueueJob<Position2> job = new ParallelQueueJob<>() {
|
||||||
|
@Override
|
||||||
|
public void execute(Position2 p) {
|
||||||
|
plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Regenerating";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable e) {
|
||||||
|
sender().sendMessage("Error while regenerating chunks");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Convert objects in the \"convert\" folder")
|
@Decree(description = "Convert objects in the \"convert\" folder")
|
||||||
|
@ -61,15 +61,12 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
@ -94,8 +91,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
@Setter
|
@Setter
|
||||||
private volatile StudioGenerator studioGenerator;
|
private volatile StudioGenerator studioGenerator;
|
||||||
|
|
||||||
private boolean initialized = false;
|
|
||||||
|
|
||||||
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
|
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
|
||||||
setup = new AtomicBoolean(false);
|
setup = new AtomicBoolean(false);
|
||||||
studioGenerator = null;
|
studioGenerator = null;
|
||||||
@ -114,10 +109,11 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onWorldInit(WorldInitEvent event) {
|
public void onWorldInit(WorldInitEvent event) {
|
||||||
try {
|
try {
|
||||||
if (initialized || !world.name().equals(event.getWorld().getName()))
|
if (!world.name().equals(event.getWorld().getName())) return;
|
||||||
return;
|
Iris.instance.unregisterListener(this);
|
||||||
AutoClosing.closeContext();
|
AutoClosing.closeContext();
|
||||||
INMS.get().removeCustomDimensions(event.getWorld());
|
INMS.get().removeCustomDimensions(event.getWorld());
|
||||||
|
|
||||||
world.setRawWorldSeed(event.getWorld().getSeed());
|
world.setRawWorldSeed(event.getWorld().getSeed());
|
||||||
Engine engine = getEngine(event.getWorld());
|
Engine engine = getEngine(event.getWorld());
|
||||||
if (engine == null) {
|
if (engine == null) {
|
||||||
@ -128,7 +124,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
try {
|
try {
|
||||||
INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld());
|
INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld());
|
||||||
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
|
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
|
||||||
initialized = true;
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -138,7 +133,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld());
|
INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld());
|
||||||
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
|
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
|
||||||
spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld()));
|
spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld()));
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -194,50 +188,57 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
try {
|
||||||
loadLock.acquire();
|
loadLock.acquire();
|
||||||
IrisBiomeStorage st = new IrisBiomeStorage();
|
IrisBiomeStorage st = new IrisBiomeStorage();
|
||||||
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
|
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);
|
this.world.bind(world);
|
||||||
getEngine().generate(x << 4, z << 4, blocks, biomes, true);
|
getEngine().generate(x << 4, z << 4, tc, false);
|
||||||
Iris.debug("Regenerated " + x + " " + z);
|
|
||||||
int t = 0;
|
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
|
||||||
|
.thenApply(d -> {
|
||||||
|
d.addPluginChunkTicket(Iris.instance);
|
||||||
|
|
||||||
|
for (Entity ee : d.getEntities()) {
|
||||||
|
if (ee instanceof Player) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ee.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.getWorldManager().onChunkLoad(d, false);
|
||||||
|
return d;
|
||||||
|
}).get();
|
||||||
|
|
||||||
|
|
||||||
|
KList<CompletableFuture<?>> futures = new KList<>(1 + getEngine().getHeight() >> 4);
|
||||||
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
|
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
|
||||||
if (!world.isChunkLoaded(x, z)) {
|
int finalI = i << 4;
|
||||||
continue;
|
futures.add(CompletableFuture.runAsync(() -> {
|
||||||
}
|
|
||||||
|
|
||||||
Chunk c = world.getChunkAt(x, z);
|
|
||||||
for (Entity ee : c.getEntities()) {
|
|
||||||
if (ee instanceof Player) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
J.s(ee::remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
|
|
||||||
|
|
||||||
int finalI = i;
|
|
||||||
jobs.accept(() -> {
|
|
||||||
|
|
||||||
for (int xx = 0; xx < 16; xx++) {
|
for (int xx = 0; xx < 16; xx++) {
|
||||||
for (int yy = 0; yy < 16; yy++) {
|
for (int yy = 0; yy < 16; yy++) {
|
||||||
for (int zz = 0; zz < 16; zz++) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz)
|
int y = yy + finalI + world.getMinHeight();
|
||||||
.setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false);
|
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();
|
loadLock.release();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
loadLock.release();
|
loadLock.release();
|
||||||
|
@ -26,7 +26,7 @@ import com.volmit.iris.util.data.DataProvider;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
||||||
Engine getEngine();
|
Engine getEngine();
|
||||||
@ -40,7 +40,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
|||||||
return getEngine().getTarget();
|
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();
|
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