mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-12 18:04:01 +00:00
fixes
This commit is contained in:
+56
-3
@@ -68,7 +68,12 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
@@ -77,6 +82,41 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
Codec.STRING.fieldOf("dimension").forGetter((IrisModdedChunkGenerator generator) -> generator.dimensionKey)
|
||||
).apply(instance, IrisModdedChunkGenerator::new));
|
||||
|
||||
private static final AtomicInteger GEN_THREAD_SEQ = new AtomicInteger();
|
||||
private static final boolean PARALLEL_CHUNK_SYSTEM = detectParallelChunkSystem();
|
||||
private static final ExecutorService GEN_POOL = createGenPool();
|
||||
|
||||
private static boolean detectParallelChunkSystem() {
|
||||
String[] markers = {
|
||||
"com.ishland.c2me.base.ModProperties",
|
||||
"com.ishland.c2me.base.common.config.C2MEConfig",
|
||||
"com.ishland.c2me.opts.chunkio.ModProperties",
|
||||
"ca.spottedleaf.moonrise.common.util.MoonriseCommon"
|
||||
};
|
||||
for (String marker : markers) {
|
||||
try {
|
||||
Class.forName(marker, false, IrisModdedChunkGenerator.class.getClassLoader());
|
||||
return true;
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static ExecutorService createGenPool() {
|
||||
int threads = Math.max(2, Runtime.getRuntime().availableProcessors());
|
||||
ThreadPoolExecutor pool = new ThreadPoolExecutor(
|
||||
threads, threads, 30L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
runnable -> {
|
||||
Thread thread = new Thread(runnable, "Iris ModGen-" + GEN_THREAD_SEQ.incrementAndGet());
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
pool.allowCoreThreadTimeOut(true);
|
||||
return pool;
|
||||
}
|
||||
|
||||
private final String dimensionKey;
|
||||
private final String defaultPack;
|
||||
private final String defaultDimensionKey;
|
||||
@@ -221,6 +261,20 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
int dimMaxY = generationEngine.getMaxHeight();
|
||||
int height = dimMaxY - dimMinY;
|
||||
PlatformBlockState air = IrisPlatforms.get().registries().air();
|
||||
Registry<Biome> biomeRegistry = structureManager.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
|
||||
if (PARALLEL_CHUNK_SYSTEM) {
|
||||
return CompletableFuture.completedFuture(
|
||||
generateTerrain(chunk, generationEngine, pos, dimMinY, height, air, biomeRegistry, randomState));
|
||||
}
|
||||
return CompletableFuture.supplyAsync(
|
||||
() -> generateTerrain(chunk, generationEngine, pos, dimMinY, height, air, biomeRegistry, randomState),
|
||||
GEN_POOL);
|
||||
}
|
||||
|
||||
private ChunkAccess generateTerrain(ChunkAccess chunk, Engine generationEngine, ChunkPos pos,
|
||||
int dimMinY, int height, PlatformBlockState air,
|
||||
Registry<Biome> biomeRegistry, RandomState randomState) {
|
||||
ModdedBlockBuffer blocks = new ModdedBlockBuffer(height, air);
|
||||
Hunk<PlatformBiome> biomes = Hunk.newArrayHunk(16, height, 16);
|
||||
try {
|
||||
@@ -228,7 +282,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
} catch (GenerationSessionException e) {
|
||||
if (e.isExpectedTeardown()) {
|
||||
LOGGER.debug("Iris chunk {},{} skipped: engine sealed for hotload/teardown", pos.x(), pos.z());
|
||||
return CompletableFuture.completedFuture(chunk);
|
||||
return chunk;
|
||||
}
|
||||
LOGGER.error("Iris failed to generate chunk {},{}", pos.x(), pos.z(), e);
|
||||
throw new IllegalStateException("Iris generation failed for chunk " + pos.x() + "," + pos.z(), e);
|
||||
@@ -239,9 +293,8 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
|
||||
writeBlocks(chunk, blocks, dimMinY, height);
|
||||
Heightmap.primeHeightmaps(chunk, EnumSet.of(Heightmap.Types.WORLD_SURFACE_WG, Heightmap.Types.OCEAN_FLOOR_WG));
|
||||
Registry<Biome> biomeRegistry = structureManager.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
chunk.fillBiomesFromNoise(new HunkBiomeResolver(this, biomes, biomeRegistry, pos, dimMinY, height), randomState.sampler());
|
||||
return CompletableFuture.completedFuture(chunk);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private Holder<Biome> fallbackBiome(Registry<Biome> registry) {
|
||||
|
||||
+139
-6
@@ -24,6 +24,7 @@ import art.arcane.iris.core.pregenerator.PregenMantleBackpressure;
|
||||
import art.arcane.iris.core.pregenerator.PregeneratorMethod;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.volmlib.util.mantle.runtime.Mantle;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkResult;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
@@ -31,21 +32,36 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final TicketType PREGEN_TICKET = new TicketType(TicketType.NO_TIMEOUT, TicketType.FLAG_LOADING | TicketType.FLAG_KEEP_DIMENSION_ACTIVE);
|
||||
private static final int ADAPTIVE_TIMEOUT_STEP = 3;
|
||||
private static final long ADAPTIVE_RECOVERY_INTERVAL = 64L;
|
||||
private static final boolean PARALLEL_CHUNK_SYSTEM = detectParallelChunkSystem();
|
||||
|
||||
private final ServerLevel level;
|
||||
private final Engine engine;
|
||||
private final boolean sync;
|
||||
private final int maxInFlight;
|
||||
private final int minInFlight;
|
||||
private final Semaphore semaphore;
|
||||
private final int permits;
|
||||
private final Object permitMonitor = new Object();
|
||||
private final AtomicInteger inFlight = new AtomicInteger();
|
||||
private final AtomicInteger inFlightPeak = new AtomicInteger();
|
||||
private final AtomicInteger adaptiveLimit;
|
||||
private final AtomicInteger timeoutStreak = new AtomicInteger();
|
||||
private final AtomicLong completed = new AtomicLong();
|
||||
private final int timeoutSeconds;
|
||||
private final PregenMantleBackpressure backpressure;
|
||||
|
||||
@@ -57,9 +73,11 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
this.level = level;
|
||||
this.engine = engine;
|
||||
this.sync = sync;
|
||||
this.permits = Math.min(96, Math.max(8, Runtime.getRuntime().availableProcessors() * 2));
|
||||
this.semaphore = new Semaphore(permits, true);
|
||||
IrisSettings.IrisSettingsPregen pregen = IrisSettings.get().getPregen();
|
||||
this.maxInFlight = Math.max(8, pregen.getModdedPregenInFlight());
|
||||
this.minInFlight = Math.max(4, Math.min(16, maxInFlight / 4));
|
||||
this.semaphore = new Semaphore(maxInFlight, true);
|
||||
this.adaptiveLimit = new AtomicInteger(maxInFlight);
|
||||
this.timeoutSeconds = Math.max(120, pregen.getChunkLoadTimeoutSeconds());
|
||||
this.backpressure = new PregenMantleBackpressure(
|
||||
this::getMantle,
|
||||
@@ -73,19 +91,29 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
LOGGER.info("Iris modded pregen init: dim={} mode={} inFlightCap={} timeout={}s",
|
||||
level.dimension().identifier(), sync ? "sync" : "async", sync ? 1 : permits, timeoutSeconds);
|
||||
LOGGER.info("Iris modded pregen init: dim={} mode={} inFlightCap={} timeout={}s workerPool={} parallelChunkSystem={}",
|
||||
level.dimension().identifier(),
|
||||
sync ? "sync" : "async",
|
||||
sync ? 1 : maxInFlight,
|
||||
timeoutSeconds,
|
||||
describeWorkerPool(),
|
||||
PARALLEL_CHUNK_SYSTEM ? "yes" : "no");
|
||||
if (!sync && !PARALLEL_CHUNK_SYSTEM) {
|
||||
LOGGER.info("Iris pregen note: this loader uses the vanilla main-thread chunk system, which caps pregen throughput. For Bukkit-level speed on Fabric install C2ME (Concurrent Chunk Management Engine); on servers use Paper.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (!sync) {
|
||||
try {
|
||||
semaphore.tryAcquire(permits, 5, TimeUnit.SECONDS);
|
||||
semaphore.tryAcquire(maxInFlight, 5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
LOGGER.info("Iris modded pregen done: dim={} completed={} peakInFlight={} finalLimit={}",
|
||||
level.dimension().identifier(), completed.get(), inFlightPeak.get(), adaptiveLimit.get());
|
||||
saveLevel(true);
|
||||
}
|
||||
|
||||
@@ -174,11 +202,17 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
private void generateChunkAsync(int x, int z, PregenListener listener) {
|
||||
listener.onChunkGenerating(x, z);
|
||||
try {
|
||||
synchronized (permitMonitor) {
|
||||
while (inFlight.get() >= adaptiveLimit.get()) {
|
||||
permitMonitor.wait(500L);
|
||||
}
|
||||
}
|
||||
semaphore.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
markSubmitted();
|
||||
|
||||
ChunkPos pos = new ChunkPos(x, z);
|
||||
CompletableFuture<?> loadFuture = CompletableFuture
|
||||
@@ -189,6 +223,9 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
level.getServer().execute(() -> level.getChunkSource().removeTicketWithRadius(PREGEN_TICKET, pos, 0));
|
||||
try {
|
||||
if (error != null) {
|
||||
if (unwrap(error) instanceof TimeoutException) {
|
||||
onTimeout();
|
||||
}
|
||||
LOGGER.warn("Iris pregen chunk {},{} failed: {}", x, z, error.toString());
|
||||
listener.onChunkFailed(x, z);
|
||||
return;
|
||||
@@ -198,15 +235,70 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
listener.onChunkFailed(x, z);
|
||||
return;
|
||||
}
|
||||
onSuccess();
|
||||
listener.onChunkGenerated(x, z);
|
||||
cleanupMantleChunk(x, z);
|
||||
listener.onChunkCleaned(x, z);
|
||||
} finally {
|
||||
markFinished();
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void markSubmitted() {
|
||||
int current = inFlight.incrementAndGet();
|
||||
inFlightPeak.accumulateAndGet(current, Math::max);
|
||||
}
|
||||
|
||||
private void markFinished() {
|
||||
inFlight.decrementAndGet();
|
||||
completed.incrementAndGet();
|
||||
synchronized (permitMonitor) {
|
||||
permitMonitor.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void onTimeout() {
|
||||
if (timeoutStreak.incrementAndGet() % ADAPTIVE_TIMEOUT_STEP == 0) {
|
||||
adjustAdaptiveLimit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private void onSuccess() {
|
||||
int streak = timeoutStreak.get();
|
||||
if (streak > 0) {
|
||||
timeoutStreak.compareAndSet(streak, Math.max(0, streak - 2));
|
||||
return;
|
||||
}
|
||||
if ((completed.get() & (ADAPTIVE_RECOVERY_INTERVAL - 1L)) == 0L) {
|
||||
adjustAdaptiveLimit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustAdaptiveLimit(int direction) {
|
||||
while (true) {
|
||||
int current = adaptiveLimit.get();
|
||||
int next;
|
||||
if (direction < 0) {
|
||||
next = Math.max(minInFlight, current - 1);
|
||||
} else {
|
||||
int deficit = maxInFlight - current;
|
||||
int step = deficit > (maxInFlight / 2) ? Math.max(2, maxInFlight / 8) : 1;
|
||||
next = Math.min(maxInFlight, current + step);
|
||||
}
|
||||
if (next == current) {
|
||||
return;
|
||||
}
|
||||
if (adaptiveLimit.compareAndSet(current, next)) {
|
||||
synchronized (permitMonitor) {
|
||||
permitMonitor.notifyAll();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupMantleChunk(int x, int z) {
|
||||
try {
|
||||
engine.getMantle().forceCleanupChunk(x, z);
|
||||
@@ -214,6 +306,47 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
}
|
||||
|
||||
private String describeWorkerPool() {
|
||||
try {
|
||||
Field field = MinecraftServer.class.getDeclaredField("executor");
|
||||
field.setAccessible(true);
|
||||
Object exec = field.get(level.getServer());
|
||||
if (exec == null) {
|
||||
return "unknown";
|
||||
}
|
||||
if (exec instanceof ThreadPoolExecutor tpe) {
|
||||
return "ThreadPoolExecutor(core=" + tpe.getCorePoolSize() + ",max=" + tpe.getMaximumPoolSize() + ")";
|
||||
}
|
||||
if (exec instanceof ForkJoinPool fjp) {
|
||||
return "ForkJoinPool(parallelism=" + fjp.getParallelism() + ")";
|
||||
}
|
||||
return exec.getClass().getSimpleName();
|
||||
} catch (Throwable e) {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private static Throwable unwrap(Throwable error) {
|
||||
return error != null && error.getCause() != null ? error.getCause() : error;
|
||||
}
|
||||
|
||||
private static boolean detectParallelChunkSystem() {
|
||||
String[] markers = {
|
||||
"com.ishland.c2me.base.ModProperties",
|
||||
"com.ishland.c2me.base.common.config.C2MEConfig",
|
||||
"com.ishland.c2me.opts.chunkio.ModProperties",
|
||||
"ca.spottedleaf.moonrise.common.util.MoonriseCommon"
|
||||
};
|
||||
for (String marker : markers) {
|
||||
try {
|
||||
Class.forName(marker, false, ModdedPregenMethod.class.getClassLoader());
|
||||
return true;
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mantle getMantle() {
|
||||
return engine.getMantle().getMantle();
|
||||
|
||||
+3
@@ -119,6 +119,9 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
if (engine == null || engine.isClosed() || engine.getMantle().getMantle().isClosed()) {
|
||||
return;
|
||||
}
|
||||
if (pregenTargets(engine)) {
|
||||
return;
|
||||
}
|
||||
if (flush) {
|
||||
try {
|
||||
engine.save();
|
||||
|
||||
@@ -154,11 +154,21 @@ public class IrisSettings {
|
||||
public int maxResidentTectonicPlates = 96;
|
||||
public int mantleBackpressureWaitMs = 25;
|
||||
public int mantleBackpressureTimeoutMs = 60_000;
|
||||
public int moddedPregenInFlight = 0;
|
||||
|
||||
public int getChunkLoadTimeoutSeconds() {
|
||||
return Math.max(5, Math.min(chunkLoadTimeoutSeconds, 120));
|
||||
}
|
||||
|
||||
public int getModdedPregenInFlight() {
|
||||
if (moddedPregenInFlight > 0) {
|
||||
return Math.min(512, moddedPregenInFlight);
|
||||
}
|
||||
|
||||
int cpu = Math.max(1, Runtime.getRuntime().availableProcessors());
|
||||
return Math.max(16, Math.min(48, cpu * 2));
|
||||
}
|
||||
|
||||
public int getMaxResidentTectonicPlates() {
|
||||
return Math.max(16, maxResidentTectonicPlates);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.data.cache.Cache;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.*;
|
||||
import art.arcane.iris.platform.bukkit.BukkitBiome;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
@@ -215,7 +215,7 @@ public class IrisComplex implements DataProvider {
|
||||
regionStream.contextInjecting((c, xx, zz) -> IrisContext.getOr(engine).getChunkContext().getRegion().get(xx, zz)).get(x, z), x, z, fluidHeight))
|
||||
.cache2D("trueBiomeStream", engine, cacheSize).waste("True Biome Stream");
|
||||
trueBiomeDerivativeStream = trueBiomeStream.contextInjecting((c, x, z) -> IrisContext.getOr(engine).getChunkContext().getBiome().get(x, z))
|
||||
.convert((b) -> (PlatformBiome) BukkitBiome.of(b.getDerivative())).cache2D("trueBiomeDerivativeStream", engine, cacheSize).waste("True Biome Derivative Stream");
|
||||
.convert((b) -> IrisPlatforms.get().registries().biome(b.getDerivativeKey())).cache2D("trueBiomeDerivativeStream", engine, cacheSize).waste("True Biome Derivative Stream");
|
||||
heightFluidStream = heightStream.contextInjecting((c, x, z) -> IrisContext.getOr(engine).getChunkContext().getHeight().getDouble(x, z))
|
||||
.max(fluidHeight).cache2DDouble("heightFluidStream", engine, cacheSize).waste("Height Fluid Stream");
|
||||
maxHeightStream = ProceduralStream.ofDouble((x, z) -> height).waste("Max Height Stream");
|
||||
|
||||
@@ -22,7 +22,6 @@ import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.EngineAssignedActuator;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisBiomeCustom;
|
||||
import art.arcane.iris.platform.bukkit.BukkitBiome;
|
||||
import art.arcane.iris.util.project.context.ChunkContext;
|
||||
import art.arcane.volmlib.util.documentation.BlockCoordinates;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
@@ -33,7 +32,6 @@ import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
public class IrisBiomeActuator extends EngineAssignedActuator<PlatformBiome> {
|
||||
private final RNG rng;
|
||||
@@ -62,11 +60,9 @@ public class IrisBiomeActuator extends EngineAssignedActuator<PlatformBiome> {
|
||||
biome = IrisPlatforms.get().registries().biome(key);
|
||||
matter = BiomeInjectMatter.get(IrisPlatforms.get().biomeWriter().biomeIdFor(key));
|
||||
} else {
|
||||
Biome v = ib.getSkyBiome(rng, x, 0, z);
|
||||
PlatformBiome fallback = BukkitBiome.of(v);
|
||||
PlatformBiome resolved = IrisPlatforms.get().registries().biome(fallback.key());
|
||||
biome = resolved == null ? fallback : resolved;
|
||||
matter = BiomeInjectMatter.get(v);
|
||||
String skyKey = ib.getSkyBiomeKey(rng, x, 0, z);
|
||||
biome = IrisPlatforms.get().registries().biome(skyKey);
|
||||
matter = BiomeInjectMatter.get(IrisPlatforms.get().biomeWriter().biomeIdFor(skyKey));
|
||||
}
|
||||
|
||||
if (biome != null) {
|
||||
|
||||
+6
-16
@@ -18,7 +18,6 @@
|
||||
|
||||
package art.arcane.iris.engine.modifier;
|
||||
|
||||
import art.arcane.iris.platform.bukkit.BukkitBlockResolution;
|
||||
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.IrisComplex;
|
||||
@@ -46,11 +45,8 @@ import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.MatterBiomeInject;
|
||||
import art.arcane.volmlib.util.matter.slices.BiomeInjectMatter;
|
||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
import art.arcane.iris.platform.bukkit.BukkitBlockState;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
|
||||
@@ -261,11 +257,10 @@ public class IrisFloatingChildBiomeModifier extends EngineAssignedModifier<Platf
|
||||
IrisFloatingChildBiomes entry = sample.entry;
|
||||
Integer localFluidHeight = entry.getLocalFluidHeight();
|
||||
if (localFluidHeight != null && localFluidHeight > 0) {
|
||||
BlockData rawFluid = BukkitBlockResolution.get(entry.getFluidBlock());
|
||||
if (rawFluid == null) {
|
||||
rawFluid = BukkitBlockResolution.get("minecraft:water");
|
||||
PlatformBlockState fluid = B.getStateOrNull(entry.getFluidBlock());
|
||||
if (fluid == null) {
|
||||
fluid = B.getState("minecraft:water");
|
||||
}
|
||||
PlatformBlockState fluid = BukkitBlockState.of(rawFluid);
|
||||
int fluidCap = Math.min(sample.thickness - 1, localFluidHeight);
|
||||
for (int k = 1; k <= fluidCap; k++) {
|
||||
if (sample.solidMask[k]) {
|
||||
@@ -324,7 +319,7 @@ public class IrisFloatingChildBiomeModifier extends EngineAssignedModifier<Platf
|
||||
int max = Math.max(1, chunkHeight - topY);
|
||||
if (topY + 1 < chunkHeight) {
|
||||
PlatformBlockState above = output.get(xf, topY + 1, zf);
|
||||
if (above == null || BukkitBlockResolution.isAir((BlockData) above.nativeHandle())) {
|
||||
if (above == null || above.isAir()) {
|
||||
try {
|
||||
RNG colRng = rng.nextParallelRNG((int) FloatingIslandSample.columnSeed(baseSeed, wx, wz));
|
||||
FloatingDecorator.decorateColumn(getEngine(), target, IrisDecorationPart.NONE, xf, zf, wx, wz, topY, max, output, colRng, NOOP_DECORATION_MISS);
|
||||
@@ -357,7 +352,7 @@ public class IrisFloatingChildBiomeModifier extends EngineAssignedModifier<Platf
|
||||
fluidTopY = y;
|
||||
}
|
||||
}
|
||||
if (fluidTopY > 0 && fluidTopY + 1 < chunkHeight && BukkitBlockResolution.isAir(unwrap(output.get(xf, fluidTopY + 1, zf)))) {
|
||||
if (fluidTopY > 0 && fluidTopY + 1 < chunkHeight && B.isAir(output.get(xf, fluidTopY + 1, zf))) {
|
||||
try {
|
||||
seaSurfaceDecorator.decorate(xf, zf, wx, wx + 1, wx - 1, wz, wz + 1, wz - 1, output, target, fluidTopY, chunkHeight);
|
||||
} catch (Throwable e) {
|
||||
@@ -397,17 +392,12 @@ public class IrisFloatingChildBiomeModifier extends EngineAssignedModifier<Platf
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockData unwrap(PlatformBlockState state) {
|
||||
return state == null ? null : (BlockData) state.nativeHandle();
|
||||
}
|
||||
|
||||
private MatterBiomeInject createSkyBiomeMatter(IrisBiome target, int wx, int wz) {
|
||||
if (target.isCustom()) {
|
||||
IrisBiomeCustom custom = target.getCustomBiome(rng, wx, 0, wz);
|
||||
return BiomeInjectMatter.get(IrisPlatforms.get().biomeWriter().biomeIdFor(getDimension().getLoadKey() + ":" + custom.getId()));
|
||||
}
|
||||
|
||||
Biome v = target.getSkyBiome(rng, wx, 0, wz);
|
||||
return BiomeInjectMatter.get(v);
|
||||
return BiomeInjectMatter.get(IrisPlatforms.get().biomeWriter().biomeIdFor(target.getSkyBiomeKey(rng, wx, 0, wz)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import art.arcane.volmlib.util.collection.KSet;
|
||||
import art.arcane.iris.util.common.data.B;
|
||||
import art.arcane.iris.util.common.data.DataProvider;
|
||||
import art.arcane.iris.util.common.data.registry.RegistryUtil;
|
||||
import art.arcane.volmlib.util.data.VanillaBiomeMap;
|
||||
import art.arcane.volmlib.util.data.VanillaBiomeColors;
|
||||
import art.arcane.volmlib.util.inventorygui.RandomColor;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
@@ -298,6 +298,10 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
return resolved == null ? namespacedBiomeKey(derivative) : resolved;
|
||||
}
|
||||
|
||||
public String getDerivativeKey() {
|
||||
return namespacedBiomeKey(derivative);
|
||||
}
|
||||
|
||||
private static String namespacedBiomeKey(String key) {
|
||||
if (key == null || key.isBlank()) {
|
||||
return null;
|
||||
@@ -802,6 +806,30 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
return getBiomeGenerator(rng).fit(getBiomeScatterResolved(), x, y, z);
|
||||
}
|
||||
|
||||
public String getSkyBiomeKey(RNG rng, double x, double y, double z) {
|
||||
if (biomeSkyScatter.size() == 1) {
|
||||
return namespacedBiomeKey(biomeSkyScatter.get(0));
|
||||
}
|
||||
|
||||
if (biomeSkyScatter.isEmpty()) {
|
||||
return getGroundBiomeKey(rng, x, y, z);
|
||||
}
|
||||
|
||||
return namespacedBiomeKey(biomeSkyScatter.get(getBiomeGenerator(rng).fit(0, biomeSkyScatter.size() - 1, x, y, z)));
|
||||
}
|
||||
|
||||
public String getGroundBiomeKey(RNG rng, double x, double y, double z) {
|
||||
if (biomeScatter.isEmpty()) {
|
||||
return namespacedBiomeKey(derivative);
|
||||
}
|
||||
|
||||
if (biomeScatter.size() == 1) {
|
||||
return namespacedBiomeKey(biomeScatter.get(0));
|
||||
}
|
||||
|
||||
return namespacedBiomeKey(biomeScatter.get(getBiomeGenerator(rng).fit(0, biomeScatter.size() - 1, x, y, z)));
|
||||
}
|
||||
|
||||
public PlatformBlockState getSurfaceBlock(int x, int z, RNG rng, IrisData idm) {
|
||||
if (getLayers().isEmpty()) {
|
||||
return B.getState("AIR");
|
||||
@@ -816,13 +844,14 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
return this.cacheColor.aquire(() -> {
|
||||
if (this.color == null) {
|
||||
RandomColor randomColor = new RandomColor(getName().hashCode());
|
||||
if (this.getVanillaDerivative() == null) {
|
||||
String vanillaKey = this.getVanillaDerivativeKey();
|
||||
RandomColor.Color col = vanillaKey == null ? null : VanillaBiomeColors.getColorType(vanillaKey);
|
||||
if (col == null) {
|
||||
IrisLogging.warn("No vanilla biome found for " + getName());
|
||||
return new Color(randomColor.randomColor());
|
||||
}
|
||||
RandomColor.Color col = VanillaBiomeMap.getColorType(this.getVanillaDerivative());
|
||||
RandomColor.Luminosity lum = VanillaBiomeMap.getColorLuminosity(this.getVanillaDerivative());
|
||||
RandomColor.SaturationType sat = VanillaBiomeMap.getColorSaturatiom(this.getVanillaDerivative());
|
||||
RandomColor.Luminosity lum = VanillaBiomeColors.getColorLuminosity(vanillaKey);
|
||||
RandomColor.SaturationType sat = VanillaBiomeColors.getColorSaturation(vanillaKey);
|
||||
int newColorI = randomColor.randomColor(col, col == RandomColor.Color.MONOCHROME ? RandomColor.SaturationType.MONOCHROME : sat, lum);
|
||||
|
||||
return new Color(newColorI);
|
||||
|
||||
@@ -29,7 +29,7 @@ import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.volmlib.util.collection.KSet;
|
||||
import art.arcane.iris.util.common.data.DataProvider;
|
||||
import art.arcane.volmlib.util.data.VanillaBiomeMap;
|
||||
import art.arcane.volmlib.util.data.VanillaBiomeColors;
|
||||
import art.arcane.volmlib.util.inventorygui.RandomColor;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
@@ -448,10 +448,11 @@ public class IrisRegion extends IrisRegistrant implements IRare {
|
||||
int index = rand.nextInt(biomes.size());
|
||||
IrisBiome biome = biomes.get(index);
|
||||
|
||||
if (biome.getVanillaDerivative() != null) {
|
||||
RandomColor.Color col = VanillaBiomeMap.getColorType(biome.getVanillaDerivative());
|
||||
RandomColor.Luminosity lum = VanillaBiomeMap.getColorLuminosity(biome.getVanillaDerivative());
|
||||
RandomColor.SaturationType sat = VanillaBiomeMap.getColorSaturatiom(biome.getVanillaDerivative());
|
||||
String vanillaKey = biome.getVanillaDerivativeKey();
|
||||
RandomColor.Color col = vanillaKey == null ? null : VanillaBiomeColors.getColorType(vanillaKey);
|
||||
if (col != null) {
|
||||
RandomColor.Luminosity lum = VanillaBiomeColors.getColorLuminosity(vanillaKey);
|
||||
RandomColor.SaturationType sat = VanillaBiomeColors.getColorSaturation(vanillaKey);
|
||||
int newColorI = randomColor.randomColor(col, col == RandomColor.Color.MONOCHROME ? RandomColor.SaturationType.MONOCHROME : sat, lum);
|
||||
return new Color(newColorI);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user