mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 04:37:47 +00:00
f
This commit is contained in:
-130
@@ -1,130 +0,0 @@
|
||||
package art.arcane.iris.core.nms.v26_2_R1;
|
||||
|
||||
import art.arcane.iris.core.lifecycle.WorldReplacementSeed;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import io.papermc.paper.world.saveddata.PaperLevelOverrides;
|
||||
import io.papermc.paper.world.saveddata.PaperWorldMetadata;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||
import net.minecraft.world.level.storage.SavedDataStorage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
final class CurrentPaperWorldDataWriter {
|
||||
private static final long SNAPSHOT_TIMEOUT_SECONDS = 30L;
|
||||
|
||||
private CurrentPaperWorldDataWriter() {
|
||||
}
|
||||
|
||||
static void write(
|
||||
Path sourceWorldDirectory,
|
||||
Path targetWorldDirectory,
|
||||
long seed
|
||||
) throws IOException {
|
||||
CraftServer craftServer = (CraftServer) Bukkit.getServer();
|
||||
MinecraftServer server = craftServer.getHandle().getServer();
|
||||
PaperLevelOverrides levelOverrides = captureLevelOverrides(craftServer, server);
|
||||
|
||||
Path targetWorld = targetWorldDirectory.toAbsolutePath().normalize();
|
||||
UUID metadataUuid = UUID.randomUUID();
|
||||
WorldReplacementSeed.copyWithAuthoritativeSeed(sourceWorldDirectory, targetWorld, seed);
|
||||
try (SavedDataStorage savedDataStorage = new SavedDataStorage(
|
||||
targetWorld.resolve("data"),
|
||||
server.getFixerUpper(),
|
||||
server.registryAccess()
|
||||
)) {
|
||||
savedDataStorage.set(PaperWorldMetadata.TYPE, new PaperWorldMetadata(metadataUuid));
|
||||
savedDataStorage.set(PaperLevelOverrides.TYPE, levelOverrides);
|
||||
}
|
||||
|
||||
List<Path> requiredDataFiles = List.of(
|
||||
targetWorld.resolve("data/minecraft/world_gen_settings.dat"),
|
||||
targetWorld.resolve("data/paper/metadata.dat"),
|
||||
targetWorld.resolve("data/paper/level_overrides.dat")
|
||||
);
|
||||
for (Path requiredDataFile : requiredDataFiles) {
|
||||
if (!Files.isRegularFile(requiredDataFile, LinkOption.NOFOLLOW_LINKS)) {
|
||||
throw new IOException("Current Paper world data was not written: " + requiredDataFile);
|
||||
}
|
||||
}
|
||||
|
||||
long writtenSeed = WorldReplacementSeed.readAuthoritativeSeed(targetWorld);
|
||||
if (writtenSeed != seed) {
|
||||
throw new IOException("Current Paper world data did not retain the requested seed.");
|
||||
}
|
||||
|
||||
try (SavedDataStorage verificationStorage = new SavedDataStorage(
|
||||
targetWorld.resolve("data"),
|
||||
server.getFixerUpper(),
|
||||
server.registryAccess()
|
||||
)) {
|
||||
PaperWorldMetadata metadata = verificationStorage.get(PaperWorldMetadata.TYPE);
|
||||
if (metadata == null || !metadataUuid.equals(metadata.uuid())) {
|
||||
throw new IOException("Current Paper world metadata could not be verified.");
|
||||
}
|
||||
PaperLevelOverrides overrides = verificationStorage.get(PaperLevelOverrides.TYPE);
|
||||
if (overrides == null || overrides.isInitialized()) {
|
||||
throw new IOException("Current Paper level overrides could not be verified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PaperLevelOverrides captureLevelOverrides(
|
||||
CraftServer craftServer,
|
||||
MinecraftServer server
|
||||
) throws IOException {
|
||||
if (craftServer.isGlobalTickThread()) {
|
||||
return createLevelOverrides(craftServer, server);
|
||||
}
|
||||
if (J.isFolia() && J.isPrimaryThread()) {
|
||||
throw new IOException("Current Paper world data cannot be staged from a Folia region tick thread.");
|
||||
}
|
||||
|
||||
CompletableFuture<PaperLevelOverrides> captured = new CompletableFuture<>();
|
||||
boolean scheduled = J.runGlobal(() -> {
|
||||
try {
|
||||
captured.complete(createLevelOverrides(craftServer, server));
|
||||
} catch (Throwable failure) {
|
||||
captured.completeExceptionally(failure);
|
||||
}
|
||||
});
|
||||
if (!scheduled) {
|
||||
throw new IOException("Could not schedule the current Paper level-data snapshot on the global thread.");
|
||||
}
|
||||
|
||||
try {
|
||||
return captured.get(SNAPSHOT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException failure) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("Interrupted while capturing current Paper level data.", failure);
|
||||
} catch (ExecutionException failure) {
|
||||
throw new IOException("Could not capture current Paper level data.", failure.getCause());
|
||||
} catch (TimeoutException failure) {
|
||||
throw new IOException("Timed out while capturing current Paper level data.", failure);
|
||||
}
|
||||
}
|
||||
|
||||
private static PaperLevelOverrides createLevelOverrides(
|
||||
CraftServer craftServer,
|
||||
MinecraftServer server
|
||||
) throws IOException {
|
||||
if (!craftServer.isGlobalTickThread()) {
|
||||
throw new IOException("Current Paper level data must be captured on the global tick thread.");
|
||||
}
|
||||
if (!(server.getWorldData().overworldData() instanceof PrimaryLevelData primaryLevelData)) {
|
||||
throw new IOException("Paper primary level data is unavailable for current world data staging.");
|
||||
}
|
||||
return PaperLevelOverrides.createFromLiveLevelData(primaryLevelData);
|
||||
}
|
||||
}
|
||||
+2
-14
@@ -154,7 +154,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -1572,8 +1571,7 @@ public class NMSBinding implements INMSBinding {
|
||||
injected.set(true);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.error(C.RED + "Failed to inject Bukkit");
|
||||
e.printStackTrace();
|
||||
IrisLogging.reportError(C.RED + "Failed to inject Bukkit", e);
|
||||
ResettableClassFileTransformer partialServerLevel = serverLevelTransformer;
|
||||
ResettableClassFileTransformer partialStorageAccess = levelStorageAccessTransformer;
|
||||
serverLevelTransformer = null;
|
||||
@@ -1627,22 +1625,12 @@ public class NMSBinding implements INMSBinding {
|
||||
try {
|
||||
transformer.reset(Agent.getInstrumentation(), AgentBuilder.RedefinitionStrategy.RETRANSFORMATION);
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.error(C.RED + "Failed to remove Bukkit world lifecycle injection");
|
||||
e.printStackTrace();
|
||||
IrisLogging.reportError(C.RED + "Failed to remove Bukkit world lifecycle injection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCurrentPaperWorldData(
|
||||
Path sourceWorldDirectory,
|
||||
Path targetWorldDirectory,
|
||||
long seed
|
||||
) throws IOException {
|
||||
CurrentPaperWorldDataWriter.write(sourceWorldDirectory, targetWorldDirectory, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean awaitServerShutdownBoundary(long timeout, TimeUnit unit) {
|
||||
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getHandle().getServer();
|
||||
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
package art.arcane.iris.core.nms.v26_2_R1;
|
||||
|
||||
import art.arcane.iris.core.nms.INMSBinding;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NMSBindingCurrentPaperWorldDataContractTest {
|
||||
@Test
|
||||
public void bindingDelegatesWithoutLinkingPaperSavedDataClasses() throws Exception {
|
||||
String bindingSource = Files.readString(bindingSourcePath()).replace("\r\n", "\n");
|
||||
String writer = section(
|
||||
bindingSource,
|
||||
"public void writeCurrentPaperWorldData(",
|
||||
"public boolean awaitServerShutdownBoundary("
|
||||
);
|
||||
|
||||
assertTrue(writer.contains("CurrentPaperWorldDataWriter.write("));
|
||||
assertFalse(bindingSource.contains("PaperWorldMetadata"));
|
||||
assertFalse(bindingSource.contains("PaperLevelOverrides"));
|
||||
assertFalse(bindingSource.contains("io.papermc.paper.world.saveddata"));
|
||||
|
||||
InputStream classResource = NMSBindingCurrentPaperWorldDataContractTest.class
|
||||
.getResourceAsStream("NMSBinding.class");
|
||||
assertNotNull(classResource);
|
||||
try (InputStream input = classResource) {
|
||||
String classFile = new String(input.readAllBytes(), StandardCharsets.ISO_8859_1);
|
||||
assertFalse(classFile.contains("PaperWorldMetadata"));
|
||||
assertFalse(classFile.contains("PaperLevelOverrides"));
|
||||
assertFalse(classFile.contains("io/papermc/paper/world/saveddata"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stagesAllCurrentPaperWorldDataFromLiveServerState() throws Exception {
|
||||
String writer = Files.readString(writerSourcePath()).replace("\r\n", "\n");
|
||||
|
||||
assertTrue(writer.contains("WorldReplacementSeed.copyWithAuthoritativeSeed("));
|
||||
assertTrue(writer.contains("UUID metadataUuid = UUID.randomUUID()"));
|
||||
assertTrue(writer.contains("new PaperWorldMetadata(metadataUuid)"));
|
||||
assertTrue(writer.contains("captureLevelOverrides(craftServer, server)"));
|
||||
assertTrue(writer.indexOf("captureLevelOverrides(craftServer, server)")
|
||||
< writer.indexOf("WorldReplacementSeed.copyWithAuthoritativeSeed("));
|
||||
assertTrue(writer.contains("new SavedDataStorage("));
|
||||
assertTrue(writer.contains("server.getFixerUpper()"));
|
||||
assertTrue(writer.contains("server.registryAccess()"));
|
||||
assertTrue(writer.contains("data/minecraft/world_gen_settings.dat"));
|
||||
assertTrue(writer.contains("data/paper/metadata.dat"));
|
||||
assertTrue(writer.contains("data/paper/level_overrides.dat"));
|
||||
assertTrue(writer.contains("WorldReplacementSeed.readAuthoritativeSeed(targetWorld)"));
|
||||
assertTrue(writer.contains("verificationStorage.get(PaperWorldMetadata.TYPE)"));
|
||||
assertTrue(writer.contains("metadataUuid.equals(metadata.uuid())"));
|
||||
assertTrue(writer.contains("verificationStorage.get(PaperLevelOverrides.TYPE)"));
|
||||
assertTrue(writer.contains("overrides == null || overrides.isInitialized()"));
|
||||
assertTrue(writer.contains("Files.isRegularFile(requiredDataFile, LinkOption.NOFOLLOW_LINKS)"));
|
||||
assertFalse(writer.toLowerCase().contains("migrat"));
|
||||
assertFalse(writer.toLowerCase().contains("fallback"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void capturesOnlyLiveLevelOverridesOnTheGlobalThread() throws Exception {
|
||||
String source = Files.readString(writerSourcePath()).replace("\r\n", "\n");
|
||||
String capture = section(
|
||||
source,
|
||||
"private static PaperLevelOverrides captureLevelOverrides(",
|
||||
"private static PaperLevelOverrides createLevelOverrides("
|
||||
);
|
||||
String create = section(
|
||||
source,
|
||||
"private static PaperLevelOverrides createLevelOverrides(",
|
||||
"\n }\n}"
|
||||
);
|
||||
|
||||
assertTrue(capture.contains("craftServer.isGlobalTickThread()"));
|
||||
assertTrue(capture.contains("J.isFolia() && J.isPrimaryThread()"));
|
||||
assertTrue(capture.contains("J.runGlobal("));
|
||||
assertTrue(capture.contains("createLevelOverrides(craftServer, server)"));
|
||||
assertTrue(capture.contains("captured.get(SNAPSHOT_TIMEOUT_SECONDS"));
|
||||
assertTrue(capture.contains("Thread.currentThread().interrupt()"));
|
||||
assertTrue(create.contains("if (!craftServer.isGlobalTickThread())"));
|
||||
assertTrue(create.indexOf("if (!craftServer.isGlobalTickThread())")
|
||||
< create.indexOf("server.getWorldData().overworldData()"));
|
||||
assertTrue(create.contains("PaperLevelOverrides.createFromLiveLevelData(primaryLevelData)"));
|
||||
assertFalse(capture.contains("WorldReplacementSeed"));
|
||||
assertFalse(capture.contains("SavedDataStorage"));
|
||||
assertFalse(capture.contains("Files."));
|
||||
assertFalse(create.contains("WorldReplacementSeed"));
|
||||
assertFalse(create.contains("SavedDataStorage"));
|
||||
assertFalse(create.contains("Files."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsupportedBindingsRejectCurrentPaperWorldDataStaging() {
|
||||
INMSBinding binding = (INMSBinding) Proxy.newProxyInstance(
|
||||
INMSBinding.class.getClassLoader(),
|
||||
new Class<?>[]{INMSBinding.class},
|
||||
(proxy, method, arguments) -> InvocationHandler.invokeDefault(proxy, method, arguments)
|
||||
);
|
||||
|
||||
UnsupportedOperationException error = assertThrows(
|
||||
UnsupportedOperationException.class,
|
||||
() -> binding.writeCurrentPaperWorldData(Path.of("source"), Path.of("target"), 1L)
|
||||
);
|
||||
assertTrue(error.getMessage().contains("does not support current Paper world data staging"));
|
||||
}
|
||||
|
||||
private static Path bindingSourcePath() {
|
||||
return Path.of(System.getProperty("iris.nmsBindingSource"));
|
||||
}
|
||||
|
||||
private static Path writerSourcePath() {
|
||||
return bindingSourcePath().resolveSibling("CurrentPaperWorldDataWriter.java");
|
||||
}
|
||||
|
||||
private static String section(String source, String startMarker, String endMarker) {
|
||||
int start = source.indexOf(startMarker);
|
||||
int end = source.indexOf(endMarker, start);
|
||||
assertTrue("Missing source section starting with " + startMarker, start >= 0);
|
||||
assertTrue("Missing source section ending with " + endMarker, end > start);
|
||||
return source.substring(start, end);
|
||||
}
|
||||
}
|
||||
@@ -172,9 +172,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
try {
|
||||
InstanceState.updateInstanceId();
|
||||
} catch (Throwable ex) {
|
||||
System.err.println("[Iris] Failed to update instance id: " + ex.getClass().getSimpleName()
|
||||
+ (ex.getMessage() == null ? "" : " - " + ex.getMessage()));
|
||||
ex.printStackTrace();
|
||||
IrisLogging.reportError("Failed to update the Iris instance id.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +348,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
try {
|
||||
object.run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}, RNG.r.i(100, 1200));
|
||||
@@ -490,7 +487,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
pw.close();
|
||||
Iris.info("DUMPED! See " + fi.getAbsolutePath());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError("Failed to write the Iris thread dump.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +658,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
(EngineWorldManagerProvider) IrisWorldManager::new);
|
||||
IrisServices.register(WorldDeletionQueue.class, pendingWorldDeletes);
|
||||
IrisServices.register(ManagedWorldLoader.class, (ManagedWorldLoader) this::loadManagedWorld);
|
||||
SettingsHotloadWatch watch = new SettingsHotloadWatch(getDataFile("settings.json"));
|
||||
SettingsHotloadWatch watch = new SettingsHotloadWatch(getDataFile("iris.json"));
|
||||
settingsHotloadWatch = watch;
|
||||
// Stale-temp cleanup must complete before services enable: StudioSVC.onEnable downloads
|
||||
// packs through cache/temp on an async thread, and a concurrent delete of that folder
|
||||
@@ -774,7 +771,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
|
||||
private void autoStartStudio() {
|
||||
if (IrisSettings.get().getStudio().isAutoStartDefaultStudio()) {
|
||||
Iris.info("Starting up auto Studio!");
|
||||
Iris.debug("Starting up auto Studio!");
|
||||
try {
|
||||
Player r = new KList<>(getServer().getOnlinePlayers()).getRandom();
|
||||
Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> {
|
||||
@@ -782,7 +779,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
final Location spawn = w.getSpawnLocation();
|
||||
for (Player i : getServer().getOnlinePlayers()) {
|
||||
final Runnable playerTask = () -> {
|
||||
i.setGameMode(GameMode.CREATIVE);
|
||||
i.setGameMode(GameMode.SPECTATOR);
|
||||
BukkitPlatform.teleportAsync(i, spawn);
|
||||
};
|
||||
if (!J.runEntity(i, playerTask)) {
|
||||
@@ -802,10 +799,9 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
audiences = new Bindings.Adventure(this);
|
||||
BukkitPlatform.hostAudiences(audiences);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
IrisSettings.get().getGeneral().setUseConsoleCustomColors(false);
|
||||
IrisSettings.get().getGeneral().setUseCustomColorsIngame(false);
|
||||
Iris.error("Failed to setup Adventure API... No custom colors :(");
|
||||
Iris.reportError("Failed to set up Adventure; custom colors are disabled.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -903,14 +899,14 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
if (IrisToolbelt.isServerStopping()) {
|
||||
quiesceRuntimeForServerShutdown("pre-unload:" + reason);
|
||||
startPostStopFinisher();
|
||||
Iris.info("Pre-unload hook deferred generator teardown until Paper closes its chunk schedulers.");
|
||||
Iris.debug("Pre-unload hook deferred generator teardown until Paper closes its chunk schedulers.");
|
||||
return;
|
||||
}
|
||||
if (alreadyDrained.get()) {
|
||||
Iris.info("Pre-unload hook skipped; Iris already drained.");
|
||||
Iris.debug("Pre-unload hook skipped; Iris already drained.");
|
||||
return;
|
||||
}
|
||||
Iris.info("BileTools pre-unload hook fired (" + reason + "). Freezing all Iris worlds.");
|
||||
Iris.debug("BileTools pre-unload hook fired (" + reason + "). Freezing all Iris worlds.");
|
||||
drainOnce("pre-unload:" + reason, 45L);
|
||||
}
|
||||
|
||||
@@ -1088,7 +1084,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
}
|
||||
}
|
||||
if (generators.isEmpty()) {
|
||||
Iris.info("No Iris worlds to freeze.");
|
||||
Iris.debug("No Iris worlds to freeze.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1112,7 +1108,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
try {
|
||||
CompletableFuture.allOf(closes.toArray(new CompletableFuture<?>[0]))
|
||||
.get(timeoutSeconds, TimeUnit.SECONDS);
|
||||
Iris.info("All Iris chunk generators parked. Safe to unload.");
|
||||
Iris.debug("All Iris chunk generators parked. Safe to unload.");
|
||||
} catch (TimeoutException e) {
|
||||
Iris.warn("Iris generator drain timed out after " + timeoutSeconds + "s; unload proceeding anyway.");
|
||||
} catch (InterruptedException e) {
|
||||
@@ -1201,7 +1197,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
try {
|
||||
Iris.syncJobs.next().run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
@@ -1209,7 +1204,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
}
|
||||
|
||||
private void bstats() {
|
||||
if (IrisSettings.get().getGeneral().isPluginMetrics()) {
|
||||
if (IrisSettings.get().getGeneral().isMetrics()) {
|
||||
Bindings.setupBstats(this);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -242,7 +242,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
||||
try (CountingDataInputStream in = CountingDataInputStream.wrap(new BufferedInputStream(new FileInputStream(base)))) {
|
||||
TectonicPlate.read(1088, in, true, IrisEngineMantle.createRuntimeDataAdapter(activeEngine.getData()), IrisEngineMantle.createRuntimeHooks());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError("Failed to inspect the Iris tectonic plate.", e);
|
||||
}
|
||||
} else {
|
||||
Matter.read(section);
|
||||
@@ -282,7 +282,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
||||
MCAFile MCARegion = MCAUtil.read(mca);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError("Failed to inspect Minecraft region files.", e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -339,7 +339,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError("Failed to inspect server network interfaces.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,22 +22,16 @@ import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.BukkitWorldReconciler;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.IrisStartupValidation;
|
||||
import art.arcane.iris.core.DatapackInstallResult;
|
||||
import art.arcane.iris.core.IrisWorldStorage;
|
||||
import art.arcane.iris.core.IrisWorlds;
|
||||
import art.arcane.iris.core.PendingWorldReplacementManager;
|
||||
import art.arcane.iris.core.ServerConfigurator;
|
||||
import art.arcane.iris.core.lifecycle.BukkitWorldConfiguration;
|
||||
import art.arcane.iris.core.lifecycle.IrisWorldRemovalService;
|
||||
import art.arcane.iris.core.lifecycle.LifecycleOperationCoordinator;
|
||||
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.core.pack.AtomicDirectoryPublisher;
|
||||
import art.arcane.iris.core.pack.PackDownloader;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.core.pack.PackValidationRegistry;
|
||||
import art.arcane.iris.core.service.StudioSVC;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||
@@ -62,9 +56,7 @@ import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -160,16 +152,6 @@ public class CommandIris implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (J.isFolia()) {
|
||||
boolean staged = stageFoliaWorldCreation(worldName, dimension, seed);
|
||||
if (!staged) {
|
||||
return;
|
||||
}
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_WORLD_STAGING_COMPLETED_RESTARTING_SERVER_GENERATE_LOAD, MessageArgument.untrusted("worldName", worldName)));
|
||||
ServerConfigurator.restart("Iris staged Folia world \"" + worldName + "\" for startup.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
IrisToolbelt.createWorld()
|
||||
.dimension(resolvedType)
|
||||
@@ -263,116 +245,6 @@ public class CommandIris implements DirectorExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean stageFoliaWorldCreation(String name, IrisDimension dimension, long seed) {
|
||||
try {
|
||||
IrisStartupValidation.requireWorldCreationReady();
|
||||
PackValidationRegistry.requireLoadable(
|
||||
dimension.getLoader().getDataFolder().getName());
|
||||
} catch (RuntimeException exception) {
|
||||
sender().sendMessage(C.RED + exception.getMessage());
|
||||
return false;
|
||||
}
|
||||
NamespacedKey worldKey = IrisWorldStorage.managedKeyFromName(name);
|
||||
LifecycleOperationCoordinator.Lease worldLease = null;
|
||||
File worldFolder = IrisWorldStorage.requireSafeManagedDimensionRoot(worldKey);
|
||||
Path stagedWorld = null;
|
||||
try {
|
||||
LifecycleOperationCoordinator coordinator = LifecycleOperationCoordinator.get();
|
||||
worldLease = coordinator.acquire(
|
||||
LifecycleOperationCoordinator.Domain.WORLD_MUTATION,
|
||||
LifecycleOperationCoordinator.OperationKind.WORLD_CREATE,
|
||||
worldKey.toString());
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_RUNTIME_WORLD_CREATION_IS_DISABLED_ON_FOLIA));
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_PREPARING_WORLD_FILES_BUKKIT_YML_NEXT_STARTUP));
|
||||
if (worldFolder.exists()) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_THAT_FOLDER_ALREADY_EXISTS));
|
||||
return false;
|
||||
}
|
||||
|
||||
DatapackInstallResult datapackResult = ServerConfigurator.installDataPacksIfChanged(true);
|
||||
if (!datapackResult.succeeded()) {
|
||||
sender().sendMessage(C.RED + "Failed to compile the Iris datapack. No world files were staged.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Path targetWorld = worldFolder.toPath().toAbsolutePath().normalize();
|
||||
Path namespaceRoot = targetWorld.getParent();
|
||||
if (namespaceRoot == null) {
|
||||
throw new IOException("Iris world target has no namespace directory: " + targetWorld);
|
||||
}
|
||||
Files.createDirectories(namespaceRoot);
|
||||
stagedWorld = Files.createTempDirectory(namespaceRoot, ".iris-create-" + worldKey.getKey() + "-");
|
||||
Path sourceOverworld = IrisWorldStorage.dimensionRoot(
|
||||
IrisWorldStorage.levelRoot(),
|
||||
NamespacedKey.minecraft("overworld")
|
||||
).toPath();
|
||||
INMS.get().writeCurrentPaperWorldData(sourceOverworld, stagedWorld, seed);
|
||||
|
||||
IrisDimension installed = Iris.service(StudioSVC.class).installIntoWorld(
|
||||
sender(),
|
||||
dimension,
|
||||
stagedWorld.toFile()
|
||||
);
|
||||
if (installed == null) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_FAILED_STAGE_WORLD_FILES_DIMENSION, MessageArgument.untrusted("value", dimension.getLoadKey())));
|
||||
return false;
|
||||
}
|
||||
|
||||
try (AtomicDirectoryPublisher.Publication publication = AtomicDirectoryPublisher.publishAbsent(
|
||||
stagedWorld,
|
||||
targetWorld
|
||||
)) {
|
||||
stagedWorld = null;
|
||||
if (!registerWorldInBukkitYml(worldKey, dimension.getLoadKey(), seed)) {
|
||||
return false;
|
||||
}
|
||||
publication.commit();
|
||||
}
|
||||
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_STAGED_IRIS_WORLD_WITH_GENERATOR_IRIS_SEED, MessageArgument.untrusted("name", name), MessageArgument.untrusted("value", dimension.getLoadKey()), MessageArgument.untrusted("seed", seed)));
|
||||
return true;
|
||||
} catch (LifecycleOperationCoordinator.BusyException e) {
|
||||
sender().sendMessage(C.YELLOW + e.getMessage());
|
||||
return false;
|
||||
} catch (Throwable e) {
|
||||
sender().sendMessage(C.RED + "Failed to stage the complete Iris world: " + e.getMessage());
|
||||
Iris.reportError("Failed to stage complete Folia world \"" + worldKey + "\".", e);
|
||||
return false;
|
||||
} finally {
|
||||
if (stagedWorld != null) {
|
||||
deleteDirectorySafely(stagedWorld.toFile());
|
||||
}
|
||||
if (worldLease != null) {
|
||||
worldLease.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean registerWorldInBukkitYml(NamespacedKey worldKey, String dimension, Long seed) {
|
||||
String configuredWorldName = IrisWorldStorage.configuredWorldName(
|
||||
worldKey,
|
||||
IrisWorldStorage.levelRoot().getName()
|
||||
);
|
||||
try {
|
||||
BukkitWorldConfiguration.register(BUKKIT_YML, configuredWorldName, dimension, seed);
|
||||
Iris.info("Registered \"" + configuredWorldName + "\" in bukkit.yml");
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_FAILED_UPDATE_BUKKIT_YML, MessageArgument.untrusted("value", String.valueOf(e.getMessage()))));
|
||||
Iris.error("Failed to update bukkit.yml!");
|
||||
Iris.reportError(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteDirectorySafely(File directory) {
|
||||
try {
|
||||
AtomicDirectoryPublisher.deleteTree(directory.toPath());
|
||||
} catch (IOException e) {
|
||||
Iris.reportError("Failed to roll back staged world folder \"" + directory.getAbsolutePath() + "\".", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean reportExpectedCreationInterruption(Throwable failure) {
|
||||
Throwable current = failure;
|
||||
while (current != null) {
|
||||
|
||||
+25
-19
@@ -24,6 +24,7 @@ import art.arcane.iris.core.link.WorldEditLink;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.core.runtime.ObjectStudioActivation;
|
||||
import art.arcane.iris.core.runtime.StudioOpenCoordinator;
|
||||
import art.arcane.iris.core.runtime.WorldRuntimeControlService;
|
||||
import art.arcane.iris.core.service.ObjectSVC;
|
||||
import art.arcane.iris.core.service.StudioSVC;
|
||||
@@ -171,24 +172,29 @@ public class CommandObject implements DirectorExecutor {
|
||||
|
||||
IrisDimension finalHost = hostDimension;
|
||||
try {
|
||||
Iris.service(StudioSVC.class).open(commandSender, seed, hostDimension.getLoadKey(), world -> {
|
||||
if (world == null) return;
|
||||
try {
|
||||
WorldRuntimeControlService.get().applyObjectStudioWorldRules(world);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError("Failed to apply object studio world rules for " + world.getName(), e);
|
||||
}
|
||||
Iris.service(StudioSVC.class).open(
|
||||
commandSender,
|
||||
seed,
|
||||
hostDimension.getLoadKey(),
|
||||
StudioOpenCoordinator.StudioOpenKind.OBJECT,
|
||||
world -> {
|
||||
if (world == null) return;
|
||||
try {
|
||||
WorldRuntimeControlService.get().applyObjectStudioWorldRules(world);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError("Failed to apply object studio world rules for " + world.getName(), e);
|
||||
}
|
||||
|
||||
if (commandSender.isPlayer()) {
|
||||
Player p = commandSender.player();
|
||||
if (p != null) {
|
||||
Location target = new Location(world, 0.5D, 66D, 0.5D);
|
||||
J.runEntity(p, () -> {
|
||||
BukkitPlatform.teleportAsync(p, target).thenRun(() -> p.setGameMode(GameMode.CREATIVE));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (commandSender.isPlayer()) {
|
||||
Player p = commandSender.player();
|
||||
if (p != null) {
|
||||
Location target = new Location(world, 0.5D, 66D, 0.5D);
|
||||
J.runEntity(p, () -> {
|
||||
BukkitPlatform.teleportAsync(p, target).thenRun(() -> p.setGameMode(GameMode.CREATIVE));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError("Failed to open object studio world \"" + finalHost.getLoadKey() + "\".", e);
|
||||
commandSender.sendMessage(IrisLanguage.text(BukkitCommandMessages.COMMAND_OBJECT_FAILED_OPEN_OBJECT_STUDIO, MessageArgument.untrusted("value", String.valueOf(e.getMessage()))));
|
||||
@@ -360,7 +366,7 @@ public class CommandObject implements DirectorExecutor {
|
||||
o.write(o.getLoadFile());
|
||||
} catch (IOException e) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_OBJECT_FAILED_SAVE_OBJECT, MessageArgument.untrusted("value", o.getLoadFile()), MessageArgument.untrusted("value2", String.valueOf(e.getMessage()))));
|
||||
e.printStackTrace();
|
||||
Iris.reportError("Failed to save object " + o.getLoadFile() + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +432,7 @@ public class CommandObject implements DirectorExecutor {
|
||||
try {
|
||||
IrisConverter.convertSchematics(sender());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError("Failed to convert schematics to Iris objects.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@ public class CommandPregen implements DirectorExecutor {
|
||||
} catch (Throwable e) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_PREGEN_FAILED_START_PREGENERATION_SEE_CONSOLE_DETAILS));
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,6 @@ import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -573,7 +572,6 @@ public class CommandStudio implements DirectorExecutor {
|
||||
IO.writeAll(report, fileText.toString("\n"));
|
||||
} catch (IOException e) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_DONE, MessageArgument.untrusted("value", report.getPath())));
|
||||
@@ -663,9 +661,6 @@ public class CommandStudio implements DirectorExecutor {
|
||||
Iris.reportError("Studio teleport failed for player \"" + player.getName() + "\".", failure);
|
||||
return;
|
||||
}
|
||||
if (Boolean.TRUE.equals(teleported)) {
|
||||
J.runEntity(player, () -> player.setGameMode(GameMode.CREATIVE));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -831,7 +826,6 @@ public class CommandStudio implements DirectorExecutor {
|
||||
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_REPORTED, MessageArgument.untrusted("value", ff.getPath())));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
+209
-13
@@ -18,14 +18,17 @@
|
||||
|
||||
package art.arcane.iris.core.gui;
|
||||
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.platform.bukkit.BukkitWorldBinding;
|
||||
import art.arcane.iris.core.runtime.WorldRuntimeControlService;
|
||||
import art.arcane.iris.engine.IrisComplex;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.render.RenderType;
|
||||
import art.arcane.iris.engine.object.IrisWorld;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.platform.bukkit.BukkitWorldBinding;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@@ -36,15 +39,21 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static art.arcane.iris.util.common.data.registry.Attributes.MAX_HEALTH;
|
||||
|
||||
public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
private final Engine engine;
|
||||
private final AtomicBoolean nativeTeleportActive = new AtomicBoolean();
|
||||
private final AtomicBoolean playerRefreshQueued = new AtomicBoolean();
|
||||
private final AtomicLong teleportSequence = new AtomicLong();
|
||||
private final AtomicReference<VisionTeleportRequest> latestTeleport = new AtomicReference<>();
|
||||
private volatile List<GuiMarker> playerMarkers = List.of();
|
||||
|
||||
public BukkitVisionOverlay(Engine engine) {
|
||||
@@ -144,25 +153,198 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
|
||||
@Override
|
||||
public void teleport(double worldX, double worldZ) {
|
||||
IrisWorld target = engine.getWorld();
|
||||
if (!target.hasPlatformWorld()) {
|
||||
VisionTeleportRequest request = new VisionTeleportRequest(
|
||||
teleportSequence.incrementAndGet(),
|
||||
VisionGUI.floorWorldCoordinate(worldX),
|
||||
VisionGUI.floorWorldCoordinate(worldZ));
|
||||
latestTeleport.set(request);
|
||||
startTeleport(request);
|
||||
}
|
||||
|
||||
private void startTeleport(VisionTeleportRequest request) {
|
||||
if (!request.processing.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
J.runGlobal(() -> {
|
||||
boolean scheduled = J.runGlobal(() -> {
|
||||
IrisWorld target = engine.getWorld();
|
||||
if (!isCurrent(request, target)) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
World world = BukkitWorldBinding.world(target);
|
||||
if (world == null) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
List<Player> players = BukkitWorldBinding.players(target);
|
||||
if (players.isEmpty()) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
Player player = players.get(0);
|
||||
World world = player.getWorld();
|
||||
int xx = (int) worldX;
|
||||
int zz = (int) worldZ;
|
||||
J.runRegion(world, xx >> 4, zz >> 4, () -> {
|
||||
int yy = world.getHighestBlockYAt(xx, zz) + 1;
|
||||
Location destination = new Location(world, xx, yy, zz);
|
||||
J.runEntity(player, () -> BukkitPlatform.teleportAsync(player, destination));
|
||||
});
|
||||
requestTeleportChunk(request, target, player, world);
|
||||
});
|
||||
if (!scheduled) {
|
||||
finish(request);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestTeleportChunk(
|
||||
VisionTeleportRequest request,
|
||||
IrisWorld target,
|
||||
Player player,
|
||||
World world
|
||||
) {
|
||||
int blockX = request.blockX;
|
||||
int blockZ = request.blockZ;
|
||||
int chunkX = blockX >> 4;
|
||||
int chunkZ = blockZ >> 4;
|
||||
CompletableFuture<Chunk> requested;
|
||||
try {
|
||||
requested = WorldRuntimeControlService.get().requestChunkAsync(
|
||||
world,
|
||||
chunkX,
|
||||
chunkZ,
|
||||
true,
|
||||
true
|
||||
);
|
||||
} catch (Throwable failure) {
|
||||
fail(request, target, world, failure);
|
||||
return;
|
||||
}
|
||||
if (requested == null) {
|
||||
fail(request, target, world, new IllegalStateException(
|
||||
"Vision destination chunk request returned no future."));
|
||||
return;
|
||||
}
|
||||
requested.whenComplete((chunk, failure) -> {
|
||||
if (!isCurrent(request, target)) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
if (failure != null) {
|
||||
fail(request, target, world, failure);
|
||||
return;
|
||||
}
|
||||
if (chunk == null || chunk.getWorld() != world) {
|
||||
fail(request, target, world, new IllegalStateException(
|
||||
"Vision destination chunk request returned no chunk."));
|
||||
return;
|
||||
}
|
||||
boolean scheduled = J.runRegion(world, chunkX, chunkZ, () -> {
|
||||
if (!isCurrent(request, target)) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
int yy = world.getHighestBlockYAt(blockX, blockZ) + 1;
|
||||
Location destination = new Location(world, blockX, yy, blockZ);
|
||||
if (!J.runEntity(player, () -> delegateTeleport(
|
||||
request,
|
||||
target,
|
||||
player,
|
||||
world,
|
||||
destination))) {
|
||||
fail(request, target, world, new IllegalStateException(
|
||||
"Failed to schedule the Vision teleport on the player entity."));
|
||||
}
|
||||
});
|
||||
if (!scheduled) {
|
||||
fail(request, target, world, new IllegalStateException(
|
||||
"Failed to schedule the Vision surface lookup on its owning region."));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void delegateTeleport(
|
||||
VisionTeleportRequest request,
|
||||
IrisWorld target,
|
||||
Player player,
|
||||
World world,
|
||||
Location destination
|
||||
) {
|
||||
if (!isCurrent(request, target) || !player.isOnline() || player.getWorld() != world) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
if (!nativeTeleportActive.compareAndSet(false, true)) {
|
||||
finish(request);
|
||||
return;
|
||||
}
|
||||
if (!isCurrent(request, target)) {
|
||||
nativeTeleportActive.set(false);
|
||||
finish(request);
|
||||
restartLatest(request);
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Boolean> teleport;
|
||||
try {
|
||||
teleport = BukkitPlatform.teleportAsync(player, destination);
|
||||
} catch (Throwable failure) {
|
||||
nativeTeleportActive.set(false);
|
||||
fail(request, target, world, failure);
|
||||
restartLatest(request);
|
||||
return;
|
||||
}
|
||||
if (teleport == null) {
|
||||
nativeTeleportActive.set(false);
|
||||
fail(request, target, world, new IllegalStateException(
|
||||
"Vision teleport returned no completion future."));
|
||||
restartLatest(request);
|
||||
return;
|
||||
}
|
||||
teleport.whenComplete((success, failure) -> {
|
||||
nativeTeleportActive.set(false);
|
||||
finish(request);
|
||||
if (isCurrent(request, target)) {
|
||||
if (failure != null) {
|
||||
reportTeleportFailure(world, request.blockX, request.blockZ, failure);
|
||||
} else if (!Boolean.TRUE.equals(success)) {
|
||||
reportTeleportFailure(world, request.blockX, request.blockZ, new IllegalStateException(
|
||||
"Vision teleport did not complete successfully."));
|
||||
}
|
||||
}
|
||||
restartLatest(request);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isCurrent(VisionTeleportRequest request, IrisWorld target) {
|
||||
VisionTeleportRequest current = latestTeleport.get();
|
||||
return current != null
|
||||
&& current.sequence == request.sequence
|
||||
&& target != null
|
||||
&& engine.getWorld() == target
|
||||
&& target.hasPlatformWorld()
|
||||
&& !engine.isClosing()
|
||||
&& !engine.isClosed();
|
||||
}
|
||||
|
||||
private void fail(
|
||||
VisionTeleportRequest request,
|
||||
IrisWorld target,
|
||||
World world,
|
||||
Throwable failure
|
||||
) {
|
||||
finish(request);
|
||||
if (isCurrent(request, target)) {
|
||||
reportTeleportFailure(world, request.blockX, request.blockZ, failure);
|
||||
}
|
||||
}
|
||||
|
||||
private void finish(VisionTeleportRequest request) {
|
||||
request.processing.set(false);
|
||||
}
|
||||
|
||||
private void restartLatest(VisionTeleportRequest completed) {
|
||||
VisionTeleportRequest current = latestTeleport.get();
|
||||
if (current != null && current != completed) {
|
||||
startTeleport(current);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportTeleportFailure(World world, int blockX, int blockZ, Throwable failure) {
|
||||
IrisLogging.reportError("Vision could not teleport to " + world.getName() + "@"
|
||||
+ blockX + "," + blockZ + ".", failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -179,4 +361,18 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
};
|
||||
return file == null ? null : file.getName();
|
||||
}
|
||||
|
||||
private static final class VisionTeleportRequest {
|
||||
private final long sequence;
|
||||
private final int blockX;
|
||||
private final int blockZ;
|
||||
private final AtomicBoolean processing;
|
||||
|
||||
private VisionTeleportRequest(long sequence, int blockX, int blockZ) {
|
||||
this.sequence = sequence;
|
||||
this.blockX = blockX;
|
||||
this.blockZ = blockZ;
|
||||
processing = new AtomicBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +605,6 @@ public final class IrisEngineSVC implements IrisService {
|
||||
private static void reportFailure(String message, Throwable exception) {
|
||||
IrisLogging.reportError(exception);
|
||||
IrisLogging.error("EngineSVC: " + message);
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
private final class Registered {
|
||||
|
||||
+17
@@ -20,6 +20,7 @@ package art.arcane.iris.core.service;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.protocol.EngineResolver;
|
||||
import art.arcane.iris.core.protocol.IrisCursorRequestService;
|
||||
import art.arcane.iris.core.protocol.IrisProtocolServer;
|
||||
import art.arcane.iris.core.protocol.IrisServerTransport;
|
||||
import art.arcane.iris.core.protocol.IrisSession;
|
||||
@@ -55,6 +56,7 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
|
||||
private IrisSessionRegistry registry;
|
||||
private IrisProtocolServer protocolServer;
|
||||
private IrisCursorRequestService cursorService;
|
||||
private IrisVisionRequestService visionService;
|
||||
|
||||
@Override
|
||||
@@ -66,6 +68,8 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
protocolServer = new IrisProtocolServer(registry, SERVER_CAPABILITIES, brand(), true);
|
||||
EngineResolver engineResolver = IrisProtocolService::resolveEngine;
|
||||
protocolServer.setEngineResolver(engineResolver);
|
||||
cursorService = IrisCursorRequestService.create(engineResolver, registry);
|
||||
protocolServer.setCursorInfoHandler(cursorService);
|
||||
visionService = IrisVisionRequestService.create(engineResolver, registry);
|
||||
protocolServer.setVisionTileHandler(visionService);
|
||||
IrisServices.register(IrisProtocolServer.class, protocolServer);
|
||||
@@ -81,13 +85,22 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
messenger.unregisterIncomingPluginChannel(Iris.instance, IrisProtocol.CHANNEL, this);
|
||||
messenger.unregisterOutgoingPluginChannel(Iris.instance, IrisProtocol.CHANNEL);
|
||||
IrisSessionRegistry current = registry;
|
||||
IrisCursorRequestService cursor = cursorService;
|
||||
IrisVisionRequestService vision = visionService;
|
||||
if (current != null) {
|
||||
for (IrisSession session : current.all()) {
|
||||
current.unregister(session.id());
|
||||
if (cursor != null) {
|
||||
cursor.clearSession(session.id());
|
||||
}
|
||||
if (vision != null) {
|
||||
vision.clearSession(session.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
registry = null;
|
||||
protocolServer = null;
|
||||
cursorService = null;
|
||||
visionService = null;
|
||||
}
|
||||
|
||||
@@ -117,6 +130,10 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
}
|
||||
String sessionId = event.getPlayer().getUniqueId().toString();
|
||||
current.unregister(sessionId);
|
||||
IrisCursorRequestService cursor = cursorService;
|
||||
if (cursor != null) {
|
||||
cursor.clearSession(sessionId);
|
||||
}
|
||||
IrisVisionRequestService vision = visionService;
|
||||
if (vision != null) {
|
||||
vision.clearSession(sessionId);
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
@@ -61,18 +62,30 @@ import org.bukkit.util.BlockVector;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static art.arcane.iris.util.common.data.registry.Particles.CRIT_MAGIC;
|
||||
import static art.arcane.iris.util.common.data.registry.Particles.REDSTONE;
|
||||
|
||||
public class WandSVC implements IrisService {
|
||||
private static final int MS_PER_TICK = Integer.parseInt(System.getProperty("iris.ms_per_tick", "30"));
|
||||
private static final int PLAYER_RESCAN_INTERVAL_TICKS = 100;
|
||||
|
||||
private static ItemStack dust;
|
||||
private static ItemStack wand;
|
||||
|
||||
private final Map<UUID, Player> activePlayers = new ConcurrentHashMap<>();
|
||||
private final AtomicBoolean playerRescanScheduled = new AtomicBoolean(false);
|
||||
private volatile boolean enabled;
|
||||
private int taskId = -1;
|
||||
private int ticksUntilPlayerRescan = 0;
|
||||
|
||||
public static void pasteSchematic(IrisObject s, Location at) {
|
||||
s.place(at);
|
||||
}
|
||||
@@ -174,7 +187,6 @@ public class WandSVC implements IrisService {
|
||||
|
||||
return s;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
|
||||
@@ -196,7 +208,6 @@ public class WandSVC implements IrisService {
|
||||
|
||||
return WorldMatter.createMatter(p.getName(), f[0], f[1]);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
|
||||
@@ -307,8 +318,18 @@ public class WandSVC implements IrisService {
|
||||
}
|
||||
|
||||
public static Location[] getCuboidFromItem(ItemStack is) {
|
||||
if (is == null) {
|
||||
return new Location[]{null, null};
|
||||
}
|
||||
ItemMeta im = is.getItemMeta();
|
||||
return new Location[]{stringToLocation(im.getLore().get(0)), stringToLocation(im.getLore().get(1))};
|
||||
if (im == null) {
|
||||
return new Location[]{null, null};
|
||||
}
|
||||
List<String> lore = im.getLore();
|
||||
if (lore == null || lore.size() < 2) {
|
||||
return new Location[]{null, null};
|
||||
}
|
||||
return new Location[]{stringToLocation(lore.get(0)), stringToLocation(lore.get(1))};
|
||||
}
|
||||
|
||||
public static Location[] getCuboid(Player p) {
|
||||
@@ -343,30 +364,47 @@ public class WandSVC implements IrisService {
|
||||
* @return True if it is
|
||||
*/
|
||||
public static boolean isWand(ItemStack is) {
|
||||
if (is == null || is.getItemMeta() == null) {
|
||||
if (is == null) {
|
||||
return false;
|
||||
}
|
||||
Byte marker = is.getItemMeta().getPersistentDataContainer().get(wandKey(), PersistentDataType.BYTE);
|
||||
if (marker != null && marker == (byte) 1) {
|
||||
ItemMeta meta = is.getItemMeta();
|
||||
if (meta == null) {
|
||||
return false;
|
||||
}
|
||||
Byte marker = meta.getPersistentDataContainer().get(wandKey(), PersistentDataType.BYTE);
|
||||
if (marker != null && marker.byteValue() == 1) {
|
||||
return true;
|
||||
}
|
||||
return is.getType().equals(wand.getType()) &&
|
||||
is.getItemMeta().getDisplayName().equals(wand.getItemMeta().getDisplayName()) &&
|
||||
is.getItemMeta().getEnchants().equals(wand.getItemMeta().getEnchants()) &&
|
||||
is.getItemMeta().getItemFlags().equals(wand.getItemMeta().getItemFlags());
|
||||
ItemStack template = wand;
|
||||
if (template == null || !is.getType().equals(template.getType())) {
|
||||
return false;
|
||||
}
|
||||
ItemMeta templateMeta = template.getItemMeta();
|
||||
return templateMeta != null
|
||||
&& Objects.equals(meta.getDisplayName(), templateMeta.getDisplayName())
|
||||
&& meta.getEnchants().equals(templateMeta.getEnchants())
|
||||
&& meta.getItemFlags().equals(templateMeta.getItemFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
wand = createWand();
|
||||
dust = createDust();
|
||||
|
||||
J.ar(this::tickAll, 0);
|
||||
enabled = true;
|
||||
activePlayers.clear();
|
||||
ticksUntilPlayerRescan = 0;
|
||||
taskId = J.ar(this::tickAll, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
|
||||
enabled = false;
|
||||
if (taskId != -1) {
|
||||
J.car(taskId);
|
||||
taskId = -1;
|
||||
}
|
||||
activePlayers.clear();
|
||||
playerRescanScheduled.set(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,11 +413,16 @@ public class WandSVC implements IrisService {
|
||||
*/
|
||||
private void tickAll() {
|
||||
try {
|
||||
J.runGlobal(() -> {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
J.runEntity(p, () -> tick(p));
|
||||
}
|
||||
});
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
if (ticksUntilPlayerRescan-- <= 0) {
|
||||
ticksUntilPlayerRescan = PLAYER_RESCAN_INTERVAL_TICKS;
|
||||
rescanPlayers();
|
||||
}
|
||||
for (Player player : activePlayers.values()) {
|
||||
J.runEntity(player, () -> tick(player));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
@@ -387,20 +430,53 @@ public class WandSVC implements IrisService {
|
||||
|
||||
public void tick(Player p) {
|
||||
try {
|
||||
try {
|
||||
if ((IrisSettings.get().getWorld().worldEditWandCUI && isHoldingWand(p)) || isWand(p.getInventory().getItemInMainHand())) {
|
||||
Location[] d = getCuboid(p);
|
||||
if (d == null || d[0] == null || d[1] == null) return;
|
||||
new WandSelection(new Cuboid(d[0], d[1]), p).draw();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
if (!p.isOnline()) {
|
||||
activePlayers.remove(p.getUniqueId(), p);
|
||||
return;
|
||||
}
|
||||
Location[] selection = getCuboid(p);
|
||||
if (!hasCompleteSelection(selection)) {
|
||||
activePlayers.remove(p.getUniqueId(), p);
|
||||
return;
|
||||
}
|
||||
new WandSelection(new Cuboid(selection[0], selection[1]), p).draw();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rescanPlayers() {
|
||||
if (!playerRescanScheduled.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
if (!J.runGlobal(() -> {
|
||||
try {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
J.runEntity(player, () -> refreshPlayer(player));
|
||||
}
|
||||
} finally {
|
||||
playerRescanScheduled.set(false);
|
||||
}
|
||||
})) {
|
||||
playerRescanScheduled.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshPlayer(Player player) {
|
||||
if (enabled && player.isOnline() && hasCompleteSelection(getCuboid(player))) {
|
||||
activePlayers.put(player.getUniqueId(), player);
|
||||
return;
|
||||
}
|
||||
activePlayers.remove(player.getUniqueId(), player);
|
||||
}
|
||||
|
||||
private static boolean hasCompleteSelection(Location[] selection) {
|
||||
return selection != null && selection.length >= 2 && selection[0] != null && selection[1] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the outline of a selected region
|
||||
*
|
||||
@@ -492,6 +568,7 @@ public class WandSVC implements IrisService {
|
||||
return;
|
||||
try {
|
||||
if (isHoldingIrisWand(e.getPlayer())) {
|
||||
activePlayers.put(e.getPlayer().getUniqueId(), e.getPlayer());
|
||||
if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().getInventory().setItemInMainHand(update(true, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
|
||||
@@ -517,6 +594,11 @@ public class WandSVC implements IrisService {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerQuitEvent event) {
|
||||
activePlayers.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the player holding Dust?
|
||||
*
|
||||
|
||||
@@ -23,16 +23,18 @@ import art.arcane.volmlib.util.math.M;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import static art.arcane.iris.util.common.data.registry.Particles.REDSTONE;
|
||||
|
||||
public class WandSelection {
|
||||
private static final double STEP = 0.10;
|
||||
private static final double MAX_DISTANCE = 256D;
|
||||
private static final double MAX_DISTANCE_SQUARED = MAX_DISTANCE * MAX_DISTANCE;
|
||||
|
||||
private final Cuboid c;
|
||||
private final Player p;
|
||||
private static final double STEP = 0.10;
|
||||
|
||||
public WandSelection(Cuboid c, Player p) {
|
||||
this.c = c;
|
||||
@@ -45,57 +47,91 @@ public class WandSelection {
|
||||
return;
|
||||
}
|
||||
|
||||
double maxDistanceSquared = 256 * 256;
|
||||
int particleCount = 0;
|
||||
|
||||
// cube!
|
||||
Location[][] edges = {
|
||||
{c.getLowerNE(), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ())},
|
||||
{c.getLowerNE(), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ())},
|
||||
{c.getLowerNE(), new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ())},
|
||||
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ())},
|
||||
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getUpperZ() + 1)},
|
||||
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getUpperZ() + 1)}
|
||||
};
|
||||
double minX = c.getLowerX();
|
||||
double minY = c.getLowerY();
|
||||
double minZ = c.getLowerZ();
|
||||
double maxX = c.getUpperX() + 1D;
|
||||
double maxY = c.getUpperY() + 1D;
|
||||
double maxZ = c.getUpperZ() + 1D;
|
||||
double playerX = playerLoc.getX();
|
||||
double playerY = playerLoc.getY();
|
||||
double playerZ = playerLoc.getZ();
|
||||
|
||||
for (Location[] edge : edges) {
|
||||
Vector direction = edge[1].toVector().subtract(edge[0].toVector());
|
||||
double length = direction.length();
|
||||
direction.normalize();
|
||||
drawX(minX, maxX, minY, minZ, playerX, playerY, playerZ);
|
||||
drawX(minX, maxX, maxY, minZ, playerX, playerY, playerZ);
|
||||
drawX(minX, maxX, minY, maxZ, playerX, playerY, playerZ);
|
||||
drawX(minX, maxX, maxY, maxZ, playerX, playerY, playerZ);
|
||||
drawY(minY, maxY, minX, minZ, playerX, playerY, playerZ);
|
||||
drawY(minY, maxY, maxX, minZ, playerX, playerY, playerZ);
|
||||
drawY(minY, maxY, minX, maxZ, playerX, playerY, playerZ);
|
||||
drawY(minY, maxY, maxX, maxZ, playerX, playerY, playerZ);
|
||||
drawZ(minZ, maxZ, minX, minY, playerX, playerY, playerZ);
|
||||
drawZ(minZ, maxZ, maxX, minY, playerX, playerY, playerZ);
|
||||
drawZ(minZ, maxZ, minX, maxY, playerX, playerY, playerZ);
|
||||
drawZ(minZ, maxZ, maxX, maxY, playerX, playerY, playerZ);
|
||||
}
|
||||
|
||||
for (double d = 0; d <= length; d += STEP) {
|
||||
Location particleLoc = edge[0].clone().add(direction.clone().multiply(d));
|
||||
private void drawX(double start, double end, double y, double z, double playerX, double playerY, double playerZ) {
|
||||
double fixedDistanceSquared = square(playerY - y) + square(playerZ - z);
|
||||
drawAxis(start, end, playerX, fixedDistanceSquared, (double coordinate, double distanceSquared) ->
|
||||
spawnParticle(coordinate, y, z, distanceSquared));
|
||||
}
|
||||
|
||||
if (playerLoc.distanceSquared(particleLoc) > maxDistanceSquared) {
|
||||
continue;
|
||||
}
|
||||
private void drawY(double start, double end, double x, double z, double playerX, double playerY, double playerZ) {
|
||||
double fixedDistanceSquared = square(playerX - x) + square(playerZ - z);
|
||||
drawAxis(start, end, playerY, fixedDistanceSquared, (double coordinate, double distanceSquared) ->
|
||||
spawnParticle(x, coordinate, z, distanceSquared));
|
||||
}
|
||||
|
||||
spawnParticle(particleLoc, playerLoc);
|
||||
particleCount++;
|
||||
}
|
||||
private void drawZ(double start, double end, double x, double y, double playerX, double playerY, double playerZ) {
|
||||
double fixedDistanceSquared = square(playerX - x) + square(playerY - y);
|
||||
drawAxis(start, end, playerZ, fixedDistanceSquared, (double coordinate, double distanceSquared) ->
|
||||
spawnParticle(x, y, coordinate, distanceSquared));
|
||||
}
|
||||
|
||||
private void drawAxis(double start, double end, double playerCoordinate, double fixedDistanceSquared, AxisParticle particle) {
|
||||
if (fixedDistanceSquared > MAX_DISTANCE_SQUARED) {
|
||||
return;
|
||||
}
|
||||
double visibleRadius = Math.sqrt(MAX_DISTANCE_SQUARED - fixedDistanceSquared);
|
||||
double visibleStart = Math.max(start, playerCoordinate - visibleRadius);
|
||||
double visibleEnd = Math.min(end, playerCoordinate + visibleRadius);
|
||||
if (visibleStart > visibleEnd) {
|
||||
return;
|
||||
}
|
||||
int firstSample = (int) Math.max(0D, Math.ceil((visibleStart - start) / STEP));
|
||||
int lastSample = (int) Math.floor((visibleEnd - start) / STEP);
|
||||
for (int index = firstSample; index <= lastSample; index++) {
|
||||
double coordinate = start + index * STEP;
|
||||
double distanceSquared = fixedDistanceSquared + square(playerCoordinate - coordinate);
|
||||
particle.spawn(coordinate, distanceSquared);
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnParticle(Location particleLoc, Location playerLoc) {
|
||||
double accuracy = M.lerpInverse(0, 64 * 64, playerLoc.distanceSquared(particleLoc));
|
||||
private void spawnParticle(double x, double y, double z, double distanceSquared) {
|
||||
double accuracy = M.lerpInverse(0, 64 * 64, distanceSquared);
|
||||
double dist = M.lerp(0.125, 3.5, accuracy);
|
||||
|
||||
if (M.r(Math.min(dist * 5, 0.9D) * 0.995)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float hue = (float) (0.5f + (Math.sin((particleLoc.getX() + particleLoc.getY() + particleLoc.getZ() + (p.getTicksLived() / 2f)) / 20f) / 2));
|
||||
float hue = (float) (0.5f + (Math.sin((x + y + z + (p.getTicksLived() / 2f)) / 20f) / 2));
|
||||
Color color = Color.getHSBColor(hue, 1, 1);
|
||||
|
||||
p.spawnParticle(REDSTONE, particleLoc,
|
||||
p.spawnParticle(REDSTONE, x, y, z,
|
||||
0, 0, 0, 0, 1,
|
||||
new Particle.DustOptions(org.bukkit.Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()),
|
||||
(float) dist * 3f));
|
||||
}
|
||||
|
||||
private static double square(double value) {
|
||||
return value * value;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface AxisParticle {
|
||||
void spawn(double coordinate, double distanceSquared);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-27
@@ -5,44 +5,31 @@ import org.junit.Test;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CommandIrisFoliaCreateContractTest {
|
||||
@Test
|
||||
public void ordinaryFoliaCreateRestartsOnlyAfterSuccessfulStagingAndFeedback() throws Exception {
|
||||
public void ordinaryFoliaCreateUsesTheSharedRuntimeCreationPath() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.commandIrisSource")));
|
||||
String foliaCreate = source.substring(
|
||||
source.indexOf("if (J.isFolia()) {"),
|
||||
source.indexOf(" try {", source.indexOf("if (J.isFolia()) {"))
|
||||
String create = source.substring(
|
||||
source.indexOf(" public void create("),
|
||||
source.indexOf(" @Director(", source.indexOf(" public void create("))
|
||||
);
|
||||
|
||||
int stage = foliaCreate.indexOf("stageFoliaWorldCreation(worldName, dimension, seed)");
|
||||
int failureExit = foliaCreate.indexOf("if (!staged)");
|
||||
int feedback = foliaCreate.indexOf("COMMAND_IRIS_WORLD_STAGING_COMPLETED_RESTARTING_SERVER_GENERATE_LOAD");
|
||||
int restart = foliaCreate.indexOf("ServerConfigurator.restart(\"Iris staged Folia world");
|
||||
|
||||
assertTrue(stage >= 0);
|
||||
assertTrue(stage < failureExit);
|
||||
assertTrue(failureExit < feedback);
|
||||
assertTrue(feedback < restart);
|
||||
assertTrue(create.contains("IrisToolbelt.createWorld()"));
|
||||
assertTrue(create.contains(".studio(false)"));
|
||||
assertTrue(create.contains(".create();"));
|
||||
assertFalse(create.contains("J.isFolia()"));
|
||||
assertFalse(create.contains("ServerConfigurator.restart("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foliaStagePublishesCurrentPaperDataBeforeRegisteringStartupAlias() throws Exception {
|
||||
public void obsoleteFoliaStagingSurfaceIsRemoved() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.commandIrisSource")));
|
||||
int methodStart = source.indexOf("private boolean stageFoliaWorldCreation(");
|
||||
int methodEnd = source.indexOf("private boolean registerWorldInBukkitYml(", methodStart);
|
||||
String staging = source.substring(methodStart, methodEnd);
|
||||
|
||||
int currentPaperData = staging.indexOf("INMS.get().writeCurrentPaperWorldData(");
|
||||
int pack = staging.indexOf("installIntoWorld(");
|
||||
int publication = staging.indexOf("AtomicDirectoryPublisher.publishAbsent(");
|
||||
int registration = staging.indexOf("registerWorldInBukkitYml(worldKey");
|
||||
|
||||
assertTrue(currentPaperData >= 0);
|
||||
assertTrue(currentPaperData < pack);
|
||||
assertTrue(pack < publication);
|
||||
assertTrue(publication < registration);
|
||||
assertTrue(source.contains("IrisWorldStorage.configuredWorldName("));
|
||||
assertFalse(source.contains("stageFoliaWorldCreation"));
|
||||
assertFalse(source.contains("writeCurrentPaperWorldData"));
|
||||
assertFalse(source.contains("COMMAND_IRIS_RUNTIME_WORLD_CREATION_IS_DISABLED_ON_FOLIA"));
|
||||
}
|
||||
}
|
||||
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
package art.arcane.iris.core.gui;
|
||||
|
||||
import art.arcane.iris.core.runtime.WorldRuntimeControlService;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.IrisWorld;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.platform.bukkit.BukkitWorldBinding;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class BukkitVisionOverlayFoliaContractTest {
|
||||
@Test
|
||||
public void teleportLoadsTheDestinationChunkBeforeItsOwningRegionReadsTheSurface() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/gui/BukkitVisionOverlay.java"
|
||||
)).replace("\r\n", "\n");
|
||||
String request = method(source, "private void requestTeleportChunk(");
|
||||
|
||||
assertBefore(request, "requestChunkAsync(", "requested.whenComplete(");
|
||||
assertBefore(request, "requested.whenComplete(", "J.runRegion(");
|
||||
assertBefore(request, "J.runRegion(", "world.getHighestBlockYAt(");
|
||||
assertBefore(request, "world.getHighestBlockYAt(", "J.runEntity(");
|
||||
assertTrue(request.contains("chunkX,\n chunkZ,\n true,\n true"));
|
||||
assertEquals(1, occurrences(request, "world.getHighestBlockYAt("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void teleportReportsAsyncAndSchedulingFailuresWithDestinationContext() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/gui/BukkitVisionOverlay.java"
|
||||
)).replace("\r\n", "\n");
|
||||
String request = method(source, "private void requestTeleportChunk(");
|
||||
String reporter = method(source, "private void reportTeleportFailure(");
|
||||
|
||||
assertTrue(request.contains("if (requested == null)"));
|
||||
assertTrue(request.contains("if (failure != null)"));
|
||||
assertTrue(request.contains("if (chunk == null ||"));
|
||||
assertTrue(request.contains("if (!J.runEntity("));
|
||||
assertTrue(request.contains("if (!scheduled)"));
|
||||
assertTrue(reporter.contains("IrisLogging.reportError("));
|
||||
assertTrue(reporter.contains("world.getName()"));
|
||||
assertTrue(reporter.contains("blockX + \",\" + blockZ"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void teleportObservesNativeCompletionAndRejectsFalseSettlement() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/gui/BukkitVisionOverlay.java"
|
||||
)).replace("\r\n", "\n");
|
||||
String delegate = method(source, "private void delegateTeleport(");
|
||||
|
||||
assertTrue(delegate.contains("teleport.whenComplete("));
|
||||
assertTrue(delegate.contains("!Boolean.TRUE.equals(success)"));
|
||||
assertTrue(delegate.contains("restartLatest(request)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staleChunkCompletionCannotTeleportOverTheLatestRequest() {
|
||||
VisionHarness harness = new VisionHarness();
|
||||
CompletableFuture<Chunk> firstChunk = new CompletableFuture<>();
|
||||
CompletableFuture<Chunk> secondChunk = new CompletableFuture<>();
|
||||
harness.stubChunk(0, 0, firstChunk);
|
||||
harness.stubChunk(2, 2, secondChunk);
|
||||
|
||||
try (harness) {
|
||||
harness.overlay.teleport(1.5D, 1.5D);
|
||||
harness.overlay.teleport(33.5D, 33.5D);
|
||||
|
||||
firstChunk.complete(harness.chunk);
|
||||
assertEquals(0, harness.destinations.size());
|
||||
secondChunk.complete(harness.chunk);
|
||||
|
||||
assertEquals(1, harness.destinations.size());
|
||||
assertEquals(33, harness.destinations.get(0).getBlockX());
|
||||
assertEquals(33, harness.destinations.get(0).getBlockZ());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void latestRequestRunsAfterAnOlderNativeTeleportSettles() {
|
||||
VisionHarness harness = new VisionHarness();
|
||||
harness.stubChunk(0, 0, CompletableFuture.completedFuture(harness.chunk));
|
||||
harness.stubChunk(2, 2, CompletableFuture.completedFuture(harness.chunk));
|
||||
CompletableFuture<Boolean> firstTeleport = new CompletableFuture<>();
|
||||
CompletableFuture<Boolean> secondTeleport = new CompletableFuture<>();
|
||||
harness.nativeTeleports.add(firstTeleport);
|
||||
harness.nativeTeleports.add(secondTeleport);
|
||||
|
||||
try (harness) {
|
||||
harness.overlay.teleport(1.5D, 1.5D);
|
||||
harness.overlay.teleport(33.5D, 33.5D);
|
||||
assertEquals(1, harness.destinations.size());
|
||||
|
||||
firstTeleport.complete(true);
|
||||
assertEquals(2, harness.destinations.size());
|
||||
assertEquals(33, harness.destinations.get(1).getBlockX());
|
||||
assertEquals(33, harness.destinations.get(1).getBlockZ());
|
||||
secondTeleport.complete(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertBefore(String source, String first, String second) {
|
||||
int firstIndex = source.indexOf(first);
|
||||
int secondIndex = source.indexOf(second);
|
||||
assertTrue("Missing source contract token: " + first, firstIndex >= 0);
|
||||
assertTrue("Missing source contract token: " + second, secondIndex >= 0);
|
||||
assertTrue(first + " must occur before " + second, firstIndex < secondIndex);
|
||||
}
|
||||
|
||||
private static int occurrences(String source, String match) {
|
||||
int count = 0;
|
||||
int offset = 0;
|
||||
while ((offset = source.indexOf(match, offset)) >= 0) {
|
||||
count++;
|
||||
offset += match.length();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue("Missing source contract signature: " + signature, start >= 0);
|
||||
int openBrace = source.indexOf('{', start);
|
||||
assertTrue("Missing source contract method body: " + signature, openBrace >= 0);
|
||||
int depth = 0;
|
||||
for (int index = openBrace; index < source.length(); index++) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source contract method: " + signature);
|
||||
}
|
||||
|
||||
private static final class VisionHarness implements AutoCloseable {
|
||||
private final Engine engine;
|
||||
private final IrisWorld target;
|
||||
private final World world;
|
||||
private final Player player;
|
||||
private final Chunk chunk;
|
||||
private final WorldRuntimeControlService runtime;
|
||||
private final MockedStatic<J> scheduling;
|
||||
private final MockedStatic<BukkitWorldBinding> binding;
|
||||
private final MockedStatic<WorldRuntimeControlService> runtimeAccess;
|
||||
private final MockedStatic<BukkitPlatform> platform;
|
||||
private final List<Location> destinations;
|
||||
private final List<CompletableFuture<Boolean>> nativeTeleports;
|
||||
private final AtomicInteger nativeTeleportIndex;
|
||||
private final BukkitVisionOverlay overlay;
|
||||
|
||||
private VisionHarness() {
|
||||
engine = mock(Engine.class);
|
||||
target = mock(IrisWorld.class);
|
||||
world = mock(World.class);
|
||||
player = mock(Player.class);
|
||||
chunk = mock(Chunk.class);
|
||||
runtime = mock(WorldRuntimeControlService.class);
|
||||
destinations = new ArrayList<>();
|
||||
nativeTeleports = new ArrayList<>();
|
||||
nativeTeleportIndex = new AtomicInteger();
|
||||
|
||||
when(engine.getWorld()).thenReturn(target);
|
||||
when(target.hasPlatformWorld()).thenReturn(true);
|
||||
when(player.isOnline()).thenReturn(true);
|
||||
when(player.getWorld()).thenReturn(world);
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
when(world.getHighestBlockYAt(anyInt(), anyInt())).thenReturn(70);
|
||||
|
||||
scheduling = mockStatic(J.class);
|
||||
scheduling.when(() -> J.runGlobal(any(Runnable.class))).thenAnswer(invocation -> {
|
||||
invocation.getArgument(0, Runnable.class).run();
|
||||
return true;
|
||||
});
|
||||
scheduling.when(() -> J.runRegion(
|
||||
same(world),
|
||||
anyInt(),
|
||||
anyInt(),
|
||||
any(Runnable.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
invocation.getArgument(3, Runnable.class).run();
|
||||
return true;
|
||||
});
|
||||
scheduling.when(() -> J.runEntity(same(player), any(Runnable.class))).thenAnswer(invocation -> {
|
||||
invocation.getArgument(1, Runnable.class).run();
|
||||
return true;
|
||||
});
|
||||
|
||||
binding = mockStatic(BukkitWorldBinding.class);
|
||||
binding.when(() -> BukkitWorldBinding.world(target)).thenReturn(world);
|
||||
binding.when(() -> BukkitWorldBinding.players(target)).thenReturn(List.of(player));
|
||||
|
||||
runtimeAccess = mockStatic(WorldRuntimeControlService.class);
|
||||
runtimeAccess.when(WorldRuntimeControlService::get).thenReturn(runtime);
|
||||
|
||||
platform = mockStatic(BukkitPlatform.class);
|
||||
platform.when(() -> BukkitPlatform.teleportAsync(same(player), any(Location.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
destinations.add(invocation.getArgument(1, Location.class));
|
||||
int index = nativeTeleportIndex.getAndIncrement();
|
||||
return index < nativeTeleports.size()
|
||||
? nativeTeleports.get(index)
|
||||
: CompletableFuture.completedFuture(true);
|
||||
});
|
||||
overlay = new BukkitVisionOverlay(engine);
|
||||
}
|
||||
|
||||
private void stubChunk(
|
||||
int chunkX,
|
||||
int chunkZ,
|
||||
CompletableFuture<Chunk> requested
|
||||
) {
|
||||
when(runtime.requestChunkAsync(
|
||||
same(world),
|
||||
eq(chunkX),
|
||||
eq(chunkZ),
|
||||
eq(true),
|
||||
eq(true))).thenReturn(requested);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
platform.close();
|
||||
runtimeAccess.close();
|
||||
binding.close();
|
||||
scheduling.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-5
@@ -11,15 +11,14 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class StudioPlayerModeContractTest {
|
||||
@Test
|
||||
public void studioEntryKeepsPlayersEligibleForNaturalSpawning() throws IOException {
|
||||
public void autoStartedStudioUsesSpectatorMode() throws IOException {
|
||||
String plugin = Files.readString(Path.of("src/main/java/art/arcane/iris/Iris.java")).replace("\r\n", "\n");
|
||||
String commands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandStudio.java")).replace("\r\n", "\n");
|
||||
|
||||
assertFalse(plugin.contains("GameMode.SPECTATOR"));
|
||||
assertFalse(commands.contains("GameMode.SPECTATOR"));
|
||||
assertTrue(plugin.contains("GameMode.CREATIVE"));
|
||||
assertTrue(commands.contains("GameMode.CREATIVE"));
|
||||
assertFalse(plugin.contains("GameMode.CREATIVE"));
|
||||
assertFalse(commands.contains("GameMode.CREATIVE"));
|
||||
assertTrue(plugin.contains("GameMode.SPECTATOR"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -32,8 +31,23 @@ public class StudioPlayerModeContractTest {
|
||||
|
||||
assertTrue(method.contains("StudioSVC studioService = Iris.service(StudioSVC.class)"));
|
||||
assertTrue(method.contains("studioService.teleportToActiveProject(player)"));
|
||||
assertFalse(method.contains("setGameMode("));
|
||||
assertFalse(method.contains("getActiveProject()"));
|
||||
assertFalse(method.contains("BukkitPlatform.teleportAsync"));
|
||||
assertFalse(method.contains("BukkitWorldBinding.spawnLocation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editingStudiosRemainCreative() throws IOException {
|
||||
String objectCommands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandObject.java")).replace("\r\n", "\n");
|
||||
String jigsawCommands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandJigsaw.java")).replace("\r\n", "\n");
|
||||
|
||||
assertTrue(objectCommands.contains("GameMode.CREATIVE"));
|
||||
assertTrue(objectCommands.contains("StudioOpenCoordinator.StudioOpenKind.OBJECT"));
|
||||
assertTrue(jigsawCommands.contains("GameMode.CREATIVE"));
|
||||
assertFalse(objectCommands.contains("GameMode.SPECTATOR"));
|
||||
assertFalse(jigsawCommands.contains("GameMode.SPECTATOR"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public final class IrisClient {
|
||||
case IrisMessage.VisionTile visionTile -> TILES.onVisionTile(visionTile);
|
||||
case IrisMessage.VisionMarkers visionMarkers -> MARKERS.onMarkers(visionMarkers);
|
||||
case IrisMessage.PregenRegionDelta delta -> REGIONS.onDelta(delta, PREGEN.activeJobId());
|
||||
case IrisMessage.StudioHotload hotload -> TOASTS.enqueueHotload(hotload.packKey(), hotload.changedFiles(), hotload.failed(), hotload.message());
|
||||
case IrisMessage.StudioHotload hotload -> onStudioHotload(hotload);
|
||||
case IrisMessage.Toast toast -> TOASTS.enqueue(toast.kind(), toast.title(), toast.body());
|
||||
default -> {
|
||||
}
|
||||
@@ -167,4 +167,29 @@ public final class IrisClient {
|
||||
REGIONS.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void onStudioHotload(IrisMessage.StudioHotload hotload) {
|
||||
if (shouldInvalidateForHotload(DIMENSION.status(), hotload)) {
|
||||
TILES.clear();
|
||||
MARKERS.clear();
|
||||
CURSOR.clear();
|
||||
}
|
||||
TOASTS.enqueueHotload(
|
||||
hotload.packKey(),
|
||||
hotload.changedFiles(),
|
||||
hotload.failed(),
|
||||
hotload.message()
|
||||
);
|
||||
}
|
||||
|
||||
static boolean shouldInvalidateForHotload(
|
||||
IrisMessage.DimensionStatus status,
|
||||
IrisMessage.StudioHotload hotload
|
||||
) {
|
||||
return status != null
|
||||
&& status.irisWorld()
|
||||
&& hotload != null
|
||||
&& !hotload.failed()
|
||||
&& status.packKey().equals(hotload.packKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.fabric.mixin;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.fabric.FabricForcedDatapackSources;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.server.packs.repository.RepositorySource;
|
||||
@@ -26,7 +27,6 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PackRepositoryMixin {
|
||||
}
|
||||
// Client resource-pack repositories legitimately have no ServerPacksSource; a missing server-data
|
||||
// repository is reported once at boot by ModdedForcedDatapack.verifyInjected().
|
||||
LoggerFactory.getLogger("Iris").debug(
|
||||
ModdedIrisLog.debug(
|
||||
"Iris forced datapack source not attached: no ServerPacksSource among {} source(s) {}",
|
||||
sources.length, Arrays.toString(sources));
|
||||
}
|
||||
|
||||
+7
-10
@@ -82,8 +82,6 @@ import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
@@ -98,7 +96,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.IntBinaryOperator;
|
||||
|
||||
public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
// Vanilla-shaped fallback for an unbound generator (matches IrisDimension defaults). getMinY,
|
||||
// getSeaLevel and getGenDepth are called from world creation and client screens, so they must
|
||||
// answer without disk I/O and without throwing before a level is bound.
|
||||
@@ -368,7 +365,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
// Bind time: a feature-order cycle is reported here, once, and degrades to features-off. Non-waiting for
|
||||
// the same reason as repointAndBind: this method owns the generator monitor.
|
||||
importedFeatures.prepareWithoutWaiting(bound);
|
||||
LOGGER.info("Iris bound {}: chunk system {}", level.dimension().identifier(), ModdedGenPool.describeChunkSystem());
|
||||
ModdedIrisLog.info("Iris bound {}: chunk system {}", level.dimension().identifier(), ModdedGenPool.describeChunkSystem());
|
||||
}
|
||||
|
||||
private Engine bindEngine(ServerLevel level) {
|
||||
@@ -601,7 +598,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
try {
|
||||
heightMetadata = configuredPack().metadata();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.warn("Iris generator '{}' could not pre-resolve pack heights for {}:{}: {}",
|
||||
ModdedIrisLog.warn("Iris generator '{}' could not pre-resolve pack heights for {}:{}: {}",
|
||||
dimensionKey, activePack, activeDimensionKey, e.toString());
|
||||
}
|
||||
}
|
||||
@@ -726,7 +723,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
Engine generationEngine = engine();
|
||||
ChunkPos pos = chunk.getPos();
|
||||
lastChunkGenAt = System.currentTimeMillis();
|
||||
LOGGER.debug("Iris generating chunk {},{}", pos.x(), pos.z());
|
||||
ModdedIrisLog.debug("Iris generating chunk {},{}", pos.x(), pos.z());
|
||||
|
||||
PlatformBlockState air = IrisPlatforms.get().registries().air();
|
||||
|
||||
@@ -744,7 +741,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
try (GenerationSessionLease lease = generationEngine.acquireGenerationLease("modded_chunk_pipeline");
|
||||
IrisContext.Scope ignored = IrisContext.open(generationEngine, lease.sessionId(), null)) {
|
||||
if (announced.compareAndSet(false, true)) {
|
||||
LOGGER.info("Iris generating {} through IrisModdedChunkGenerator (dim={} first chunk {},{})",
|
||||
ModdedIrisLog.info("Iris generating {} through IrisModdedChunkGenerator (dim={} first chunk {},{})",
|
||||
dimensionKey, generationEngine.getDimension().getLoadKey(), pos.x(), pos.z());
|
||||
}
|
||||
int dimMinY = generationEngine.getMinHeight();
|
||||
@@ -763,14 +760,14 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
||||
return chunk;
|
||||
} catch (GenerationSessionException e) {
|
||||
if (generationEngine.isClosing() || e.isExpectedTeardown()) {
|
||||
LOGGER.debug("Iris chunk {},{} skipped: engine sealed for hotload/teardown", pos.x(), pos.z());
|
||||
ModdedIrisLog.debug("Iris chunk {},{} skipped: engine sealed for hotload/teardown", pos.x(), pos.z());
|
||||
throw new IllegalStateException(
|
||||
"Iris chunk generation was rejected during an engine transition.", e);
|
||||
}
|
||||
LOGGER.error("Iris failed to generate chunk {},{}", pos.x(), pos.z(), e);
|
||||
ModdedIrisLog.error("Iris failed to generate chunk {},{}", pos.x(), pos.z(), e);
|
||||
throw new IllegalStateException("Iris generation failed for chunk " + pos.x() + "," + pos.z(), e);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris failed to generate chunk {},{}", pos.x(), pos.z(), e);
|
||||
ModdedIrisLog.error("Iris failed to generate chunk {},{}", pos.x(), pos.z(), e);
|
||||
throw new IllegalStateException("Iris generation failed for chunk " + pos.x() + "," + pos.z(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -32,7 +30,6 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class MainWorldService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String MARKER_NAME = "mainworld.pending";
|
||||
private static final String PROPERTIES_NAME = "server.properties";
|
||||
/**
|
||||
@@ -80,12 +77,12 @@ public final class MainWorldService {
|
||||
if (!target.equals(currentType)) {
|
||||
writeLevelProperties(properties, target, config.mainWorldSeed());
|
||||
markPending();
|
||||
LOGGER.warn("Iris main world '{}' staged: {} level-type set to {}. Restart again to generate it (this boot still uses the previous overworld; player data is kept).",
|
||||
ModdedIrisLog.warn("Iris main world '{}' staged: {} level-type set to {}. Restart again to generate it (this boot still uses the previous overworld; player data is kept).",
|
||||
pack, properties, target);
|
||||
if (config.mainWorldAutoRestart()) {
|
||||
LOGGER.warn("Iris mainWorldAutoRestart is enabled; stopping the JVM now with exit status {} so a restart wrapper brings the server back on the new main world.",
|
||||
ModdedIrisLog.warn("Iris mainWorldAutoRestart is enabled; stopping the JVM now with exit status {} so a restart wrapper brings the server back on the new main world.",
|
||||
AUTO_RESTART_EXIT_STATUS);
|
||||
LOGGER.warn("Configure the start script to restart the server on exit status {} (status 0 means a clean stop, so it must not be reused for this).",
|
||||
ModdedIrisLog.warn("Configure the start script to restart the server on exit status {} (status 0 means a clean stop, so it must not be reused for this).",
|
||||
AUTO_RESTART_EXIT_STATUS);
|
||||
System.exit(AUTO_RESTART_EXIT_STATUS);
|
||||
}
|
||||
@@ -102,16 +99,16 @@ public final class MainWorldService {
|
||||
// bootstrap: there is no prior overworld to move aside, so this is nothing to quarantine, not a
|
||||
// reason to refuse startup.
|
||||
clearPending();
|
||||
LOGGER.warn("Iris main world '{}' had nothing to quarantine: {} does not exist. Continuing boot; the overworld generates as {}.",
|
||||
ModdedIrisLog.warn("Iris main world '{}' had nothing to quarantine: {} does not exist. Continuing boot; the overworld generates as {}.",
|
||||
pack, missing.path(), target);
|
||||
return;
|
||||
}
|
||||
Path recovery = quarantineVanillaDimensions(worldRoot);
|
||||
clearPending();
|
||||
LOGGER.warn("Iris main world '{}' generated fresh: moved the prior overworld/nether/end data from {} to {} so this boot regenerates them as {} (player data kept).",
|
||||
ModdedIrisLog.warn("Iris main world '{}' generated fresh: moved the prior overworld/nether/end data from {} to {} so this boot regenerates them as {} (player data kept).",
|
||||
pack, worldRoot, recovery, target);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris main world reconciliation failed", e);
|
||||
ModdedIrisLog.error("Iris main world reconciliation failed", e);
|
||||
throw new IllegalStateException(
|
||||
"Iris refused startup after main-world reconciliation failed", e);
|
||||
}
|
||||
@@ -119,7 +116,7 @@ public final class MainWorldService {
|
||||
|
||||
public static boolean stage(String packRef, long seed) {
|
||||
if (ModdedEngineBootstrap.loader().clientEnvironment()) {
|
||||
LOGGER.error("Iris main-world replacement is only available on dedicated servers; use the Create World generator selector in singleplayer");
|
||||
ModdedIrisLog.error("Iris main-world replacement is only available on dedicated servers; use the Create World generator selector in singleplayer");
|
||||
return false;
|
||||
}
|
||||
Path instanceRoot = verifiedInstanceRoot("stage the Iris main world");
|
||||
@@ -131,7 +128,7 @@ public final class MainWorldService {
|
||||
markPending();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris failed to stage the main world in server.properties", e);
|
||||
ModdedIrisLog.error("Iris failed to stage the main world in server.properties", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +137,7 @@ public final class MainWorldService {
|
||||
try {
|
||||
clearPending();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris failed to clear the pending main world marker", e);
|
||||
ModdedIrisLog.error("Iris failed to clear the pending main world marker", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +153,8 @@ public final class MainWorldService {
|
||||
if (Files.isRegularFile(workingDirectory.resolve(PROPERTIES_NAME))) {
|
||||
return workingDirectory;
|
||||
}
|
||||
LOGGER.error("Iris refuses to {}: no {} in the server working directory {}", operation, PROPERTIES_NAME, workingDirectory);
|
||||
LOGGER.error("Iris only edits main-world properties in the directory the dedicated server reads {} from, and it moves no world data outside it. Start the server from its instance directory, or clear mainWorldPack in irisworldgen/modded.json.", PROPERTIES_NAME);
|
||||
ModdedIrisLog.error("Iris refuses to {}: no {} in the server working directory {}", operation, PROPERTIES_NAME, workingDirectory);
|
||||
ModdedIrisLog.error("Iris only edits main-world properties in the directory the dedicated server reads {} from, and it moves no world data outside it. Start the server from its instance directory, or clear mainWorldPack in irisworldgen/modded.json.", PROPERTIES_NAME);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -305,7 +302,7 @@ public final class MainWorldService {
|
||||
return List.of(arguments.get());
|
||||
}
|
||||
} catch (RuntimeException unavailable) {
|
||||
LOGGER.debug("Iris could not read the process arguments", unavailable);
|
||||
ModdedIrisLog.debug("Iris could not read the process arguments", unavailable);
|
||||
}
|
||||
// Whitespace split only: sun.java.command is a flattened string with no quoting information, so a
|
||||
// --universe or --world value containing spaces cannot be recovered from it. Deliberately not parsed
|
||||
|
||||
@@ -29,8 +29,6 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -39,7 +37,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String VANILLA_FALLBACK_KEY = "minecraft:plains";
|
||||
private static final int MAX_CACHED_IDS = 4096;
|
||||
/** NUL cannot occur in a pack or registry key, so the composite cache key stays unambiguous. */
|
||||
@@ -61,7 +58,7 @@ public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
||||
return 0;
|
||||
}
|
||||
if (key == null) {
|
||||
LOGGER.warn("Iris biome writer got a null biome key; falling back to {}", VANILLA_FALLBACK_KEY);
|
||||
ModdedIrisLog.warn("Iris biome writer got a null biome key; falling back to {}", VANILLA_FALLBACK_KEY);
|
||||
return fallbackId(registry);
|
||||
}
|
||||
|
||||
@@ -217,7 +214,7 @@ public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
||||
|
||||
private void reportMissingServer(String operation, String fallback) {
|
||||
if (serverMissingReported.compareAndSet(false, true)) {
|
||||
LOGGER.warn("Iris cannot {} before the Minecraft server is available; {}", operation, fallback);
|
||||
ModdedIrisLog.warn("Iris cannot {} before the Minecraft server is available; {}", operation, fallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -43,14 +43,11 @@ import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class ModdedBlockBreakHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final ConcurrentHashMap<BreakKey, PendingBreak> PENDING = new ConcurrentHashMap<>();
|
||||
|
||||
private ModdedBlockBreakHandler() {
|
||||
@@ -72,7 +69,7 @@ public final class ModdedBlockBreakHandler {
|
||||
if (scheduler == null) {
|
||||
// finishPending is the only thing that evicts an unconsumed entry. With no scheduler there is no
|
||||
// sweep, so an entry inserted here would leak for the rest of the server uptime.
|
||||
LOGGER.debug("Iris skipped block-break provenance at {},{},{}: scheduler unavailable",
|
||||
ModdedIrisLog.debug("Iris skipped block-break provenance at {},{},{}: scheduler unavailable",
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
return;
|
||||
}
|
||||
@@ -150,7 +147,7 @@ public final class ModdedBlockBreakHandler {
|
||||
try {
|
||||
return evaluate(level, position, pending);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris block-break processing failed at {},{},{} in {}", position.getX(), position.getY(), position.getZ(),
|
||||
ModdedIrisLog.error("Iris block-break processing failed at {},{},{} in {}", position.getX(), position.getY(), position.getZ(),
|
||||
level.dimension().identifier(), error);
|
||||
return Result.empty();
|
||||
}
|
||||
@@ -182,7 +179,7 @@ public final class ModdedBlockBreakHandler {
|
||||
try {
|
||||
return evaluateDrops(level, position, brokenState, engine);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris managed block-drop processing failed at {},{},{} in {}", position.getX(), position.getY(), position.getZ(),
|
||||
ModdedIrisLog.error("Iris managed block-drop processing failed at {},{},{} in {}", position.getX(), position.getY(), position.getZ(),
|
||||
level.dimension().identifier(), error);
|
||||
return Result.empty();
|
||||
}
|
||||
@@ -315,7 +312,7 @@ public final class ModdedBlockBreakHandler {
|
||||
try {
|
||||
return irisGenerator.commandEngine();
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris could not resolve the engine for a block break in {}", level.dimension().identifier(), error);
|
||||
ModdedIrisLog.error("Iris could not resolve the engine for a block break in {}", level.dimension().identifier(), error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-14
@@ -46,8 +46,6 @@ import net.minecraft.world.level.storage.DerivedLevelData;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import net.minecraft.world.level.storage.ServerLevelData;
|
||||
import net.minecraft.world.level.storage.WorldData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -60,7 +58,6 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class ModdedDimensionManager {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Object LOCK = new Object();
|
||||
private static final ConcurrentHashMap<String, Handle> HANDLES = new ConcurrentHashMap<>();
|
||||
private static final TicketType TELEPORT_WARM_TICKET = new TicketType(TicketType.NO_TIMEOUT,
|
||||
@@ -137,7 +134,7 @@ public final class ModdedDimensionManager {
|
||||
if (present == null || !(present.getChunkSource().getGenerator() instanceof IrisModdedChunkGenerator generator)) {
|
||||
throw new IllegalStateException("Iris cannot inject dimension '" + dimensionId + "': a non-Iris level with that id is already loaded");
|
||||
}
|
||||
LOGGER.warn("Iris dimension '{}' is already present in the running server; reusing it", dimensionId);
|
||||
ModdedIrisLog.warn("Iris dimension '{}' is already present in the running server; reusing it", dimensionId);
|
||||
generator.repointAndBind(present, pack, packDimensionKey, seed);
|
||||
Handle handle = new Handle(dimensionId, pack, packDimensionKey, seed, present, generator);
|
||||
HANDLES.put(dimensionId, handle);
|
||||
@@ -147,10 +144,10 @@ public final class ModdedDimensionManager {
|
||||
try {
|
||||
Handle handle = inject(server, serverAccess, dimensionId, key, pack, packDimensionKey, seed);
|
||||
HANDLES.put(dimensionId, handle);
|
||||
LOGGER.info("Iris injected runtime dimension '{}' (pack={} dim={} seed={})", dimensionId, pack, packDimensionKey, seed);
|
||||
ModdedIrisLog.info("Iris injected runtime dimension '{}' (pack={} dim={} seed={})", dimensionId, pack, packDimensionKey, seed);
|
||||
return handle;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris failed to inject runtime dimension '{}' (pack={} dim={} seed={})", dimensionId, pack, packDimensionKey, seed, e);
|
||||
ModdedIrisLog.error("Iris failed to inject runtime dimension '{}' (pack={} dim={} seed={})", dimensionId, pack, packDimensionKey, seed, e);
|
||||
throw new IllegalStateException("Iris runtime dimension injection failed for " + dimensionId, e);
|
||||
}
|
||||
}
|
||||
@@ -233,11 +230,11 @@ public final class ModdedDimensionManager {
|
||||
if (wipeStorage) {
|
||||
ModdedDimensionStorage.wipe(server, key);
|
||||
}
|
||||
LOGGER.info("Iris removed runtime dimension '{}'", dimensionId);
|
||||
ModdedIrisLog.info("Iris removed runtime dimension '{}'", dimensionId);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
rollbackRemoval(server, serverAccess, key, level, generator, generatorUnbound, e);
|
||||
LOGGER.error("Iris failed to remove runtime dimension '{}'", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris failed to remove runtime dimension '{}'", dimensionId, e);
|
||||
throw new IllegalStateException("Iris runtime dimension removal failed for " + dimensionId, e);
|
||||
}
|
||||
}
|
||||
@@ -256,7 +253,7 @@ public final class ModdedDimensionManager {
|
||||
if (rollbackFailure != failure) {
|
||||
failure.addSuppressed(rollbackFailure);
|
||||
}
|
||||
LOGGER.error("Iris failed to restore the engine for retained runtime dimension '{}'",
|
||||
ModdedIrisLog.error("Iris failed to restore the engine for retained runtime dimension '{}'",
|
||||
key.identifier(), rollbackFailure);
|
||||
}
|
||||
}
|
||||
@@ -282,7 +279,7 @@ public final class ModdedDimensionManager {
|
||||
.whenComplete((Object result, Throwable error) -> server.execute(() -> {
|
||||
level.getChunkSource().removeTicketWithRadius(TELEPORT_WARM_TICKET, chunkPos, 1);
|
||||
if (error != null) {
|
||||
LOGGER.warn("Iris chunk warm for teleport into '{}' at {},{} failed: {}", dimensionId, chunkPos.x(), chunkPos.z(), error.toString());
|
||||
ModdedIrisLog.warn("Iris chunk warm for teleport into '{}' at {},{} failed: {}", dimensionId, chunkPos.x(), chunkPos.z(), error.toString());
|
||||
}
|
||||
ServerPlayer target = server.getPlayerList().getPlayer(playerId);
|
||||
if (target == null) {
|
||||
@@ -325,7 +322,7 @@ public final class ModdedDimensionManager {
|
||||
}
|
||||
return dimension;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris could not load pack '{}' dimension '{}' for dimension type resolution",
|
||||
ModdedIrisLog.error("Iris could not load pack '{}' dimension '{}' for dimension type resolution",
|
||||
pack, packDimensionKey, e);
|
||||
if (e instanceof Error fatalError) {
|
||||
throw fatalError;
|
||||
@@ -401,19 +398,19 @@ public final class ModdedDimensionManager {
|
||||
}
|
||||
} catch (Throwable cleanupError) {
|
||||
failure.addSuppressed(cleanupError);
|
||||
LOGGER.error("Iris failed to remove a partially injected level for {}", key.identifier(), cleanupError);
|
||||
ModdedIrisLog.error("Iris failed to remove a partially injected level for {}", key.identifier(), cleanupError);
|
||||
}
|
||||
try {
|
||||
generator.unbindEngine(level);
|
||||
} catch (Throwable cleanupError) {
|
||||
failure.addSuppressed(cleanupError);
|
||||
LOGGER.error("Iris failed to close a partially bound engine for {}", key.identifier(), cleanupError);
|
||||
ModdedIrisLog.error("Iris failed to close a partially bound engine for {}", key.identifier(), cleanupError);
|
||||
}
|
||||
try {
|
||||
level.close();
|
||||
} catch (Throwable cleanupError) {
|
||||
failure.addSuppressed(cleanupError);
|
||||
LOGGER.error("Iris failed to close a partially injected level for {}", key.identifier(), cleanupError);
|
||||
ModdedIrisLog.error("Iris failed to close a partially injected level for {}", key.identifier(), cleanupError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-11
@@ -22,8 +22,6 @@ import art.arcane.volmlib.util.json.JSONArray;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
@@ -41,7 +39,6 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class ModdedDimensionRegistryStore {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String FILE_NAME = "iris-dimensions.json";
|
||||
private static final Pattern ID_FIELD = Pattern.compile("\"id\"\\s*:\\s*\"([^\"]+)\"");
|
||||
|
||||
@@ -68,13 +65,13 @@ public final class ModdedDimensionRegistryStore {
|
||||
try {
|
||||
return load(file);
|
||||
} catch (RuntimeException corrupt) {
|
||||
LOGGER.error("Iris persistent dimension registry at {} is corrupt; quarantining it and continuing boot",
|
||||
ModdedIrisLog.error("Iris persistent dimension registry at {} is corrupt; quarantining it and continuing boot",
|
||||
file, corrupt);
|
||||
List<String> lostIds = salvageIds(file);
|
||||
if (lostIds.isEmpty()) {
|
||||
LOGGER.error("Iris could not recover any dimension ids from the corrupt registry; re-create the worlds with /iris world create");
|
||||
ModdedIrisLog.error("Iris could not recover any dimension ids from the corrupt registry; re-create the worlds with /iris world create");
|
||||
} else {
|
||||
LOGGER.error("Iris lost {} persistent dimension(s) from the corrupt registry: {}",
|
||||
ModdedIrisLog.error("Iris lost {} persistent dimension(s) from the corrupt registry: {}",
|
||||
lostIds.size(), String.join(", ", lostIds));
|
||||
}
|
||||
quarantine(file);
|
||||
@@ -93,7 +90,7 @@ public final class ModdedDimensionRegistryStore {
|
||||
}
|
||||
}
|
||||
} catch (IOException | RuntimeException unreadable) {
|
||||
LOGGER.warn("Iris could not scan the corrupt persistent dimension registry at {} for lost ids", file, unreadable);
|
||||
ModdedIrisLog.warn("Iris could not scan the corrupt persistent dimension registry at {} for lost ids", file, unreadable);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
@@ -102,9 +99,9 @@ public final class ModdedDimensionRegistryStore {
|
||||
Path broken = file.resolveSibling(FILE_NAME + ".broken-" + System.currentTimeMillis());
|
||||
try {
|
||||
Files.move(file, broken, StandardCopyOption.REPLACE_EXISTING);
|
||||
LOGGER.error("Iris moved the corrupt persistent dimension registry to {}", broken);
|
||||
ModdedIrisLog.error("Iris moved the corrupt persistent dimension registry to {}", broken);
|
||||
} catch (IOException failure) {
|
||||
LOGGER.error("Iris could not quarantine the corrupt persistent dimension registry at {}; delete it by hand",
|
||||
ModdedIrisLog.error("Iris could not quarantine the corrupt persistent dimension registry at {}; delete it by hand",
|
||||
file, failure);
|
||||
}
|
||||
}
|
||||
@@ -134,14 +131,14 @@ public final class ModdedDimensionRegistryStore {
|
||||
PersistentDimension previous = deduplicated.putIfAbsent(
|
||||
id, new PersistentDimension(id, pack, dimension, entry.getLong("seed")));
|
||||
if (previous != null) {
|
||||
LOGGER.warn("Iris persistent dimension registry entry {} in {} duplicates id '{}'; keeping the first",
|
||||
ModdedIrisLog.warn("Iris persistent dimension registry entry {} in {} duplicates id '{}'; keeping the first",
|
||||
index, file, id);
|
||||
}
|
||||
} catch (RuntimeException invalidEntry) {
|
||||
if (raw != null) {
|
||||
unparsed.add(raw);
|
||||
}
|
||||
LOGGER.warn("Iris persistent dimension registry entry {} in {} is invalid ({}); kept verbatim: {}",
|
||||
ModdedIrisLog.warn("Iris persistent dimension registry entry {} in {} is invalid ({}); kept verbatim: {}",
|
||||
index, file, invalidEntry.getMessage(), raw);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -23,8 +23,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -35,7 +33,6 @@ import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class ModdedDimensionStorage {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final List<String> CHUNK_DATA_FOLDERS = List.of("region", "entities", "poi", "mantle");
|
||||
|
||||
private ModdedDimensionStorage() {
|
||||
@@ -56,7 +53,7 @@ public final class ModdedDimensionStorage {
|
||||
"Iris failed to completely wipe dimension storage at "
|
||||
+ storageFolder.getAbsolutePath(), e);
|
||||
}
|
||||
LOGGER.info("Iris wiped dimension storage at {}", storageFolder.getAbsolutePath());
|
||||
ModdedIrisLog.info("Iris wiped dimension storage at {}", storageFolder.getAbsolutePath());
|
||||
}
|
||||
|
||||
private static void deleteRecursively(Path root) throws IOException {
|
||||
|
||||
+7
-10
@@ -55,13 +55,10 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.storage.LevelData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
public final class ModdedEngineBootstrap {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String[] CORE_SELF_TEST_CLASSES = {
|
||||
"art.arcane.iris.engine.IrisEngine",
|
||||
"art.arcane.iris.util.common.data.B",
|
||||
@@ -156,7 +153,7 @@ public final class ModdedEngineBootstrap {
|
||||
try {
|
||||
generator.unbindEngine(level);
|
||||
} catch (Throwable exception) {
|
||||
LOGGER.error("Iris engine unload failed for {}", level.dimension().identifier(), exception);
|
||||
ModdedIrisLog.error("Iris engine unload failed for {}", level.dimension().identifier(), exception);
|
||||
if (exception instanceof RuntimeException runtimeException) {
|
||||
throw runtimeException;
|
||||
}
|
||||
@@ -207,7 +204,7 @@ public final class ModdedEngineBootstrap {
|
||||
if (failure != null) {
|
||||
// The shutdown path must not propagate: propagating aborts the remaining loader stop handlers and
|
||||
// can leave the level unsaved. Every stage already logged its own failure.
|
||||
LOGGER.error("Iris modded shutdown completed with failures", failure);
|
||||
ModdedIrisLog.error("Iris modded shutdown completed with failures", failure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +213,7 @@ public final class ModdedEngineBootstrap {
|
||||
action.run();
|
||||
return failure;
|
||||
} catch (Throwable stageFailure) {
|
||||
LOGGER.error("Iris modded shutdown stage '{}' failed", stage, stageFailure);
|
||||
ModdedIrisLog.error("Iris modded shutdown stage '{}' failed", stage, stageFailure);
|
||||
if (failure == null) {
|
||||
return stageFailure;
|
||||
}
|
||||
@@ -255,7 +252,7 @@ public final class ModdedEngineBootstrap {
|
||||
BlockPos position = reconciledSpawnPosition(surfaceY, level.getMinY(), level.getHeight());
|
||||
server.setRespawnData(LevelData.RespawnData.of(
|
||||
level.dimension(), position, current.yaw(), current.pitch()));
|
||||
LOGGER.info("Iris spawn reconciled for {} at {},{},{}", dimensionId,
|
||||
ModdedIrisLog.info("Iris spawn reconciled for {} at {},{},{}", dimensionId,
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
@@ -321,7 +318,7 @@ public final class ModdedEngineBootstrap {
|
||||
Class.forName(className, true, classLoader);
|
||||
loadedClasses++;
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris core self-test failed to initialize {}", className, error);
|
||||
ModdedIrisLog.error("Iris core self-test failed to initialize {}", className, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +401,7 @@ public final class ModdedEngineBootstrap {
|
||||
ModdedIrisSplash.print(boundLoader);
|
||||
} catch (Throwable splashFailure) {
|
||||
// A cosmetic banner must never roll back the platform bind.
|
||||
LOGGER.warn("Iris splash could not be printed", splashFailure);
|
||||
ModdedIrisLog.warn("Iris splash could not be printed", splashFailure);
|
||||
}
|
||||
createdServices.enableAll();
|
||||
runtime = new BoundRuntime(created, createdServices);
|
||||
@@ -413,7 +410,7 @@ public final class ModdedEngineBootstrap {
|
||||
} catch (Throwable failure) {
|
||||
createdServices.rollback(failure);
|
||||
rollback.restore(failure);
|
||||
LOGGER.error("Iris modded platform binding failed", failure);
|
||||
ModdedIrisLog.error("Iris modded platform binding failed", failure);
|
||||
if (failure instanceof RuntimeException runtimeException) {
|
||||
throw runtimeException;
|
||||
}
|
||||
|
||||
+23
-26
@@ -39,8 +39,6 @@ import net.minecraft.server.packs.PathPackResources;
|
||||
import net.minecraft.server.packs.repository.Pack;
|
||||
import net.minecraft.server.packs.repository.PackSource;
|
||||
import net.minecraft.server.packs.repository.RepositorySource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -67,7 +65,6 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class ModdedForcedDatapack {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String PACK_ID = "iris_worldgen";
|
||||
private static final String PACK_FOLDER = "iris";
|
||||
private static final String HASH_FILE_NAME = "packs.hash";
|
||||
@@ -111,7 +108,7 @@ public final class ModdedForcedDatapack {
|
||||
return requireReadablePack(current.directory());
|
||||
} catch (RuntimeException unreadable) {
|
||||
published = null;
|
||||
LOGGER.error("Iris could not read the published forced datapack at {}; regenerating",
|
||||
ModdedIrisLog.error("Iris could not read the published forced datapack at {}; regenerating",
|
||||
current.directory(), unreadable);
|
||||
}
|
||||
}
|
||||
@@ -125,19 +122,19 @@ public final class ModdedForcedDatapack {
|
||||
reason = "stale cache (hash changed)";
|
||||
} else {
|
||||
if (hash.isEmpty() && STALE_SERVE_LOGGED.compareAndSet(false, true)) {
|
||||
LOGGER.warn("Iris cannot hash the installed packs; serving the last generated forced datapack from {} unverified",
|
||||
ModdedIrisLog.warn("Iris cannot hash the installed packs; serving the last generated forced datapack from {} unverified",
|
||||
state.directory());
|
||||
}
|
||||
try {
|
||||
return requireReadablePack(state.directory());
|
||||
} catch (RuntimeException unreadable) {
|
||||
published = null;
|
||||
LOGGER.error("Iris could not read the published forced datapack at {}; regenerating",
|
||||
ModdedIrisLog.error("Iris could not read the published forced datapack at {}; regenerating",
|
||||
state.directory(), unreadable);
|
||||
}
|
||||
reason = "unreadable published pack";
|
||||
}
|
||||
LOGGER.info("Iris forced datapack cache is unusable ({}); generating it once now", reason);
|
||||
ModdedIrisLog.info("Iris forced datapack cache is unusable ({}); generating it once now", reason);
|
||||
return buildPack();
|
||||
}
|
||||
}
|
||||
@@ -151,11 +148,11 @@ public final class ModdedForcedDatapack {
|
||||
if (packs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
LOGGER.error("===============================================================");
|
||||
LOGGER.error("Iris forced datapack '{}' was never loaded by this server.", PACK_ID);
|
||||
LOGGER.error("{} installed pack(s) at {} contributed no dimension types or custom biomes.", packs.size(), packsRoot);
|
||||
LOGGER.error("Datapack source injection failed for this loader (mixin/event not applied), so world creation will fail and restarting will not fix it.");
|
||||
LOGGER.error("===============================================================");
|
||||
ModdedIrisLog.error("===============================================================");
|
||||
ModdedIrisLog.error("Iris forced datapack '{}' was never loaded by this server.", PACK_ID);
|
||||
ModdedIrisLog.error("{} installed pack(s) at {} contributed no dimension types or custom biomes.", packs.size(), packsRoot);
|
||||
ModdedIrisLog.error("Datapack source injection failed for this loader (mixin/event not applied), so world creation will fail and restarting will not fix it.");
|
||||
ModdedIrisLog.error("===============================================================");
|
||||
}
|
||||
|
||||
public static Path datapackRoot() {
|
||||
@@ -172,7 +169,7 @@ public final class ModdedForcedDatapack {
|
||||
} catch (RuntimeException | Error generationFailure) {
|
||||
Path lastKnownGood = packDirectory();
|
||||
if (Files.isRegularFile(lastKnownGood.resolve("pack.mcmeta"))) {
|
||||
LOGGER.error("Iris kept the last known-good generated datapack after regeneration failed",
|
||||
ModdedIrisLog.error("Iris kept the last known-good generated datapack after regeneration failed",
|
||||
generationFailure);
|
||||
return requireReadablePack(lastKnownGood);
|
||||
}
|
||||
@@ -201,7 +198,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
return write();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris failed to generate the forced startup datapack", e);
|
||||
ModdedIrisLog.error("Iris failed to generate the forced startup datapack", e);
|
||||
if (e instanceof RuntimeException runtimeException) {
|
||||
throw runtimeException;
|
||||
}
|
||||
@@ -222,10 +219,10 @@ public final class ModdedForcedDatapack {
|
||||
String currentHash = packsHashOrEmpty();
|
||||
PublishedState state = publishedState();
|
||||
if (state != null && !currentHash.isEmpty() && state.packsHash().equals(currentHash)) {
|
||||
LOGGER.debug("Iris forced datapack is current ({}); skipping regeneration", reason);
|
||||
ModdedIrisLog.debug("Iris forced datapack is current ({}); skipping regeneration", reason);
|
||||
return false;
|
||||
}
|
||||
LOGGER.info("Iris regenerating the forced datapack ({})", reason);
|
||||
ModdedIrisLog.info("Iris regenerating the forced datapack ({})", reason);
|
||||
regenerate();
|
||||
return true;
|
||||
}
|
||||
@@ -240,7 +237,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
regenerateIfStale(reason);
|
||||
} catch (Throwable failure) {
|
||||
LOGGER.error("Iris forced datapack regeneration failed ({})", reason, failure);
|
||||
ModdedIrisLog.error("Iris forced datapack regeneration failed ({})", reason, failure);
|
||||
}
|
||||
};
|
||||
ModdedScheduler scheduler = ModdedEngineBootstrap.schedulerOrNull();
|
||||
@@ -301,7 +298,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
return Files.readString(hashFile, StandardCharsets.UTF_8).trim();
|
||||
} catch (IOException unreadable) {
|
||||
LOGGER.warn("Iris could not read the forced datapack hash at {}", hashFile, unreadable);
|
||||
ModdedIrisLog.warn("Iris could not read the forced datapack hash at {}", hashFile, unreadable);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -332,7 +329,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
hash = packsHash();
|
||||
} catch (IOException | RuntimeException failure) {
|
||||
LOGGER.warn("Iris could not hash the installed packs directory", failure);
|
||||
ModdedIrisLog.warn("Iris could not hash the installed packs directory", failure);
|
||||
hash = "";
|
||||
}
|
||||
packsHashMemo = new HashMemo(hash, now);
|
||||
@@ -412,9 +409,9 @@ public final class ModdedForcedDatapack {
|
||||
if (!presetIds.isEmpty()) {
|
||||
writeWorldPresetTag(stagingDirectory, presetIds);
|
||||
}
|
||||
LOGGER.info("Iris forced startup datapack staged: {} pack(s), {} world preset(s), {} custom biome(s) at {}", packCount, presetIds.size(), countBiomes(seenBiomes), stagingDirectory);
|
||||
ModdedIrisLog.info("Iris forced startup datapack staged: {} pack(s), {} world preset(s), {} custom biome(s) at {}", packCount, presetIds.size(), countBiomes(seenBiomes), stagingDirectory);
|
||||
if (packCount == 0) {
|
||||
LOGGER.warn("Iris installed NO worldgen packs into the forced datapack - custom biomes and their colors will NOT generate. Install a pack with /iris download pack=overworld, /iris download pack=underworld, or /iris download link=<zip-url>, then restart before creating an Iris world.");
|
||||
ModdedIrisLog.warn("Iris installed NO worldgen packs into the forced datapack - custom biomes and their colors will NOT generate. Install a pack with /iris download pack=overworld, /iris download pack=underworld, or /iris download link=<zip-url>, then restart before creating an Iris world.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,13 +422,13 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
validation = PackValidator.validateForDatapackBootstrap(sourcePack);
|
||||
} catch (Throwable validationFailure) {
|
||||
LOGGER.error("Iris excluded pack '{}' from Create World because validation failed",
|
||||
ModdedIrisLog.error("Iris excluded pack '{}' from Create World because validation failed",
|
||||
sourcePack.getName(), validationFailure);
|
||||
rethrowIfUnrecoverable(validationFailure);
|
||||
return false;
|
||||
}
|
||||
if (!validation.isLoadable()) {
|
||||
LOGGER.error("Iris excluded pack '{}' from Create World: {} blocking validation error(s); first error: {}",
|
||||
ModdedIrisLog.error("Iris excluded pack '{}' from Create World: {} blocking validation error(s); first error: {}",
|
||||
sourcePack.getName(), validation.getBlockingErrors().size(),
|
||||
validation.getBlockingErrors().getFirst());
|
||||
return false;
|
||||
@@ -447,7 +444,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
installed = installPack(sourcePack, fixer, packFolders, packBiomes, packPresetIds);
|
||||
} catch (Throwable installationFailure) {
|
||||
LOGGER.error("Iris excluded pack '{}' from Create World because datapack serialization failed",
|
||||
ModdedIrisLog.error("Iris excluded pack '{}' from Create World because datapack serialization failed",
|
||||
sourcePack.getName(), installationFailure);
|
||||
rethrowIfUnrecoverable(installationFailure);
|
||||
installed = false;
|
||||
@@ -465,7 +462,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
clean(packStagingDirectory);
|
||||
} catch (Throwable cleanupFailure) {
|
||||
LOGGER.warn("Iris could not remove temporary datapack staging for pack '{}'",
|
||||
ModdedIrisLog.warn("Iris could not remove temporary datapack staging for pack '{}'",
|
||||
sourcePack.getName(), cleanupFailure);
|
||||
}
|
||||
}
|
||||
@@ -728,7 +725,7 @@ public final class ModdedForcedDatapack {
|
||||
try {
|
||||
clean(backupDirectory);
|
||||
} catch (Throwable cleanupError) {
|
||||
LOGGER.warn("Iris published the forced datapack but could not remove backup {}",
|
||||
ModdedIrisLog.warn("Iris published the forced datapack but could not remove backup {}",
|
||||
backupDirectory, cleanupError);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -42,7 +40,6 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
* missing hop serializes generation on the loader's chunk threads.
|
||||
*/
|
||||
public final class ModdedGenPool {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final long SHUTDOWN_DRAIN_MILLIS = 2_000L;
|
||||
private static final String[] C2ME_MARKERS = {
|
||||
"com.ishland.c2me.base.ModProperties",
|
||||
@@ -116,7 +113,7 @@ public final class ModdedGenPool {
|
||||
if (pool.awaitTermination(SHUTDOWN_DRAIN_MILLIS, TimeUnit.MILLISECONDS)) {
|
||||
return;
|
||||
}
|
||||
LOGGER.debug("Iris gen pool did not drain in {}ms, forcing shutdown", SHUTDOWN_DRAIN_MILLIS);
|
||||
ModdedIrisLog.debug("Iris gen pool did not drain in {}ms, forcing shutdown", SHUTDOWN_DRAIN_MILLIS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
@@ -131,7 +128,7 @@ public final class ModdedGenPool {
|
||||
if (detected == null) {
|
||||
detected = new ChunkSystem(false, "vanilla");
|
||||
}
|
||||
LOGGER.info("Iris chunk system: {} (parallel={}, generation on {})",
|
||||
ModdedIrisLog.info("Iris chunk system: {} (parallel={}, generation on {})",
|
||||
detected.description(),
|
||||
detected.parallel() ? "yes" : "no",
|
||||
detected.parallel() ? "loader threads" : "Iris gen pool");
|
||||
@@ -182,7 +179,7 @@ public final class ModdedGenPool {
|
||||
try {
|
||||
value = field.get(null);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not read {}.{}: {}", configClass.getName(), section, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not read {}.{}: {}", configClass.getName(), section, e.toString());
|
||||
continue;
|
||||
}
|
||||
if (value instanceof Boolean flag) {
|
||||
@@ -209,7 +206,7 @@ public final class ModdedGenPool {
|
||||
return flag;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not read {}.{}: {}", type.getName(), name, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not read {}.{}: {}", type.getName(), name, e.toString());
|
||||
}
|
||||
}
|
||||
Method method = declaredMethodOrNull(type, name);
|
||||
@@ -219,7 +216,7 @@ public final class ModdedGenPool {
|
||||
return flag;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not call {}.{}(): {}", type.getName(), name, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not call {}.{}(): {}", type.getName(), name, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,7 +238,7 @@ public final class ModdedGenPool {
|
||||
return number.intValue();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not read {}.{}: {}", marker.getName(), name, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not read {}.{}: {}", marker.getName(), name, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +251,7 @@ public final class ModdedGenPool {
|
||||
try {
|
||||
pool = field.get(null);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not read {}.{}: {}", marker.getName(), poolName, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not read {}.{}: {}", marker.getName(), poolName, e.toString());
|
||||
continue;
|
||||
}
|
||||
if (pool == null) {
|
||||
@@ -281,7 +278,7 @@ public final class ModdedGenPool {
|
||||
return number.intValue();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not call {}.{}(): {}", current.getName(), name, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not call {}.{}(): {}", current.getName(), name, e.toString());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -305,7 +302,7 @@ public final class ModdedGenPool {
|
||||
} catch (NoSuchFieldException e) {
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not access field {}.{}: {}", type.getName(), name, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not access field {}.{}: {}", type.getName(), name, e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -318,7 +315,7 @@ public final class ModdedGenPool {
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe could not access method {}.{}(): {}", type.getName(), name, e.toString());
|
||||
ModdedIrisLog.debug("Iris chunk system probe could not access method {}.{}(): {}", type.getName(), name, e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -336,7 +333,7 @@ public final class ModdedGenPool {
|
||||
try {
|
||||
return Class.forName(name, false, ModdedGenPool.class.getClassLoader());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris chunk system probe: {} absent ({})", name, e.getClass().getSimpleName());
|
||||
ModdedIrisLog.debug("Iris chunk system probe: {} absent ({})", name, e.getClass().getSimpleName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-9
@@ -46,8 +46,6 @@ import net.minecraft.world.level.levelgen.RandomSupport;
|
||||
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
||||
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -76,7 +74,6 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* {@link #generationSettings} answers exactly what vanilla's default getter answers.
|
||||
*/
|
||||
final class ModdedImportedFeatureStage {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String CYCLE_MARKER = "Feature order cycle found";
|
||||
private static final long NO_GENERATION = Long.MIN_VALUE;
|
||||
|
||||
@@ -179,7 +176,7 @@ final class ModdedImportedFeatureStage {
|
||||
try {
|
||||
control = NativeFeatureGenerationPolicy.control(engine);
|
||||
} catch (RuntimeException error) {
|
||||
LOGGER.error("Iris could not read importedFeatures for this dimension; features off: {}",
|
||||
ModdedIrisLog.error("Iris could not read importedFeatures for this dimension; features off: {}",
|
||||
error.toString());
|
||||
markInert(generation);
|
||||
return;
|
||||
@@ -193,7 +190,7 @@ final class ModdedImportedFeatureStage {
|
||||
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
||||
built = buildTable(engine, control, generation);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris importedFeatures is off for {}: feature table construction failed: {}",
|
||||
ModdedIrisLog.error("Iris importedFeatures is off for {}: feature table construction failed: {}",
|
||||
dimensionKey(engine), error.toString());
|
||||
markInert(generation);
|
||||
return;
|
||||
@@ -207,7 +204,7 @@ final class ModdedImportedFeatureStage {
|
||||
// Arm the worldcheck log watch here, before any chunk decorates: arming from the first pass instead
|
||||
// missed every far-chunk write the first chunk made. No-op unless -Diris.worldcheck is set.
|
||||
WorldCheckFeaturePlacement.arm();
|
||||
LOGGER.info("Iris importedFeatures on for {}: {} biomes, {} steps, {} custom-biome derivative maps",
|
||||
ModdedIrisLog.info("Iris importedFeatures on for {}: {} biomes, {} steps, {} custom-biome derivative maps",
|
||||
dimensionKey(engine), built.biomes().size(), built.steps().size(),
|
||||
built.derivatives().size());
|
||||
}
|
||||
@@ -222,7 +219,7 @@ final class ModdedImportedFeatureStage {
|
||||
// detection depend on JVM hash order and turns a real cycle into an intermittent one.
|
||||
List<Holder<Biome>> biomes = biomeSource.orderedPossibleBiomes();
|
||||
if (biomes.isEmpty()) {
|
||||
LOGGER.error("Iris importedFeatures is on but {} exposes no biomes; features off",
|
||||
ModdedIrisLog.error("Iris importedFeatures is on but {} exposes no biomes; features off",
|
||||
dimensionKey(engine));
|
||||
return null;
|
||||
}
|
||||
@@ -245,7 +242,7 @@ final class ModdedImportedFeatureStage {
|
||||
if (message == null || !message.contains(CYCLE_MARKER)) {
|
||||
throw error;
|
||||
}
|
||||
LOGGER.error("Iris importedFeatures is off for {}: the registered placed features cannot be ordered."
|
||||
ModdedIrisLog.error("Iris importedFeatures is off for {}: the registered placed features cannot be ordered."
|
||||
+ " {}. Remove or reorder the conflicting content, or leave"
|
||||
+ " importedFeatures.enabled false.",
|
||||
dimensionKey(engine), message);
|
||||
@@ -276,7 +273,7 @@ final class ModdedImportedFeatureStage {
|
||||
derivative = biomeSource.registeredBiome(derivativeKey);
|
||||
}
|
||||
if (derivative == null) {
|
||||
LOGGER.warn("Iris importedFeatures: vanilla derivative {} of biome {} is not registered;"
|
||||
ModdedIrisLog.warn("Iris importedFeatures: vanilla derivative {} of biome {} is not registered;"
|
||||
+ " its custom biomes generate no imported features",
|
||||
derivativeKey, irisBiome.getLoadKey());
|
||||
continue;
|
||||
|
||||
@@ -54,18 +54,55 @@ public final class ModdedIrisLog {
|
||||
LOGGER.info("[Iris/DEBUG] " + clean(message));
|
||||
}
|
||||
|
||||
public static void debug(String format, Object... arguments) {
|
||||
RenderedLog rendered = render(format, arguments);
|
||||
if (rendered.error() == null) {
|
||||
debug(rendered.message());
|
||||
return;
|
||||
}
|
||||
if (!debugEnabled()) {
|
||||
LOGGER.debug(clean(rendered.message()), rendered.error());
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.info("[Iris/DEBUG] " + clean(rendered.message()), rendered.error());
|
||||
}
|
||||
|
||||
public static void info(String message) {
|
||||
LOGGER.info(clean(message));
|
||||
}
|
||||
|
||||
public static void info(String format, Object... arguments) {
|
||||
RenderedLog rendered = render(format, arguments);
|
||||
if (rendered.error() != null) {
|
||||
LOGGER.info(clean(rendered.message()), rendered.error());
|
||||
return;
|
||||
}
|
||||
info(rendered.message());
|
||||
}
|
||||
|
||||
public static void warn(String message) {
|
||||
LOGGER.warn(clean(message));
|
||||
}
|
||||
|
||||
public static void warn(String format, Object... arguments) {
|
||||
RenderedLog rendered = render(format, arguments);
|
||||
if (rendered.error() != null) {
|
||||
LOGGER.warn(clean(rendered.message()), rendered.error());
|
||||
return;
|
||||
}
|
||||
warn(rendered.message());
|
||||
}
|
||||
|
||||
public static void error(String message) {
|
||||
LOGGER.error(clean(message));
|
||||
}
|
||||
|
||||
public static void error(String format, Object... arguments) {
|
||||
RenderedLog rendered = render(format, arguments);
|
||||
error(rendered.message(), rendered.error());
|
||||
}
|
||||
|
||||
public static void error(String message, Throwable error) {
|
||||
if (error == null) {
|
||||
error(message);
|
||||
@@ -79,6 +116,34 @@ public final class ModdedIrisLog {
|
||||
return IrisLogging.clean(message);
|
||||
}
|
||||
|
||||
static RenderedLog render(String format, Object... arguments) {
|
||||
String source = format == null ? "null" : format;
|
||||
if (arguments == null || arguments.length == 0) {
|
||||
return new RenderedLog(source, null);
|
||||
}
|
||||
|
||||
int argumentCount = arguments.length;
|
||||
Throwable error = arguments[argumentCount - 1] instanceof Throwable throwable ? throwable : null;
|
||||
if (error != null) {
|
||||
argumentCount--;
|
||||
}
|
||||
|
||||
StringBuilder output = new StringBuilder(source.length() + argumentCount * 8);
|
||||
int cursor = 0;
|
||||
int argumentIndex = 0;
|
||||
while (argumentIndex < argumentCount) {
|
||||
int placeholder = source.indexOf("{}", cursor);
|
||||
if (placeholder < 0) {
|
||||
break;
|
||||
}
|
||||
output.append(source, cursor, placeholder);
|
||||
output.append(String.valueOf(arguments[argumentIndex++]));
|
||||
cursor = placeholder + 2;
|
||||
}
|
||||
output.append(source, cursor, source.length());
|
||||
return new RenderedLog(output.toString(), error);
|
||||
}
|
||||
|
||||
private static boolean debugEnabled() {
|
||||
try {
|
||||
IrisSettings settings = IrisSettings.settings != null ? IrisSettings.settings : IrisSettings.get();
|
||||
@@ -97,4 +162,7 @@ public final class ModdedIrisLog {
|
||||
DEBUG_SETTING_WARNING_LOGGED = true;
|
||||
LOGGER.warn("Iris debug logging setting could not be read", error);
|
||||
}
|
||||
|
||||
record RenderedLog(String message, Throwable error) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -40,7 +38,6 @@ import java.util.function.BooleanSupplier;
|
||||
* references and is safe on a dedicated server.
|
||||
*/
|
||||
public final class ModdedMixinAudit {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final AtomicBoolean AUDITED = new AtomicBoolean(false);
|
||||
|
||||
private static final List<ExpectedMixin> EXPECTED = List.of(
|
||||
@@ -95,20 +92,20 @@ public final class ModdedMixinAudit {
|
||||
}
|
||||
}
|
||||
if (missing.isEmpty()) {
|
||||
LOGGER.info("Iris mixin audit ok on {} ({} dist): {}", platform,
|
||||
ModdedIrisLog.info("Iris mixin audit ok on {} ({} dist): {}", platform,
|
||||
clientEnvironment ? "client" : "server", String.join(", ", applied));
|
||||
return;
|
||||
}
|
||||
LOGGER.error("===============================================================");
|
||||
LOGGER.error("Iris mixin audit FAILED on {} ({} dist): {} of {} expected mixin(s) were not applied.",
|
||||
ModdedIrisLog.error("===============================================================");
|
||||
ModdedIrisLog.error("Iris mixin audit FAILED on {} ({} dist): {} of {} expected mixin(s) were not applied.",
|
||||
platform, clientEnvironment ? "client" : "server", missing.size(),
|
||||
missing.size() + applied.size());
|
||||
for (String entry : missing) {
|
||||
LOGGER.error(" missing: {}", entry);
|
||||
ModdedIrisLog.error(" missing: {}", entry);
|
||||
}
|
||||
LOGGER.error("The mixin config was not registered for this loader (fabric.mod.json mixins, neoforge.mods.toml [[mixins]], forge MixinConfigs manifest attribute).");
|
||||
LOGGER.error("Entity persistence, custom mob loot, parallel structure safety, or Iris world-type labels are disabled until this is fixed.");
|
||||
LOGGER.error("===============================================================");
|
||||
ModdedIrisLog.error("The mixin config was not registered for this loader (fabric.mod.json mixins, neoforge.mods.toml [[mixins]], forge MixinConfigs manifest attribute).");
|
||||
ModdedIrisLog.error("Entity persistence, custom mob loot, parallel structure safety, or Iris world-type labels are disabled until this is fixed.");
|
||||
ModdedIrisLog.error("===============================================================");
|
||||
}
|
||||
|
||||
private static boolean isApplied(ExpectedMixin expected) {
|
||||
@@ -126,7 +123,7 @@ public final class ModdedMixinAudit {
|
||||
}
|
||||
return false;
|
||||
} catch (ClassNotFoundException | LinkageError unavailable) {
|
||||
LOGGER.warn("Iris mixin audit could not inspect {}", expected.targetClass(), unavailable);
|
||||
ModdedIrisLog.warn("Iris mixin audit could not inspect {}", expected.targetClass(), unavailable);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,8 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class ModdedModConfig {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile ModdedModConfig instance;
|
||||
|
||||
@@ -128,7 +125,7 @@ public final class ModdedModConfig {
|
||||
json.optLong("mainWorldSeed", defaults.mainWorldSeed),
|
||||
json.optBoolean("mainWorldAutoRestart", defaults.mainWorldAutoRestart));
|
||||
} catch (RuntimeException | IOException e) {
|
||||
LOGGER.error("Iris modded config at {} is invalid; using defaults", file, e);
|
||||
ModdedIrisLog.error("Iris modded config at {} is invalid; using defaults", file, e);
|
||||
return defaults;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +142,7 @@ public final class ModdedModConfig {
|
||||
Files.createDirectories(file.getParent());
|
||||
Files.writeString(file, json.toString(4), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris failed to write modded config at {}", file, e);
|
||||
ModdedIrisLog.error("Iris failed to write modded config at {}", file, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-25
@@ -29,8 +29,6 @@ import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -48,7 +46,6 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public final class ModdedParityProbe {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String DIMENSION_KEY = "overworld";
|
||||
private static final long SEED = 1337L;
|
||||
private static final int BIOME_STEP = 4;
|
||||
@@ -82,7 +79,7 @@ public final class ModdedParityProbe {
|
||||
}
|
||||
|
||||
if (server == null) {
|
||||
LOGGER.error("[parity] server did not become ready within 10 minutes");
|
||||
ModdedIrisLog.error("[parity] server did not become ready within 10 minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,10 +87,10 @@ public final class ModdedParityProbe {
|
||||
try {
|
||||
match = run(server, config);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("[parity] probe failed", e);
|
||||
ModdedIrisLog.error("[parity] probe failed", e);
|
||||
}
|
||||
|
||||
LOGGER.info("[parity] shutting down dev server (result={})", match ? "MATCH" : "MISMATCH");
|
||||
ModdedIrisLog.info("[parity] shutting down dev server (result={})", match ? "MATCH" : "MISMATCH");
|
||||
server.halt(false);
|
||||
}
|
||||
|
||||
@@ -112,7 +109,7 @@ public final class ModdedParityProbe {
|
||||
|
||||
File packSource = new File(packPath);
|
||||
if (!packSource.isDirectory()) {
|
||||
LOGGER.error("[parity] pack folder not found: {}", packSource.getAbsolutePath());
|
||||
ModdedIrisLog.error("[parity] pack folder not found: {}", packSource.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,14 +118,14 @@ public final class ModdedParityProbe {
|
||||
|
||||
File workRoot = Files.createTempDirectory("iris-parity").toFile();
|
||||
File pack = clonePack(packSource, workRoot);
|
||||
LOGGER.info("[parity] pack: {}", packSource.getAbsolutePath());
|
||||
LOGGER.info("[parity] work copy: {}", pack.getAbsolutePath());
|
||||
LOGGER.info("[parity] radius: {} ({} chunks)", radius, (2 * radius + 1) * (2 * radius + 1));
|
||||
ModdedIrisLog.info("[parity] pack: {}", packSource.getAbsolutePath());
|
||||
ModdedIrisLog.info("[parity] work copy: {}", pack.getAbsolutePath());
|
||||
ModdedIrisLog.info("[parity] radius: {} ({} chunks)", radius, (2 * radius + 1) * (2 * radius + 1));
|
||||
|
||||
IrisData data = IrisData.get(pack);
|
||||
IrisDimension dimension = data.getDimensionLoader().load(DIMENSION_KEY);
|
||||
if (dimension == null) {
|
||||
LOGGER.error("[parity] dimension '{}' did not load from {}", DIMENSION_KEY, pack.getAbsolutePath());
|
||||
ModdedIrisLog.error("[parity] dimension '{}' did not load from {}", DIMENSION_KEY, pack.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -147,7 +144,7 @@ public final class ModdedParityProbe {
|
||||
int minY = dimension.getMinHeight();
|
||||
int maxY = dimension.getMaxHeight();
|
||||
int height = maxY - minY;
|
||||
LOGGER.info("[parity] engine up: dim={} seed={} minY={} maxY={}", engine.getDimension().getLoadKey(), engine.getSeedManager().getSeed(), minY, maxY);
|
||||
ModdedIrisLog.info("[parity] engine up: dim={} seed={} minY={} maxY={}", engine.getDimension().getLoadKey(), engine.getSeedManager().getSeed(), minY, maxY);
|
||||
|
||||
Map<String, String> goldenChunks = new HashMap<>();
|
||||
String goldenCombined = null;
|
||||
@@ -173,7 +170,7 @@ public final class ModdedParityProbe {
|
||||
goldenChunks.put(line.substring(0, second), line);
|
||||
}
|
||||
}
|
||||
LOGGER.info("[parity] golden: {} ({} chunks, combined={})", goldenPath, goldenChunks.size(), goldenCombined);
|
||||
ModdedIrisLog.info("[parity] golden: {} ({} chunks, combined={})", goldenPath, goldenChunks.size(), goldenCombined);
|
||||
}
|
||||
|
||||
PlatformBlockState airState = IrisPlatforms.get().registries().air();
|
||||
@@ -198,9 +195,9 @@ public final class ModdedParityProbe {
|
||||
|
||||
if (!failures.isEmpty()) {
|
||||
failed++;
|
||||
LOGGER.error("[parity] chunk {},{} FAILED ({} error(s))", cx, cz, failures.size());
|
||||
ModdedIrisLog.error("[parity] chunk {},{} FAILED ({} error(s))", cx, cz, failures.size());
|
||||
for (Throwable failure : failures) {
|
||||
LOGGER.error("[parity] chunk {},{} error", cx, cz, failure);
|
||||
ModdedIrisLog.error("[parity] chunk {},{} error", cx, cz, failure);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -212,9 +209,9 @@ public final class ModdedParityProbe {
|
||||
String golden = goldenChunks.get(key);
|
||||
if (golden != null && !golden.equals(line)) {
|
||||
mismatches.add(key);
|
||||
LOGGER.warn("[parity] chunk {} MISMATCH", key);
|
||||
LOGGER.warn("[parity] golden: {}", golden);
|
||||
LOGGER.warn("[parity] actual: {}", line);
|
||||
ModdedIrisLog.warn("[parity] chunk {} MISMATCH", key);
|
||||
ModdedIrisLog.warn("[parity] golden: {}", golden);
|
||||
ModdedIrisLog.warn("[parity] actual: {}", line);
|
||||
if (mismatches.size() == 1) {
|
||||
diffDeep(cx, cz, blocks, height, minY);
|
||||
}
|
||||
@@ -231,9 +228,9 @@ public final class ModdedParityProbe {
|
||||
boolean match = goldenChunks.isEmpty() ? combinedMatch : (chunkMatch && (radius != 8 || combinedMatch));
|
||||
|
||||
if (!goldenChunks.isEmpty()) {
|
||||
LOGGER.info("[parity] per-chunk: {}/{} matched golden ({} failed)", body.size() - mismatches.size(), body.size(), failed);
|
||||
ModdedIrisLog.info("[parity] per-chunk: {}/{} matched golden ({} failed)", body.size() - mismatches.size(), body.size(), failed);
|
||||
}
|
||||
LOGGER.info("[parity] combined={} expected={} {} ({}/{})",
|
||||
ModdedIrisLog.info("[parity] combined={} expected={} {} ({}/{})",
|
||||
combined.substring(0, 12), expected, match ? "MATCH" : "MISMATCH", body.size() - mismatches.size(), targets.size());
|
||||
return match;
|
||||
}
|
||||
@@ -246,7 +243,7 @@ public final class ModdedParityProbe {
|
||||
try {
|
||||
Path goldenDump = Path.of(deepDir, cx + "_" + cz + ".txt");
|
||||
if (!Files.exists(goldenDump)) {
|
||||
LOGGER.warn("[parity] no deep dump for chunk {},{} at {}", cx, cz, goldenDump);
|
||||
ModdedIrisLog.warn("[parity] no deep dump for chunk {},{} at {}", cx, cz, goldenDump);
|
||||
return;
|
||||
}
|
||||
List<String> golden = Files.readAllLines(goldenDump, StandardCharsets.UTF_8);
|
||||
@@ -267,15 +264,15 @@ public final class ModdedParityProbe {
|
||||
String g = i < golden.size() ? golden.get(i) : "<missing>";
|
||||
String a = i < actual.size() ? actual.get(i) : "<missing>";
|
||||
if (!g.equals(a)) {
|
||||
LOGGER.warn("[parity] deep diff line {}: golden='{}' actual='{}'", i, g, a);
|
||||
ModdedIrisLog.warn("[parity] deep diff line {}: golden='{}' actual='{}'", i, g, a);
|
||||
shown++;
|
||||
}
|
||||
}
|
||||
File out = new File(IrisPlatforms.get().dataFolder("parity"), "deep-" + cx + "_" + cz + ".txt");
|
||||
Files.write(out.toPath(), actual, StandardCharsets.UTF_8);
|
||||
LOGGER.warn("[parity] full actual dump: {}", out.getAbsolutePath());
|
||||
ModdedIrisLog.warn("[parity] full actual dump: {}", out.getAbsolutePath());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.warn("[parity] deep diff failed", e);
|
||||
ModdedIrisLog.warn("[parity] deep diff failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +364,7 @@ public final class ModdedParityProbe {
|
||||
}
|
||||
} else {
|
||||
for (Throwable error : batch) {
|
||||
LOGGER.warn("[parity] engine-init reported error (non-fatal)", error);
|
||||
ModdedIrisLog.warn("[parity] engine-init reported error (non-fatal)", error);
|
||||
}
|
||||
quietSince = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
+1
-4
@@ -21,8 +21,6 @@ package art.arcane.iris.modded;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -31,7 +29,6 @@ import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class ModdedPrimaryWorldRouter {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int TICK_INTERVAL = 20;
|
||||
|
||||
private static final Set<UUID> routed = ConcurrentHashMap.newKeySet();
|
||||
@@ -96,7 +93,7 @@ public final class ModdedPrimaryWorldRouter {
|
||||
ModdedDimensionManager.teleport(player, server, primary, player.getX(), Double.MIN_VALUE, player.getZ());
|
||||
routed.add(id);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris failed to route player {} to primary world '{}'", id, primary, e);
|
||||
ModdedIrisLog.error("Iris failed to route player {} to primary world '{}'", id, primary, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-4
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.core.protocol.EngineResolver;
|
||||
import art.arcane.iris.core.protocol.IrisCursorRequestService;
|
||||
import art.arcane.iris.core.protocol.IrisProtocolServer;
|
||||
import art.arcane.iris.core.protocol.IrisSession;
|
||||
import art.arcane.iris.core.protocol.IrisSessionRegistry;
|
||||
@@ -30,8 +31,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
@@ -43,7 +42,6 @@ public final class ModdedProtocolHandler {
|
||||
| IrisProtocol.CAPABILITY_CURSOR
|
||||
| IrisProtocol.CAPABILITY_STUDIO;
|
||||
private static final int DIMENSION_SYNC_INTERVAL_TICKS = 5;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private static final ConcurrentHashMap<String, Engine> SESSION_ENGINES = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, String> SESSION_LEVELS = new ConcurrentHashMap<>();
|
||||
@@ -53,6 +51,7 @@ public final class ModdedProtocolHandler {
|
||||
private static volatile IrisSessionRegistry registry;
|
||||
private static volatile IrisProtocolServer protocolServer;
|
||||
private static volatile ModdedProtocolTransport transport;
|
||||
private static volatile IrisCursorRequestService cursorRequests;
|
||||
private static volatile IrisVisionRequestService visionRequests;
|
||||
private static int dimensionSyncTicks;
|
||||
|
||||
@@ -80,11 +79,14 @@ public final class ModdedProtocolHandler {
|
||||
return engine == null || engine.isClosed() ? null : engine;
|
||||
};
|
||||
protocol.setEngineResolver(engineResolver);
|
||||
IrisCursorRequestService cursorService = IrisCursorRequestService.create(engineResolver, sessionRegistry);
|
||||
protocol.setCursorInfoHandler(cursorService);
|
||||
IrisVisionRequestService visionService = IrisVisionRequestService.create(engineResolver, sessionRegistry);
|
||||
protocol.setVisionTileHandler(visionService);
|
||||
registry = sessionRegistry;
|
||||
transport = serverTransport;
|
||||
protocolServer = protocol;
|
||||
cursorRequests = cursorService;
|
||||
visionRequests = visionService;
|
||||
IrisServices.register(IrisProtocolServer.class, protocol);
|
||||
if (server.getPlayerList() == null) {
|
||||
@@ -98,10 +100,14 @@ public final class ModdedProtocolHandler {
|
||||
public static void stop() {
|
||||
IrisServices.remove(IrisProtocolServer.class);
|
||||
IrisSessionRegistry current = registry;
|
||||
IrisCursorRequestService cursor = cursorRequests;
|
||||
IrisVisionRequestService vision = visionRequests;
|
||||
if (current != null) {
|
||||
for (IrisSession session : current.all()) {
|
||||
current.unregister(session.id());
|
||||
if (cursor != null) {
|
||||
cursor.clearSession(session.id());
|
||||
}
|
||||
if (vision != null) {
|
||||
vision.clearSession(session.id());
|
||||
}
|
||||
@@ -114,6 +120,7 @@ public final class ModdedProtocolHandler {
|
||||
registry = null;
|
||||
protocolServer = null;
|
||||
transport = null;
|
||||
cursorRequests = null;
|
||||
visionRequests = null;
|
||||
}
|
||||
|
||||
@@ -147,6 +154,10 @@ public final class ModdedProtocolHandler {
|
||||
if (current != null) {
|
||||
current.unregister(sessionId);
|
||||
}
|
||||
IrisCursorRequestService cursor = cursorRequests;
|
||||
if (cursor != null) {
|
||||
cursor.clearSession(sessionId);
|
||||
}
|
||||
IrisVisionRequestService vision = visionRequests;
|
||||
if (vision != null) {
|
||||
vision.clearSession(sessionId);
|
||||
@@ -229,7 +240,7 @@ public final class ModdedProtocolHandler {
|
||||
Engine engine = generator.engineIfBound();
|
||||
return engine == null || engine.isClosed() ? null : engine;
|
||||
} catch (Throwable failure) {
|
||||
LOGGER.error("Iris dimension status engine lookup failed for {}", level.dimension().identifier(), failure);
|
||||
ModdedIrisLog.error("Iris dimension status engine lookup failed for {}", level.dimension().identifier(), failure);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ package art.arcane.iris.modded;
|
||||
import art.arcane.iris.spi.PlatformScheduler;
|
||||
import art.arcane.iris.spi.PlatformWorld;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -41,7 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public final class ModdedScheduler implements PlatformScheduler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int ASYNC_MAX_THREADS = Math.max(4, Runtime.getRuntime().availableProcessors());
|
||||
private static final long ASYNC_KEEP_ALIVE_SECONDS = 30L;
|
||||
private static final int ASYNC_BACKLOG_WARN = 8192;
|
||||
@@ -85,10 +82,10 @@ public final class ModdedScheduler implements PlatformScheduler {
|
||||
rejectionAwareTask.reject();
|
||||
}
|
||||
if (executor.isShutdown()) {
|
||||
LOGGER.debug("Iris async task dropped: scheduler is shut down");
|
||||
ModdedIrisLog.debug("Iris async task dropped: scheduler is shut down");
|
||||
return;
|
||||
}
|
||||
LOGGER.error("Iris async task rejected by the executor (queued={} active={})",
|
||||
ModdedIrisLog.error("Iris async task rejected by the executor (queued={} active={})",
|
||||
executor.getQueue().size(), executor.getActiveCount());
|
||||
};
|
||||
}
|
||||
@@ -217,7 +214,7 @@ public final class ModdedScheduler implements PlatformScheduler {
|
||||
if (now - last < ASYNC_BACKLOG_WARN_INTERVAL_MILLIS || !lastBacklogWarnAt.compareAndSet(last, now)) {
|
||||
return;
|
||||
}
|
||||
LOGGER.warn("Iris async backlog {} tasks (threads={}); async work is falling behind", queued, executor.getPoolSize());
|
||||
ModdedIrisLog.warn("Iris async backlog {} tasks (threads={}); async work is falling behind", queued, executor.getPoolSize());
|
||||
}
|
||||
|
||||
private void drain() {
|
||||
@@ -262,7 +259,7 @@ public final class ModdedScheduler implements PlatformScheduler {
|
||||
try {
|
||||
task.run();
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris scheduled task failed", error);
|
||||
ModdedIrisLog.error("Iris scheduled task failed", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -35,7 +33,6 @@ import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ModdedServerLevels implements ModdedServerAccess {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int CAPTURE_ATTEMPTS = 16;
|
||||
private static volatile Snapshot snapshot;
|
||||
|
||||
@@ -125,7 +122,7 @@ public final class ModdedServerLevels implements ModdedServerAccess {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
LOGGER.error("Iris could not snapshot the level map after {} attempts; readers will see the previous snapshot", CAPTURE_ATTEMPTS);
|
||||
ModdedIrisLog.error("Iris could not snapshot the level map after {} attempts; readers will see the previous snapshot", CAPTURE_ATTEMPTS);
|
||||
Snapshot current = snapshot;
|
||||
return current != null && current.server() == server ? current : null;
|
||||
}
|
||||
|
||||
+5
-8
@@ -21,14 +21,11 @@ package art.arcane.iris.modded;
|
||||
import art.arcane.iris.modded.service.ModdedService;
|
||||
import art.arcane.iris.modded.service.ModdedTickableService;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class ModdedServiceManager {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private final Map<Class<? extends ModdedService>, ModdedService> services = new LinkedHashMap<>();
|
||||
private boolean enabled = false;
|
||||
@@ -103,7 +100,7 @@ public final class ModdedServiceManager {
|
||||
service.onDisable();
|
||||
} catch (Throwable serviceFailure) {
|
||||
failed++;
|
||||
LOGGER.error("Iris service onDisable failed for {}", service.getClass().getName(), serviceFailure);
|
||||
ModdedIrisLog.error("Iris service onDisable failed for {}", service.getClass().getName(), serviceFailure);
|
||||
if (failure == null) {
|
||||
failure = serviceFailure;
|
||||
} else if (serviceFailure != failure) {
|
||||
@@ -113,7 +110,7 @@ public final class ModdedServiceManager {
|
||||
}
|
||||
enabled = false;
|
||||
if (failure != null) {
|
||||
LOGGER.error("Iris disabled all services with {} failure(s)", failed, failure);
|
||||
ModdedIrisLog.error("Iris disabled all services with {} failure(s)", failed, failure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +129,7 @@ public final class ModdedServiceManager {
|
||||
try {
|
||||
service.onServerTick(server);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris service tick failed for {}", service.getClass().getName(), error);
|
||||
ModdedIrisLog.error("Iris service tick failed for {}", service.getClass().getName(), error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,12 +140,12 @@ public final class ModdedServiceManager {
|
||||
if (cleanupError != failure) {
|
||||
failure.addSuppressed(cleanupError);
|
||||
}
|
||||
LOGGER.error("Iris service rollback failed for {}", service.getClass().getName(), cleanupError);
|
||||
ModdedIrisLog.error("Iris service rollback failed for {}", service.getClass().getName(), cleanupError);
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeException serviceFailure(ModdedService service, Throwable failure) {
|
||||
LOGGER.error("Iris service onEnable failed for {}", service.getClass().getName(), failure);
|
||||
ModdedIrisLog.error("Iris service onEnable failed for {}", service.getClass().getName(), failure);
|
||||
if (failure instanceof RuntimeException runtimeException) {
|
||||
return runtimeException;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ import net.minecraft.commands.Commands;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -43,7 +41,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class ModdedStartup {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final AtomicBoolean PREPARED = new AtomicBoolean(false);
|
||||
private static final AtomicBoolean STARTED = new AtomicBoolean(false);
|
||||
|
||||
@@ -76,7 +73,7 @@ public final class ModdedStartup {
|
||||
}
|
||||
if (!PackDirectoryResolver.listVisiblePackDirectories(legacy).isEmpty()) {
|
||||
File real = art.arcane.iris.spi.IrisPlatforms.get().packsFolderNoCreate();
|
||||
LOGGER.warn("Iris found packs under the legacy directory {} - modded packs load from {} only. Move them there.",
|
||||
ModdedIrisLog.warn("Iris found packs under the legacy directory {} - modded packs load from {} only. Move them there.",
|
||||
legacy.getAbsolutePath(), real.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
@@ -85,7 +82,7 @@ public final class ModdedStartup {
|
||||
legacy.delete();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris legacy packs directory check failed", e);
|
||||
ModdedIrisLog.debug("Iris legacy packs directory check failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +101,7 @@ public final class ModdedStartup {
|
||||
try {
|
||||
ModdedForcedDatapack.regenerateIfStale("boot");
|
||||
} catch (Throwable failure) {
|
||||
LOGGER.error("Iris could not refresh the forced datapack at boot", failure);
|
||||
ModdedIrisLog.error("Iris could not refresh the forced datapack at boot", failure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +130,7 @@ public final class ModdedStartup {
|
||||
List<File> packDirs = PackDirectoryResolver.listVisiblePackDirectories(packsRoot);
|
||||
PackValidationRegistry.clear();
|
||||
if (packDirs.isEmpty()) {
|
||||
LOGGER.info("Iris found no packs to validate under {}; install one with /iris download pack=overworld, /iris download pack=underworld, or /iris download link=<zip-url>",
|
||||
ModdedIrisLog.info("Iris found no packs to validate under {}; install one with /iris download pack=overworld, /iris download pack=underworld, or /iris download link=<zip-url>",
|
||||
packsRoot.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
@@ -142,19 +139,19 @@ public final class ModdedStartup {
|
||||
PackValidationResult result = PackValidator.validate(packDir);
|
||||
PackValidationRegistry.publish(result);
|
||||
if (!result.isLoadable()) {
|
||||
LOGGER.error("Iris pack '{}' FAILED validation with {} blocking error(s); world/studio creation will be refused. First error: {}",
|
||||
ModdedIrisLog.error("Iris pack '{}' FAILED validation with {} blocking error(s); world/studio creation will be refused. First error: {}",
|
||||
result.getPackName(), result.getBlockingErrors().size(),
|
||||
result.getBlockingErrors().getFirst());
|
||||
} else if (!result.getWarnings().isEmpty()) {
|
||||
LOGGER.info("Iris pack '{}' validated ({} warning(s)).", result.getPackName(), result.getWarnings().size());
|
||||
ModdedIrisLog.info("Iris pack '{}' validated ({} warning(s)).", result.getPackName(), result.getWarnings().size());
|
||||
for (String warning : result.getWarnings()) {
|
||||
LOGGER.warn(" [{}] {}", result.getPackName(), warning);
|
||||
ModdedIrisLog.warn(" [{}] {}", result.getPackName(), warning);
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("Iris pack '{}' validated.", result.getPackName());
|
||||
ModdedIrisLog.info("Iris pack '{}' validated.", result.getPackName());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris pack validation failed for '{}'", packDir.getName(), e);
|
||||
ModdedIrisLog.error("Iris pack validation failed for '{}'", packDir.getName(), e);
|
||||
String detail = e.getMessage();
|
||||
if (detail == null || detail.isBlank()) {
|
||||
detail = e.getClass().getSimpleName();
|
||||
@@ -190,7 +187,7 @@ public final class ModdedStartup {
|
||||
} catch (BrokenPackException e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris required world-creation validation failed for '{}'", pack, e);
|
||||
ModdedIrisLog.error("Iris required world-creation validation failed for '{}'", pack, e);
|
||||
String detail = e.getMessage();
|
||||
if (detail == null || detail.isBlank()) {
|
||||
detail = e.getClass().getSimpleName();
|
||||
@@ -220,17 +217,17 @@ public final class ModdedStartup {
|
||||
try {
|
||||
ModdedDimensionManager.create(server, dimension.id(), dimension.pack(), dimension.dimension(), dimension.seed());
|
||||
injected++;
|
||||
LOGGER.info("Iris re-injected {}/{} '{}' (pack={} dim={}) in {}ms",
|
||||
ModdedIrisLog.info("Iris re-injected {}/{} '{}' (pack={} dim={}) in {}ms",
|
||||
index, dimensions.size(), dimension.id(), dimension.pack(), dimension.dimension(),
|
||||
System.currentTimeMillis() - dimensionStartedAt);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris failed to re-inject persistent dimension '{}' (pack={} dim={} seed={})", dimension.id(), dimension.pack(), dimension.dimension(), dimension.seed(), e);
|
||||
ModdedIrisLog.error("Iris failed to re-inject persistent dimension '{}' (pack={} dim={} seed={})", dimension.id(), dimension.pack(), dimension.dimension(), dimension.seed(), e);
|
||||
if (e instanceof OutOfMemoryError outOfMemory) {
|
||||
throw outOfMemory;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOGGER.info("Iris re-injected {}/{} persistent dimension(s) at startup in {}ms",
|
||||
ModdedIrisLog.info("Iris re-injected {}/{} persistent dimension(s) at startup in {}ms",
|
||||
injected, dimensions.size(), System.currentTimeMillis() - startedAt);
|
||||
}
|
||||
|
||||
@@ -245,7 +242,7 @@ public final class ModdedStartup {
|
||||
}
|
||||
}
|
||||
} catch (IOException | RuntimeException unreadable) {
|
||||
LOGGER.debug("Iris could not stat {} for validation reuse; revalidating", root, unreadable);
|
||||
ModdedIrisLog.debug("Iris could not stat {} for validation reuse; revalidating", root, unreadable);
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
return newest;
|
||||
|
||||
@@ -32,8 +32,6 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
@@ -53,7 +51,6 @@ public final class ModdedWorldCheck {
|
||||
private static final long SERVER_WAIT_TIMEOUT_MILLIS = 600000L;
|
||||
private static final long SERVER_WAIT_INTERVAL_MILLIS = 250L;
|
||||
private static final long SERVER_TASK_TIMEOUT_MILLIS = 900000L;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
// halt, not exit: awaitStopAndExit already waited for MinecraftServer.halt(true), and exit() would run the
|
||||
// shutdown hooks and block behind the server thread it just stopped, so a finished check could hang forever.
|
||||
private static final ProcessExit PROCESS_EXIT = Runtime.getRuntime()::halt;
|
||||
@@ -100,7 +97,7 @@ public final class ModdedWorldCheck {
|
||||
}
|
||||
|
||||
if (server == null) {
|
||||
LOGGER.error("[worldcheck] server did not finish starting within 10 minutes");
|
||||
ModdedIrisLog.error("[worldcheck] server did not finish starting within 10 minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,15 +112,15 @@ public final class ModdedWorldCheck {
|
||||
}
|
||||
)).get(SERVER_TASK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("[worldcheck] coordinator interrupted", e);
|
||||
ModdedIrisLog.error("[worldcheck] coordinator interrupted", e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (TimeoutException e) {
|
||||
LOGGER.error("[worldcheck] server task did not finish within {}ms", SERVER_TASK_TIMEOUT_MILLIS);
|
||||
ModdedIrisLog.error("[worldcheck] server task did not finish within {}ms", SERVER_TASK_TIMEOUT_MILLIS);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("[worldcheck] check failed", e);
|
||||
ModdedIrisLog.error("[worldcheck] check failed", e);
|
||||
} finally {
|
||||
int resultCode = exitCode;
|
||||
LOGGER.info("[worldcheck] shutting down dev server (result={})", resultCode == EXIT_PASS ? "PASS" : "FAIL");
|
||||
ModdedIrisLog.info("[worldcheck] shutting down dev server (result={})", resultCode == EXIT_PASS ? "PASS" : "FAIL");
|
||||
MinecraftServer serverRef = server;
|
||||
if (serverRef != null && stopRequested.get()) {
|
||||
awaitStopAndExit(() -> serverRef.halt(true), resultCode, processExit);
|
||||
@@ -138,12 +135,12 @@ public final class ModdedWorldCheck {
|
||||
try {
|
||||
exitCode = check.getAsBoolean() ? EXIT_PASS : EXIT_FAILURE;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("[worldcheck] check failed", e);
|
||||
ModdedIrisLog.error("[worldcheck] check failed", e);
|
||||
}
|
||||
try {
|
||||
requestStop.run();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("[worldcheck] server stop request failed", e);
|
||||
ModdedIrisLog.error("[worldcheck] server stop request failed", e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return exitCode;
|
||||
@@ -159,7 +156,7 @@ public final class ModdedWorldCheck {
|
||||
awaitStop.run();
|
||||
} catch (Throwable e) {
|
||||
exitCode = EXIT_FAILURE;
|
||||
LOGGER.error("[worldcheck] waiting for server shutdown failed", e);
|
||||
ModdedIrisLog.error("[worldcheck] waiting for server shutdown failed", e);
|
||||
} finally {
|
||||
if (interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
@@ -171,25 +168,25 @@ public final class ModdedWorldCheck {
|
||||
private static WorldCheckPreparation run(MinecraftServer server) {
|
||||
ServerLevel level = targetLevel(server);
|
||||
if (level == null) {
|
||||
LOGGER.error("[worldcheck] no Iris dimension is loaded");
|
||||
ModdedIrisLog.error("[worldcheck] no Iris dimension is loaded");
|
||||
return new WorldCheckPreparation(false, false, false, false,
|
||||
new NativeStructureGate(false, 0, false, null));
|
||||
}
|
||||
|
||||
String levelId = level.dimension().identifier().toString();
|
||||
String generatorClass = level.getChunkSource().getGenerator().getClass().getName();
|
||||
LOGGER.info("[worldcheck] {} generator: {}", levelId, generatorClass);
|
||||
ModdedIrisLog.info("[worldcheck] {} generator: {}", levelId, generatorClass);
|
||||
IrisModdedChunkGenerator generator = level.getChunkSource().getGenerator() instanceof IrisModdedChunkGenerator iris
|
||||
? iris : null;
|
||||
boolean irisGenerator = generator != null;
|
||||
if (!irisGenerator) {
|
||||
LOGGER.error("[worldcheck] {} is NOT using IrisModdedChunkGenerator", levelId);
|
||||
ModdedIrisLog.error("[worldcheck] {} is NOT using IrisModdedChunkGenerator", levelId);
|
||||
}
|
||||
boolean dimensionTypeOk = generator != null
|
||||
&& WorldCheckDimensionContract.checkDimensionType(level, generator);
|
||||
|
||||
BlockPos spawn = level.getRespawnData().pos();
|
||||
LOGGER.info("[worldcheck] spawn: {} {} {} (minY={} height={})", spawn.getX(), spawn.getY(), spawn.getZ(), level.getMinY(), level.getHeight());
|
||||
ModdedIrisLog.info("[worldcheck] spawn: {} {} {} (minY={} height={})", spawn.getX(), spawn.getY(), spawn.getZ(), level.getMinY(), level.getHeight());
|
||||
|
||||
MessageDigest digest = WorldCheckPredicates.sha256();
|
||||
List<String> samples = new ArrayList<>();
|
||||
@@ -210,9 +207,9 @@ public final class ModdedWorldCheck {
|
||||
}
|
||||
|
||||
for (int i = 0; i < Math.min(6, samples.size()); i++) {
|
||||
LOGGER.info("[worldcheck] surface sample: {}", samples.get(i));
|
||||
ModdedIrisLog.info("[worldcheck] surface sample: {}", samples.get(i));
|
||||
}
|
||||
LOGGER.info("[worldcheck] surface digest: {} ({} columns, {} distinct surface blocks: {})",
|
||||
ModdedIrisLog.info("[worldcheck] surface digest: {} ({} columns, {} distinct surface blocks: {})",
|
||||
HexFormat.of().formatHex(digest.digest()).substring(0, 12), samples.size(), surfaceKeys.size(), surfaceKeys);
|
||||
|
||||
ChunkAccess zeroChunk = level.getChunk(0, 0);
|
||||
@@ -230,16 +227,16 @@ public final class ModdedWorldCheck {
|
||||
columnKeys.add(BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString());
|
||||
}
|
||||
}
|
||||
LOGGER.info("[worldcheck] chunk 0,0: {} non-empty sections of {}; column blocks at (8,*,8): {}",
|
||||
ModdedIrisLog.info("[worldcheck] chunk 0,0: {} non-empty sections of {}; column blocks at (8,*,8): {}",
|
||||
nonEmptySections, zeroChunk.getSections().length, columnKeys);
|
||||
|
||||
boolean sectionsOk = nonEmptySections >= 4;
|
||||
boolean varietyOk = columnKeys.size() >= 2 || surfaceKeys.size() >= 2;
|
||||
if (!sectionsOk) {
|
||||
LOGGER.error("[worldcheck] chunk 0,0 looks empty/vanilla-flat ({} non-empty sections)", nonEmptySections);
|
||||
ModdedIrisLog.error("[worldcheck] chunk 0,0 looks empty/vanilla-flat ({} non-empty sections)", nonEmptySections);
|
||||
}
|
||||
if (!varietyOk) {
|
||||
LOGGER.error("[worldcheck] generated terrain has no block variety (flat-world signature)");
|
||||
ModdedIrisLog.error("[worldcheck] generated terrain has no block variety (flat-world signature)");
|
||||
}
|
||||
|
||||
boolean entityMixinsOk = WorldCheckDimensionContract.checkEntityMixins(level);
|
||||
@@ -262,7 +259,7 @@ public final class ModdedWorldCheck {
|
||||
WorldCheckPredicates.qaEvent("village_poi_metric", "village", poiOk,
|
||||
"inBounds=" + poi.inBounds() + ",outOfBounds=" + poi.outOfBounds());
|
||||
if (!poiOk) {
|
||||
LOGGER.error("[worldcheck] village POI audit failed: inBounds={} outOfBounds={}",
|
||||
ModdedIrisLog.error("[worldcheck] village POI audit failed: inBounds={} outOfBounds={}",
|
||||
poi.inBounds(), poi.outOfBounds());
|
||||
}
|
||||
} else {
|
||||
@@ -271,12 +268,12 @@ public final class ModdedWorldCheck {
|
||||
int passed = structureGate.nonVillagePassed()
|
||||
+ (structureGate.villagePassBeforePoi() && poiOk ? 1 : 0);
|
||||
boolean structurePass = structureGate.passBeforePoi() && poiOk;
|
||||
LOGGER.info("[worldcheck] native structure gate: {}/{} passed", passed,
|
||||
ModdedIrisLog.info("[worldcheck] native structure gate: {}/{} passed", passed,
|
||||
WorldCheckStructureAudit.STRUCTURE_CHECKS.size());
|
||||
WorldCheckPredicates.qaEvent("structure_aggregate", "all", structurePass,
|
||||
"passed=" + passed + ",total=" + WorldCheckStructureAudit.STRUCTURE_CHECKS.size());
|
||||
boolean pass = preparation.nonStructurePass() && structurePass;
|
||||
LOGGER.info("[worldcheck] {}", pass ? "PASS" : "FAIL");
|
||||
ModdedIrisLog.info("[worldcheck] {}", pass ? "PASS" : "FAIL");
|
||||
WorldCheckPredicates.qaEvent("worldcheck_final", "all", pass,
|
||||
"structures=" + WorldCheckStructureAudit.STRUCTURE_CHECKS.size()
|
||||
+ ",terrain=" + preparation.terrainOk()
|
||||
@@ -295,7 +292,7 @@ public final class ModdedWorldCheck {
|
||||
if (requested != null) {
|
||||
return requested;
|
||||
}
|
||||
LOGGER.error("[worldcheck] requested dimension '{}' is not loaded", target);
|
||||
ModdedIrisLog.error("[worldcheck] requested dimension '{}' is not loaded", target);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+11
-14
@@ -31,8 +31,6 @@ import art.arcane.iris.modded.command.ModdedGuiHost;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -42,7 +40,6 @@ import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class ModdedWorldEngines {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final ConcurrentHashMap<ServerLevel, Engine> ENGINES = new ConcurrentHashMap<>();
|
||||
|
||||
private ModdedWorldEngines() {
|
||||
@@ -64,7 +61,7 @@ public final class ModdedWorldEngines {
|
||||
try {
|
||||
evictOrThrow(level);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris engine evict close failed for {}", level.dimension().identifier(), e);
|
||||
ModdedIrisLog.error("Iris engine evict close failed for {}", level.dimension().identifier(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +77,7 @@ public final class ModdedWorldEngines {
|
||||
}
|
||||
// The GUI host holds strong Engine/ServerLevel references with no other remove path.
|
||||
ModdedGuiHost.unbind(removed[0]);
|
||||
LOGGER.info("Iris engine evicted for {}", level.dimension().identifier());
|
||||
ModdedIrisLog.info("Iris engine evicted for {}", level.dimension().identifier());
|
||||
}
|
||||
|
||||
static Engine prepareReplacement(ServerLevel level, String pack, String dimensionKey, long seedOverride) {
|
||||
@@ -111,7 +108,7 @@ public final class ModdedWorldEngines {
|
||||
IrisData data = IrisData.openRuntime(packDir);
|
||||
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
|
||||
if (dimension == null) {
|
||||
LOGGER.error("Iris pack '{}' at {} does not contain dimension '{}' (expected dimensions/{}.json). Install a matching Iris pack and restart.",
|
||||
ModdedIrisLog.error("Iris pack '{}' at {} does not contain dimension '{}' (expected dimensions/{}.json). Install a matching Iris pack and restart.",
|
||||
pack, packDir.getAbsolutePath(), dimensionKey, dimensionKey);
|
||||
throw new IllegalStateException("Iris dimension '" + dimensionKey + "' missing from pack " + packDir.getAbsolutePath());
|
||||
}
|
||||
@@ -142,7 +139,7 @@ public final class ModdedWorldEngines {
|
||||
throw failure;
|
||||
}
|
||||
|
||||
LOGGER.info("Iris engine up for {}: pack={} dim={} seed={} height={}..{}",
|
||||
ModdedIrisLog.info("Iris engine up for {}: pack={} dim={} seed={} height={}..{}",
|
||||
level.dimension().identifier(), packDir.getAbsolutePath(), dimension.getLoadKey(), seed, dimension.getMinHeight(), dimension.getMaxHeight());
|
||||
return engine;
|
||||
}
|
||||
@@ -182,11 +179,11 @@ public final class ModdedWorldEngines {
|
||||
return packDir;
|
||||
}
|
||||
|
||||
LOGGER.error("===============================================================");
|
||||
LOGGER.error("Iris pack '{}' is not installed.", pack);
|
||||
LOGGER.error("Expected a pack folder at: {}", packDir.getAbsolutePath());
|
||||
LOGGER.error("Install an Iris pack there (the folder must contain dimensions/{}.json) and restart the server.", dimensionKey);
|
||||
LOGGER.error("===============================================================");
|
||||
ModdedIrisLog.error("===============================================================");
|
||||
ModdedIrisLog.error("Iris pack '{}' is not installed.", pack);
|
||||
ModdedIrisLog.error("Expected a pack folder at: {}", packDir.getAbsolutePath());
|
||||
ModdedIrisLog.error("Install an Iris pack there (the folder must contain dimensions/{}.json) and restart the server.", dimensionKey);
|
||||
ModdedIrisLog.error("===============================================================");
|
||||
throw new IllegalStateException("Iris pack not installed: " + packDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
@@ -215,9 +212,9 @@ public final class ModdedWorldEngines {
|
||||
+ level.dimension().identifier());
|
||||
}
|
||||
}
|
||||
LOGGER.info("Iris engine closed for {}", level.dimension().identifier());
|
||||
ModdedIrisLog.info("Iris engine closed for {}", level.dimension().identifier());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris engine close failed for {}", level.dimension().identifier(), e);
|
||||
ModdedIrisLog.error("Iris engine close failed for {}", level.dimension().identifier(), e);
|
||||
if (failure == null) {
|
||||
failure = e;
|
||||
} else if (e != failure) {
|
||||
|
||||
+4
-7
@@ -25,11 +25,8 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
final class WorldCheckDimensionContract {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private WorldCheckDimensionContract() {
|
||||
}
|
||||
@@ -44,13 +41,13 @@ final class WorldCheckDimensionContract {
|
||||
+ ",levelMinY=" + level.getMinY() + ",levelHeight=" + level.getHeight();
|
||||
WorldCheckPredicates.qaEvent("dimension_type", dimension.getLoadKey(), pass, detail);
|
||||
if (!pass) {
|
||||
LOGGER.error("[worldcheck] dimension type mismatch for {}: {}", dimension.getLoadKey(), detail);
|
||||
ModdedIrisLog.error("[worldcheck] dimension type mismatch for {}: {}", dimension.getLoadKey(), detail);
|
||||
} else {
|
||||
LOGGER.info("[worldcheck] dimension type contract: {}", detail);
|
||||
ModdedIrisLog.info("[worldcheck] dimension type contract: {}", detail);
|
||||
}
|
||||
return pass;
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("[worldcheck] could not validate the Iris dimension type contract", error);
|
||||
ModdedIrisLog.error("[worldcheck] could not validate the Iris dimension type contract", error);
|
||||
WorldCheckPredicates.qaEvent("dimension_type", generator.activeDimensionKey(), false,
|
||||
"validationError=" + error.getClass().getSimpleName() + ":" + error.getMessage());
|
||||
return false;
|
||||
@@ -102,7 +99,7 @@ final class WorldCheckDimensionContract {
|
||||
WorldCheckPredicates.qaEvent("entity_mixin", "persistence", pass,
|
||||
"vanilla=" + vanillaSave + ",suppressed=" + suppressed + ",restored=" + restored);
|
||||
if (!pass) {
|
||||
LOGGER.error("[worldcheck] shared entity mixins are not active on this loader");
|
||||
ModdedIrisLog.error("[worldcheck] shared entity mixins are not active on this loader");
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
|
||||
+1
-4
@@ -20,14 +20,11 @@ package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.engine.framework.StructureVerticalBounds;
|
||||
import art.arcane.iris.modded.WorldCheckStructureAudit.StructureCheck;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
final class WorldCheckPredicates {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private WorldCheckPredicates() {
|
||||
}
|
||||
@@ -39,7 +36,7 @@ final class WorldCheckPredicates {
|
||||
}
|
||||
|
||||
static void qaEvent(String event, String structure, boolean pass, String detail) {
|
||||
LOGGER.info(qaEventJson(event, structure, pass, detail));
|
||||
ModdedIrisLog.info(qaEventJson(event, structure, pass, detail));
|
||||
}
|
||||
|
||||
static String qaEventJson(String event, String structure, boolean pass, String detail) {
|
||||
|
||||
+20
-23
@@ -48,8 +48,6 @@ import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -77,7 +75,6 @@ final class WorldCheckStructureAudit {
|
||||
private static final int MAX_FOOTPRINT_CHUNKS = 96;
|
||||
private static final int MAX_START_REFERENCE_CHUNKS = 16;
|
||||
private static final int MAX_STRUCTURE_CANDIDATES = 1024;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private WorldCheckStructureAudit() {
|
||||
}
|
||||
@@ -123,13 +120,13 @@ final class WorldCheckStructureAudit {
|
||||
}
|
||||
}
|
||||
boolean registryOk = registered.size() == check.registryKeys().size();
|
||||
LOGGER.info("[worldcheck] {} registry: {}/{} resolved {}", check.label(), registered.size(),
|
||||
ModdedIrisLog.info("[worldcheck] {} registry: {}/{} resolved {}", check.label(), registered.size(),
|
||||
check.registryKeys().size(), registeredKeys);
|
||||
WorldCheckPredicates.qaEvent("structure_registry", check.label(), registryOk,
|
||||
"resolved=" + registered.size() + ",expected=" + check.registryKeys().size()
|
||||
+ ",keys=" + String.join("|", registeredKeys));
|
||||
if (!registryOk) {
|
||||
LOGGER.error("[worldcheck] {} registry resolution failed; expected {}", check.label(), check.registryKeys());
|
||||
ModdedIrisLog.error("[worldcheck] {} registry resolution failed; expected {}", check.label(), check.registryKeys());
|
||||
WorldCheckPredicates.emitSkipped(check, "registry", "structure_reachability", "structure_locate",
|
||||
"structure_start_reference", "structure_footprint", "structure_material",
|
||||
"structure_block_entity");
|
||||
@@ -149,12 +146,12 @@ final class WorldCheckStructureAudit {
|
||||
}
|
||||
}
|
||||
boolean reachableOk = !reachable.isEmpty();
|
||||
LOGGER.info("[worldcheck] {} biome-reachable through Iris: {}", check.label(), reachableKeys);
|
||||
ModdedIrisLog.info("[worldcheck] {} biome-reachable through Iris: {}", check.label(), reachableKeys);
|
||||
WorldCheckPredicates.qaEvent("structure_reachability", check.label(), reachableOk,
|
||||
"reachable=" + reachable.size() + ",registered=" + registered.size()
|
||||
+ ",keys=" + String.join("|", reachableKeys));
|
||||
if (!reachableOk) {
|
||||
LOGGER.error("[worldcheck] {} cannot generate in any biome produced by this Iris pack", check.label());
|
||||
ModdedIrisLog.error("[worldcheck] {} cannot generate in any biome produced by this Iris pack", check.label());
|
||||
WorldCheckPredicates.emitSkipped(check, "reachability", "structure_locate", "structure_start_reference",
|
||||
"structure_footprint", "structure_material", "structure_block_entity");
|
||||
return new StructureCheckResult(false, null);
|
||||
@@ -170,7 +167,7 @@ final class WorldCheckStructureAudit {
|
||||
"method=placement_candidates,millis=" + locateMillis + ",radius=" + check.locateRadius()
|
||||
+ ",result=" + (foundKey == null ? "none" : foundKey));
|
||||
if (found == null) {
|
||||
LOGGER.error("[worldcheck] {} native placement candidates produced no valid start within {} rings after {}ms",
|
||||
ModdedIrisLog.error("[worldcheck] {} native placement candidates produced no valid start within {} rings after {}ms",
|
||||
check.label(), check.locateRadius(), locateMillis);
|
||||
WorldCheckPredicates.emitSkipped(check, "locate", "structure_start_reference", "structure_footprint",
|
||||
"structure_material", "structure_block_entity");
|
||||
@@ -178,11 +175,11 @@ final class WorldCheckStructureAudit {
|
||||
}
|
||||
|
||||
BlockPos position = found.getFirst();
|
||||
LOGGER.info("[worldcheck] {} generated candidate: {} {} {} in {}ms (radius={}, result={})",
|
||||
ModdedIrisLog.info("[worldcheck] {} generated candidate: {} {} {} in {}ms (radius={}, result={})",
|
||||
check.label(), position.getX(), position.getY(), position.getZ(), locateMillis,
|
||||
check.locateRadius(), foundKey);
|
||||
if (!locateOk) {
|
||||
LOGGER.error("[worldcheck] {} candidate scan returned unexpected structure {}", check.label(), foundKey);
|
||||
ModdedIrisLog.error("[worldcheck] {} candidate scan returned unexpected structure {}", check.label(), foundKey);
|
||||
WorldCheckPredicates.emitSkipped(check, "locate", "structure_start_reference", "structure_footprint",
|
||||
"structure_material", "structure_block_entity");
|
||||
return new StructureCheckResult(false, null);
|
||||
@@ -196,13 +193,13 @@ final class WorldCheckStructureAudit {
|
||||
boolean validStart = start != null && start.isValid();
|
||||
int references = targetChunk.getReferencesForStructure(structure).size();
|
||||
boolean startReferenceOk = WorldCheckPredicates.hasNativeStructureEvidence(validStart, references);
|
||||
LOGGER.info("[worldcheck] {} target chunk {},{}: valid start={}, references={}",
|
||||
ModdedIrisLog.info("[worldcheck] {} target chunk {},{}: valid start={}, references={}",
|
||||
check.label(), chunkX, chunkZ, validStart, references);
|
||||
WorldCheckPredicates.qaEvent("structure_start_reference", check.label(), startReferenceOk,
|
||||
"chunk=" + chunkX + "," + chunkZ + ",validStart=" + validStart
|
||||
+ ",references=" + references);
|
||||
if (!startReferenceOk || !validStart) {
|
||||
LOGGER.error("[worldcheck] {} located at chunk {},{} but no resolvable valid start was generated",
|
||||
ModdedIrisLog.error("[worldcheck] {} located at chunk {},{} but no resolvable valid start was generated",
|
||||
check.label(), chunkX, chunkZ);
|
||||
WorldCheckPredicates.emitSkipped(check, "start_reference", "structure_footprint", "structure_material",
|
||||
"structure_block_entity");
|
||||
@@ -221,7 +218,7 @@ final class WorldCheckStructureAudit {
|
||||
"configured=" + decision.yShift() + ",applied="
|
||||
+ (appliedShift == null ? "unrecorded" : appliedShift));
|
||||
if (!verticalShiftOk) {
|
||||
LOGGER.error("[worldcheck] {} expected vertical shift {} but generation recorded {}",
|
||||
ModdedIrisLog.error("[worldcheck] {} expected vertical shift {} but generation recorded {}",
|
||||
check.label(), decision.yShift(), appliedShift);
|
||||
}
|
||||
|
||||
@@ -229,7 +226,7 @@ final class WorldCheckStructureAudit {
|
||||
boolean footprintOk = footprint.inspectedChunks() > 0
|
||||
&& footprint.evidenceChunks() == footprint.inspectedChunks()
|
||||
&& footprint.coveredPieces() == footprint.totalPieces();
|
||||
LOGGER.info("[worldcheck] {} footprint: chunks={}/{} evidence={} pieces={}/{}",
|
||||
ModdedIrisLog.info("[worldcheck] {} footprint: chunks={}/{} evidence={} pieces={}/{}",
|
||||
check.label(), footprint.inspectedChunks(), footprint.availableChunks(),
|
||||
footprint.evidenceChunks(), footprint.coveredPieces(), footprint.totalPieces());
|
||||
WorldCheckPredicates.qaEvent("structure_footprint", check.label(), footprintOk,
|
||||
@@ -239,7 +236,7 @@ final class WorldCheckStructureAudit {
|
||||
|
||||
boolean materialOk = WorldCheckPredicates.hasCharacteristicMaterialEvidence(footprint.characteristicBlocks(),
|
||||
footprint.characteristicChunks(), footprint.materialScannedChunks());
|
||||
LOGGER.info("[worldcheck] {} material: blocks={} chunks={}/{}",
|
||||
ModdedIrisLog.info("[worldcheck] {} material: blocks={} chunks={}/{}",
|
||||
check.label(), footprint.characteristicBlocks(), footprint.characteristicChunks(),
|
||||
footprint.materialScannedChunks());
|
||||
WorldCheckPredicates.qaEvent("structure_material", check.label(), materialOk,
|
||||
@@ -250,7 +247,7 @@ final class WorldCheckStructureAudit {
|
||||
if (check.label().equals("mansion")) {
|
||||
boolean overlap = footprint.vegetationBlocks() > 0;
|
||||
vegetationOk = WorldCheckPredicates.mansionVegetationPass(footprint.vegetationBlocks());
|
||||
LOGGER.info("[worldcheck] mansion vegetation metric: remaining log/leaf blocks={} columns={} overlap={}",
|
||||
ModdedIrisLog.info("[worldcheck] mansion vegetation metric: remaining log/leaf blocks={} columns={} overlap={}",
|
||||
footprint.vegetationBlocks(), footprint.vegetationColumns(), overlap);
|
||||
WorldCheckPredicates.qaEvent("mansion_vegetation_metric", check.label(), vegetationOk,
|
||||
"remainingLogsOrLeaves=" + footprint.vegetationBlocks() + ",columns="
|
||||
@@ -261,7 +258,7 @@ final class WorldCheckStructureAudit {
|
||||
PendingVillagePoi pendingPoi = null;
|
||||
if (check.label().equals("village")) {
|
||||
foundationOk = WorldCheckPredicates.villageFoundationPass(footprint.foundationGapColumns());
|
||||
LOGGER.info("[worldcheck] village foundation metric: bases={} cobblestone={} columns={} unsupported={}",
|
||||
ModdedIrisLog.info("[worldcheck] village foundation metric: bases={} cobblestone={} columns={} unsupported={}",
|
||||
footprint.foundationBaseColumns(), footprint.foundationBlocks(),
|
||||
footprint.foundationColumns(), footprint.foundationGapColumns());
|
||||
WorldCheckPredicates.qaEvent("village_foundation_metric", check.label(), foundationOk,
|
||||
@@ -272,26 +269,26 @@ final class WorldCheckStructureAudit {
|
||||
}
|
||||
|
||||
boolean blockEntityOk = footprint.blockEntityStates() == footprint.blockEntitiesPresent();
|
||||
LOGGER.info("[worldcheck] {} block entities: state blocks={}, present={}, missing={}",
|
||||
ModdedIrisLog.info("[worldcheck] {} block entities: state blocks={}, present={}, missing={}",
|
||||
check.label(), footprint.blockEntityStates(), footprint.blockEntitiesPresent(),
|
||||
footprint.blockEntityStates() - footprint.blockEntitiesPresent());
|
||||
WorldCheckPredicates.qaEvent("structure_block_entity", check.label(), blockEntityOk,
|
||||
"states=" + footprint.blockEntityStates() + ",present=" + footprint.blockEntitiesPresent()
|
||||
+ ",missing=" + (footprint.blockEntityStates() - footprint.blockEntitiesPresent()));
|
||||
if (!footprintOk) {
|
||||
LOGGER.error("[worldcheck] {} structure footprint is incomplete", check.label());
|
||||
ModdedIrisLog.error("[worldcheck] {} structure footprint is incomplete", check.label());
|
||||
}
|
||||
if (!materialOk) {
|
||||
LOGGER.error("[worldcheck] {} has no distributed characteristic structure material", check.label());
|
||||
ModdedIrisLog.error("[worldcheck] {} has no distributed characteristic structure material", check.label());
|
||||
}
|
||||
if (!blockEntityOk) {
|
||||
LOGGER.error("[worldcheck] {} generated block-entity states without matching block entities", check.label());
|
||||
ModdedIrisLog.error("[worldcheck] {} generated block-entity states without matching block entities", check.label());
|
||||
}
|
||||
if (!vegetationOk) {
|
||||
LOGGER.error("[worldcheck] mansion vegetation still intersects the generated structure footprint");
|
||||
ModdedIrisLog.error("[worldcheck] mansion vegetation still intersects the generated structure footprint");
|
||||
}
|
||||
if (!foundationOk) {
|
||||
LOGGER.error("[worldcheck] village has unsupported foundation columns after stilt placement");
|
||||
ModdedIrisLog.error("[worldcheck] village has unsupported foundation columns after stilt placement");
|
||||
}
|
||||
boolean pass = verticalShiftOk && footprintOk && materialOk && blockEntityOk
|
||||
&& vegetationOk && foundationOk;
|
||||
|
||||
+16
-18
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.api;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.modded.ModdedBlockResolution;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -25,8 +26,6 @@ import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -57,7 +56,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
* next provider.
|
||||
*/
|
||||
public final class ModdedCustomContentRegistry {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final List<ModdedDataProvider> PROVIDERS = new CopyOnWriteArrayList<>();
|
||||
private static final Map<String, BlockState> CUSTOM_BLOCKS = new ConcurrentHashMap<>();
|
||||
private static volatile boolean scanned = false;
|
||||
@@ -77,14 +75,14 @@ public final class ModdedCustomContentRegistry {
|
||||
}
|
||||
Identifier identifier = Identifier.tryParse(namespace + ":" + key);
|
||||
if (identifier == null) {
|
||||
LOGGER.warn("Iris custom block data registration rejected invalid id {}:{}", namespace, key);
|
||||
ModdedIrisLog.warn("Iris custom block data registration rejected invalid id {}:{}", namespace, key);
|
||||
return;
|
||||
}
|
||||
BlockState parsed;
|
||||
try {
|
||||
parsed = ModdedBlockResolution.strictParse(state).handle();
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris custom block data '{}:{}' has unparseable state '{}'", namespace, key, state, error);
|
||||
ModdedIrisLog.error("Iris custom block data '{}:{}' has unparseable state '{}'", namespace, key, state, error);
|
||||
return;
|
||||
}
|
||||
DiscoveryBatch activeBatch = discoveryBatch;
|
||||
@@ -93,7 +91,7 @@ public final class ModdedCustomContentRegistry {
|
||||
} else {
|
||||
activeBatch.customBlocks.put(identifier.toString(), parsed);
|
||||
}
|
||||
LOGGER.info("Iris registered custom block data {}:{} -> {}", namespace, key, state);
|
||||
ModdedIrisLog.info("Iris registered custom block data {}:{} -> {}", namespace, key, state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +110,7 @@ public final class ModdedCustomContentRegistry {
|
||||
}
|
||||
for (ModdedDataProvider existing : PROVIDERS) {
|
||||
if (existing.modId().equals(provider.modId())) {
|
||||
LOGGER.warn("Iris custom content provider for '{}' already registered; ignoring duplicate", provider.modId());
|
||||
ModdedIrisLog.warn("Iris custom content provider for '{}' already registered; ignoring duplicate", provider.modId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -120,9 +118,9 @@ public final class ModdedCustomContentRegistry {
|
||||
try {
|
||||
provider.init();
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris custom content provider '{}' failed to initialize", provider.modId(), error);
|
||||
ModdedIrisLog.error("Iris custom content provider '{}' failed to initialize", provider.modId(), error);
|
||||
}
|
||||
LOGGER.info("Iris registered custom content provider '{}'", provider.modId());
|
||||
ModdedIrisLog.info("Iris registered custom content provider '{}'", provider.modId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +157,7 @@ public final class ModdedCustomContentRegistry {
|
||||
CUSTOM_BLOCKS.putAll(batch.customBlocks);
|
||||
scanned = true;
|
||||
for (ModdedDataProvider provider : batch.additions) {
|
||||
LOGGER.info("Iris registered custom content provider '{}'", provider.modId());
|
||||
ModdedIrisLog.info("Iris registered custom content provider '{}'", provider.modId());
|
||||
}
|
||||
return new Discovery(previousProviders, previousCustomBlocks,
|
||||
previousDiscoveryComplete, true);
|
||||
@@ -171,7 +169,7 @@ public final class ModdedCustomContentRegistry {
|
||||
failure.addSuppressed(rollbackFailure);
|
||||
}
|
||||
}
|
||||
LOGGER.warn("Iris custom content provider discovery failed at {}",
|
||||
ModdedIrisLog.warn("Iris custom content provider discovery failed at {}",
|
||||
providerIdentity(failingProvider), failure);
|
||||
if (failure instanceof RuntimeException runtimeException) {
|
||||
throw runtimeException;
|
||||
@@ -242,7 +240,7 @@ public final class ModdedCustomContentRegistry {
|
||||
try {
|
||||
types = provider.getTypes(type);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris custom content provider '{}' failed listing {} types", provider.modId(), type, error);
|
||||
ModdedIrisLog.error("Iris custom content provider '{}' failed listing {} types", provider.modId(), type, error);
|
||||
continue;
|
||||
}
|
||||
if (types == null) {
|
||||
@@ -288,7 +286,7 @@ public final class ModdedCustomContentRegistry {
|
||||
return resolved;
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris custom content provider '{}' failed resolving block {}", provider.modId(), key, error);
|
||||
ModdedIrisLog.error("Iris custom content provider '{}' failed resolving block {}", provider.modId(), key, error);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -302,7 +300,7 @@ public final class ModdedCustomContentRegistry {
|
||||
public static void processBlockPlacement(Engine engine, ServerLevel level, BlockPos position, String key) {
|
||||
Identifier base = parseIdentifier(key);
|
||||
if (base == null) {
|
||||
LOGGER.warn("Iris deferred custom block placement rejected invalid id {}", key);
|
||||
ModdedIrisLog.warn("Iris deferred custom block placement rejected invalid id {}", key);
|
||||
return;
|
||||
}
|
||||
Map<String, String> state = parseState(key);
|
||||
@@ -314,11 +312,11 @@ public final class ModdedCustomContentRegistry {
|
||||
provider.processBlockPlacement(new ModdedBlockPlacementContext(
|
||||
engine, level, position.immutable(), base, state, level.getBlockState(position)));
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris custom content provider '{}' failed post-placement for {} at {}", provider.modId(), key, position, error);
|
||||
ModdedIrisLog.error("Iris custom content provider '{}' failed post-placement for {} at {}", provider.modId(), key, position, error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
LOGGER.warn("Iris deferred custom block placement has no provider for {}", key);
|
||||
ModdedIrisLog.warn("Iris deferred custom block placement has no provider for {}", key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,7 +341,7 @@ public final class ModdedCustomContentRegistry {
|
||||
return entity;
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris custom content provider '{}' failed spawning mob {}", provider.modId(), key, error);
|
||||
ModdedIrisLog.error("Iris custom content provider '{}' failed spawning mob {}", provider.modId(), key, error);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -439,7 +437,7 @@ public final class ModdedCustomContentRegistry {
|
||||
"Iris custom content provider returned a null mod id");
|
||||
for (ModdedDataProvider existing : providers) {
|
||||
if (modId.equals(existing.modId())) {
|
||||
LOGGER.warn("Iris custom content provider for '{}' already registered; ignoring duplicate", modId);
|
||||
ModdedIrisLog.warn("Iris custom content provider for '{}' already registered; ignoring duplicate", modId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-9
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.IrisMessages;
|
||||
@@ -51,8 +52,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -67,7 +66,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
|
||||
public final class IrisModdedCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final long DOWNLOAD_SHUTDOWN_POLL_SECONDS = 15L;
|
||||
private static final Object DOWNLOAD_MONITOR = new Object();
|
||||
|
||||
@@ -82,7 +80,7 @@ public final class IrisModdedCommands {
|
||||
LiteralCommandNode<CommandSourceStack> root = dispatcher.register(ModdedCommandTree.rootTree());
|
||||
dispatcher.register(Commands.literal("ir").redirect(root));
|
||||
dispatcher.register(Commands.literal("irs").redirect(root));
|
||||
IrisLogging.info("Iris /iris command tree registered");
|
||||
IrisLogging.debug("Iris /iris command tree registered");
|
||||
}
|
||||
|
||||
public static void openDownloadAdmission() {
|
||||
@@ -108,7 +106,7 @@ public final class IrisModdedCommands {
|
||||
try {
|
||||
if (!execution.await(DOWNLOAD_SHUTDOWN_POLL_SECONDS, TimeUnit.SECONDS) && !warned) {
|
||||
warned = true;
|
||||
LOGGER.warn(execution.isPublishing()
|
||||
ModdedIrisLog.warn(execution.isPublishing()
|
||||
? "Waiting for atomic pack publication to finish before Iris shutdown."
|
||||
: "Waiting for the active pack download to cancel before Iris shutdown.");
|
||||
}
|
||||
@@ -354,7 +352,7 @@ public final class IrisModdedCommands {
|
||||
accepted = scheduler.asyncIfRunning(execution, execution::cancel);
|
||||
} catch (Throwable error) {
|
||||
execution.cancel();
|
||||
LOGGER.error("Iris pack download dispatch failed for {}", target, error);
|
||||
ModdedIrisLog.error("Iris pack download dispatch failed for {}", target, error);
|
||||
fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||
MessageArgument.untrusted("pack", target),
|
||||
@@ -363,7 +361,7 @@ public final class IrisModdedCommands {
|
||||
}
|
||||
if (!accepted) {
|
||||
execution.cancel();
|
||||
LOGGER.error("Iris pack download dispatch rejected for {} because the scheduler is shut down", target);
|
||||
ModdedIrisLog.error("Iris pack download dispatch rejected for {} because the scheduler is shut down", target);
|
||||
fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||
MessageArgument.untrusted("pack", target),
|
||||
@@ -416,7 +414,7 @@ public final class IrisModdedCommands {
|
||||
dispatchDownloadFeedback(source, () -> fail(source, error.getMessage()));
|
||||
return;
|
||||
} catch (IOException | RuntimeException error) {
|
||||
LOGGER.error("Iris pack download failed for {}", target, error);
|
||||
ModdedIrisLog.error("Iris pack download failed for {}", target, error);
|
||||
}
|
||||
dispatchDownloadFeedback(source, () -> fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||
@@ -512,7 +510,7 @@ public final class IrisModdedCommands {
|
||||
try {
|
||||
return irisGenerator.commandEngine();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris engine lookup failed for {}", level.dimension().identifier(), e);
|
||||
ModdedIrisLog.error("Iris engine lookup failed for {}", level.dimension().identifier(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
@@ -40,8 +41,6 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -66,7 +65,6 @@ final class ModdedCommandSuggestions {
|
||||
static final SuggestionProvider<CommandSourceStack> PACK_NAMES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestPackNames(context, builder);
|
||||
static final SuggestionProvider<CommandSourceStack> DIMENSION_NAMES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestDimensionNames(context, builder);
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int TAB_FAILURE_KEYS_MAX = 256;
|
||||
private static final Set<String> REPORTED_TAB_FAILURES = ConcurrentHashMap.newKeySet();
|
||||
private static final long PACK_NAME_CACHE_TTL_MS = 3_000L;
|
||||
@@ -180,7 +178,7 @@ final class ModdedCommandSuggestions {
|
||||
if (REPORTED_TAB_FAILURES.size() > TAB_FAILURE_KEYS_MAX) {
|
||||
REPORTED_TAB_FAILURES.clear();
|
||||
}
|
||||
LOGGER.warn("Iris tab-complete for {} in {} failed; suggestions will be empty", suggestion, origin, error);
|
||||
ModdedIrisLog.warn("Iris tab-complete for {} in {} failed; suggestions will be empty", suggestion, origin, error);
|
||||
}
|
||||
|
||||
private static String tabOrigin(CommandSourceStack source) {
|
||||
|
||||
+5
-7
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
@@ -35,8 +36,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -56,7 +55,6 @@ import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
public final class ModdedDatapackCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
private static final String WORLD_PACK_NAME = "iris";
|
||||
|
||||
@@ -170,7 +168,7 @@ public final class ModdedDatapackCommands {
|
||||
try {
|
||||
json = dimension.getDimensionType().toJson(DataVersion.getLatest().get());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris dimension type generation failed for {}", dimension.getLoadKey(), e);
|
||||
ModdedIrisLog.error("Iris dimension type generation failed for {}", dimension.getLoadKey(), e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_DATAPACK_COMMANDS_DIMENSION_TYPE_GENERATION_FAILED, MessageArgument.untrusted("value", level.dimension().identifier()), MessageArgument.untrusted("value2", String.valueOf(e.getMessage()))));
|
||||
continue;
|
||||
}
|
||||
@@ -180,7 +178,7 @@ public final class ModdedDatapackCommands {
|
||||
Files.writeString(output.toPath(), json, StandardCharsets.UTF_8);
|
||||
written.add(output.getPath());
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris dimension type write failed for {}", output, e);
|
||||
ModdedIrisLog.error("Iris dimension type write failed for {}", output, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_DATAPACK_COMMANDS_FAILED_WRITE, MessageArgument.untrusted("output", output), MessageArgument.untrusted("value", String.valueOf(e.getMessage()))));
|
||||
}
|
||||
}
|
||||
@@ -204,7 +202,7 @@ public final class ModdedDatapackCommands {
|
||||
Files.writeString(mcmeta.toPath(), meta, StandardCharsets.UTF_8);
|
||||
written.add(mcmeta.getPath());
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris pack.mcmeta write failed for {}", mcmeta, e);
|
||||
ModdedIrisLog.error("Iris pack.mcmeta write failed for {}", mcmeta, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_DATAPACK_COMMANDS_FAILED_WRITE_2, MessageArgument.untrusted("mcmeta", mcmeta), MessageArgument.untrusted("value", String.valueOf(e.getMessage()))));
|
||||
return 0;
|
||||
}
|
||||
@@ -237,7 +235,7 @@ public final class ModdedDatapackCommands {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris datapack import scan failed for pack {}", pack.getName(), e);
|
||||
ModdedIrisLog.error("Iris datapack import scan failed for pack {}", pack.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -18,13 +18,12 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
@@ -37,7 +36,6 @@ import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
final class ModdedDeveloperCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
|
||||
private ModdedDeveloperCommands() {
|
||||
@@ -71,7 +69,7 @@ final class ModdedDeveloperCommands {
|
||||
}
|
||||
return 1;
|
||||
} catch (SocketException error) {
|
||||
LOGGER.error("Iris developer network dump failed", error);
|
||||
ModdedIrisLog.error("Iris developer network dump failed", error);
|
||||
ModdedCommandFeedback.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_DEVELOPER_COMMANDS_NETWORK_SCAN_FAILED, MessageArgument.untrusted("value", error.getClass().getSimpleName())));
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-6
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
@@ -46,8 +47,6 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
@@ -62,7 +61,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class ModdedDustRevealer {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int MAX_HITS = 2_048;
|
||||
private static final int PARTICLE_BATCH_SIZE = 64;
|
||||
private static final DustParticleOptions REVEAL_DUST = new DustParticleOptions(0xFFD24A, 1.2F);
|
||||
@@ -231,7 +229,7 @@ public final class ModdedDustRevealer {
|
||||
}
|
||||
|
||||
private static void revealFailure(ModdedScheduler scheduler, RevealRun run, Throwable error) {
|
||||
LOGGER.error("Iris dust reveal failed for {} at {}", run.key(), coordinates(run.origin()), error);
|
||||
ModdedIrisLog.error("Iris dust reveal failed for {} at {}", run.key(), coordinates(run.origin()), error);
|
||||
scheduler.global(() -> {
|
||||
if (ACTIVE_RUNS.remove(run.playerId(), run)) {
|
||||
run.player().sendSystemMessage(Component.literal(
|
||||
@@ -415,7 +413,7 @@ public final class ModdedDustRevealer {
|
||||
}
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris dust column-object lookup failed at {}, {}, {}",
|
||||
ModdedIrisLog.error("Iris dust column-object lookup failed at {}, {}, {}",
|
||||
x, relativeY + minHeight, z, error);
|
||||
}
|
||||
return null;
|
||||
@@ -458,7 +456,7 @@ public final class ModdedDustRevealer {
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris dust {} failed", operation, error);
|
||||
ModdedIrisLog.error("Iris dust {} failed", operation, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.gui.GuiHost;
|
||||
import art.arcane.iris.core.loader.IrisRegistrant;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
@@ -29,14 +30,11 @@ import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.io.File;
|
||||
|
||||
final class ModdedEditCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private ModdedEditCommands() {
|
||||
}
|
||||
@@ -123,7 +121,7 @@ final class ModdedEditCommands {
|
||||
try {
|
||||
Desktop.getDesktop().open(file);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris edit failed to open {}", file, e);
|
||||
ModdedIrisLog.error("Iris edit failed to open {}", file, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_COULD_NOT_OPEN, MessageArgument.untrusted("value", file.getName()), MessageArgument.untrusted("value2", e.getClass().getSimpleName())));
|
||||
return 0;
|
||||
}
|
||||
|
||||
+3
-5
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.runtime.GoldenHashEngine;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.modded.ModdedBlockBuffer;
|
||||
@@ -29,8 +30,6 @@ import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -47,7 +46,6 @@ public final class ModdedGoldenHash {
|
||||
VERIFY
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final AtomicBoolean ACTIVE = new AtomicBoolean(false);
|
||||
|
||||
private final CommandSourceStack source;
|
||||
@@ -96,7 +94,7 @@ public final class ModdedGoldenHash {
|
||||
MessageArgument.trusted("threads", Math.max(1, threads)),
|
||||
MessageArgument.untrusted("mode", mode)
|
||||
));
|
||||
LOGGER.info("goldenhash start: dim={} seed={} radius={} threads={} mode={} file={}",
|
||||
ModdedIrisLog.info("goldenhash start: dim={} seed={} radius={} threads={} mode={} file={}",
|
||||
engine.getDimension().getLoadKey(), engine.getSeedManager().getSeed(), boundedRadius, Math.max(1, threads), mode, scan.hashEngine.getGoldenFile().getName());
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
@@ -182,7 +180,7 @@ public final class ModdedGoldenHash {
|
||||
|
||||
@Override
|
||||
public void chunkFailed(int chunkX, int chunkZ, Throwable error) {
|
||||
LOGGER.error("goldenhash chunk {},{} failed", chunkX, chunkZ, error);
|
||||
ModdedIrisLog.error("goldenhash chunk {},{} failed", chunkX, chunkZ, error);
|
||||
ModdedGoldenHash.this.fail(IrisLanguage.plain(
|
||||
RuntimeProgressMessages.GOLDEN_CHUNK_FAILED,
|
||||
MessageArgument.trusted("x", chunkX),
|
||||
|
||||
+4
-6
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
@@ -51,8 +52,6 @@ import net.minecraft.world.entity.Relative;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -64,7 +63,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
final class ModdedLocateCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final long LOCATE_TIMEOUT_MS = 120000L;
|
||||
private static final int NATIVE_STRUCTURE_LOCATE_RADIUS = 100;
|
||||
private static final ConcurrentHashMap<UUID, CompletableFuture<Position2>> ACTIVE_LOCATE_REQUESTS = new ConcurrentHashMap<>();
|
||||
@@ -260,7 +258,7 @@ final class ModdedLocateCommands {
|
||||
server.execute(() -> teleportToStructure(source, level, player, targetX, targetY, targetZ,
|
||||
"Iris-placed structure " + key));
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris structure locate failed for {}", key, e);
|
||||
ModdedIrisLog.error("Iris structure locate failed for {}", key, e);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCH_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()))));
|
||||
}
|
||||
}, "Iris Structure Locator");
|
||||
@@ -302,7 +300,7 @@ final class ModdedLocateCommands {
|
||||
teleportToStructure(source, level, player, targetX, targetY, targetZ,
|
||||
"native structure " + target.key());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Native structure locate failed for {}", target.key(), e);
|
||||
ModdedIrisLog.error("Native structure locate failed for {}", target.key(), e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCH_NATIVE_STRUCTURE_FAILED, MessageArgument.untrusted("value", target.key()), MessageArgument.untrusted("value2", e.getClass().getSimpleName())));
|
||||
}
|
||||
}
|
||||
@@ -518,7 +516,7 @@ final class ModdedLocateCommands {
|
||||
return;
|
||||
}
|
||||
if (failure != null) {
|
||||
LOGGER.error("Iris locate failed for {}", label, failure);
|
||||
ModdedIrisLog.error("Iris locate failed for {}", label, failure);
|
||||
server.execute(() -> {
|
||||
if (ACTIVE_LOCATE_REQUESTS.remove(playerId, search)) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCH_FAILED_2, MessageArgument.untrusted("failure", failure)));
|
||||
|
||||
+10
-12
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.tools.TreePlausibilizeBatch;
|
||||
import art.arcane.iris.core.tools.TreePlausibilizer;
|
||||
@@ -54,8 +55,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -74,7 +73,6 @@ import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
public final class ModdedObjectCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
private static final long MAX_SAVE_VOLUME = 500000L;
|
||||
private static final long MAX_AUTOSELECT_VOLUME = 100000L;
|
||||
@@ -313,7 +311,7 @@ public final class ModdedObjectCommands {
|
||||
try {
|
||||
object.write(file);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris object save failed for {}", file.getAbsolutePath(), e);
|
||||
ModdedIrisLog.error("Iris object save failed for {}", file.getAbsolutePath(), e);
|
||||
if (finalClaimed) {
|
||||
// Never leave a 0-byte claim file permanently blocking non-overwrite saves.
|
||||
file.delete();
|
||||
@@ -332,7 +330,7 @@ public final class ModdedObjectCommands {
|
||||
tileNote.append(" (").append(tilesSkipped[0]).append(" tile state(s) could not be captured)");
|
||||
}
|
||||
server.execute(() -> IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_SAVED_OBJECTS_IOB_X_X_BLOCK_S, MessageArgument.untrusted("value", engine.getData().getDataFolder().getName()), MessageArgument.untrusted("name", name), MessageArgument.untrusted("w", w), MessageArgument.untrusted("h", h), MessageArgument.untrusted("d", d), MessageArgument.untrusted("value2", object.getBlocks().size()), MessageArgument.untrusted("tileNote", tileNote))));
|
||||
LOGGER.info("Iris object save: {} {}x{}x{} blocks={} tilesSaved={} tilesSkipped={} -> {}", name, w, h, d, object.getBlocks().size(), tilesSaved[0], tilesSkipped[0], file.getAbsolutePath());
|
||||
ModdedIrisLog.info("Iris object save: {} {}x{}x{} blocks={} tilesSaved={} tilesSkipped={} -> {}", name, w, h, d, object.getBlocks().size(), tilesSaved[0], tilesSkipped[0], file.getAbsolutePath());
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
@@ -378,7 +376,7 @@ public final class ModdedObjectCommands {
|
||||
String blockKey = BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
|
||||
return ModdedTileData.capture(blockKey, snbt);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris tile capture failed at {} {} {}", pos.getX(), pos.getY(), pos.getZ(), e);
|
||||
ModdedIrisLog.error("Iris tile capture failed at {} {} {}", pos.getX(), pos.getY(), pos.getZ(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -391,7 +389,7 @@ public final class ModdedObjectCommands {
|
||||
try {
|
||||
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris object load failed for {}", key, e);
|
||||
ModdedIrisLog.error("Iris object load failed for {}", key, e);
|
||||
}
|
||||
if (object == null || object.getBlocks().size() == 0) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_EMPTY_OBJECT, MessageArgument.untrusted("key", key)));
|
||||
@@ -419,7 +417,7 @@ public final class ModdedObjectCommands {
|
||||
try {
|
||||
object.place(target.getX(), target.getY() + object.getCenter().getY(), target.getZ(), placer, placement, new RNG(), null);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris paste failed for {}", key, e);
|
||||
ModdedIrisLog.error("Iris paste failed for {}", key, e);
|
||||
ModdedObjectUndo.record(player == null ? ModdedObjectUndo.CONSOLE : player.getUUID(), level, placer.undoSnapshot());
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_PASTE_FAILED_PARTIAL_CHANGES_RECORDED_UNDO, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||
return 0;
|
||||
@@ -428,7 +426,7 @@ public final class ModdedObjectCommands {
|
||||
ModdedObjectUndo.record(owner, level, placer.undoSnapshot());
|
||||
String tileNote = tileNote(placer);
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_PLACED_AT_ROT_WRITE_S_NON_AIR, MessageArgument.untrusted("key", key), MessageArgument.untrusted("value", target.getX()), MessageArgument.untrusted("value2", target.getY()), MessageArgument.untrusted("value3", target.getZ()), MessageArgument.untrusted("rotation", rotation), MessageArgument.untrusted("value4", placer.writes()), MessageArgument.untrusted("value5", placer.nonAirWrites()), MessageArgument.untrusted("tileNote", tileNote)));
|
||||
LOGGER.info("Iris paste: {} at {},{},{} rot={} writes={} nonAir={} tilesRestored={} tilesSkipped={}",
|
||||
ModdedIrisLog.info("Iris paste: {} at {},{},{} rot={} writes={} nonAir={} tilesRestored={} tilesSkipped={}",
|
||||
key, target.getX(), target.getY(), target.getZ(), rotation, placer.writes(), placer.nonAirWrites(), placer.restoredTiles(), placer.skippedTiles());
|
||||
return placer.writes() > 0 ? 1 : 0;
|
||||
}
|
||||
@@ -608,7 +606,7 @@ public final class ModdedObjectCommands {
|
||||
try {
|
||||
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris object load failed for {}", key, e);
|
||||
ModdedIrisLog.error("Iris object load failed for {}", key, e);
|
||||
}
|
||||
if (object == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_OBJECT, MessageArgument.untrusted("key", key)));
|
||||
@@ -648,7 +646,7 @@ public final class ModdedObjectCommands {
|
||||
try {
|
||||
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris object load failed for {}", key, e);
|
||||
ModdedIrisLog.error("Iris object load failed for {}", key, e);
|
||||
}
|
||||
if (object == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_OBJECT_2, MessageArgument.untrusted("key", key)));
|
||||
@@ -665,7 +663,7 @@ public final class ModdedObjectCommands {
|
||||
try {
|
||||
object.write(file);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris object shrink save failed for {}", file.getAbsolutePath(), e);
|
||||
ModdedIrisLog.error("Iris object shrink save failed for {}", file.getAbsolutePath(), e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_FAILED_SAVE_OBJECT_2, MessageArgument.untrusted("value", file.getName()), MessageArgument.untrusted("value2", String.valueOf(e.getMessage()))));
|
||||
return 0;
|
||||
}
|
||||
|
||||
+2
-4
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.IObjectPlacer;
|
||||
@@ -37,14 +38,11 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
final class ModdedObjectPlacer implements IObjectPlacer {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int DEFAULT_FLUID_HEIGHT = 63;
|
||||
|
||||
private final ServerLevel level;
|
||||
@@ -199,7 +197,7 @@ final class ModdedObjectPlacer implements IObjectPlacer {
|
||||
}
|
||||
restoredTiles++;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris tile restore failed at {} {} {}", xx, yy, zz, e);
|
||||
ModdedIrisLog.error("Iris tile restore failed at {} {} {}", xx, yy, zz, e);
|
||||
skippedTiles++;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -18,13 +18,12 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
@@ -34,7 +33,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public final class ModdedObjectUndo {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int MAX_ENTRIES_PER_OWNER = 32;
|
||||
private static final ConcurrentHashMap<UUID, Deque<Entry>> UNDOS = new ConcurrentHashMap<>();
|
||||
private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
|
||||
@@ -48,7 +46,7 @@ public final class ModdedObjectUndo {
|
||||
|
||||
public static void init() {
|
||||
if (INITIALIZED.compareAndSet(false, true)) {
|
||||
LOGGER.info("Iris object undo service ready (bounded to {} paste(s) per player)", MAX_ENTRIES_PER_OWNER);
|
||||
ModdedIrisLog.info("Iris object undo service ready (bounded to {} paste(s) per player)", MAX_ENTRIES_PER_OWNER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +91,7 @@ public final class ModdedObjectUndo {
|
||||
// dimension id must never have blocks replayed into the dead ServerLevel.
|
||||
MinecraftServer server = entry.level().getServer();
|
||||
if (server == null || server.getLevel(entry.level().dimension()) != entry.level()) {
|
||||
LOGGER.warn("Iris object undo: skipped a stale entry for removed dimension {}",
|
||||
ModdedIrisLog.warn("Iris object undo: skipped a stale entry for removed dimension {}",
|
||||
entry.level().dimension().identifier());
|
||||
continue;
|
||||
}
|
||||
@@ -103,10 +101,10 @@ public final class ModdedObjectUndo {
|
||||
entry.level().setBlock(block.getKey(), block.getValue(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
|
||||
writes++;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris object undo: failed to revert a block at {}", block.getKey(), e);
|
||||
ModdedIrisLog.error("Iris object undo: failed to revert a block at {}", block.getKey(), e);
|
||||
}
|
||||
}
|
||||
LOGGER.info("Iris object undo: reverted {} block(s) in {}", writes, entry.level().dimension().identifier());
|
||||
ModdedIrisLog.info("Iris object undo: reverted {} block(s) in {}", writes, entry.level().dimension().identifier());
|
||||
reverted++;
|
||||
}
|
||||
return reverted;
|
||||
|
||||
+2
-4
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.core.pack.PackResourceCleanup;
|
||||
@@ -31,8 +32,6 @@ import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,7 +43,6 @@ import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
public final class ModdedPackCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
|
||||
private ModdedPackCommands() {
|
||||
@@ -139,7 +137,7 @@ public final class ModdedPackCommands {
|
||||
}
|
||||
server.execute(() -> report(source, result));
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris pack validation failed for {}", target.getName(), e);
|
||||
ModdedIrisLog.error("Iris pack validation failed for {}", target.getName(), e);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_PACK_COMMANDS_VALIDATION_FAILED, MessageArgument.untrusted("value", target.getName()), MessageArgument.untrusted("value2", String.valueOf(e.getMessage())))));
|
||||
broken++;
|
||||
}
|
||||
|
||||
+18
-20
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.pregenerator.PregenListener;
|
||||
import art.arcane.iris.core.pregenerator.PregenMantleBackpressure;
|
||||
@@ -31,8 +32,6 @@ import net.minecraft.server.level.ChunkResult;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -48,7 +47,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
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;
|
||||
@@ -106,7 +104,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
@Override
|
||||
public void init() {
|
||||
pauseGuard.suspend();
|
||||
LOGGER.info("Iris modded pregen init: dim={} mode={} inFlightCap={} timeout={}s workerPool={} chunkSystem={}",
|
||||
ModdedIrisLog.info("Iris modded pregen init: dim={} mode={} inFlightCap={} timeout={}s workerPool={} chunkSystem={}",
|
||||
level.dimension().identifier(),
|
||||
sync ? "sync" : "async",
|
||||
sync ? 1 : maxInFlight,
|
||||
@@ -114,7 +112,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
describeWorkerPool(),
|
||||
ModdedGenPool.describeChunkSystem());
|
||||
if (!sync && !ModdedGenPool.parallelChunkSystem()) {
|
||||
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.");
|
||||
ModdedIrisLog.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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +126,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
LOGGER.info("Iris modded pregen done: dim={} completed={} peakInFlight={} finalLimit={}",
|
||||
ModdedIrisLog.info("Iris modded pregen done: dim={} completed={} peakInFlight={} finalLimit={}",
|
||||
level.dimension().identifier(), completed.get(), inFlightPeak.get(), adaptiveLimit.get());
|
||||
if (deferFinalSaveIfRequested()) {
|
||||
return;
|
||||
@@ -245,7 +243,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
long remainingNanos = deadline - System.nanoTime();
|
||||
if (remainingNanos <= 0L) {
|
||||
LOGGER.warn("Iris pregen level save did not complete in time for {}", level.dimension().identifier());
|
||||
ModdedIrisLog.warn("Iris pregen level save did not complete in time for {}", level.dimension().identifier());
|
||||
return;
|
||||
}
|
||||
long waitMillis = Math.max(1L, Math.min(FINAL_SAVE_POLL_MILLIS,
|
||||
@@ -260,7 +258,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
continue;
|
||||
} catch (ExecutionException e) {
|
||||
Throwable cause = e.getCause() == null ? e : e.getCause();
|
||||
LOGGER.error("Iris pregen level save failed for {}", level.dimension().identifier(), cause);
|
||||
ModdedIrisLog.error("Iris pregen level save failed for {}", level.dimension().identifier(), cause);
|
||||
throw new IllegalStateException("Iris pregen level save failed for "
|
||||
+ level.dimension().identifier(), cause);
|
||||
}
|
||||
@@ -337,7 +335,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
try {
|
||||
Object result = loadFuture.get(timeoutSeconds, TimeUnit.SECONDS);
|
||||
if (result instanceof ChunkResult<?> chunkResult && !chunkResult.isSuccess()) {
|
||||
LOGGER.warn("Iris pregen chunk {},{} returned no chunk: {}", x, z, chunkResult.getError());
|
||||
ModdedIrisLog.warn("Iris pregen chunk {},{} returned no chunk: {}", x, z, chunkResult.getError());
|
||||
listener.onChunkFailed(x, z);
|
||||
return;
|
||||
}
|
||||
@@ -364,7 +362,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
// this abort the pregen thread spins hot against the dead chunk source until the JVM dies.
|
||||
if (level.getServer().isStopped() || !level.getServer().isRunning()) {
|
||||
if (SERVER_DEAD_LOGGED.compareAndSet(false, true)) {
|
||||
LOGGER.error("Iris pregen aborting: the server is no longer running (dim={})", level.dimension().identifier());
|
||||
ModdedIrisLog.error("Iris pregen aborting: the server is no longer running (dim={})", level.dimension().identifier());
|
||||
}
|
||||
listener.onChunkFailed(x, z);
|
||||
ModdedPregenJob.stop();
|
||||
@@ -401,7 +399,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
return;
|
||||
}
|
||||
if (result instanceof ChunkResult<?> chunkResult && !chunkResult.isSuccess()) {
|
||||
LOGGER.warn("Iris pregen chunk {},{} returned no chunk: {}", x, z, chunkResult.getError());
|
||||
ModdedIrisLog.warn("Iris pregen chunk {},{} returned no chunk: {}", x, z, chunkResult.getError());
|
||||
listener.onChunkFailed(x, z);
|
||||
return;
|
||||
}
|
||||
@@ -425,10 +423,10 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
private void logChunkFailure(int x, int z, Throwable failure) {
|
||||
Throwable cause = unwrap(failure);
|
||||
if (failureDetailLogged.compareAndSet(false, true)) {
|
||||
LOGGER.warn("Iris pregen chunk {},{} failed; first failure follows", x, z, cause);
|
||||
ModdedIrisLog.warn("Iris pregen chunk {},{} failed; first failure follows", x, z, cause);
|
||||
return;
|
||||
}
|
||||
LOGGER.warn("Iris pregen chunk {},{} failed: {}", x, z, cause.toString());
|
||||
ModdedIrisLog.warn("Iris pregen chunk {},{} failed: {}", x, z, cause.toString());
|
||||
}
|
||||
|
||||
private void markFinished() {
|
||||
@@ -500,7 +498,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
try {
|
||||
engine.getMantle().forceCleanupChunk(x, z);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.debug("Iris pregen mantle cleanup skipped for {},{}: {}", x, z, e.toString());
|
||||
ModdedIrisLog.debug("Iris pregen mantle cleanup skipped for {},{}: {}", x, z, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +564,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
try {
|
||||
current = dedicated.pauseWhenEmptySeconds();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.warn("Iris pregen could not read pause-when-empty-seconds: {}", e.toString());
|
||||
ModdedIrisLog.warn("Iris pregen could not read pause-when-empty-seconds: {}", e.toString());
|
||||
return;
|
||||
}
|
||||
if (current <= 0) {
|
||||
@@ -591,7 +589,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
suspendedFrom.set(current);
|
||||
armCrashRestore();
|
||||
LOGGER.info("Iris pregen: suspending pause-when-empty (was {}s), restored when the job ends", current);
|
||||
ModdedIrisLog.info("Iris pregen: suspending pause-when-empty (was {}s), restored when the job ends", current);
|
||||
}
|
||||
|
||||
private void restore() {
|
||||
@@ -606,9 +604,9 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
}
|
||||
try {
|
||||
dedicated.setPauseWhenEmptySeconds(previous);
|
||||
LOGGER.info("Iris pregen: {} pause-when-empty ({}s)", what, previous);
|
||||
ModdedIrisLog.info("Iris pregen: {} pause-when-empty ({}s)", what, previous);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris pregen could not restore pause-when-empty-seconds={}: {}. Set pause-when-empty-seconds={} in server.properties.",
|
||||
ModdedIrisLog.error("Iris pregen could not restore pause-when-empty-seconds={}: {}. Set pause-when-empty-seconds={} in server.properties.",
|
||||
previous, e.toString(), previous);
|
||||
}
|
||||
}
|
||||
@@ -655,11 +653,11 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
||||
if (!pauseStillArmed()) {
|
||||
return;
|
||||
}
|
||||
LOGGER.error("Iris pregen is timing out on an empty server while pause-when-empty-seconds is active: the paused server stops ticking. Set pause-when-empty-seconds=0 in server.properties, or keep a player online while pregenerating.");
|
||||
ModdedIrisLog.error("Iris pregen is timing out on an empty server while pause-when-empty-seconds is active: the paused server stops ticking. Set pause-when-empty-seconds=0 in server.properties, or keep a player online while pregenerating.");
|
||||
}
|
||||
|
||||
private void refuse(int current, String reason) {
|
||||
LOGGER.error("Iris pregen could not suspend pause-when-empty-seconds={} ({}). The server stops ticking once empty, which stalls pregen: set pause-when-empty-seconds=0 in server.properties, or keep a player online while pregenerating.",
|
||||
ModdedIrisLog.error("Iris pregen could not suspend pause-when-empty-seconds={} ({}). The server stops ticking once empty, which stalls pregen: set pause-when-empty-seconds=0 in server.properties, or keep a player online while pregenerating.",
|
||||
current, reason);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.tools.WorldMaintenance;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.mantle.EngineMantle;
|
||||
@@ -51,8 +52,6 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -65,7 +64,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
public final class ModdedRegen {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int APPLY_AHEAD = 8;
|
||||
private static final long CHUNK_SLOT_TIMEOUT_MILLIS = 120000L;
|
||||
private static final long FINAL_APPLY_TIMEOUT_MILLIS = 300000L;
|
||||
@@ -101,7 +99,7 @@ public final class ModdedRegen {
|
||||
ModdedRegen job = new ModdedRegen(source, level, generator, engine, centerX, centerZ, radius);
|
||||
int chunks = (job.radius * 2 + 1) * (job.radius * 2 + 1);
|
||||
job.ok("Regen started: " + chunks + " chunk(s) around " + centerX + "," + centerZ + ". Deleting and regenerating in place.");
|
||||
LOGGER.info("Iris regen start: dim={} center={},{} radius={} chunks={}",
|
||||
ModdedIrisLog.info("Iris regen start: dim={} center={},{} radius={} chunks={}",
|
||||
level.dimension().identifier(), centerX, centerZ, job.radius, chunks);
|
||||
Thread thread = new Thread(job::run, "Iris Regenerate");
|
||||
thread.setDaemon(true);
|
||||
@@ -117,11 +115,11 @@ public final class ModdedRegen {
|
||||
List<int[]> targets = ChunkSpiral.centerOut(centerX, centerZ, radius);
|
||||
int applied = regenerate(targets);
|
||||
ok("Regen finished: " + applied + "/" + targets.size() + " chunk(s) in " + Form.duration(M.ms() - startedAt, 2));
|
||||
LOGGER.info("Iris regen done: {}/{} chunks in {}ms", applied, targets.size(), M.ms() - startedAt);
|
||||
ModdedIrisLog.info("Iris regen done: {}/{} chunks in {}ms", applied, targets.size(), M.ms() - startedAt);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris regen failed", e);
|
||||
ModdedIrisLog.error("Iris regen failed", e);
|
||||
fail("Regen failed: " + e);
|
||||
} finally {
|
||||
WorldMaintenance.endWorldMaintenance(worldIdentity, "regen");
|
||||
@@ -155,7 +153,7 @@ public final class ModdedRegen {
|
||||
int chunkZ = target[1];
|
||||
if (!inFlight.tryAcquire(CHUNK_SLOT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
|
||||
aborted.set(true);
|
||||
LOGGER.error("Iris regen aborted: chunk {},{} waited {}ms for an apply slot ({}/{} done)",
|
||||
ModdedIrisLog.error("Iris regen aborted: chunk {},{} waited {}ms for an apply slot ({}/{} done)",
|
||||
chunkX, chunkZ, CHUNK_SLOT_TIMEOUT_MILLIS, completed.get(), total);
|
||||
fail("Regen aborted: apply pipeline stalled at " + completed.get() + "/" + total + " chunk(s)");
|
||||
break;
|
||||
@@ -173,7 +171,7 @@ public final class ModdedRegen {
|
||||
try {
|
||||
engine.generate(chunkX << 4, chunkZ << 4, blocks, biomes, false);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris regen chunk {},{} generation failed", chunkX, chunkZ, e);
|
||||
ModdedIrisLog.error("Iris regen chunk {},{} generation failed", chunkX, chunkZ, e);
|
||||
fail("Chunk " + chunkX + "," + chunkZ + " generation FAILED: " + e.getClass().getSimpleName());
|
||||
completed.incrementAndGet();
|
||||
inFlight.release();
|
||||
@@ -190,7 +188,7 @@ public final class ModdedRegen {
|
||||
success = true;
|
||||
applied.incrementAndGet();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris regen chunk {},{} apply failed", chunkX, chunkZ, e);
|
||||
ModdedIrisLog.error("Iris regen chunk {},{} apply failed", chunkX, chunkZ, e);
|
||||
fail("Chunk " + chunkX + "," + chunkZ + " apply FAILED: " + e.getClass().getSimpleName());
|
||||
} finally {
|
||||
int done = completed.incrementAndGet();
|
||||
@@ -212,7 +210,7 @@ public final class ModdedRegen {
|
||||
if (!allApplied.await(FINAL_APPLY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
|
||||
aborted.set(true);
|
||||
long outstanding = allApplied.getCount();
|
||||
LOGGER.error("Iris regen aborted: {} of {} chunk(s) did not finish within {}ms",
|
||||
ModdedIrisLog.error("Iris regen aborted: {} of {} chunk(s) did not finish within {}ms",
|
||||
outstanding, total, FINAL_APPLY_TIMEOUT_MILLIS);
|
||||
fail("Regen aborted: " + outstanding + " of " + total + " chunk(s) never finished");
|
||||
}
|
||||
|
||||
+2
-4
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.structure.StructureIndexService;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
@@ -40,8 +41,6 @@ import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@@ -53,7 +52,6 @@ import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
public final class ModdedStructureCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
|
||||
private static final SuggestionProvider<CommandSourceStack> IRIS_STRUCTURE_KEYS = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestIrisStructureKeys(context, builder);
|
||||
@@ -213,7 +211,7 @@ public final class ModdedStructureCommands {
|
||||
piece.getObject().place(piece.getX(), piece.getY(), piece.getZ(), placer, config, rng, null, null, data);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris structure place failed for {}", key, e);
|
||||
ModdedIrisLog.error("Iris structure place failed for {}", key, e);
|
||||
ModdedObjectUndo.record(owner, level, placer.undoSnapshot());
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STRUCTURE_COMMANDS_PLACE_FAILED_PARTIAL_CHANGES_RECORDED_UNDO, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||
return 0;
|
||||
|
||||
+23
-23
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.gui.GuiHost;
|
||||
import art.arcane.iris.core.gui.NoiseExplorerGUI;
|
||||
@@ -63,8 +64,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Relative;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.zeroturnaround.zip.ZipUtil;
|
||||
|
||||
import java.awt.Desktop;
|
||||
@@ -85,7 +84,6 @@ import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
public final class ModdedStudioCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
private static final Pattern PROJECT_NAME = Pattern.compile("[a-z0-9_-]+");
|
||||
private static final Pattern STUDIO_ID_SANITIZER = Pattern.compile("[^a-z0-9_-]");
|
||||
@@ -284,7 +282,7 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
workspace = ModdedWorkspaceGenerator.writeWorkspace(IrisData.get(folder), folder, open);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris workspace write failed for {}", folder, e);
|
||||
ModdedIrisLog.error("Iris workspace write failed for {}", folder, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_FAILED_WRITE_WORKSPACE, MessageArgument.untrusted("value", folder.getAbsolutePath()), MessageArgument.untrusted("value2", String.valueOf(e.getMessage()))));
|
||||
return 0;
|
||||
}
|
||||
@@ -299,7 +297,7 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
Desktop.getDesktop().open(workspace);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris workspace open failed for {}", workspace, e);
|
||||
ModdedIrisLog.error("Iris workspace open failed for {}", workspace, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_COULD_NOT_OPEN, MessageArgument.untrusted("value", workspace.getName()), MessageArgument.untrusted("value2", e.getClass().getSimpleName())));
|
||||
return 0;
|
||||
}
|
||||
@@ -380,8 +378,9 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
File packFolder = new File(ModdedPackCommands.packsRoot(), pack);
|
||||
if (!new File(packFolder, "dimensions/" + pack + ".json").isFile()) {
|
||||
server.execute(() -> IrisModdedCommands.fail(source, "Pack '" + pack
|
||||
+ "' is not installed. Use /iris download pack=overworld or pack=underworld, then restart."));
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||
MessageArgument.untrusted("pack", pack))));
|
||||
return;
|
||||
}
|
||||
IrisData data = IrisData.get(packFolder);
|
||||
@@ -393,7 +392,7 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
ModdedWorkspaceGenerator.writeWorkspace(data, packFolder, true);
|
||||
} catch (Throwable workspaceError) {
|
||||
LOGGER.error("Iris workspace write failed for {}", packFolder, workspaceError);
|
||||
ModdedIrisLog.error("Iris workspace write failed for {}", packFolder, workspaceError);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_FAILED_WRITE_WORKSPACE,
|
||||
MessageArgument.untrusted("value", packFolder.getAbsolutePath()),
|
||||
@@ -407,7 +406,7 @@ public final class ModdedStudioCommands {
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio open failed for {}", pack, e);
|
||||
ModdedIrisLog.error("Iris studio open failed for {}", pack, e);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_STUDIO_OPEN_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e)))));
|
||||
}
|
||||
}
|
||||
@@ -417,7 +416,7 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
handle = ModdedDimensionManager.create(server, dimensionId, pack, pack, seed);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris console studio injection failed for {} ({})", dimensionId, pack, e);
|
||||
ModdedIrisLog.error("Iris console studio injection failed for {} ({})", dimensionId, pack, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_STUDIO_INJECTION_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e))));
|
||||
return;
|
||||
}
|
||||
@@ -430,7 +429,7 @@ public final class ModdedStudioCommands {
|
||||
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris console studio surface probe failed for {}", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris console studio surface probe failed for {}", dimensionId, e);
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_CONSOLE_STUDIO_OPEN_NOW_RUNS_SEED_TRANSIENT_NOT_WRITTEN_IRIS, MessageArgument.untrusted("dimensionId", dimensionId), MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("seed", seed)));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_ENTER_IT_WITH_EXECUTE_RUN_TP_S_8_5_8, MessageArgument.untrusted("dimensionId", dimensionId), MessageArgument.untrusted("surface", surface)));
|
||||
@@ -447,7 +446,7 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
handle = ModdedDimensionManager.create(server, dimensionId, pack, pack, seed);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio injection failed for {} ({})", dimensionId, pack, e);
|
||||
ModdedIrisLog.error("Iris studio injection failed for {} ({})", dimensionId, pack, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_STUDIO_INJECTION_FAILED_2, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e))));
|
||||
return;
|
||||
}
|
||||
@@ -460,7 +459,7 @@ public final class ModdedStudioCommands {
|
||||
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio surface probe failed for {}", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris studio surface probe failed for {}", dimensionId, e);
|
||||
}
|
||||
player.teleportTo(studio, 8.5D, surface, 8.5D, java.util.Set.<Relative>of(), player.getYRot(), player.getXRot(), false);
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_STUDIO_OPEN_NOW_RUNS_SEED_USE_IRIS_STUDIO_CLOSE_WHEN, MessageArgument.untrusted("dimensionId", dimensionId), MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("seed", seed)));
|
||||
@@ -480,7 +479,7 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
ModdedDimensionManager.remove(server, dimensionId, true);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio close failed for {}", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris studio close failed for {}", dimensionId, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_STUDIO_CLOSE_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e))));
|
||||
return 0;
|
||||
}
|
||||
@@ -553,7 +552,7 @@ public final class ModdedStudioCommands {
|
||||
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris tpstudio surface probe failed", e);
|
||||
ModdedIrisLog.error("Iris tpstudio surface probe failed", e);
|
||||
}
|
||||
player.teleportTo(studio, 8.5D, surface, 8.5D, java.util.Set.<Relative>of(), player.getYRot(), player.getXRot(), false);
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_TELEPORTED_YOUR_STUDIO, MessageArgument.untrusted("dimensionId", dimensionId)));
|
||||
@@ -593,22 +592,23 @@ public final class ModdedStudioCommands {
|
||||
try {
|
||||
File templateFolder = new File(packsRoot, template);
|
||||
if (!new File(templateFolder, "dimensions/" + template + ".json").isFile()) {
|
||||
server.execute(() -> IrisModdedCommands.fail(source, "Template pack '" + template
|
||||
+ "' is not installed. Install its zip with /iris download link=<zip-url>, then restart."));
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||
MessageArgument.untrusted("pack", template))));
|
||||
return;
|
||||
}
|
||||
IrisProjectCopier.copyProject(templateFolder, target, template, name);
|
||||
try {
|
||||
ModdedWorkspaceGenerator.writeWorkspace(IrisData.get(target), target);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris studio create workspace generation failed for {}", name, e);
|
||||
ModdedIrisLog.error("Iris studio create workspace generation failed for {}", name, e);
|
||||
}
|
||||
server.execute(() -> {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_CREATED_PROJECT_AT, MessageArgument.untrusted("name", name), MessageArgument.untrusted("value", target.getAbsolutePath())));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_EDIT_DIMENSIONS_JSON_REST_PACK_VSCODE_WORKSPACE_WITH_JSON_SCHEMA, MessageArgument.untrusted("name", name)));
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio create failed for {}", name, e);
|
||||
ModdedIrisLog.error("Iris studio create failed for {}", name, e);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PROJECT_CREATION_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e)))));
|
||||
}
|
||||
}, "Iris Studio Create");
|
||||
@@ -630,7 +630,7 @@ public final class ModdedStudioCommands {
|
||||
File result = compilePackage(folder, dimKey);
|
||||
server.execute(() -> IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PACKAGE_COMPILED, MessageArgument.untrusted("value", result.getAbsolutePath()))));
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris package failed for {}", dimKey, e);
|
||||
ModdedIrisLog.error("Iris package failed for {}", dimKey, e);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PACKAGING_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e)))));
|
||||
}
|
||||
}, "Iris Studio Package");
|
||||
@@ -728,7 +728,7 @@ public final class ModdedStudioCommands {
|
||||
IO.copyFile(objectFile, new File(folder, "objects/" + objectKey + ".iob"));
|
||||
hashes.append(IO.hash(objectFile));
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris package failed to copy object {}", objectKey, e);
|
||||
ModdedIrisLog.error("Iris package failed to copy object {}", objectKey, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,7 +793,7 @@ public final class ModdedStudioCommands {
|
||||
IO.writeAll(new File(folder, category + "/" + key + ".json"), json);
|
||||
return IO.hash(json);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris package failed to write {}/{}", category, key, e);
|
||||
ModdedIrisLog.error("Iris package failed to write {}/{}", category, key, e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -838,7 +838,7 @@ public final class ModdedStudioCommands {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_RARITY, MessageArgument.untrusted("key", key), MessageArgument.untrusted("rarity", rarity), MessageArgument.untrusted("value", Form.f((double) count.get() / totalTasks * 100, 2))));
|
||||
}));
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris region sampling failed", e);
|
||||
ModdedIrisLog.error("Iris region sampling failed", e);
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_REGION_SAMPLING_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()))));
|
||||
}
|
||||
}, "Iris Region Sampler");
|
||||
|
||||
+5
-7
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
||||
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
||||
@@ -31,8 +32,6 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@@ -44,7 +43,6 @@ import java.util.TreeMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
final class ModdedUnregisteredStructures {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private ModdedUnregisteredStructures() {
|
||||
}
|
||||
@@ -67,13 +65,13 @@ final class ModdedUnregisteredStructures {
|
||||
.filter((ExcludedStructure entry) -> entry.status() == ReportStatus.UNPLACED)
|
||||
.count();
|
||||
long hidden = excluded.size() - unregistered - unplaced;
|
||||
LOGGER.info("[Iris goto unregistered] {} structure candidate(s) excluded from /iris goto structure in {}",
|
||||
ModdedIrisLog.info("[Iris goto unregistered] {} structure candidate(s) excluded from /iris goto structure in {}",
|
||||
excluded.size(), dimension);
|
||||
for (ExcludedStructure entry : excluded) {
|
||||
LOGGER.info("[Iris goto unregistered] [{}] {} - {}",
|
||||
ModdedIrisLog.info("[Iris goto unregistered] [{}] {} - {}",
|
||||
entry.status().label(), entry.key(), entry.reason());
|
||||
}
|
||||
LOGGER.info("[Iris goto unregistered] Inventory scope is the live registry, this pack's "
|
||||
ModdedIrisLog.info("[Iris goto unregistered] Inventory scope is the live registry, this pack's "
|
||||
+ "nativeStructures placements, and structureLoader editable resources. This is deterministic "
|
||||
+ "eligibility analysis and performs no chunk search; absent unmanaged datapack resources "
|
||||
+ "cannot be inferred after registry loading.");
|
||||
@@ -82,7 +80,7 @@ final class ModdedUnregisteredStructures {
|
||||
+ unregistered + " unregistered, " + unplaced + " unplaced).");
|
||||
return 1;
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris failed to build the excluded structure report for {}",
|
||||
ModdedIrisLog.error("Iris failed to build the excluded structure report for {}",
|
||||
level.dimension().identifier(), error);
|
||||
IrisModdedCommands.fail(source,
|
||||
"Iris could not build the excluded structure report; see the server console.");
|
||||
|
||||
+2
-4
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
@@ -42,8 +43,6 @@ import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.component.ItemLore;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
@@ -52,7 +51,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class ModdedWandService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final ConcurrentHashMap<UUID, Selection> SELECTIONS = new ConcurrentHashMap<>();
|
||||
private static final String WAND_TAG = "iris_wand";
|
||||
private static final String DUST_TAG = "iris_dust";
|
||||
@@ -213,7 +211,7 @@ public final class ModdedWandService {
|
||||
draw(player.level(), player, selection);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris wand selection draw failed", e);
|
||||
ModdedIrisLog.error("Iris wand selection draw failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-6
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.IrisMessages;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
@@ -66,8 +67,6 @@ import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -77,7 +76,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class ModdedWhatCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE =
|
||||
Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
private static final SuggestionProvider<CommandSourceStack> MARKER_TYPES =
|
||||
@@ -343,7 +341,7 @@ public final class ModdedWhatCommands {
|
||||
MessageArgument.untrusted("object", object)));
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris object lookup failed for /iris what block at {}, {}, {}",
|
||||
ModdedIrisLog.error("Iris object lookup failed for /iris what block at {}, {}, {}",
|
||||
pos.getX(), pos.getY(), pos.getZ(), error);
|
||||
}
|
||||
}
|
||||
@@ -486,7 +484,7 @@ public final class ModdedWhatCommands {
|
||||
|
||||
private static void markerFailure(CommandSourceStack source,
|
||||
ModdedScheduler scheduler, MarkerRun run, Throwable error) {
|
||||
LOGGER.error("Iris marker scan failed for {}", run.marker(), error);
|
||||
ModdedIrisLog.error("Iris marker scan failed for {}", run.marker(), error);
|
||||
scheduler.global(() -> {
|
||||
if (ACTIVE_MARKER_RUNS.remove(run.playerId(), run)) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
@@ -514,7 +512,7 @@ public final class ModdedWhatCommands {
|
||||
private static void logLookupFailure(CommandSourceStack source,
|
||||
String operation, Throwable error,
|
||||
TextKey message) {
|
||||
LOGGER.error("Iris /what {} lookup failed in {}", operation,
|
||||
ModdedIrisLog.error("Iris /what {} lookup failed in {}", operation,
|
||||
source.getLevel().dimension().identifier(), error);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
message,
|
||||
|
||||
+11
-11
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.pack.BrokenPackException;
|
||||
import art.arcane.iris.core.pack.PackValidationRegistry;
|
||||
@@ -42,8 +43,6 @@ import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.IdentifierArgument;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -57,7 +56,6 @@ import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
public final class ModdedWorldCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
private static final String DEFAULT_NAMESPACE = "irisworldgen";
|
||||
private static final long DEFAULT_SEED = 1337L;
|
||||
@@ -174,8 +172,9 @@ public final class ModdedWorldCommands {
|
||||
if (packFolder.isDirectory()) {
|
||||
return enableInstalled(source, server, dimensionId, pack, packDimension, seed);
|
||||
}
|
||||
IrisModdedCommands.fail(source, "Pack '" + pack
|
||||
+ "' is not installed. Use /iris download pack=overworld or pack=underworld, then restart.");
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_WORLD_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||
MessageArgument.untrusted("pack", pack)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -189,7 +188,7 @@ public final class ModdedWorldCommands {
|
||||
try {
|
||||
ModdedDimensionManager.createPersistent(server, dimensionId, pack, packDimension, seed);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris world injection failed for {} (pack={} dim={})", dimensionId, pack, packDimension, e);
|
||||
ModdedIrisLog.error("Iris world injection failed for {} (pack={} dim={})", dimensionId, pack, packDimension, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_FAILED_INJECT_IRIS_WORLD, MessageArgument.untrusted("dimensionId", dimensionId), MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e))));
|
||||
return 0;
|
||||
}
|
||||
@@ -220,7 +219,7 @@ public final class ModdedWorldCommands {
|
||||
try {
|
||||
ModdedDimensionManager.createPersistent(server, dimensionId, pack, packDimension, seed);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris primary world injection failed for {} (pack={} dim={})", dimensionId, pack, packDimension, e);
|
||||
ModdedIrisLog.error("Iris primary world injection failed for {} (pack={} dim={})", dimensionId, pack, packDimension, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_FAILED_INJECT_IRIS_PRIMARY_WORLD, MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e))));
|
||||
return 0;
|
||||
}
|
||||
@@ -265,8 +264,9 @@ public final class ModdedWorldCommands {
|
||||
if (packFolder.isDirectory()) {
|
||||
return applyMainWorld(source, pack, packDimension, packRaw, seed);
|
||||
}
|
||||
IrisModdedCommands.fail(source, "Pack '" + pack
|
||||
+ "' is not installed. Use /iris download pack=overworld or pack=underworld, then restart.");
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_WORLD_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||
MessageArgument.untrusted("pack", pack)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ public final class ModdedWorldCommands {
|
||||
return 0;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris main world pack load failed for {} (dim={})", pack, packDimension, e);
|
||||
ModdedIrisLog.error("Iris main world pack load failed for {} (dim={})", pack, packDimension, e);
|
||||
if (PackValidationRegistry.get(pack) == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_PACK_IS_NOT_READY_YET_STILL_LOADING_VALIDATING_TRY_COMMAND, MessageArgument.untrusted("pack", pack)));
|
||||
return 0;
|
||||
@@ -384,7 +384,7 @@ public final class ModdedWorldCommands {
|
||||
try {
|
||||
removed = ModdedDimensionManager.removePersistent(server, dimensionId, wipeStorage);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris world removal failed for {}", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris world removal failed for {}", dimensionId, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_FAILED_REMOVE_IRIS_WORLD, MessageArgument.untrusted("dimensionId", dimensionId), MessageArgument.untrusted("value", e.getClass().getSimpleName()), MessageArgument.trusted("errorMessage", IrisLanguage.errorDetail(e))));
|
||||
return 0;
|
||||
}
|
||||
|
||||
+8
-10
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.service;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.service.EngineMaintenance;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
@@ -27,8 +28,6 @@ import art.arcane.iris.modded.ModdedWorldEngines;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.util.project.context.IrisContext;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -42,7 +41,6 @@ import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class ModdedEngineMaintenanceService implements ModdedTickableService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final long MAINTENANCE_PERIOD_MILLIS = 2_000L;
|
||||
private static final long SAVE_PERIOD_MILLIS = 60_000L;
|
||||
private static final long SHUTDOWN_TIMEOUT_SECONDS = 30L;
|
||||
@@ -120,7 +118,7 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
} catch (RejectedExecutionException exception) {
|
||||
inFlight.remove(engine);
|
||||
if (active == service && !active.isShutdown()) {
|
||||
LOGGER.error("Iris rejected engine maintenance for {}", engineName(engine), exception);
|
||||
ModdedIrisLog.error("Iris rejected engine maintenance for {}", engineName(engine), exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,7 +146,7 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
|
||||
EngineMaintenance.Outcome outcome = EngineMaintenance.run(engine);
|
||||
if (outcome.unloadedTectonicPlates() > 0) {
|
||||
LOGGER.debug("Iris unloaded {} tectonic plates in {}ms for {}",
|
||||
ModdedIrisLog.debug("Iris unloaded {} tectonic plates in {}ms for {}",
|
||||
outcome.unloadedTectonicPlates(), outcome.unloadDurationMillis(), engineName(engine));
|
||||
}
|
||||
} catch (GenerationSessionException exception) {
|
||||
@@ -156,13 +154,13 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
return;
|
||||
}
|
||||
IrisLogging.reportError(exception);
|
||||
LOGGER.error("Iris engine maintenance session failed for {}", engineName(engine), exception);
|
||||
ModdedIrisLog.error("Iris engine maintenance session failed for {}", engineName(engine), exception);
|
||||
} catch (Throwable exception) {
|
||||
if (EngineMaintenance.isMantleClosed(exception)) {
|
||||
return;
|
||||
}
|
||||
IrisLogging.reportError(exception);
|
||||
LOGGER.error("Iris engine maintenance failed for {}", engineName(engine), exception);
|
||||
ModdedIrisLog.error("Iris engine maintenance failed for {}", engineName(engine), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +178,7 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
return;
|
||||
}
|
||||
IrisLogging.reportError(exception);
|
||||
LOGGER.error("Iris engine save failed for {}", engineName(engine), exception);
|
||||
ModdedIrisLog.error("Iris engine save failed for {}", engineName(engine), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,13 +210,13 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
IllegalStateException failure = new IllegalStateException(
|
||||
"Iris engine maintenance workers did not stop after shutdownNow");
|
||||
IrisLogging.reportError(failure);
|
||||
LOGGER.error("Iris engine maintenance did not terminate; active engine lifecycle leases will block unsafe shutdown", failure);
|
||||
ModdedIrisLog.error("Iris engine maintenance did not terminate; active engine lifecycle leases will block unsafe shutdown", failure);
|
||||
return false;
|
||||
} catch (InterruptedException exception) {
|
||||
active.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
IrisLogging.reportError(exception);
|
||||
LOGGER.error("Interrupted while draining Iris engine maintenance", exception);
|
||||
ModdedIrisLog.error("Interrupted while draining Iris engine maintenance", exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -18,11 +18,10 @@
|
||||
|
||||
package art.arcane.iris.modded.service;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.framework.MeteredCache;
|
||||
import art.arcane.iris.engine.framework.PreservationRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
@@ -31,7 +30,6 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public final class ModdedPreservationService implements ModdedService, PreservationRegistry {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final long DEREFERENCE_INTERVAL_MILLIS = 60000L;
|
||||
|
||||
private final List<Thread> threads = new CopyOnWriteArrayList<>();
|
||||
@@ -107,17 +105,17 @@ public final class ModdedPreservationService implements ModdedService, Preservat
|
||||
}
|
||||
try {
|
||||
thread.interrupt();
|
||||
LOGGER.info("Iris preservation interrupted thread {}", thread.getName());
|
||||
ModdedIrisLog.info("Iris preservation interrupted thread {}", thread.getName());
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris preservation failed to interrupt thread {}", thread.getName(), error);
|
||||
ModdedIrisLog.error("Iris preservation failed to interrupt thread {}", thread.getName(), error);
|
||||
}
|
||||
}
|
||||
for (ExecutorService service : services) {
|
||||
try {
|
||||
service.shutdownNow();
|
||||
LOGGER.info("Iris preservation shut down executor {}", service);
|
||||
ModdedIrisLog.info("Iris preservation shut down executor {}", service);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris preservation failed to shut down executor {}", service, error);
|
||||
ModdedIrisLog.error("Iris preservation failed to shut down executor {}", service, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,6 +60,6 @@ public final class ModdedSettingsHotloadService implements ModdedTickableService
|
||||
}
|
||||
|
||||
private static File settingsFile() {
|
||||
return IrisPlatforms.get().dataFile("settings.json");
|
||||
return IrisPlatforms.get().dataFile("iris.json");
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded.service;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.gui.PregeneratorJob;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.tools.WorldMaintenance;
|
||||
@@ -37,8 +38,6 @@ import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.io.ReactiveFolder;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
@@ -52,7 +51,6 @@ import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public final class ModdedStudioHotloadService implements ModdedTickableService, EnginePlatformHooks {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String STUDIO_DIMENSION_PREFIX = "irisworldgen:studio_";
|
||||
private static final long POLL_MILLIS = 250L;
|
||||
private static final long CHECK_LATCH_MILLIS = 1_000L;
|
||||
@@ -237,7 +235,7 @@ public final class ModdedStudioHotloadService implements ModdedTickableService,
|
||||
folder.check();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio hotload check failed for {}", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris studio hotload check failed for {}", dimensionId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,9 +247,9 @@ public final class ModdedStudioHotloadService implements ModdedTickableService,
|
||||
try {
|
||||
engine.hotloadSilently();
|
||||
generator.onHotload();
|
||||
LOGGER.info("Iris studio hotload {} pack={} {}ms", dimensionId, engine.getDimension().getLoadKey(), System.currentTimeMillis() - start);
|
||||
ModdedIrisLog.info("Iris studio hotload {} pack={} {}ms", dimensionId, engine.getDimension().getLoadKey(), System.currentTimeMillis() - start);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris studio hotload failed for {}", dimensionId, e);
|
||||
ModdedIrisLog.error("Iris studio hotload failed for {}", dimensionId, e);
|
||||
throw new IllegalStateException("Iris studio hotload failed for " + dimensionId, e);
|
||||
}
|
||||
}
|
||||
@@ -275,7 +273,7 @@ public final class ModdedStudioHotloadService implements ModdedTickableService,
|
||||
IrisData data = engine.getData();
|
||||
ModdedWorkspaceGenerator.writeWorkspace(data, data.getDataFolder());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris {} failed for {}", operation, engine.getDimension().getLoadKey(), e);
|
||||
ModdedIrisLog.error("Iris {} failed for {}", operation, engine.getDimension().getLoadKey(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -1,5 +1,6 @@
|
||||
package art.arcane.iris.modded.service;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||
import art.arcane.iris.modded.ModdedScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -12,8 +13,6 @@ import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -21,7 +20,6 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
final class ModdedTreeFellerPresentation {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int MIN_BLOCKS_PER_PULSE = 4;
|
||||
private static final int MAX_BLOCKS_PER_PULSE = 64;
|
||||
private static final int TARGET_EROSION_PULSES = 60;
|
||||
@@ -215,13 +213,13 @@ final class ModdedTreeFellerPresentation {
|
||||
|
||||
private void reportEffectFailure(Throwable error) {
|
||||
if (effectFailureReported.compareAndSet(false, true)) {
|
||||
LOGGER.error("Iris modded tree-feller presentation failed", error);
|
||||
ModdedIrisLog.error("Iris modded tree-feller presentation failed", error);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportDeliveryFailure(Throwable error) {
|
||||
if (deliveryFailureReported.compareAndSet(false, true)) {
|
||||
LOGGER.error("Iris modded tree-feller drop delivery failed", error);
|
||||
ModdedIrisLog.error("Iris modded tree-feller drop delivery failed", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,5 +1,6 @@
|
||||
package art.arcane.iris.modded.service;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.service.tree.TreeDefinitionIndex;
|
||||
import art.arcane.iris.core.service.tree.TreeMarkerTraversal;
|
||||
@@ -23,8 +24,6 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -38,7 +37,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
public final class ModdedTreeFellerService implements ModdedTickableService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final ThreadLocal<Integer> BREAK_PROBE_DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||
|
||||
private final AtomicBoolean enabled = new AtomicBoolean();
|
||||
@@ -245,7 +243,7 @@ public final class ModdedTreeFellerService implements ModdedTickableService {
|
||||
(x, y, z) -> markerAt(prepared.engine(), prepared.minimumY(), x, y, z)
|
||||
);
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris modded tree-feller discovery failed", error);
|
||||
ModdedIrisLog.error("Iris modded tree-feller discovery failed", error);
|
||||
discovery = new TreeMarkerTraversal.Discovery(List.of(), false);
|
||||
}
|
||||
TreeMarkerTraversal.Discovery resolved = discovery;
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package art.arcane.iris.client;
|
||||
|
||||
import art.arcane.iris.spi.protocol.IrisMessage;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisClientHotloadTest {
|
||||
private static final IrisMessage.DimensionStatus OVERWORLD = new IrisMessage.DimensionStatus(
|
||||
"overworld",
|
||||
"pack",
|
||||
1L,
|
||||
-64,
|
||||
320,
|
||||
true
|
||||
);
|
||||
|
||||
@Test
|
||||
public void successfulCurrentPackHotloadInvalidatesWorldCaches() {
|
||||
IrisMessage.StudioHotload hotload = new IrisMessage.StudioHotload("pack", 0, false, "");
|
||||
|
||||
assertTrue(IrisClient.shouldInvalidateForHotload(OVERWORLD, hotload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failedOrUnrelatedHotloadRetainsWorldCaches() {
|
||||
assertFalse(IrisClient.shouldInvalidateForHotload(
|
||||
OVERWORLD,
|
||||
new IrisMessage.StudioHotload("pack", 0, true, "failed")
|
||||
));
|
||||
assertFalse(IrisClient.shouldInvalidateForHotload(
|
||||
OVERWORLD,
|
||||
new IrisMessage.StudioHotload("other", 0, false, "")
|
||||
));
|
||||
assertFalse(IrisClient.shouldInvalidateForHotload(null, null));
|
||||
}
|
||||
}
|
||||
+48
@@ -5,7 +5,10 @@ import org.junit.Test;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
@@ -24,4 +27,49 @@ public class ModdedIrisLogLevelCoverageTest {
|
||||
String body = source.substring(router, source.indexOf("public static void debug(", router));
|
||||
assertTrue(body, body.contains("default -> info(message);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void slf4jStyleArgumentsAndTrailingThrowableArePreserved() {
|
||||
RuntimeException failure = new RuntimeException("broken");
|
||||
|
||||
ModdedIrisLog.RenderedLog rendered = ModdedIrisLog.render("chunk {},{} failed", 4, 9, failure);
|
||||
|
||||
assertEquals("chunk 4,9 failed", rendered.message());
|
||||
assertEquals(failure, rendered.error());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formattedDebugThrowableUsesTheVisibleDebugRouteWhenEnabled() throws IOException {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedIrisLog.java"));
|
||||
int start = source.indexOf("public static void debug(String format, Object... arguments)");
|
||||
int end = source.indexOf("public static void info(String message)", start);
|
||||
assertTrue("formatted debug overload not found", start >= 0);
|
||||
assertTrue("formatted debug overload boundary not found", end > start);
|
||||
String body = source.substring(start, end);
|
||||
|
||||
assertTrue(body, body.contains("if (!debugEnabled())"));
|
||||
assertTrue(body, body.contains("LOGGER.info(\"[Iris/DEBUG] \" + clean(rendered.message()), rendered.error())"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void moddedProductionUsesTheIrisLogFrontDoor() throws IOException {
|
||||
Path root = Path.of(System.getProperty("iris.moddedCommonSources"));
|
||||
try (Stream<Path> files = Files.walk(root)) {
|
||||
List<Path> bypasses = files
|
||||
.filter(path -> path.toString().endsWith(".java"))
|
||||
.filter(path -> !path.getFileName().toString().equals("ModdedIrisLog.java"))
|
||||
.filter(path -> {
|
||||
try {
|
||||
String source = Files.readString(path);
|
||||
return source.contains("LoggerFactory.getLogger")
|
||||
|| source.contains("private static final Logger LOGGER");
|
||||
} catch (IOException unreadable) {
|
||||
throw new IllegalStateException(unreadable);
|
||||
}
|
||||
})
|
||||
.toList();
|
||||
assertTrue(bypasses.toString(), bypasses.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ public class ModdedPlatformPathsTest {
|
||||
File iris = new File(temporaryFolder.getRoot(), "iris");
|
||||
|
||||
assertEquals(iris, platform.dataFolder());
|
||||
assertEquals(new File(iris, "settings.json"), platform.dataFile("settings.json"));
|
||||
assertEquals(new File(iris, "iris.json"), platform.dataFile("iris.json"));
|
||||
assertEquals(new File(iris, "parity"), platform.dataFolder("parity"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user