Added 1.21.1 mod targets

- Build Fabric, Forge and NeoForge per target listed in gradle/mod-targets.json (1.21.1, 26.3)
- Add 1.21.1 adapter source overlays under adapters/*/src/versions/1.21.1
- Add verifyModdedMatrix and per-target Java runtime verification of loader jars
- Re-inject persistent dimensions from the levels-ready hook before the watchdog starts
- Wait for queued chunks and the final save before pregen completes
- Add the 1.21.1 data version and datapack supported_formats range
- Cascade regions whose sea or shore pool loses every biome
- Use Gson calls available on the 1.21.1 runtime
This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-16 10:25:19 -04:00
1 parent 0ca33068f3
commit 62062c4a95
58 files changed
+3279 -133

No files matched your search

@@ -166,6 +166,12 @@ public final class ModdedEngineBootstrap {
ModdedStartup.prepareForStartup();
}
public static void levelsReady(NativeModdedServer server) {
server.refreshWorlds();
bindWorldGenerators(server);
ModdedStartup.reinjectPersistentDimensions(server);
}
public static void serverStarted(NativeModdedServer server) {
// Prime the off-thread level snapshot before anything can read it; the per-tick refresh in
// ModdedScheduler.tick has not run yet at this point.
@@ -14,6 +14,7 @@ public final class ModdedLifecycleCallbacks {
return new NativeModdedCallbacks(
ModdedEngineBootstrap::serverAboutToStart,
ModdedEngineBootstrap::start,
ModdedEngineBootstrap::levelsReady,
ModdedEngineBootstrap::serverStarted,
ModdedEngineBootstrap::stop,
ModdedEngineBootstrap::stopped,
@@ -45,6 +45,9 @@ public final class ModdedMixinAudit {
private static final AtomicBoolean AUDITED = new AtomicBoolean(false);
static final List<ExpectedMixin> EXPECTED = List.of(
new ExpectedMixin(ENTITY_CONFIG, "ServerLevelsReadyMixin",
NativeMixinTarget.SERVER, "volmlib$levelsReady",
false, NativeMixinFlags::levelsReadyRan),
new ExpectedMixin(ENTITY_CONFIG, "RegistryClientNamesMixin",
NativeMixinTarget.REGISTRY_PACKET, "volmlib$clientRegistryNames",
false, NativeMixinFlags::registryClientNamesRan),
@@ -91,7 +91,6 @@ public final class ModdedStartup {
}
ModdedForcedDatapack.verifyInjected();
ModdedMixinAudit.runOnce();
reinjectPersistentDimensions(server);
ModdedScheduler scheduler = ModdedEngineBootstrap.schedulerOrNull();
if (scheduler == null) {
@@ -114,15 +114,9 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
@Override
public void close() {
try {
if (!sync) {
try {
semaphore.tryAcquire(maxInFlight, 5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
ModdedIrisLog.info("Iris modded pregen done: dim={} completed={} peakInFlight={} finalLimit={}",
runtime.worldIdentity(), completed.get(), inFlightPeak.get(), adaptiveLimit.get());
awaitPendingChunks();
ModdedIrisLog.info("Iris modded pregen closing: dim={} completed={} pending={} peakInFlight={} finalLimit={}",
runtime.worldIdentity(), completed.get(), inFlight.get(), inFlightPeak.get(), adaptiveLimit.get());
try {
engine.syncGenerationHistory();
} catch (RuntimeException e) {
@@ -180,6 +174,39 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|| queuedFinalSave.get() != null;
}
private void awaitPendingChunks() {
if (sync || runtime.isServerThread()) {
return;
}
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(timeoutSeconds)
+ TimeUnit.MILLISECONDS.toNanos(FINAL_SAVE_TIMEOUT_MILLIS);
boolean interrupted = false;
try {
while (inFlight.get() > 0) {
if (finalSaveOnServerThread.get() || !runtime.isRunning()) {
return;
}
if (System.nanoTime() >= deadline) {
throw new IllegalStateException("Iris pregen chunk callbacks did not finish for "
+ runtime.worldIdentity() + ": " + inFlight.get() + " pending");
}
try {
synchronized (permitMonitor) {
if (inFlight.get() > 0) {
permitMonitor.wait(FINAL_SAVE_POLL_MILLIS);
}
}
} catch (InterruptedException ignored) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
private void saveLevel(boolean wait) {
if (wait) {
saveFinalLevel();
@@ -237,30 +264,36 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
private void awaitFinalSave(FinalSaveRequest request) {
long deadline = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(FINAL_SAVE_TIMEOUT_MILLIS);
while (true) {
if (deferFinalSaveIfRequested()) {
return;
boolean interrupted = false;
try {
while (true) {
if (deferFinalSaveIfRequested()) {
return;
}
long remainingNanos = deadline - System.nanoTime();
if (remainingNanos <= 0L) {
ModdedIrisLog.warn("Iris pregen level save did not complete in time for {}", runtime.worldIdentity());
return;
}
long waitMillis = Math.max(1L, Math.min(FINAL_SAVE_POLL_MILLIS,
TimeUnit.NANOSECONDS.toMillis(remainingNanos)));
try {
request.completion().get(waitMillis, TimeUnit.MILLISECONDS);
return;
} catch (InterruptedException ignored) {
interrupted = true;
} catch (TimeoutException e) {
continue;
} catch (ExecutionException e) {
Throwable cause = e.getCause() == null ? e : e.getCause();
ModdedIrisLog.error("Iris pregen level save failed for {}", runtime.worldIdentity(), cause);
throw new IllegalStateException("Iris pregen level save failed for "
+ runtime.worldIdentity(), cause);
}
}
long remainingNanos = deadline - System.nanoTime();
if (remainingNanos <= 0L) {
ModdedIrisLog.warn("Iris pregen level save did not complete in time for {}", runtime.worldIdentity());
return;
}
long waitMillis = Math.max(1L, Math.min(FINAL_SAVE_POLL_MILLIS,
TimeUnit.NANOSECONDS.toMillis(remainingNanos)));
try {
request.completion().get(waitMillis, TimeUnit.MILLISECONDS);
return;
} catch (InterruptedException e) {
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
return;
} catch (TimeoutException e) {
continue;
} catch (ExecutionException e) {
Throwable cause = e.getCause() == null ? e : e.getCause();
ModdedIrisLog.error("Iris pregen level save failed for {}", runtime.worldIdentity(), cause);
throw new IllegalStateException("Iris pregen level save failed for "
+ runtime.worldIdentity(), cause);
}
}
}