mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-03 08:26:11 +00:00
stability improvements for the chunk updater
This commit is contained in:
parent
7faa727bd2
commit
c38bb1cd01
@ -5,11 +5,14 @@ import com.volmit.iris.core.tools.IrisToolbelt;
|
|||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
|
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.RollingSequence;
|
import com.volmit.iris.util.math.RollingSequence;
|
||||||
import com.volmit.iris.util.math.Spiraler;
|
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
@ -22,55 +25,37 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public class ChunkUpdater {
|
public class ChunkUpdater {
|
||||||
private AtomicBoolean paused;
|
private final AtomicBoolean paused = new AtomicBoolean();
|
||||||
private AtomicBoolean cancelled;
|
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||||
private KMap<Chunk, Long> lastUse;
|
private final KMap<Chunk, Long> lastUse = new KMap<>();
|
||||||
private KMap<Chunk, AtomicInteger> counters;
|
private final KMap<Chunk, AtomicInteger> counters = new KMap<>();
|
||||||
private final RollingSequence chunksPerSecond;
|
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
||||||
private final AtomicInteger worldheightsize;
|
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
||||||
private final AtomicInteger worldwidthsize;
|
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
||||||
private final AtomicInteger totalChunks;
|
private final AtomicInteger chunksProcessedLast = new AtomicInteger();
|
||||||
private final AtomicInteger totalMaxChunks;
|
private final AtomicInteger chunksUpdated = new AtomicInteger();
|
||||||
private final AtomicInteger totalMcaregions;
|
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
|
||||||
private final AtomicInteger position;
|
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() / getProperty(), 1);
|
||||||
private AtomicInteger chunksProcessed;
|
private final Semaphore semaphore = new Semaphore(256);
|
||||||
private AtomicInteger chunksUpdated;
|
private final PlayerCounter playerCounter = new PlayerCounter(semaphore, 256);
|
||||||
private AtomicLong startTime;
|
private final AtomicLong startTime = new AtomicLong();
|
||||||
private ExecutorService executor;
|
private final Dimensions dimensions;
|
||||||
private ExecutorService chunkExecutor;
|
private final PregenTask task;
|
||||||
private ScheduledExecutorService scheduler;
|
private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit);
|
||||||
private CompletableFuture future;
|
private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit);
|
||||||
private CountDownLatch latch;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Object pauseLock;
|
private final CountDownLatch latch;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final World world;
|
private final World world;
|
||||||
|
|
||||||
public ChunkUpdater(World world) {
|
public ChunkUpdater(World world) {
|
||||||
this.engine = IrisToolbelt.access(world).getEngine();
|
this.engine = IrisToolbelt.access(world).getEngine();
|
||||||
this.chunksPerSecond = new RollingSequence(5);
|
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.lastUse = new KMap<>();
|
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
|
||||||
this.counters = new KMap<>();
|
this.task = dimensions.task();
|
||||||
this.worldheightsize = new AtomicInteger(calculateWorldDimensions(new File(world.getWorldFolder(), "region"), 1));
|
this.totalMaxChunks.set(dimensions.count * 1024);
|
||||||
this.worldwidthsize = new AtomicInteger(calculateWorldDimensions(new File(world.getWorldFolder(), "region"), 0));
|
this.scheduler = Executors.newScheduledThreadPool(1);
|
||||||
int m = Math.max(worldheightsize.get(), worldwidthsize.get());
|
|
||||||
this.executor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / (System.getProperty("iris.updater") != null ? 1 : 3), 1));
|
|
||||||
this.chunkExecutor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / (System.getProperty("iris.updater") != null ? 1 : 3), 1));
|
|
||||||
this.scheduler = Executors.newScheduledThreadPool(2);
|
|
||||||
this.future = new CompletableFuture<>();
|
|
||||||
this.startTime = new AtomicLong();
|
|
||||||
this.worldheightsize.set(m);
|
|
||||||
this.worldwidthsize.set(m);
|
|
||||||
this.totalMaxChunks = new AtomicInteger((worldheightsize.get() / 16) * (worldwidthsize.get() / 16));
|
|
||||||
this.chunksProcessed = new AtomicInteger();
|
|
||||||
this.chunksUpdated = new AtomicInteger();
|
|
||||||
this.position = new AtomicInteger(0);
|
|
||||||
this.latch = new CountDownLatch(totalMaxChunks.get());
|
this.latch = new CountDownLatch(totalMaxChunks.get());
|
||||||
this.paused = new AtomicBoolean(false);
|
|
||||||
this.pauseLock = new Object();
|
|
||||||
this.cancelled = new AtomicBoolean(false);
|
|
||||||
this.totalChunks = new AtomicInteger(0);
|
|
||||||
this.totalMcaregions = new AtomicInteger(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunks() {
|
public int getChunks() {
|
||||||
@ -107,11 +92,11 @@ public class ChunkUpdater {
|
|||||||
try {
|
try {
|
||||||
if (!paused.get()) {
|
if (!paused.get()) {
|
||||||
long eta = computeETA();
|
long eta = computeETA();
|
||||||
long elapsedSeconds = (System.currentTimeMillis() - startTime.get()) / 1000;
|
|
||||||
int processed = chunksProcessed.get();
|
int processed = chunksProcessed.get();
|
||||||
double cps = elapsedSeconds > 0 ? processed / (double) elapsedSeconds : 0;
|
double last = processed - chunksProcessedLast.getAndSet(processed);
|
||||||
|
double cps = last / ((M.ms() - lastCpsTime.getAndSet(M.ms())) / 1000d);
|
||||||
chunksPerSecond.put(cps);
|
chunksPerSecond.put(cps);
|
||||||
double percentage = ((double) chunksProcessed.get() / (double) totalMaxChunks.get()) * 100;
|
double percentage = ((double) processed / (double) totalMaxChunks.get()) * 100;
|
||||||
if (!cancelled.get()) {
|
if (!cancelled.get()) {
|
||||||
Iris.info("Updated: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta,
|
Iris.info("Updated: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta,
|
||||||
2), percentage);
|
2), percentage);
|
||||||
@ -122,35 +107,14 @@ public class ChunkUpdater {
|
|||||||
}
|
}
|
||||||
}, 0, 3, TimeUnit.SECONDS);
|
}, 0, 3, TimeUnit.SECONDS);
|
||||||
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
|
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
|
||||||
|
scheduler.scheduleAtFixedRate(playerCounter::update, 0, 5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
CompletableFuture.runAsync(() -> {
|
var t = new Thread(() -> {
|
||||||
for (int i = 0; i < totalMaxChunks.get(); i++) {
|
run();
|
||||||
if (paused.get()) {
|
|
||||||
synchronized (pauseLock) {
|
|
||||||
try {
|
|
||||||
pauseLock.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Iris.error("Interrupted while waiting for executor: ");
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
executor.submit(() -> {
|
|
||||||
if (!cancelled.get()) {
|
|
||||||
processNextChunk();
|
|
||||||
}
|
|
||||||
latch.countDown();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).thenRun(() -> {
|
|
||||||
try {
|
|
||||||
latch.await();
|
|
||||||
close();
|
close();
|
||||||
} catch (Exception e) {
|
}, "Iris Chunk Updater - " + world.getName());
|
||||||
Thread.currentThread().interrupt();
|
t.setPriority(Thread.MAX_PRIORITY);
|
||||||
}
|
t.start();
|
||||||
});
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -159,14 +123,16 @@ public class ChunkUpdater {
|
|||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
|
playerCounter.close();
|
||||||
|
semaphore.acquire(256);
|
||||||
|
|
||||||
executor.shutdown();
|
executor.shutdown();
|
||||||
executor.awaitTermination(5, TimeUnit.SECONDS);
|
executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
chunkExecutor.shutdown();
|
chunkExecutor.shutdown();
|
||||||
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
scheduler.shutdownNow();
|
scheduler.shutdownNow();
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
}
|
|
||||||
if (cancelled.get()) {
|
if (cancelled.get()) {
|
||||||
Iris.info("Updated: " + Form.f(chunksUpdated.get()) + " Chunks");
|
Iris.info("Updated: " + Form.f(chunksUpdated.get()) + " Chunks");
|
||||||
Iris.info("Irritated: " + Form.f(chunksProcessed.get()) + " of " + Form.f(totalMaxChunks.get()));
|
Iris.info("Irritated: " + Form.f(chunksProcessed.get()) + " of " + Form.f(totalMaxChunks.get()));
|
||||||
@ -177,27 +143,70 @@ public class ChunkUpdater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processNextChunk() {
|
private void run() {
|
||||||
int pos = position.getAndIncrement();
|
task.iterateRegions((rX, rZ) -> {
|
||||||
int[] coords = getChunk(pos);
|
if (cancelled.get())
|
||||||
if (loadChunksIfGenerated(coords[0], coords[1])) {
|
return;
|
||||||
Chunk c = world.getChunkAt(coords[0], coords[1]);
|
|
||||||
|
while (paused.get()) {
|
||||||
|
J.sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PregenTask.iterateRegion(rX, rZ, (x, z) -> {
|
||||||
|
while (paused.get() && !cancelled.get()) {
|
||||||
|
J.sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
semaphore.acquire();
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chunkExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
if (!cancelled.get())
|
||||||
|
processChunk(x, z);
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processChunk(int x, int z) {
|
||||||
|
if (!loadChunksIfGenerated(x, z)) {
|
||||||
|
chunksProcessed.getAndIncrement();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Chunk c = world.getChunkAt(x, z);
|
||||||
engine.getMantle().getMantle().getChunk(c);
|
engine.getMantle().getMantle().getChunk(c);
|
||||||
engine.updateChunk(c);
|
engine.updateChunk(c);
|
||||||
|
|
||||||
for (int x = -1; x <= 1; x++) {
|
for (int xx = -1; xx <= 1; xx++) {
|
||||||
for (int z = -1; z <= 1; z++) {
|
for (int zz = -1; zz <= 1; zz++) {
|
||||||
var chunk = world.getChunkAt(coords[0] + x, coords[1] + z, false);
|
var chunk = world.getChunkAt(x + xx, z + zz, false);
|
||||||
var counter = counters.get(chunk);
|
var counter = counters.get(chunk);
|
||||||
if (counter != null) counter.decrementAndGet();
|
if (counter != null) counter.decrementAndGet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
chunksUpdated.incrementAndGet();
|
chunksUpdated.incrementAndGet();
|
||||||
}
|
|
||||||
chunksProcessed.getAndIncrement();
|
chunksProcessed.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean loadChunksIfGenerated(int x, int z) {
|
private boolean loadChunksIfGenerated(int x, int z) {
|
||||||
|
if (engine.getMantle().getMantle().hasFlag(x, z, MantleFlag.ETCHED))
|
||||||
|
return false;
|
||||||
|
|
||||||
for (int dx = -1; dx <= 1; dx++) {
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
for (int dz = -1; dz <= 1; dz++) {
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
|
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
|
||||||
@ -212,11 +221,11 @@ public class ChunkUpdater {
|
|||||||
for (int dz = -1; dz <= 1; dz++) {
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
int xx = x + dx;
|
int xx = x + dx;
|
||||||
int zz = z + dz;
|
int zz = z + dz;
|
||||||
chunkExecutor.submit(() -> {
|
executor.submit(() -> {
|
||||||
try {
|
try {
|
||||||
Chunk c;
|
Chunk c;
|
||||||
try {
|
try {
|
||||||
c = PaperLib.getChunkAtAsync(world, xx, zz, false)
|
c = PaperLib.getChunkAtAsync(world, xx, zz, false, true)
|
||||||
.thenApply(chunk -> {
|
.thenApply(chunk -> {
|
||||||
chunk.addPluginChunkTicket(Iris.instance);
|
chunk.addPluginChunkTicket(Iris.instance);
|
||||||
return chunk;
|
return chunk;
|
||||||
@ -292,7 +301,7 @@ public class ChunkUpdater {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int calculateWorldDimensions(File regionDir, Integer o) {
|
private Dimensions calculateWorldDimensions(File regionDir) {
|
||||||
File[] files = regionDir.listFiles((dir, name) -> name.endsWith(".mca"));
|
File[] files = regionDir.listFiles((dir, name) -> name.endsWith(".mca"));
|
||||||
|
|
||||||
int minX = Integer.MAX_VALUE;
|
int minX = Integer.MAX_VALUE;
|
||||||
@ -305,40 +314,59 @@ public class ChunkUpdater {
|
|||||||
int x = Integer.parseInt(parts[1]);
|
int x = Integer.parseInt(parts[1]);
|
||||||
int z = Integer.parseInt(parts[2]);
|
int z = Integer.parseInt(parts[2]);
|
||||||
|
|
||||||
if (x < minX) minX = x;
|
minX = Math.min(minX, x);
|
||||||
if (x > maxX) maxX = x;
|
maxX = Math.max(maxX, x);
|
||||||
if (z < minZ) minZ = z;
|
minZ = Math.min(minZ, z);
|
||||||
if (z > maxZ) maxZ = z;
|
maxZ = Math.max(maxZ, z);
|
||||||
|
}
|
||||||
|
int oX = minX + ((maxX - minX) / 2);
|
||||||
|
int oZ = minZ + ((maxZ - minZ) / 2);
|
||||||
|
|
||||||
|
int height = maxX - minX + 1;
|
||||||
|
int width = maxZ - minZ + 1;
|
||||||
|
|
||||||
|
return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
|
||||||
|
.width((int) Math.ceil(width / 2d))
|
||||||
|
.height((int) Math.ceil(height / 2d))
|
||||||
|
.center(new Position2(oX, oZ))
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
int height = (maxX - minX + 1) * 32 * 16;
|
private record Dimensions(Position2 min, Position2 max, int count, PregenTask task) { }
|
||||||
int width = (maxZ - minZ + 1) * 32 * 16;
|
|
||||||
|
|
||||||
if (o == 1) {
|
@Data
|
||||||
return height;
|
private static class PlayerCounter {
|
||||||
}
|
private final Semaphore semaphore;
|
||||||
if (o == 0) {
|
private final int maxPermits;
|
||||||
return width;
|
private int lastCount = 0;
|
||||||
}
|
private int permits = 0;
|
||||||
return 0;
|
|
||||||
|
public void update() {
|
||||||
|
double count = Bukkit.getOnlinePlayers().size();
|
||||||
|
if (count == lastCount)
|
||||||
|
return;
|
||||||
|
double p = count == 0 ? 0 : count / (Bukkit.getMaxPlayers() / 2d);
|
||||||
|
int targetPermits = (int) (maxPermits * p);
|
||||||
|
|
||||||
|
int diff = targetPermits - permits;
|
||||||
|
permits = targetPermits;
|
||||||
|
lastCount = (int) count;
|
||||||
|
try {
|
||||||
|
if (diff > 0) semaphore.release(diff);
|
||||||
|
else semaphore.acquire(Math.abs(diff));
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] getChunk(int position) {
|
public void close() {
|
||||||
int p = -1;
|
semaphore.release(permits);
|
||||||
AtomicInteger xx = new AtomicInteger();
|
}
|
||||||
AtomicInteger zz = new AtomicInteger();
|
|
||||||
Spiraler s = new Spiraler(worldheightsize.get() * 2, worldwidthsize.get() * 2, (x, z) -> {
|
|
||||||
xx.set(x);
|
|
||||||
zz.set(z);
|
|
||||||
});
|
|
||||||
|
|
||||||
while (s.hasNext() && p++ < position) {
|
|
||||||
s.next();
|
|
||||||
}
|
}
|
||||||
int[] coords = new int[2];
|
|
||||||
coords[0] = xx.get();
|
|
||||||
coords[1] = zz.get();
|
|
||||||
|
|
||||||
return coords;
|
private static double getProperty() {
|
||||||
|
try {
|
||||||
|
return Double.parseDouble(System.getProperty("iris.updater"));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,31 +281,35 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!getMantle().getMantle().isLoaded(c)) {
|
var mantle = getMantle().getMantle();
|
||||||
|
if (!mantle.isLoaded(c)) {
|
||||||
var msg = "Mantle Chunk " + c.getX() + c.getX() + " is not loaded";
|
var msg = "Mantle Chunk " + c.getX() + c.getX() + " is not loaded";
|
||||||
if (W.getStack().getCallerClass().equals(ChunkUpdater.class)) Iris.warn(msg);
|
if (W.getStack().getCallerClass().equals(ChunkUpdater.class)) Iris.warn(msg);
|
||||||
else Iris.debug(msg);
|
else Iris.debug(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.sfut(() -> {
|
if (mantle.hasFlag(c.getX(), c.getZ(), MantleFlag.ETCHED)) return;
|
||||||
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
|
mantle.flag(c.getX(), c.getZ(), MantleFlag.ETCHED, true);
|
||||||
|
|
||||||
|
mantle.raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.sfut(() -> {
|
||||||
|
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
|
||||||
int betterY = y + getWorld().minHeight();
|
int betterY = y + getWorld().minHeight();
|
||||||
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
|
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
|
||||||
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
|
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
|
||||||
});
|
});
|
||||||
}).join());
|
}).join());
|
||||||
getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.sfut(() -> {
|
mantle.raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.sfut(() -> {
|
||||||
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
|
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
|
||||||
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
||||||
});
|
});
|
||||||
}).join());
|
}).join());
|
||||||
|
|
||||||
getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.sfut(() -> {
|
mantle.raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.sfut(() -> {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
KMap<Long, Integer> updates = new KMap<>();
|
KMap<Long, Integer> updates = new KMap<>();
|
||||||
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
||||||
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
|
mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
|
||||||
int y = yf + getWorld().minHeight();
|
int y = yf + getWorld().minHeight();
|
||||||
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
|
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
|
||||||
return;
|
return;
|
||||||
@ -335,7 +339,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
});
|
});
|
||||||
|
|
||||||
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
|
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
|
||||||
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
|
mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
|
||||||
int y = yf + getWorld().minHeight();
|
int y = yf + getWorld().minHeight();
|
||||||
if (v != null && v.isUpdate()) {
|
if (v != null && v.isUpdate()) {
|
||||||
int vx = x & 15;
|
int vx = x & 15;
|
||||||
@ -346,7 +350,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
getMantle().getMantle().deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
||||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||||
}, RNG.r.i(0, 20)).join());
|
}, RNG.r.i(0, 20)).join());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user