This commit is contained in:
Brian Neumann-Fopiano
2026-06-14 13:52:57 -04:00
parent 796d81e58b
commit 79e80bef33
14 changed files with 419 additions and 134 deletions
@@ -114,6 +114,10 @@ import java.util.regex.Pattern;
public class Iris extends VolmitPlugin implements Listener, ReloadAware {
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
static {
System.setProperty("iris.cache.fast", "true");
}
public static Iris instance;
public static Bindings.Adventure audiences;
public static MultiverseCoreLink linkMultiverseCore;
@@ -580,6 +584,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
compat = IrisCompat.configured(getDataFile("compat.json"));
IrisServices.register(IrisCompat.class, compat);
ServerConfigurator.configure();
IrisToolbelt.applyPregenPerformanceProfile();
validateAllPacks();
IrisSafeguard.execute();
getSender().setTag(getTag());
@@ -607,7 +612,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
services.values().forEach(this::registerListener);
addShutdownHook();
processPendingStartupWorldDeletes();
IrisToolbelt.applyPregenPerformanceProfile();
WorldLifecycleService.get();
WorldRuntimeControlService.get();
@@ -34,8 +34,9 @@ import io.papermc.lib.PaperLib;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@@ -350,13 +351,13 @@ public class AsyncPregenMethod implements PregeneratorMethod {
static int computePaperLikeRecommendedCap(int workerThreads) {
int normalizedWorkers = Math.max(1, workerThreads);
int recommendedCap = normalizedWorkers * 2;
if (recommendedCap < 8) {
return 8;
int recommendedCap = normalizedWorkers * 4;
if (recommendedCap < 16) {
return 16;
}
if (recommendedCap > 96) {
return 96;
if (recommendedCap > 128) {
return 128;
}
return recommendedCap;
@@ -721,13 +722,18 @@ public class AsyncPregenMethod implements PregeneratorMethod {
public static void increaseWorkerThreads() {
THREAD_COUNT.updateAndGet(i -> {
if (i > 0) return 1;
var adjusted = IrisSettings.get().getConcurrency().getWorldGenThreads();
if (i > 0) {
return 1;
}
int adjusted = IrisSettings.get().getConcurrency().getWorldGenThreads();
try {
var field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
var pool = field.get(null);
var threads = ((Thread[]) pool.getClass().getDeclaredMethod("getCoreThreads").invoke(pool)).length;
if (threads >= adjusted) return 0;
Field field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
Object pool = field.get(null);
int threads = ((Thread[]) pool.getClass().getDeclaredMethod("getCoreThreads").invoke(pool)).length;
if (threads >= adjusted) {
return 0;
}
pool.getClass().getDeclaredMethod("adjustThreadCount", int.class).invoke(pool, adjusted);
return threads;
@@ -745,11 +751,14 @@ public class AsyncPregenMethod implements PregeneratorMethod {
public static void resetWorkerThreads() {
THREAD_COUNT.updateAndGet(i -> {
if (i == 0) return 0;
if (i == 0) {
return 0;
}
try {
var field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
var pool = field.get(null);
var method = pool.getClass().getDeclaredMethod("adjustThreadCount", int.class);
Field field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
Object pool = field.get(null);
Method method = pool.getClass().getDeclaredMethod("adjustThreadCount", int.class);
method.invoke(pool, i);
return 0;
} catch (Throwable e) {
@@ -25,6 +25,7 @@ import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.UpperDimensionContext;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisOreGenerator;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.util.project.context.ChunkedDataCache;
@@ -236,8 +237,14 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<PlatformBl
int topY = Math.min(hf, chunkHeight - 1);
PlatformBlockState fluid = fluidCache.get(xf, zf);
PlatformBlockState rock = rockCache.get(xf, zf);
boolean hasSurfaceOres = !hideOres && (biome.hasSurfaceOres() || region.hasSurfaceOres() || dimension.hasSurfaceOres());
boolean hasUndergroundOres = !hideOres && (biome.hasUndergroundOres() || region.hasUndergroundOres() || dimension.hasUndergroundOres());
KList<IrisOreGenerator> biomeSurfaceOres = hideOres ? null : biome.getSurfaceOreGenerators();
KList<IrisOreGenerator> regionSurfaceOres = hideOres ? null : region.getSurfaceOreGenerators();
KList<IrisOreGenerator> dimensionSurfaceOres = hideOres ? null : dimension.getSurfaceOreGenerators();
KList<IrisOreGenerator> biomeUndergroundOres = hideOres ? null : biome.getUndergroundOreGenerators();
KList<IrisOreGenerator> regionUndergroundOres = hideOres ? null : region.getUndergroundOreGenerators();
KList<IrisOreGenerator> dimensionUndergroundOres = hideOres ? null : dimension.getUndergroundOreGenerators();
boolean hasSurfaceOres = !hideOres && (!biomeSurfaceOres.isEmpty() || !regionSurfaceOres.isEmpty() || !dimensionSurfaceOres.isEmpty());
boolean hasUndergroundOres = !hideOres && (!biomeUndergroundOres.isEmpty() || !regionUndergroundOres.isEmpty() || !dimensionUndergroundOres.isEmpty());
KList<PlatformBlockState> blocks = null;
KList<PlatformBlockState> fblocks = null;
@@ -250,9 +257,9 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<PlatformBl
PlatformBlockState ore = null;
if (hasSurfaceOres) {
ore = biome.generateSurfaceOres(realX, i, realZ, localRng, data);
ore = ore == null ? region.generateSurfaceOres(realX, i, realZ, localRng, data) : ore;
ore = ore == null ? dimension.generateSurfaceOres(realX, i, realZ, localRng, data) : ore;
ore = generateOres(biomeSurfaceOres, realX, i, realZ, localRng, data);
ore = ore == null ? generateOres(regionSurfaceOres, realX, i, realZ, localRng, data) : ore;
ore = ore == null ? generateOres(dimensionSurfaceOres, realX, i, realZ, localRng, data) : ore;
}
if (ore != null) {
h.setRaw(xf, i, zf, ore);
@@ -285,9 +292,9 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<PlatformBl
}
if (hasUndergroundOres) {
ore = biome.generateUndergroundOres(realX, i, realZ, localRng, data);
ore = ore == null ? region.generateUndergroundOres(realX, i, realZ, localRng, data) : ore;
ore = ore == null ? dimension.generateUndergroundOres(realX, i, realZ, localRng, data) : ore;
ore = generateOres(biomeUndergroundOres, realX, i, realZ, localRng, data);
ore = ore == null ? generateOres(regionUndergroundOres, realX, i, realZ, localRng, data) : ore;
ore = ore == null ? generateOres(dimensionUndergroundOres, realX, i, realZ, localRng, data) : ore;
}
if (ore != null) {
@@ -329,4 +336,21 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<PlatformBl
}
}
}
private PlatformBlockState generateOres(KList<IrisOreGenerator> oreGenerators, int x, int y, int z, RNG rng, IrisData data) {
if (oreGenerators == null || oreGenerators.isEmpty()) {
return null;
}
int oreCount = oreGenerators.size();
for (int oreIndex = 0; oreIndex < oreCount; oreIndex++) {
IrisOreGenerator oreGenerator = oreGenerators.get(oreIndex);
PlatformBlockState ore = oreGenerator.generate(x, y, z, rng, data);
if (ore != null) {
return ore;
}
}
return null;
}
}
@@ -15,10 +15,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ConcurrentHashMap;
public interface MatterGenerator {
Executor DISPATCHER = MultiBurst.burst;
MultiBurst DISPATCHER = MultiBurst.burst;
ConcurrentHashMap<MatterTaskKey, CompletableFuture<Void>> IN_FLIGHT_COMPONENTS = new ConcurrentHashMap<>();
Engine getEngine();
@@ -42,7 +43,7 @@ public interface MatterGenerator {
try (MantleWriter writer = new MantleWriter(getEngine().getMantle(), getMantle(), x, z, writeRadius, multicore)) {
for (Pair<List<MantleComponent>, Integer> pair : getComponents()) {
int passRadius = pair.getB();
List<CompletableFuture<Void>> launchedTasks = multicore ? new ArrayList<>() : null;
Set<CompletableFuture<Void>> launchedTasks = multicore ? new HashSet<>() : null;
for (int i = -passRadius; i <= passRadius; i++) {
for (int j = -passRadius; j <= passRadius; j++) {
@@ -55,6 +56,7 @@ public interface MatterGenerator {
continue;
}
List<MantleComponent> eligibleComponents = new ArrayList<>(pair.getA().size());
for (MantleComponent component : pair.getA()) {
if (!component.isEnabled()) {
continue;
@@ -88,18 +90,27 @@ public interface MatterGenerator {
}
}
int finalPassX = passX;
int finalPassZ = passZ;
MantleChunk<Matter> finalChunk = chunk;
MantleComponent finalComponent = component;
Runnable task = () -> finalChunk.raiseFlagSuspend(finalComponent.getFlag(),
() -> finalComponent.generateLayer(writer, finalPassX, finalPassZ, context));
eligibleComponents.add(component);
}
if (multicore) {
launchedTasks.add(CompletableFuture.runAsync(task, DISPATCHER));
} else {
task.run();
if (eligibleComponents.isEmpty()) {
continue;
}
int finalPassX = passX;
int finalPassZ = passZ;
Runnable task = () -> {
for (MantleComponent component : eligibleComponents) {
runComponentInline(chunk, component, writer, finalPassX, finalPassZ, context);
}
};
if (multicore) {
for (MantleComponent component : eligibleComponents) {
launchedTasks.add(runComponentAsync(chunk, component, writer, finalPassX, finalPassZ, context));
}
} else {
task.run();
}
}
}
@@ -128,4 +139,110 @@ public interface MatterGenerator {
private static long chunkKey(int x, int z) {
return (((long) x) << 32) ^ (z & 0xffffffffL);
}
private CompletableFuture<Void> runComponentAsync(
MantleChunk<Matter> chunk,
MantleComponent component,
MantleWriter writer,
int chunkX,
int chunkZ,
ChunkContext context
) {
MantleFlag flag = component.getFlag();
if (chunk.isFlagged(flag)) {
return CompletableFuture.completedFuture(null);
}
MatterTaskKey key = new MatterTaskKey(getMantle(), chunkX, chunkZ, flag.ordinal());
CompletableFuture<Void> future = new CompletableFuture<>();
CompletableFuture<Void> existing = IN_FLIGHT_COMPONENTS.putIfAbsent(key, future);
if (existing != null) {
return existing;
}
try {
if (DISPATCHER.ownsCurrentThread()) {
completeComponentTask(future, key, chunk, component, writer, chunkX, chunkZ, context);
} else {
CompletableFuture.runAsync(() -> completeComponentTask(future, key, chunk, component, writer, chunkX, chunkZ, context), DISPATCHER);
}
} catch (Throwable throwable) {
IN_FLIGHT_COMPONENTS.remove(key, future);
future.completeExceptionally(throwable);
throw throwable;
}
return future;
}
private void completeComponentTask(
CompletableFuture<Void> future,
MatterTaskKey key,
MantleChunk<Matter> chunk,
MantleComponent component,
MantleWriter writer,
int chunkX,
int chunkZ,
ChunkContext context
) {
try {
runComponentInline(chunk, component, writer, chunkX, chunkZ, context);
future.complete(null);
} catch (Throwable throwable) {
future.completeExceptionally(throwable);
throw throwable;
} finally {
IN_FLIGHT_COMPONENTS.remove(key, future);
}
}
private void runComponentInline(
MantleChunk<Matter> chunk,
MantleComponent component,
MantleWriter writer,
int chunkX,
int chunkZ,
ChunkContext context
) {
chunk.raiseFlagSuspend(component.getFlag(), () -> component.generateLayer(writer, chunkX, chunkZ, context));
}
final class MatterTaskKey {
private final Mantle<Matter> mantle;
private final int chunkX;
private final int chunkZ;
private final int flagOrdinal;
MatterTaskKey(Mantle<Matter> mantle, int chunkX, int chunkZ, int flagOrdinal) {
this.mantle = mantle;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.flagOrdinal = flagOrdinal;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof MatterTaskKey other)) {
return false;
}
return mantle == other.mantle
&& chunkX == other.chunkX
&& chunkZ == other.chunkZ
&& flagOrdinal == other.flagOrdinal;
}
@Override
public int hashCode() {
int result = System.identityHashCode(mantle);
result = 31 * result + chunkX;
result = 31 * result + chunkZ;
result = 31 * result + flagOrdinal;
return result;
}
}
}
@@ -34,6 +34,7 @@ import art.arcane.iris.util.project.hunk.Hunk;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
import art.arcane.volmlib.util.mantle.runtime.TectonicPlate;
import art.arcane.volmlib.util.math.BlockPosition;
import art.arcane.volmlib.util.math.M;
import art.arcane.volmlib.util.math.PowerOfTwoCoordinates;
@@ -229,55 +230,53 @@ public class IrisCarveModifier extends EngineAssignedModifier<PlatformBlockState
return;
}
boolean westLoaded = mantle.hasTectonicPlate(((chunkX - 1) >> 5), (chunkZ >> 5));
boolean eastLoaded = mantle.hasTectonicPlate(((chunkX + 1) >> 5), (chunkZ >> 5));
boolean northLoaded = mantle.hasTectonicPlate((chunkX >> 5), ((chunkZ - 1) >> 5));
boolean southLoaded = mantle.hasTectonicPlate((chunkX >> 5), ((chunkZ + 1) >> 5));
if (!westLoaded && !eastLoaded && !northLoaded && !southLoaded) {
MantleChunk<Matter> west = existingMantleChunk(mantle, chunkX - 1, chunkZ);
MantleChunk<Matter> east = existingMantleChunk(mantle, chunkX + 1, chunkZ);
MantleChunk<Matter> north = existingMantleChunk(mantle, chunkX, chunkZ - 1);
MantleChunk<Matter> south = existingMantleChunk(mantle, chunkX, chunkZ + 1);
if (west == null && east == null && north == null && south == null) {
return;
}
for (int yy = 1; yy <= maxY; yy++) {
for (int offset = 0; offset < 16; offset++) {
if (westLoaded) {
tryAddBoundaryWall(mantle, mc, walls, boundaryMasks, boundaryCaverns, 0, yy, offset, baseX, baseZ, -1, 0);
if (west != null) {
tryAddBoundaryWall(mc, west, walls, boundaryMasks, boundaryCaverns, 0, yy, offset, 15, offset);
}
if (eastLoaded) {
tryAddBoundaryWall(mantle, mc, walls, boundaryMasks, boundaryCaverns, 15, yy, offset, baseX, baseZ, 1, 0);
if (east != null) {
tryAddBoundaryWall(mc, east, walls, boundaryMasks, boundaryCaverns, 15, yy, offset, 0, offset);
}
if (northLoaded) {
tryAddBoundaryWall(mantle, mc, walls, boundaryMasks, boundaryCaverns, offset, yy, 0, baseX, baseZ, 0, -1);
if (north != null) {
tryAddBoundaryWall(mc, north, walls, boundaryMasks, boundaryCaverns, offset, yy, 0, offset, 15);
}
if (southLoaded) {
tryAddBoundaryWall(mantle, mc, walls, boundaryMasks, boundaryCaverns, offset, yy, 15, baseX, baseZ, 0, 1);
if (south != null) {
tryAddBoundaryWall(mc, south, walls, boundaryMasks, boundaryCaverns, offset, yy, 15, offset, 0);
}
}
}
}
private void tryAddBoundaryWall(
Mantle<Matter> mantle,
MantleChunk<Matter> mc,
MantleChunk<Matter> neighborChunk,
PackedWallBuffer walls,
ColumnMask[] boundaryMasks,
MatterCavern[] boundaryCaverns,
int localX,
int yy,
int localZ,
int baseX,
int baseZ,
int dx,
int dz
int neighborX,
int neighborZ
) {
int worldX = baseX + localX;
int worldZ = baseZ + localZ;
if (mc.get(worldX, yy, worldZ, MatterCavern.class) != null) {
if (mc.get(localX, yy, localZ, MatterCavern.class) != null) {
return;
}
MatterCavern neighbor = mantle.get(worldX + dx, yy, worldZ + dz, MatterCavern.class);
MatterCavern neighbor = neighborChunk.get(neighborX, yy, neighborZ, MatterCavern.class);
if (neighbor == null) {
return;
}
walls.put(localX, yy, localZ, neighbor);
int columnIndex = PowerOfTwoCoordinates.packLocal16(localX, localZ);
boundaryMasks[columnIndex].add(yy);
@@ -286,6 +285,14 @@ public class IrisCarveModifier extends EngineAssignedModifier<PlatformBlockState
}
}
private MantleChunk<Matter> existingMantleChunk(Mantle<Matter> mantle, int chunkX, int chunkZ) {
TectonicPlate<Matter> plate = mantle.getLoadedRegions().get(Mantle.key(chunkX >> 5, chunkZ >> 5));
if (plate == null || plate.isClosed()) {
return null;
}
return plate.get(chunkX & 31, chunkZ & 31);
}
private void processColumnFromMask(
Hunk<PlatformBlockState> output,
MantleChunk<Matter> mc,
@@ -237,6 +237,14 @@ public class IrisBiome extends IrisRegistrant implements IRare {
undergroundOreCache.reset();
}
public KList<IrisOreGenerator> getSurfaceOreGenerators() {
return getOres(true);
}
public KList<IrisOreGenerator> getUndergroundOreGenerators() {
return getOres(false);
}
private KList<IrisOreGenerator> getSurfaceOres() {
return getOres(true);
}
@@ -342,6 +342,14 @@ public class IrisDimension extends IrisRegistrant {
undergroundOreCache.reset();
}
public KList<IrisOreGenerator> getSurfaceOreGenerators() {
return getOres(true);
}
public KList<IrisOreGenerator> getUndergroundOreGenerators() {
return getOres(false);
}
private KList<IrisOreGenerator> getSurfaceOres() {
return getOres(true);
}
@@ -197,6 +197,14 @@ public class IrisRegion extends IrisRegistrant implements IRare {
undergroundOreCache.reset();
}
public KList<IrisOreGenerator> getSurfaceOreGenerators() {
return getOres(true);
}
public KList<IrisOreGenerator> getUndergroundOreGenerators() {
return getOres(false);
}
private KList<IrisOreGenerator> getSurfaceOres() {
return getOres(true);
}
@@ -22,6 +22,7 @@ import art.arcane.iris.core.nms.INMS;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.iris.util.common.data.IrisCustomData;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.LinkedHashMap;
@@ -37,18 +38,65 @@ public final class BukkitBlockState implements PlatformBlockState {
private final BlockData data;
private final String key;
private final String namespace;
private volatile Boolean air;
private volatile Boolean solid;
private volatile Boolean occluding;
private volatile Boolean fluid;
private volatile Boolean water;
private volatile Boolean foliage;
private volatile Boolean decorant;
private final Boolean air;
private final Boolean solid;
private final Boolean occluding;
private final Boolean fluid;
private final Boolean water;
private final Boolean waterLogged;
private final Boolean lit;
private final Boolean updatable;
private final Boolean foliage;
private final Boolean foliagePlantable;
private final Boolean decorant;
private final Boolean storage;
private final Boolean storageChest;
private final Boolean ore;
private final Boolean deepSlate;
private final Boolean vineBlock;
private volatile Boolean tileEntity;
private BukkitBlockState(BlockData data, String key) {
this.data = data;
this.key = key;
this.namespace = parseNamespace(key);
Material material = data.getMaterial();
if (material == null) {
this.air = null;
this.solid = null;
this.occluding = null;
this.fluid = null;
this.water = null;
this.waterLogged = null;
this.lit = null;
this.updatable = null;
this.foliage = null;
this.foliagePlantable = null;
this.decorant = null;
this.storage = null;
this.storageChest = null;
this.ore = null;
this.deepSlate = null;
this.vineBlock = null;
return;
}
this.air = BukkitBlockResolution.isAir(data);
this.solid = BukkitBlockResolution.isSolid(data);
this.occluding = material.isOccluding();
this.fluid = BukkitBlockResolution.isFluid(data);
this.water = BukkitBlockResolution.isWater(data);
this.waterLogged = BukkitBlockResolution.isWaterLogged(data);
this.lit = BukkitBlockResolution.isLit(data);
this.updatable = BukkitBlockResolution.isUpdatable(data);
this.foliage = BukkitBlockResolution.isFoliage(data);
this.foliagePlantable = BukkitBlockResolution.isFoliagePlantable(data);
this.decorant = BukkitBlockResolution.isDecorant(data);
this.storage = BukkitBlockResolution.isStorage(data);
this.storageChest = BukkitBlockResolution.isStorageChest(data);
this.ore = BukkitBlockResolution.isOre(data);
this.deepSlate = BukkitBlockResolution.isDeepSlate(data);
this.vineBlock = BukkitBlockResolution.isVineBlock(data);
}
public static BukkitBlockState of(BlockData data) {
@@ -125,32 +173,17 @@ public final class BukkitBlockState implements PlatformBlockState {
@Override
public boolean isAir() {
Boolean cached = air;
if (cached == null) {
cached = BukkitBlockResolution.isAir(data);
air = cached;
}
return cached;
return air != null ? air : BukkitBlockResolution.isAir(data);
}
@Override
public boolean isSolid() {
Boolean cached = solid;
if (cached == null) {
cached = BukkitBlockResolution.isSolid(data);
solid = cached;
}
return cached;
return solid != null ? solid : BukkitBlockResolution.isSolid(data);
}
@Override
public boolean isOccluding() {
Boolean cached = occluding;
if (cached == null) {
cached = data.getMaterial().isOccluding();
occluding = cached;
}
return cached;
return occluding != null ? occluding : data.getMaterial().isOccluding();
}
@Override
@@ -160,87 +193,67 @@ public final class BukkitBlockState implements PlatformBlockState {
@Override
public boolean isFluid() {
Boolean cached = fluid;
if (cached == null) {
cached = BukkitBlockResolution.isFluid(data);
fluid = cached;
}
return cached;
return fluid != null ? fluid : BukkitBlockResolution.isFluid(data);
}
@Override
public boolean isWater() {
Boolean cached = water;
if (cached == null) {
cached = BukkitBlockResolution.isWater(data);
water = cached;
}
return cached;
return water != null ? water : BukkitBlockResolution.isWater(data);
}
@Override
public boolean isWaterLogged() {
return BukkitBlockResolution.isWaterLogged(data);
return waterLogged != null ? waterLogged : BukkitBlockResolution.isWaterLogged(data);
}
@Override
public boolean isLit() {
return BukkitBlockResolution.isLit(data);
return lit != null ? lit : BukkitBlockResolution.isLit(data);
}
@Override
public boolean isUpdatable() {
return BukkitBlockResolution.isUpdatable(data);
return updatable != null ? updatable : BukkitBlockResolution.isUpdatable(data);
}
@Override
public boolean isFoliage() {
Boolean cached = foliage;
if (cached == null) {
cached = BukkitBlockResolution.isFoliage(data);
foliage = cached;
}
return cached;
return foliage != null ? foliage : BukkitBlockResolution.isFoliage(data);
}
@Override
public boolean isFoliagePlantable() {
return BukkitBlockResolution.isFoliagePlantable(data);
return foliagePlantable != null ? foliagePlantable : BukkitBlockResolution.isFoliagePlantable(data);
}
@Override
public boolean isDecorant() {
Boolean cached = decorant;
if (cached == null) {
cached = BukkitBlockResolution.isDecorant(data);
decorant = cached;
}
return cached;
return decorant != null ? decorant : BukkitBlockResolution.isDecorant(data);
}
@Override
public boolean isStorage() {
return BukkitBlockResolution.isStorage(data);
return storage != null ? storage : BukkitBlockResolution.isStorage(data);
}
@Override
public boolean isStorageChest() {
return BukkitBlockResolution.isStorageChest(data);
return storageChest != null ? storageChest : BukkitBlockResolution.isStorageChest(data);
}
@Override
public boolean isOre() {
return BukkitBlockResolution.isOre(data);
return ore != null ? ore : BukkitBlockResolution.isOre(data);
}
@Override
public boolean isDeepSlate() {
return BukkitBlockResolution.isDeepSlate(data);
return deepSlate != null ? deepSlate : BukkitBlockResolution.isDeepSlate(data);
}
@Override
public boolean isVineBlock() {
return BukkitBlockResolution.isVineBlock(data);
return vineBlock != null ? vineBlock : BukkitBlockResolution.isVineBlock(data);
}
@Override
@@ -255,7 +268,20 @@ public final class BukkitBlockState implements PlatformBlockState {
@Override
public boolean hasTileEntity() {
return INMS.get().hasTile(data.getMaterial());
Boolean cached = tileEntity;
if (cached == null) {
cached = INMS.get().hasTile(data.getMaterial());
tileEntity = cached;
}
return cached;
}
@Override
public boolean isAirOrFluid() {
if (air != null && fluid != null) {
return air || fluid;
}
return PlatformBlockState.super.isAirOrFluid();
}
@Override
@@ -2,19 +2,22 @@ package art.arcane.iris.util.common.data;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.iris.spi.PlatformRegistries;
import art.arcane.volmlib.util.collection.KList;
public class B {
private static volatile PlatformRegistries registries;
public static PlatformBlockState getState(String bdxf) {
return IrisPlatforms.get().registries().block(bdxf);
return registries().block(bdxf);
}
public static PlatformBlockState getStateOrNull(String bdxf) {
return IrisPlatforms.get().registries().blockOrNull(bdxf);
return registries().blockOrNull(bdxf);
}
public static PlatformBlockState getStateOrNull(String bdxf, boolean warn) {
return IrisPlatforms.get().registries().blockOrNull(bdxf, warn);
return registries().blockOrNull(bdxf, warn);
}
public static KList<PlatformBlockState> getStates(KList<String> find) {
@@ -26,11 +29,11 @@ public class B {
}
public static PlatformBlockState getAirState() {
return IrisPlatforms.get().registries().air();
return registries().air();
}
public static PlatformBlockState toDeepSlateOre(PlatformBlockState block, PlatformBlockState ore) {
return IrisPlatforms.get().registries().deepSlateOre(block, ore);
return registries().deepSlateOre(block, ore);
}
public static boolean isAir(PlatformBlockState state) {
@@ -108,4 +111,15 @@ public class B {
public static boolean matches(PlatformBlockState filter, PlatformBlockState state) {
return filter != null && state != null && filter.matches(state);
}
private static PlatformRegistries registries() {
PlatformRegistries cached = registries;
if (cached != null) {
return cached;
}
PlatformRegistries resolved = IrisPlatforms.get().registries();
registries = resolved;
return resolved;
}
}
@@ -7,6 +7,8 @@ import art.arcane.volmlib.util.math.M;
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.ExecutorsKt;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.function.IntSupplier;
public class MultiBurst extends MultiBurstSupport {
@@ -46,6 +48,20 @@ public class MultiBurst extends MultiBurstSupport {
return dispatcher;
}
public boolean ownsCurrentThread() {
Thread thread = Thread.currentThread();
if (!(thread instanceof ForkJoinWorkerThread worker)) {
return false;
}
ExecutorService service = service();
if (!(service instanceof ForkJoinPool pool)) {
return false;
}
return worker.getPool() == pool;
}
@Override
public BurstExecutor burst(int estimate) {
return new BurstExecutor(service(), estimate);
@@ -60,16 +60,47 @@ public class ChunkDataHunkHolder extends AtomicHunk<PlatformBlockState> {
}
public void apply() {
for (int i = 0; i < getHeight(); i++) {
for (int j = 0; j < getWidth(); j++) {
for (int k = 0; k < getDepth(); k++) {
PlatformBlockState b = super.getRaw(j, i, k);
int height = getHeight();
for (int x = 0; x < getWidth(); x++) {
for (int z = 0; z < getDepth(); z++) {
BlockData activeBlock = null;
int runStart = -1;
if (b != null) {
chunk.setBlock(j, i + chunk.getMinHeight(), k, (BlockData) b.nativeHandle());
for (int y = 0; y < height; y++) {
PlatformBlockState state = super.getRaw(x, y, z);
BlockData block = state == null ? null : (BlockData) state.nativeHandle();
if (block == null) {
flushRun(x, z, runStart, y, activeBlock);
activeBlock = null;
runStart = -1;
continue;
}
if (activeBlock != null && activeBlock.equals(block)) {
continue;
}
flushRun(x, z, runStart, y, activeBlock);
activeBlock = block;
runStart = y;
}
flushRun(x, z, runStart, height, activeBlock);
}
}
}
private void flushRun(int x, int z, int startY, int endY, BlockData block) {
if (block == null || startY < 0 || endY <= startY) {
return;
}
int minY = chunk.getMinHeight();
if (endY - startY == 1) {
chunk.setBlock(x, startY + minY, z, block);
return;
}
chunk.setRegion(x, startY + minY, z, x + 1, endY + minY, z + 1, block);
}
}
@@ -7,10 +7,11 @@ import static org.junit.Assert.assertEquals;
public class AsyncPregenMethodConcurrencyCapTest {
@Test
public void paperLikeRecommendedCapTracksWorkerThreads() {
assertEquals(8, AsyncPregenMethod.computePaperLikeRecommendedCap(1));
assertEquals(8, AsyncPregenMethod.computePaperLikeRecommendedCap(4));
assertEquals(24, AsyncPregenMethod.computePaperLikeRecommendedCap(12));
assertEquals(96, AsyncPregenMethod.computePaperLikeRecommendedCap(80));
assertEquals(16, AsyncPregenMethod.computePaperLikeRecommendedCap(1));
assertEquals(16, AsyncPregenMethod.computePaperLikeRecommendedCap(4));
assertEquals(48, AsyncPregenMethod.computePaperLikeRecommendedCap(12));
assertEquals(128, AsyncPregenMethod.computePaperLikeRecommendedCap(80));
assertEquals(128, AsyncPregenMethod.computePaperLikeRecommendedCap(128));
}
@Test
@@ -11,6 +11,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.assertTrue;
public class BurstExecutorSupportReentrantTest {
@Test
public void multiBurstRecognizesOwnedWorkerThread() throws Exception {
MultiBurst burst = new MultiBurst("Iris Test", Thread.NORM_PRIORITY, () -> 1);
try {
Future<Boolean> future = burst.submit(burst::ownsCurrentThread);
assertTrue(future.get(5, TimeUnit.SECONDS));
} finally {
burst.close();
}
}
@Test
public void runsNestedBurstInlineOnSameForkJoinPoolWorker() throws Exception {
ForkJoinPool pool = new ForkJoinPool(1);