mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-04-02 22:06:17 +00:00
optimize the chunk updater
This commit is contained in:
@@ -176,13 +176,13 @@ public class IrisSettings {
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class IrisSettingsUpdater {
|
public static class IrisSettingsUpdater {
|
||||||
public double threadMultiplier = 2;
|
public int maxConcurrency = 256;
|
||||||
public double chunkLoadSensitivity = 0.7;
|
public double chunkLoadSensitivity = 0.7;
|
||||||
public MsRange emptyMsRange = new MsRange(80, 100);
|
public MsRange emptyMsRange = new MsRange(80, 100);
|
||||||
public MsRange defaultMsRange = new MsRange(20, 40);
|
public MsRange defaultMsRange = new MsRange(20, 40);
|
||||||
|
|
||||||
public double getThreadMultiplier() {
|
public int getMaxConcurrency() {
|
||||||
return Math.min(Math.abs(threadMultiplier), 0.1);
|
return Math.max(Math.abs(maxConcurrency), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getChunkLoadSensitivity() {
|
public double getChunkLoadSensitivity() {
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ public class ChunkUpdater {
|
|||||||
private final AtomicInteger chunksUpdated = new AtomicInteger();
|
private final AtomicInteger chunksUpdated = new AtomicInteger();
|
||||||
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
|
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
|
||||||
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
|
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
|
||||||
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().getUpdater().getThreadMultiplier(), 1);
|
private final int maxConcurrency = IrisSettings.get().getUpdater().getMaxConcurrency();
|
||||||
private final Semaphore semaphore = new Semaphore(256);
|
private final Semaphore semaphore = new Semaphore(maxConcurrency);
|
||||||
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, 256, IrisSettings.get().getUpdater().emptyMsRange);
|
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, maxConcurrency, IrisSettings.get().getUpdater().emptyMsRange);
|
||||||
private final AtomicLong startTime = new AtomicLong();
|
private final AtomicLong startTime = new AtomicLong();
|
||||||
private final Dimensions dimensions;
|
private final Dimensions dimensions;
|
||||||
private final PregenTask task;
|
private final PregenTask task;
|
||||||
private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit);
|
private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||||
private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit);
|
private final ExecutorService chunkExecutor = Executors.newVirtualThreadPerTaskExecutor();
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
private final CountDownLatch latch;
|
private final CountDownLatch latch;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
@@ -138,10 +138,10 @@ public class ChunkUpdater {
|
|||||||
loadBalancer.close();
|
loadBalancer.close();
|
||||||
semaphore.acquire(256);
|
semaphore.acquire(256);
|
||||||
|
|
||||||
executor.shutdown();
|
|
||||||
executor.awaitTermination(5, TimeUnit.SECONDS);
|
|
||||||
chunkExecutor.shutdown();
|
chunkExecutor.shutdown();
|
||||||
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
scheduler.shutdownNow();
|
scheduler.shutdownNow();
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
|||||||
@@ -296,67 +296,63 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
try {
|
try {
|
||||||
Semaphore semaphore = new Semaphore(3);
|
Semaphore semaphore = new Semaphore(3);
|
||||||
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
|
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
|
||||||
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
|
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
|
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
||||||
int betterY = y + getWorld().minHeight();
|
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
|
||||||
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
|
if (!TileData.setTileState(block, 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!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey());
|
||||||
});
|
});
|
||||||
})));
|
}, 0));
|
||||||
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
|
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
|
chunk.iterate(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);
|
||||||
});
|
});
|
||||||
})));
|
}, 0));
|
||||||
|
|
||||||
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
|
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
KMap<Long, Integer> updates = new KMap<>();
|
int[][] grid = new int[16][16];
|
||||||
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
for (int x = 0; x < 16; x++) {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
|
for (int z = 0; z < 16; z++) {
|
||||||
|
grid[x][z] = Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RNG rng = new RNG(Cache.key(c.getX(), c.getZ()));
|
||||||
|
chunk.iterate(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())) {
|
x &= 15;
|
||||||
|
z &= 15;
|
||||||
|
Block block = c.getBlock(x, y, z);
|
||||||
|
if (!B.isFluid(block.getBlockData())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean u = false;
|
boolean u = B.isAir(block.getRelative(BlockFace.DOWN).getBlockData())
|
||||||
if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) {
|
|| B.isAir(block.getRelative(BlockFace.WEST).getBlockData())
|
||||||
u = true;
|
|| B.isAir(block.getRelative(BlockFace.EAST).getBlockData())
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) {
|
|| B.isAir(block.getRelative(BlockFace.SOUTH).getBlockData())
|
||||||
u = true;
|
|| B.isAir(block.getRelative(BlockFace.NORTH).getBlockData());
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u) {
|
if (u) grid[x][z] = Math.max(grid[x][z], y);
|
||||||
updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> {
|
|
||||||
if (vv != null) {
|
|
||||||
return Math.max(vv, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
return y;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
|
for (int x = 0; x < 16; x++) {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
|
for (int z = 0; z < 16; z++) {
|
||||||
|
if (grid[x][z] == Integer.MIN_VALUE)
|
||||||
|
continue;
|
||||||
|
update(x, grid[x][z], z, c, rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk.iterate(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;
|
update(x, y, z, c, rng);
|
||||||
int vz = z & 15;
|
|
||||||
update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ())));
|
|
||||||
if (vx > 0 && vx < 15 && vz > 0 && vz < 15) {
|
|
||||||
updateLighting(x, y, z, c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
chunk.deleteSlices(MatterUpdate.class);
|
||||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||||
}, RNG.r.i(0, 20))));
|
}, RNG.r.i(1, 20))); //Why is there a random delay here?
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -367,33 +363,21 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Runnable run(Semaphore semaphore, Runnable runnable) {
|
private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) {
|
||||||
return () -> {
|
return () -> {
|
||||||
if (!semaphore.tryAcquire())
|
if (!semaphore.tryAcquire())
|
||||||
return;
|
return;
|
||||||
try {
|
|
||||||
runnable.run();
|
J.s(() -> {
|
||||||
} finally {
|
try {
|
||||||
semaphore.release();
|
runnable.run();
|
||||||
}
|
} finally {
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
|
||||||
default void updateLighting(int x, int y, int z, Chunk c) {
|
|
||||||
Block block = c.getBlock(x, y, z);
|
|
||||||
BlockData data = block.getBlockData();
|
|
||||||
|
|
||||||
if (B.isLit(data)) {
|
|
||||||
try {
|
|
||||||
block.setType(Material.AIR, false);
|
|
||||||
block.setBlockData(data, true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
@Override
|
@Override
|
||||||
|
|
||||||
|
|||||||
@@ -610,8 +610,7 @@ public class B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isUpdatable(BlockData mat) {
|
public static boolean isUpdatable(BlockData mat) {
|
||||||
return isLit(mat)
|
return isStorage(mat)
|
||||||
|| isStorage(mat)
|
|
||||||
|| (mat instanceof PointedDripstone
|
|| (mat instanceof PointedDripstone
|
||||||
&& ((PointedDripstone) mat).getThickness().equals(PointedDripstone.Thickness.TIP));
|
&& ((PointedDripstone) mat).getThickness().equals(PointedDripstone.Thickness.TIP));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user