This commit is contained in:
Brian Neumann-Fopiano committed 2026-07-03 21:37:08 -04:00
1 parent 29ff3f01a7
commit 927c48f8c7
18 files changed
+283 -89

No files matched your search

@@ -47,6 +47,9 @@ public enum IrisRuntimeSchedulerMode {
|| containsIgnoreCase(bukkitName, "pufferfish")
|| containsIgnoreCase(bukkitVersion, "pufferfish")
|| containsIgnoreCase(serverClassName, "pufferfish")
|| containsIgnoreCase(bukkitName, "leaf")
|| containsIgnoreCase(bukkitVersion, "leaf")
|| containsIgnoreCase(serverClassName, "leaf")
|| containsIgnoreCase(bukkitName, "spigot")
|| containsIgnoreCase(bukkitVersion, "spigot")
|| containsIgnoreCase(serverClassName, "spigot")
@@ -140,28 +140,56 @@ public final class WorldRuntimeControlService {
skipAmount += 24000L;
}
TimeSkipEvent event = new TimeSkipEvent(world, TimeSkipEvent.SkipReason.CUSTOM, skipAmount);
PluginManager pluginManager = Bukkit.getPluginManager();
if (pluginManager != null) {
pluginManager.callEvent(event);
}
if (event.isCancelled()) {
return false;
long effectiveSkip = skipAmount;
if (TIME_SKIP_EVENT_AVAILABLE) {
long fired = fireTimeSkipEvent(world, skipAmount);
if (fired == TIME_SKIP_CANCELLED) {
return false;
}
effectiveSkip = fired;
}
try {
boolean written = backend.writeDayTime(world, currentTime.getAsLong() + event.getSkipAmount());
boolean written = backend.writeDayTime(world, currentTime.getAsLong() + effectiveSkip);
if (!written) {
return false;
}
backend.syncTime(world);
return true;
} catch (Throwable e) {
IrisLogging.reportError("Runtime time control failed for world \"" + world.getName() + "\".", e);
IrisLogging.debug("Runtime time lock skipped for world \"" + world.getName() + "\": " + e.getMessage());
return false;
}
}
private static final long TIME_SKIP_CANCELLED = Long.MIN_VALUE;
private static final boolean TIME_SKIP_EVENT_AVAILABLE = probeTimeSkipEvent();
private static boolean probeTimeSkipEvent() {
try {
Class.forName("org.bukkit.event.world.TimeSkipEvent$SkipReason");
return true;
} catch (Throwable e) {
return false;
}
}
private long fireTimeSkipEvent(World world, long skipAmount) {
try {
TimeSkipEvent event = new TimeSkipEvent(world, TimeSkipEvent.SkipReason.CUSTOM, skipAmount);
PluginManager pluginManager = Bukkit.getPluginManager();
if (pluginManager != null) {
pluginManager.callEvent(event);
}
if (event.isCancelled()) {
return TIME_SKIP_CANCELLED;
}
return event.getSkipAmount();
} catch (Throwable e) {
return skipAmount;
}
}
public CompletableFuture<Chunk> requestChunkAsync(World world, int chunkX, int chunkZ, boolean generate) {
return backend.requestChunkAsync(world, chunkX, chunkZ, generate);
}
@@ -63,7 +63,7 @@ public final class Tasks {
});
private static final Task SOFTWARE = Task.of("software", () -> {
Set<String> supported = Set.of("canvas", "folia", "purpur", "pufferfish", "paper", "spigot", "bukkit");
Set<String> supported = Set.of("canvas", "folia", "purpur", "pufferfish", "leaf", "paper", "spigot", "bukkit");
String serverName = server().getName().toLowerCase(Locale.ROOT);
boolean supportedServer = isCanvasServer();
if (!supportedServer) {
@@ -81,7 +81,7 @@ public final class Tasks {
return withDiagnostics(Mode.WARNING,
Diagnostic.Logger.WARN.create("Unsupported Server Software"),
Diagnostic.Logger.WARN.create("- Please consider using Canvas, Folia, Paper, or Purpur instead."));
Diagnostic.Logger.WARN.create("- Please consider using Canvas, Folia, Leaf, Paper, or Purpur instead."));
});
private static final Task VERSION = Task.of("version", () -> {
@@ -24,7 +24,7 @@ public class IrisReflectiveAPI {
}
public static void retainMantleData(String classname) {
IrisToolbelt.retainMantleDataForSlice(classname);
WorldMaintenance.retainMantleDataForSlice(classname);
}
public static void setMantleData(World world, int x, int y, int z, Object data) {
@@ -55,8 +55,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Something you really want to wear if working on Iris. Shit gets pretty hectic down there.
@@ -65,8 +63,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public class IrisToolbelt {
@ApiStatus.Internal
public static Map<String, Boolean> toolbeltConfiguration = new HashMap<>();
private static final Map<String, AtomicInteger> worldMaintenanceDepth = new ConcurrentHashMap<>();
private static final Map<String, AtomicInteger> worldMaintenanceMantleBypassDepth = new ConcurrentHashMap<>();
private static final Method BUKKIT_IS_STOPPING_METHOD = resolveBukkitIsStoppingMethod();
/**
@@ -426,19 +422,7 @@ public class IrisToolbelt {
}
public static void beginWorldMaintenance(String worldName, String reason, boolean bypassMantleStages) {
if (worldName == null) {
return;
}
int depth = worldMaintenanceDepth.computeIfAbsent(worldName, k -> new AtomicInteger()).incrementAndGet();
if (bypassMantleStages) {
worldMaintenanceMantleBypassDepth.computeIfAbsent(worldName, k -> new AtomicInteger()).incrementAndGet();
}
if (IrisSettings.get().getGeneral().isDebug()) {
IrisLogging.info("World maintenance enter: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantle=" + bypassMantleStages);
} else {
IrisLogging.debug("World maintenance enter: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantle=" + bypassMantleStages);
}
WorldMaintenance.beginWorldMaintenance(worldName, reason, bypassMantleStages);
}
public static void endWorldMaintenance(World world, String reason) {
@@ -450,36 +434,7 @@ public class IrisToolbelt {
}
public static void endWorldMaintenance(String worldName, String reason) {
if (worldName == null) {
return;
}
AtomicInteger depthCounter = worldMaintenanceDepth.get(worldName);
if (depthCounter == null) {
return;
}
int depth = depthCounter.decrementAndGet();
if (depth <= 0) {
worldMaintenanceDepth.remove(worldName, depthCounter);
depth = 0;
}
AtomicInteger bypassCounter = worldMaintenanceMantleBypassDepth.get(worldName);
int bypassDepth = 0;
if (bypassCounter != null) {
bypassDepth = bypassCounter.decrementAndGet();
if (bypassDepth <= 0) {
worldMaintenanceMantleBypassDepth.remove(worldName, bypassCounter);
bypassDepth = 0;
}
}
if (IrisSettings.get().getGeneral().isDebug()) {
IrisLogging.info("World maintenance exit: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantleDepth=" + bypassDepth);
} else {
IrisLogging.debug("World maintenance exit: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantleDepth=" + bypassDepth);
}
WorldMaintenance.endWorldMaintenance(worldName, reason);
}
public static boolean isWorldMaintenanceActive(World world) {
@@ -487,12 +442,7 @@ public class IrisToolbelt {
}
public static boolean isWorldMaintenanceActive(String worldName) {
if (worldName == null) {
return false;
}
AtomicInteger counter = worldMaintenanceDepth.get(worldName);
return counter != null && counter.get() > 0;
return WorldMaintenance.isWorldMaintenanceActive(worldName);
}
public static boolean isWorldMaintenanceBypassingMantleStages(World world) {
@@ -500,20 +450,15 @@ public class IrisToolbelt {
}
public static boolean isWorldMaintenanceBypassingMantleStages(String worldName) {
if (worldName == null) {
return false;
}
AtomicInteger counter = worldMaintenanceMantleBypassDepth.get(worldName);
return counter != null && counter.get() > 0;
return WorldMaintenance.isWorldMaintenanceBypassingMantleStages(worldName);
}
public static void retainMantleDataForSlice(String className) {
toolbeltConfiguration.put("retain.mantle." + className, Boolean.TRUE);
WorldMaintenance.retainMantleDataForSlice(className);
}
public static boolean isRetainingMantleDataForSlice(String className) {
return !toolbeltConfiguration.isEmpty() && toolbeltConfiguration.get("retain.mantle." + className) == Boolean.TRUE;
return WorldMaintenance.isRetainingMantleDataForSlice(className);
}
public static <T> T getMantleData(World world, int x, int y, int z, Class<T> of) {
@@ -0,0 +1,101 @@
package art.arcane.iris.core.tools;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.spi.IrisLogging;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public final class WorldMaintenance {
private static final Map<String, AtomicInteger> worldMaintenanceDepth = new ConcurrentHashMap<>();
private static final Map<String, AtomicInteger> worldMaintenanceMantleBypassDepth = new ConcurrentHashMap<>();
private static final Set<String> retainedMantleSlices = ConcurrentHashMap.newKeySet();
private WorldMaintenance() {
}
public static void beginWorldMaintenance(String worldName, String reason) {
beginWorldMaintenance(worldName, reason, false);
}
public static void beginWorldMaintenance(String worldName, String reason, boolean bypassMantleStages) {
if (worldName == null) {
return;
}
int depth = worldMaintenanceDepth.computeIfAbsent(worldName, k -> new AtomicInteger()).incrementAndGet();
if (bypassMantleStages) {
worldMaintenanceMantleBypassDepth.computeIfAbsent(worldName, k -> new AtomicInteger()).incrementAndGet();
}
if (IrisSettings.get().getGeneral().isDebug()) {
IrisLogging.info("World maintenance enter: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantle=" + bypassMantleStages);
} else {
IrisLogging.debug("World maintenance enter: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantle=" + bypassMantleStages);
}
}
public static void endWorldMaintenance(String worldName, String reason) {
if (worldName == null) {
return;
}
AtomicInteger depthCounter = worldMaintenanceDepth.get(worldName);
if (depthCounter == null) {
return;
}
int depth = depthCounter.decrementAndGet();
if (depth <= 0) {
worldMaintenanceDepth.remove(worldName, depthCounter);
depth = 0;
}
AtomicInteger bypassCounter = worldMaintenanceMantleBypassDepth.get(worldName);
int bypassDepth = 0;
if (bypassCounter != null) {
bypassDepth = bypassCounter.decrementAndGet();
if (bypassDepth <= 0) {
worldMaintenanceMantleBypassDepth.remove(worldName, bypassCounter);
bypassDepth = 0;
}
}
if (IrisSettings.get().getGeneral().isDebug()) {
IrisLogging.info("World maintenance exit: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantleDepth=" + bypassDepth);
} else {
IrisLogging.debug("World maintenance exit: " + worldName + " reason=" + reason + " depth=" + depth + " bypassMantleDepth=" + bypassDepth);
}
}
public static boolean isWorldMaintenanceActive(String worldName) {
if (worldName == null) {
return false;
}
AtomicInteger counter = worldMaintenanceDepth.get(worldName);
return counter != null && counter.get() > 0;
}
public static boolean isWorldMaintenanceBypassingMantleStages(String worldName) {
if (worldName == null) {
return false;
}
AtomicInteger counter = worldMaintenanceMantleBypassDepth.get(worldName);
return counter != null && counter.get() > 0;
}
public static void retainMantleDataForSlice(String className) {
if (className == null) {
return;
}
retainedMantleSlices.add(className);
}
public static boolean isRetainingMantleDataForSlice(String className) {
return className != null && retainedMantleSlices.contains(className);
}
}
@@ -20,7 +20,7 @@ package art.arcane.iris.engine;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.core.tools.WorldMaintenance;
import art.arcane.iris.engine.EnginePanic;
import art.arcane.iris.core.nms.container.Pair;
import art.arcane.iris.engine.data.cache.AtomicCache;
@@ -327,7 +327,7 @@ public class IrisEngineMantle implements EngineMantle {
@Override
public boolean shouldRetainSlice(Class<?> sliceType) {
return IrisToolbelt.isRetainingMantleDataForSlice(sliceType.getCanonicalName());
return WorldMaintenance.isRetainingMantleDataForSlice(sliceType.getCanonicalName());
}
@Override
@@ -27,7 +27,7 @@ import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.core.nms.container.BlockPos;
import art.arcane.iris.core.nms.container.Pair;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.core.tools.WorldMaintenance;
import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.UpperDimensionContext;
import art.arcane.iris.engine.data.chunk.TerrainChunk;
@@ -673,7 +673,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
return false;
}
String worldName = world.name();
if (!IrisToolbelt.isWorldMaintenanceActive(worldName)) {
if (!WorldMaintenance.isWorldMaintenanceActive(worldName)) {
return false;
}
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
@@ -18,7 +18,7 @@
package art.arcane.iris.engine.framework;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.core.tools.WorldMaintenance;
import art.arcane.iris.core.gui.PregeneratorJob;
import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.mantle.EngineMantle;
@@ -92,7 +92,7 @@ public interface EngineMode extends Staged {
}
private boolean shouldDisableContextCacheForMaintenance() {
boolean maintenanceActive = IrisToolbelt.isWorldMaintenanceActive(getEngine().getWorld().realWorld());
boolean maintenanceActive = WorldMaintenance.isWorldMaintenanceActive(getEngine().getWorld().name());
if (!maintenanceActive) {
return false;
}
@@ -23,7 +23,7 @@ import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.util.project.matter.TileWrapper;
import com.google.common.collect.ImmutableList;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.core.tools.WorldMaintenance;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.Cache;
import art.arcane.iris.engine.framework.Engine;
@@ -74,7 +74,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
this.z = z;
final boolean foliaMaintenance = J.isFolia()
&& IrisToolbelt.isWorldMaintenanceActive(engineMantle.getEngine().getWorld().realWorld());
&& WorldMaintenance.isWorldMaintenanceActive(engineMantle.getEngine().getWorld().name());
final int parallelism = foliaMaintenance ? 1 : (multicore ? Runtime.getRuntime().availableProcessors() / 2 : 4);
if (foliaMaintenance && IrisSettings.get().getGeneral().isDebug()) {
IrisLogging.info("MantleWriter using sequential chunk prefetch for maintenance regen at " + x + "," + z + ".");
@@ -43,6 +43,7 @@ import art.arcane.iris.util.common.plugin.VolmitSender;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.bukkit.World.Environment;
import org.bukkit.block.Biome;
@@ -56,7 +57,8 @@ import java.util.Map;
@NoArgsConstructor
@Desc("Represents a dimension")
@Data
@EqualsAndHashCode(callSuper = false)
@EqualsAndHashCode(callSuper = false, doNotUseGetters = true)
@ToString(doNotUseGetters = true)
public class IrisDimension extends IrisRegistrant {
private final transient AtomicCache<Position2> parallaxSize = new AtomicCache<>();
private final transient AtomicCache<CNG> rockLayerGenerator = new AtomicCache<>();
@@ -35,7 +35,9 @@ import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.noise.CNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.bukkit.DyeColor;
import org.bukkit.Material;
@@ -57,6 +59,8 @@ import java.util.Optional;
@AllArgsConstructor
@Desc("Represents a loot entry")
@Data
@EqualsAndHashCode(doNotUseGetters = true)
@ToString(doNotUseGetters = true)
public class IrisLoot {
private final transient AtomicCache<CNG> chance = new AtomicCache<>();
private final transient AtomicCache<DyeColor> dyeColorResolved = new AtomicCache<>();