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.awt.Color;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -1572,8 +1571,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
injected.set(true);
|
injected.set(true);
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.error(C.RED + "Failed to inject Bukkit");
|
IrisLogging.reportError(C.RED + "Failed to inject Bukkit", e);
|
||||||
e.printStackTrace();
|
|
||||||
ResettableClassFileTransformer partialServerLevel = serverLevelTransformer;
|
ResettableClassFileTransformer partialServerLevel = serverLevelTransformer;
|
||||||
ResettableClassFileTransformer partialStorageAccess = levelStorageAccessTransformer;
|
ResettableClassFileTransformer partialStorageAccess = levelStorageAccessTransformer;
|
||||||
serverLevelTransformer = null;
|
serverLevelTransformer = null;
|
||||||
@@ -1627,22 +1625,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
try {
|
try {
|
||||||
transformer.reset(Agent.getInstrumentation(), AgentBuilder.RedefinitionStrategy.RETRANSFORMATION);
|
transformer.reset(Agent.getInstrumentation(), AgentBuilder.RedefinitionStrategy.RETRANSFORMATION);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.error(C.RED + "Failed to remove Bukkit world lifecycle injection");
|
IrisLogging.reportError(C.RED + "Failed to remove Bukkit world lifecycle injection", e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeCurrentPaperWorldData(
|
|
||||||
Path sourceWorldDirectory,
|
|
||||||
Path targetWorldDirectory,
|
|
||||||
long seed
|
|
||||||
) throws IOException {
|
|
||||||
CurrentPaperWorldDataWriter.write(sourceWorldDirectory, targetWorldDirectory, seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean awaitServerShutdownBoundary(long timeout, TimeUnit unit) {
|
public boolean awaitServerShutdownBoundary(long timeout, TimeUnit unit) {
|
||||||
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getHandle().getServer();
|
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 {
|
try {
|
||||||
InstanceState.updateInstanceId();
|
InstanceState.updateInstanceId();
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
System.err.println("[Iris] Failed to update instance id: " + ex.getClass().getSimpleName()
|
IrisLogging.reportError("Failed to update the Iris instance id.", ex);
|
||||||
+ (ex.getMessage() == null ? "" : " - " + ex.getMessage()));
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +348,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
try {
|
try {
|
||||||
object.run();
|
object.run();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
}, RNG.r.i(100, 1200));
|
}, RNG.r.i(100, 1200));
|
||||||
@@ -490,7 +487,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
pw.close();
|
pw.close();
|
||||||
Iris.info("DUMPED! See " + fi.getAbsolutePath());
|
Iris.info("DUMPED! See " + fi.getAbsolutePath());
|
||||||
} catch (Throwable e) {
|
} 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);
|
(EngineWorldManagerProvider) IrisWorldManager::new);
|
||||||
IrisServices.register(WorldDeletionQueue.class, pendingWorldDeletes);
|
IrisServices.register(WorldDeletionQueue.class, pendingWorldDeletes);
|
||||||
IrisServices.register(ManagedWorldLoader.class, (ManagedWorldLoader) this::loadManagedWorld);
|
IrisServices.register(ManagedWorldLoader.class, (ManagedWorldLoader) this::loadManagedWorld);
|
||||||
SettingsHotloadWatch watch = new SettingsHotloadWatch(getDataFile("settings.json"));
|
SettingsHotloadWatch watch = new SettingsHotloadWatch(getDataFile("iris.json"));
|
||||||
settingsHotloadWatch = watch;
|
settingsHotloadWatch = watch;
|
||||||
// Stale-temp cleanup must complete before services enable: StudioSVC.onEnable downloads
|
// 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
|
// 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() {
|
private void autoStartStudio() {
|
||||||
if (IrisSettings.get().getStudio().isAutoStartDefaultStudio()) {
|
if (IrisSettings.get().getStudio().isAutoStartDefaultStudio()) {
|
||||||
Iris.info("Starting up auto Studio!");
|
Iris.debug("Starting up auto Studio!");
|
||||||
try {
|
try {
|
||||||
Player r = new KList<>(getServer().getOnlinePlayers()).getRandom();
|
Player r = new KList<>(getServer().getOnlinePlayers()).getRandom();
|
||||||
Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> {
|
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();
|
final Location spawn = w.getSpawnLocation();
|
||||||
for (Player i : getServer().getOnlinePlayers()) {
|
for (Player i : getServer().getOnlinePlayers()) {
|
||||||
final Runnable playerTask = () -> {
|
final Runnable playerTask = () -> {
|
||||||
i.setGameMode(GameMode.CREATIVE);
|
i.setGameMode(GameMode.SPECTATOR);
|
||||||
BukkitPlatform.teleportAsync(i, spawn);
|
BukkitPlatform.teleportAsync(i, spawn);
|
||||||
};
|
};
|
||||||
if (!J.runEntity(i, playerTask)) {
|
if (!J.runEntity(i, playerTask)) {
|
||||||
@@ -802,10 +799,9 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
audiences = new Bindings.Adventure(this);
|
audiences = new Bindings.Adventure(this);
|
||||||
BukkitPlatform.hostAudiences(audiences);
|
BukkitPlatform.hostAudiences(audiences);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
IrisSettings.get().getGeneral().setUseConsoleCustomColors(false);
|
IrisSettings.get().getGeneral().setUseConsoleCustomColors(false);
|
||||||
IrisSettings.get().getGeneral().setUseCustomColorsIngame(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()) {
|
if (IrisToolbelt.isServerStopping()) {
|
||||||
quiesceRuntimeForServerShutdown("pre-unload:" + reason);
|
quiesceRuntimeForServerShutdown("pre-unload:" + reason);
|
||||||
startPostStopFinisher();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (alreadyDrained.get()) {
|
if (alreadyDrained.get()) {
|
||||||
Iris.info("Pre-unload hook skipped; Iris already drained.");
|
Iris.debug("Pre-unload hook skipped; Iris already drained.");
|
||||||
return;
|
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);
|
drainOnce("pre-unload:" + reason, 45L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1088,7 +1084,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (generators.isEmpty()) {
|
if (generators.isEmpty()) {
|
||||||
Iris.info("No Iris worlds to freeze.");
|
Iris.debug("No Iris worlds to freeze.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1112,7 +1108,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
try {
|
try {
|
||||||
CompletableFuture.allOf(closes.toArray(new CompletableFuture<?>[0]))
|
CompletableFuture.allOf(closes.toArray(new CompletableFuture<?>[0]))
|
||||||
.get(timeoutSeconds, TimeUnit.SECONDS);
|
.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) {
|
} catch (TimeoutException e) {
|
||||||
Iris.warn("Iris generator drain timed out after " + timeoutSeconds + "s; unload proceeding anyway.");
|
Iris.warn("Iris generator drain timed out after " + timeoutSeconds + "s; unload proceeding anyway.");
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -1201,7 +1197,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
try {
|
try {
|
||||||
Iris.syncJobs.next().run();
|
Iris.syncJobs.next().run();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1209,7 +1204,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bstats() {
|
private void bstats() {
|
||||||
if (IrisSettings.get().getGeneral().isPluginMetrics()) {
|
if (IrisSettings.get().getGeneral().isMetrics()) {
|
||||||
Bindings.setupBstats(this);
|
Bindings.setupBstats(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -242,7 +242,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
|||||||
try (CountingDataInputStream in = CountingDataInputStream.wrap(new BufferedInputStream(new FileInputStream(base)))) {
|
try (CountingDataInputStream in = CountingDataInputStream.wrap(new BufferedInputStream(new FileInputStream(base)))) {
|
||||||
TectonicPlate.read(1088, in, true, IrisEngineMantle.createRuntimeDataAdapter(activeEngine.getData()), IrisEngineMantle.createRuntimeHooks());
|
TectonicPlate.read(1088, in, true, IrisEngineMantle.createRuntimeDataAdapter(activeEngine.getData()), IrisEngineMantle.createRuntimeHooks());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
Iris.reportError("Failed to inspect the Iris tectonic plate.", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Matter.read(section);
|
Matter.read(section);
|
||||||
@@ -282,7 +282,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
|||||||
MCAFile MCARegion = MCAUtil.read(mca);
|
MCAFile MCARegion = MCAUtil.read(mca);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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) {
|
} 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.core.BukkitWorldReconciler;
|
||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
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.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.IrisWorlds;
|
import art.arcane.iris.core.IrisWorlds;
|
||||||
import art.arcane.iris.core.PendingWorldReplacementManager;
|
import art.arcane.iris.core.PendingWorldReplacementManager;
|
||||||
import art.arcane.iris.core.ServerConfigurator;
|
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.IrisWorldRemovalService;
|
||||||
import art.arcane.iris.core.lifecycle.LifecycleOperationCoordinator;
|
import art.arcane.iris.core.lifecycle.LifecycleOperationCoordinator;
|
||||||
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
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.PackDownloader;
|
||||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
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.service.StudioSVC;
|
||||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||||
@@ -62,9 +56,7 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -160,16 +152,6 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
return;
|
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 {
|
try {
|
||||||
IrisToolbelt.createWorld()
|
IrisToolbelt.createWorld()
|
||||||
.dimension(resolvedType)
|
.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) {
|
private boolean reportExpectedCreationInterruption(Throwable failure) {
|
||||||
Throwable current = failure;
|
Throwable current = failure;
|
||||||
while (current != null) {
|
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.loader.IrisData;
|
||||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||||
import art.arcane.iris.core.runtime.ObjectStudioActivation;
|
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.runtime.WorldRuntimeControlService;
|
||||||
import art.arcane.iris.core.service.ObjectSVC;
|
import art.arcane.iris.core.service.ObjectSVC;
|
||||||
import art.arcane.iris.core.service.StudioSVC;
|
import art.arcane.iris.core.service.StudioSVC;
|
||||||
@@ -171,24 +172,29 @@ public class CommandObject implements DirectorExecutor {
|
|||||||
|
|
||||||
IrisDimension finalHost = hostDimension;
|
IrisDimension finalHost = hostDimension;
|
||||||
try {
|
try {
|
||||||
Iris.service(StudioSVC.class).open(commandSender, seed, hostDimension.getLoadKey(), world -> {
|
Iris.service(StudioSVC.class).open(
|
||||||
if (world == null) return;
|
commandSender,
|
||||||
try {
|
seed,
|
||||||
WorldRuntimeControlService.get().applyObjectStudioWorldRules(world);
|
hostDimension.getLoadKey(),
|
||||||
} catch (Throwable e) {
|
StudioOpenCoordinator.StudioOpenKind.OBJECT,
|
||||||
Iris.reportError("Failed to apply object studio world rules for " + world.getName(), e);
|
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()) {
|
if (commandSender.isPlayer()) {
|
||||||
Player p = commandSender.player();
|
Player p = commandSender.player();
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
Location target = new Location(world, 0.5D, 66D, 0.5D);
|
Location target = new Location(world, 0.5D, 66D, 0.5D);
|
||||||
J.runEntity(p, () -> {
|
J.runEntity(p, () -> {
|
||||||
BukkitPlatform.teleportAsync(p, target).thenRun(() -> p.setGameMode(GameMode.CREATIVE));
|
BukkitPlatform.teleportAsync(p, target).thenRun(() -> p.setGameMode(GameMode.CREATIVE));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError("Failed to open object studio world \"" + finalHost.getLoadKey() + "\".", 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()))));
|
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());
|
o.write(o.getLoadFile());
|
||||||
} catch (IOException e) {
|
} 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()))));
|
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 {
|
try {
|
||||||
IrisConverter.convertSchematics(sender());
|
IrisConverter.convertSchematics(sender());
|
||||||
} catch (Exception e) {
|
} 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) {
|
} catch (Throwable e) {
|
||||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_PREGEN_FAILED_START_PREGENERATION_SEE_CONSOLE_DETAILS));
|
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_PREGEN_FAILED_START_PREGENERATION_SEE_CONSOLE_DETAILS));
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.FluidCollisionMode;
|
import org.bukkit.FluidCollisionMode;
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -573,7 +572,6 @@ public class CommandStudio implements DirectorExecutor {
|
|||||||
IO.writeAll(report, fileText.toString("\n"));
|
IO.writeAll(report, fileText.toString("\n"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_DONE, MessageArgument.untrusted("value", report.getPath())));
|
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);
|
Iris.reportError("Studio teleport failed for player \"" + player.getName() + "\".", failure);
|
||||||
return;
|
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())));
|
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_REPORTED, MessageArgument.untrusted("value", ff.getPath())));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+209
-13
@@ -18,14 +18,17 @@
|
|||||||
|
|
||||||
package art.arcane.iris.core.gui;
|
package art.arcane.iris.core.gui;
|
||||||
|
|
||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
import art.arcane.iris.core.runtime.WorldRuntimeControlService;
|
||||||
import art.arcane.iris.platform.bukkit.BukkitWorldBinding;
|
|
||||||
import art.arcane.iris.engine.IrisComplex;
|
import art.arcane.iris.engine.IrisComplex;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.framework.render.RenderType;
|
import art.arcane.iris.engine.framework.render.RenderType;
|
||||||
import art.arcane.iris.engine.object.IrisWorld;
|
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.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.format.Form;
|
import art.arcane.volmlib.util.format.Form;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
@@ -36,15 +39,21 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static art.arcane.iris.util.common.data.registry.Attributes.MAX_HEALTH;
|
import static art.arcane.iris.util.common.data.registry.Attributes.MAX_HEALTH;
|
||||||
|
|
||||||
public final class BukkitVisionOverlay implements GuiOverlay {
|
public final class BukkitVisionOverlay implements GuiOverlay {
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
|
private final AtomicBoolean nativeTeleportActive = new AtomicBoolean();
|
||||||
private final AtomicBoolean playerRefreshQueued = 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();
|
private volatile List<GuiMarker> playerMarkers = List.of();
|
||||||
|
|
||||||
public BukkitVisionOverlay(Engine engine) {
|
public BukkitVisionOverlay(Engine engine) {
|
||||||
@@ -144,25 +153,198 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void teleport(double worldX, double worldZ) {
|
public void teleport(double worldX, double worldZ) {
|
||||||
IrisWorld target = engine.getWorld();
|
VisionTeleportRequest request = new VisionTeleportRequest(
|
||||||
if (!target.hasPlatformWorld()) {
|
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;
|
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);
|
List<Player> players = BukkitWorldBinding.players(target);
|
||||||
if (players.isEmpty()) {
|
if (players.isEmpty()) {
|
||||||
|
finish(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Player player = players.get(0);
|
Player player = players.get(0);
|
||||||
World world = player.getWorld();
|
requestTeleportChunk(request, target, player, world);
|
||||||
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));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
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
|
@Override
|
||||||
@@ -179,4 +361,18 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
|||||||
};
|
};
|
||||||
return file == null ? null : file.getName();
|
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) {
|
private static void reportFailure(String message, Throwable exception) {
|
||||||
IrisLogging.reportError(exception);
|
IrisLogging.reportError(exception);
|
||||||
IrisLogging.error("EngineSVC: " + message);
|
IrisLogging.error("EngineSVC: " + message);
|
||||||
exception.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class Registered {
|
private final class Registered {
|
||||||
|
|||||||
+17
@@ -20,6 +20,7 @@ package art.arcane.iris.core.service;
|
|||||||
|
|
||||||
import art.arcane.iris.Iris;
|
import art.arcane.iris.Iris;
|
||||||
import art.arcane.iris.core.protocol.EngineResolver;
|
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.IrisProtocolServer;
|
||||||
import art.arcane.iris.core.protocol.IrisServerTransport;
|
import art.arcane.iris.core.protocol.IrisServerTransport;
|
||||||
import art.arcane.iris.core.protocol.IrisSession;
|
import art.arcane.iris.core.protocol.IrisSession;
|
||||||
@@ -55,6 +56,7 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
|||||||
|
|
||||||
private IrisSessionRegistry registry;
|
private IrisSessionRegistry registry;
|
||||||
private IrisProtocolServer protocolServer;
|
private IrisProtocolServer protocolServer;
|
||||||
|
private IrisCursorRequestService cursorService;
|
||||||
private IrisVisionRequestService visionService;
|
private IrisVisionRequestService visionService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,6 +68,8 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
|||||||
protocolServer = new IrisProtocolServer(registry, SERVER_CAPABILITIES, brand(), true);
|
protocolServer = new IrisProtocolServer(registry, SERVER_CAPABILITIES, brand(), true);
|
||||||
EngineResolver engineResolver = IrisProtocolService::resolveEngine;
|
EngineResolver engineResolver = IrisProtocolService::resolveEngine;
|
||||||
protocolServer.setEngineResolver(engineResolver);
|
protocolServer.setEngineResolver(engineResolver);
|
||||||
|
cursorService = IrisCursorRequestService.create(engineResolver, registry);
|
||||||
|
protocolServer.setCursorInfoHandler(cursorService);
|
||||||
visionService = IrisVisionRequestService.create(engineResolver, registry);
|
visionService = IrisVisionRequestService.create(engineResolver, registry);
|
||||||
protocolServer.setVisionTileHandler(visionService);
|
protocolServer.setVisionTileHandler(visionService);
|
||||||
IrisServices.register(IrisProtocolServer.class, protocolServer);
|
IrisServices.register(IrisProtocolServer.class, protocolServer);
|
||||||
@@ -81,13 +85,22 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
|||||||
messenger.unregisterIncomingPluginChannel(Iris.instance, IrisProtocol.CHANNEL, this);
|
messenger.unregisterIncomingPluginChannel(Iris.instance, IrisProtocol.CHANNEL, this);
|
||||||
messenger.unregisterOutgoingPluginChannel(Iris.instance, IrisProtocol.CHANNEL);
|
messenger.unregisterOutgoingPluginChannel(Iris.instance, IrisProtocol.CHANNEL);
|
||||||
IrisSessionRegistry current = registry;
|
IrisSessionRegistry current = registry;
|
||||||
|
IrisCursorRequestService cursor = cursorService;
|
||||||
|
IrisVisionRequestService vision = visionService;
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
for (IrisSession session : current.all()) {
|
for (IrisSession session : current.all()) {
|
||||||
current.unregister(session.id());
|
current.unregister(session.id());
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.clearSession(session.id());
|
||||||
|
}
|
||||||
|
if (vision != null) {
|
||||||
|
vision.clearSession(session.id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
registry = null;
|
registry = null;
|
||||||
protocolServer = null;
|
protocolServer = null;
|
||||||
|
cursorService = null;
|
||||||
visionService = null;
|
visionService = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +130,10 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
|||||||
}
|
}
|
||||||
String sessionId = event.getPlayer().getUniqueId().toString();
|
String sessionId = event.getPlayer().getUniqueId().toString();
|
||||||
current.unregister(sessionId);
|
current.unregister(sessionId);
|
||||||
|
IrisCursorRequestService cursor = cursorService;
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.clearSession(sessionId);
|
||||||
|
}
|
||||||
IrisVisionRequestService vision = visionService;
|
IrisVisionRequestService vision = visionService;
|
||||||
if (vision != null) {
|
if (vision != null) {
|
||||||
vision.clearSession(sessionId);
|
vision.clearSession(sessionId);
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.inventory.EquipmentSlot;
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemFlag;
|
import org.bukkit.inventory.ItemFlag;
|
||||||
@@ -61,18 +62,30 @@ import org.bukkit.util.BlockVector;
|
|||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CountDownLatch;
|
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.CRIT_MAGIC;
|
||||||
import static art.arcane.iris.util.common.data.registry.Particles.REDSTONE;
|
import static art.arcane.iris.util.common.data.registry.Particles.REDSTONE;
|
||||||
|
|
||||||
public class WandSVC implements IrisService {
|
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 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 dust;
|
||||||
private static ItemStack wand;
|
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) {
|
public static void pasteSchematic(IrisObject s, Location at) {
|
||||||
s.place(at);
|
s.place(at);
|
||||||
}
|
}
|
||||||
@@ -174,7 +187,6 @@ public class WandSVC implements IrisService {
|
|||||||
|
|
||||||
return s;
|
return s;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +208,6 @@ public class WandSVC implements IrisService {
|
|||||||
|
|
||||||
return WorldMatter.createMatter(p.getName(), f[0], f[1]);
|
return WorldMatter.createMatter(p.getName(), f[0], f[1]);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,8 +318,18 @@ public class WandSVC implements IrisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Location[] getCuboidFromItem(ItemStack is) {
|
public static Location[] getCuboidFromItem(ItemStack is) {
|
||||||
|
if (is == null) {
|
||||||
|
return new Location[]{null, null};
|
||||||
|
}
|
||||||
ItemMeta im = is.getItemMeta();
|
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) {
|
public static Location[] getCuboid(Player p) {
|
||||||
@@ -343,30 +364,47 @@ public class WandSVC implements IrisService {
|
|||||||
* @return True if it is
|
* @return True if it is
|
||||||
*/
|
*/
|
||||||
public static boolean isWand(ItemStack is) {
|
public static boolean isWand(ItemStack is) {
|
||||||
if (is == null || is.getItemMeta() == null) {
|
if (is == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Byte marker = is.getItemMeta().getPersistentDataContainer().get(wandKey(), PersistentDataType.BYTE);
|
ItemMeta meta = is.getItemMeta();
|
||||||
if (marker != null && marker == (byte) 1) {
|
if (meta == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Byte marker = meta.getPersistentDataContainer().get(wandKey(), PersistentDataType.BYTE);
|
||||||
|
if (marker != null && marker.byteValue() == 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return is.getType().equals(wand.getType()) &&
|
ItemStack template = wand;
|
||||||
is.getItemMeta().getDisplayName().equals(wand.getItemMeta().getDisplayName()) &&
|
if (template == null || !is.getType().equals(template.getType())) {
|
||||||
is.getItemMeta().getEnchants().equals(wand.getItemMeta().getEnchants()) &&
|
return false;
|
||||||
is.getItemMeta().getItemFlags().equals(wand.getItemMeta().getItemFlags());
|
}
|
||||||
|
ItemMeta templateMeta = template.getItemMeta();
|
||||||
|
return templateMeta != null
|
||||||
|
&& Objects.equals(meta.getDisplayName(), templateMeta.getDisplayName())
|
||||||
|
&& meta.getEnchants().equals(templateMeta.getEnchants())
|
||||||
|
&& meta.getItemFlags().equals(templateMeta.getItemFlags());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
wand = createWand();
|
wand = createWand();
|
||||||
dust = createDust();
|
dust = createDust();
|
||||||
|
enabled = true;
|
||||||
J.ar(this::tickAll, 0);
|
activePlayers.clear();
|
||||||
|
ticksUntilPlayerRescan = 0;
|
||||||
|
taskId = J.ar(this::tickAll, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
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() {
|
private void tickAll() {
|
||||||
try {
|
try {
|
||||||
J.runGlobal(() -> {
|
if (!enabled) {
|
||||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
return;
|
||||||
J.runEntity(p, () -> tick(p));
|
}
|
||||||
}
|
if (ticksUntilPlayerRescan-- <= 0) {
|
||||||
});
|
ticksUntilPlayerRescan = PLAYER_RESCAN_INTERVAL_TICKS;
|
||||||
|
rescanPlayers();
|
||||||
|
}
|
||||||
|
for (Player player : activePlayers.values()) {
|
||||||
|
J.runEntity(player, () -> tick(player));
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
@@ -387,20 +430,53 @@ public class WandSVC implements IrisService {
|
|||||||
|
|
||||||
public void tick(Player p) {
|
public void tick(Player p) {
|
||||||
try {
|
try {
|
||||||
try {
|
if (!p.isOnline()) {
|
||||||
if ((IrisSettings.get().getWorld().worldEditWandCUI && isHoldingWand(p)) || isWand(p.getInventory().getItemInMainHand())) {
|
activePlayers.remove(p.getUniqueId(), p);
|
||||||
Location[] d = getCuboid(p);
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
} 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
|
* Draw the outline of a selected region
|
||||||
*
|
*
|
||||||
@@ -492,6 +568,7 @@ public class WandSVC implements IrisService {
|
|||||||
return;
|
return;
|
||||||
try {
|
try {
|
||||||
if (isHoldingIrisWand(e.getPlayer())) {
|
if (isHoldingIrisWand(e.getPlayer())) {
|
||||||
|
activePlayers.put(e.getPlayer().getUniqueId(), e.getPlayer());
|
||||||
if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
|
if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
e.getPlayer().getInventory().setItemInMainHand(update(true, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
|
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?
|
* Is the player holding Dust?
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -23,16 +23,18 @@ import art.arcane.volmlib.util.math.M;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Particle;
|
import org.bukkit.Particle;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
import static art.arcane.iris.util.common.data.registry.Particles.REDSTONE;
|
import static art.arcane.iris.util.common.data.registry.Particles.REDSTONE;
|
||||||
|
|
||||||
public class WandSelection {
|
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 Cuboid c;
|
||||||
private final Player p;
|
private final Player p;
|
||||||
private static final double STEP = 0.10;
|
|
||||||
|
|
||||||
public WandSelection(Cuboid c, Player p) {
|
public WandSelection(Cuboid c, Player p) {
|
||||||
this.c = c;
|
this.c = c;
|
||||||
@@ -45,57 +47,91 @@ public class WandSelection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double maxDistanceSquared = 256 * 256;
|
|
||||||
int particleCount = 0;
|
|
||||||
|
|
||||||
// cube!
|
// cube!
|
||||||
Location[][] edges = {
|
double minX = c.getLowerX();
|
||||||
{c.getLowerNE(), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ())},
|
double minY = c.getLowerY();
|
||||||
{c.getLowerNE(), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ())},
|
double minZ = c.getLowerZ();
|
||||||
{c.getLowerNE(), new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1)},
|
double maxX = c.getUpperX() + 1D;
|
||||||
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ())},
|
double maxY = c.getUpperY() + 1D;
|
||||||
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1)},
|
double maxZ = c.getUpperZ() + 1D;
|
||||||
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ())},
|
double playerX = playerLoc.getX();
|
||||||
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1)},
|
double playerY = playerLoc.getY();
|
||||||
{new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1)},
|
double playerZ = playerLoc.getZ();
|
||||||
{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)}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (Location[] edge : edges) {
|
drawX(minX, maxX, minY, minZ, playerX, playerY, playerZ);
|
||||||
Vector direction = edge[1].toVector().subtract(edge[0].toVector());
|
drawX(minX, maxX, maxY, minZ, playerX, playerY, playerZ);
|
||||||
double length = direction.length();
|
drawX(minX, maxX, minY, maxZ, playerX, playerY, playerZ);
|
||||||
direction.normalize();
|
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) {
|
private void drawX(double start, double end, double y, double z, double playerX, double playerY, double playerZ) {
|
||||||
Location particleLoc = edge[0].clone().add(direction.clone().multiply(d));
|
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) {
|
private void drawY(double start, double end, double x, double z, double playerX, double playerY, double playerZ) {
|
||||||
continue;
|
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);
|
private void drawZ(double start, double end, double x, double y, double playerX, double playerY, double playerZ) {
|
||||||
particleCount++;
|
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) {
|
private void spawnParticle(double x, double y, double z, double distanceSquared) {
|
||||||
double accuracy = M.lerpInverse(0, 64 * 64, playerLoc.distanceSquared(particleLoc));
|
double accuracy = M.lerpInverse(0, 64 * 64, distanceSquared);
|
||||||
double dist = M.lerp(0.125, 3.5, accuracy);
|
double dist = M.lerp(0.125, 3.5, accuracy);
|
||||||
|
|
||||||
if (M.r(Math.min(dist * 5, 0.9D) * 0.995)) {
|
if (M.r(Math.min(dist * 5, 0.9D) * 0.995)) {
|
||||||
return;
|
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);
|
Color color = Color.getHSBColor(hue, 1, 1);
|
||||||
|
|
||||||
p.spawnParticle(REDSTONE, particleLoc,
|
p.spawnParticle(REDSTONE, x, y, z,
|
||||||
0, 0, 0, 0, 1,
|
0, 0, 0, 0, 1,
|
||||||
new Particle.DustOptions(org.bukkit.Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()),
|
new Particle.DustOptions(org.bukkit.Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()),
|
||||||
(float) dist * 3f));
|
(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.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class CommandIrisFoliaCreateContractTest {
|
public class CommandIrisFoliaCreateContractTest {
|
||||||
@Test
|
@Test
|
||||||
public void ordinaryFoliaCreateRestartsOnlyAfterSuccessfulStagingAndFeedback() throws Exception {
|
public void ordinaryFoliaCreateUsesTheSharedRuntimeCreationPath() throws Exception {
|
||||||
String source = Files.readString(Path.of(System.getProperty("iris.commandIrisSource")));
|
String source = Files.readString(Path.of(System.getProperty("iris.commandIrisSource")));
|
||||||
String foliaCreate = source.substring(
|
String create = source.substring(
|
||||||
source.indexOf("if (J.isFolia()) {"),
|
source.indexOf(" public void create("),
|
||||||
source.indexOf(" try {", source.indexOf("if (J.isFolia()) {"))
|
source.indexOf(" @Director(", source.indexOf(" public void create("))
|
||||||
);
|
);
|
||||||
|
|
||||||
int stage = foliaCreate.indexOf("stageFoliaWorldCreation(worldName, dimension, seed)");
|
assertTrue(create.contains("IrisToolbelt.createWorld()"));
|
||||||
int failureExit = foliaCreate.indexOf("if (!staged)");
|
assertTrue(create.contains(".studio(false)"));
|
||||||
int feedback = foliaCreate.indexOf("COMMAND_IRIS_WORLD_STAGING_COMPLETED_RESTARTING_SERVER_GENERATE_LOAD");
|
assertTrue(create.contains(".create();"));
|
||||||
int restart = foliaCreate.indexOf("ServerConfigurator.restart(\"Iris staged Folia world");
|
assertFalse(create.contains("J.isFolia()"));
|
||||||
|
assertFalse(create.contains("ServerConfigurator.restart("));
|
||||||
assertTrue(stage >= 0);
|
|
||||||
assertTrue(stage < failureExit);
|
|
||||||
assertTrue(failureExit < feedback);
|
|
||||||
assertTrue(feedback < restart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void foliaStagePublishesCurrentPaperDataBeforeRegisteringStartupAlias() throws Exception {
|
public void obsoleteFoliaStagingSurfaceIsRemoved() throws Exception {
|
||||||
String source = Files.readString(Path.of(System.getProperty("iris.commandIrisSource")));
|
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(");
|
assertFalse(source.contains("stageFoliaWorldCreation"));
|
||||||
int pack = staging.indexOf("installIntoWorld(");
|
assertFalse(source.contains("writeCurrentPaperWorldData"));
|
||||||
int publication = staging.indexOf("AtomicDirectoryPublisher.publishAbsent(");
|
assertFalse(source.contains("COMMAND_IRIS_RUNTIME_WORLD_CREATION_IS_DISABLED_ON_FOLIA"));
|
||||||
int registration = staging.indexOf("registerWorldInBukkitYml(worldKey");
|
|
||||||
|
|
||||||
assertTrue(currentPaperData >= 0);
|
|
||||||
assertTrue(currentPaperData < pack);
|
|
||||||
assertTrue(pack < publication);
|
|
||||||
assertTrue(publication < registration);
|
|
||||||
assertTrue(source.contains("IrisWorldStorage.configuredWorldName("));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+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 {
|
public class StudioPlayerModeContractTest {
|
||||||
@Test
|
@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 plugin = Files.readString(Path.of("src/main/java/art/arcane/iris/Iris.java")).replace("\r\n", "\n");
|
||||||
String commands = Files.readString(Path.of(
|
String commands = Files.readString(Path.of(
|
||||||
"src/main/java/art/arcane/iris/core/commands/CommandStudio.java")).replace("\r\n", "\n");
|
"src/main/java/art/arcane/iris/core/commands/CommandStudio.java")).replace("\r\n", "\n");
|
||||||
|
|
||||||
assertFalse(plugin.contains("GameMode.SPECTATOR"));
|
assertFalse(plugin.contains("GameMode.CREATIVE"));
|
||||||
assertFalse(commands.contains("GameMode.SPECTATOR"));
|
assertFalse(commands.contains("GameMode.CREATIVE"));
|
||||||
assertTrue(plugin.contains("GameMode.CREATIVE"));
|
assertTrue(plugin.contains("GameMode.SPECTATOR"));
|
||||||
assertTrue(commands.contains("GameMode.CREATIVE"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -32,8 +31,23 @@ public class StudioPlayerModeContractTest {
|
|||||||
|
|
||||||
assertTrue(method.contains("StudioSVC studioService = Iris.service(StudioSVC.class)"));
|
assertTrue(method.contains("StudioSVC studioService = Iris.service(StudioSVC.class)"));
|
||||||
assertTrue(method.contains("studioService.teleportToActiveProject(player)"));
|
assertTrue(method.contains("studioService.teleportToActiveProject(player)"));
|
||||||
|
assertFalse(method.contains("setGameMode("));
|
||||||
assertFalse(method.contains("getActiveProject()"));
|
assertFalse(method.contains("getActiveProject()"));
|
||||||
assertFalse(method.contains("BukkitPlatform.teleportAsync"));
|
assertFalse(method.contains("BukkitPlatform.teleportAsync"));
|
||||||
assertFalse(method.contains("BukkitWorldBinding.spawnLocation"));
|
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.VisionTile visionTile -> TILES.onVisionTile(visionTile);
|
||||||
case IrisMessage.VisionMarkers visionMarkers -> MARKERS.onMarkers(visionMarkers);
|
case IrisMessage.VisionMarkers visionMarkers -> MARKERS.onMarkers(visionMarkers);
|
||||||
case IrisMessage.PregenRegionDelta delta -> REGIONS.onDelta(delta, PREGEN.activeJobId());
|
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());
|
case IrisMessage.Toast toast -> TOASTS.enqueue(toast.kind(), toast.title(), toast.body());
|
||||||
default -> {
|
default -> {
|
||||||
}
|
}
|
||||||
@@ -167,4 +167,29 @@ public final class IrisClient {
|
|||||||
REGIONS.clear();
|
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;
|
package art.arcane.iris.fabric.mixin;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.fabric.FabricForcedDatapackSources;
|
import art.arcane.iris.fabric.FabricForcedDatapackSources;
|
||||||
import net.minecraft.server.packs.repository.PackRepository;
|
import net.minecraft.server.packs.repository.PackRepository;
|
||||||
import net.minecraft.server.packs.repository.RepositorySource;
|
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.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ public class PackRepositoryMixin {
|
|||||||
}
|
}
|
||||||
// Client resource-pack repositories legitimately have no ServerPacksSource; a missing server-data
|
// Client resource-pack repositories legitimately have no ServerPacksSource; a missing server-data
|
||||||
// repository is reported once at boot by ModdedForcedDatapack.verifyInjected().
|
// 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) {}",
|
"Iris forced datapack source not attached: no ServerPacksSource among {} source(s) {}",
|
||||||
sources.length, Arrays.toString(sources));
|
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.StructureSet;
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -98,7 +96,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.IntBinaryOperator;
|
import java.util.function.IntBinaryOperator;
|
||||||
|
|
||||||
public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
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,
|
// 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
|
// 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.
|
// 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
|
// 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.
|
// the same reason as repointAndBind: this method owns the generator monitor.
|
||||||
importedFeatures.prepareWithoutWaiting(bound);
|
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) {
|
private Engine bindEngine(ServerLevel level) {
|
||||||
@@ -601,7 +598,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
|||||||
try {
|
try {
|
||||||
heightMetadata = configuredPack().metadata();
|
heightMetadata = configuredPack().metadata();
|
||||||
} catch (Throwable e) {
|
} 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());
|
dimensionKey, activePack, activeDimensionKey, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -726,7 +723,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
|||||||
Engine generationEngine = engine();
|
Engine generationEngine = engine();
|
||||||
ChunkPos pos = chunk.getPos();
|
ChunkPos pos = chunk.getPos();
|
||||||
lastChunkGenAt = System.currentTimeMillis();
|
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();
|
PlatformBlockState air = IrisPlatforms.get().registries().air();
|
||||||
|
|
||||||
@@ -744,7 +741,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
|||||||
try (GenerationSessionLease lease = generationEngine.acquireGenerationLease("modded_chunk_pipeline");
|
try (GenerationSessionLease lease = generationEngine.acquireGenerationLease("modded_chunk_pipeline");
|
||||||
IrisContext.Scope ignored = IrisContext.open(generationEngine, lease.sessionId(), null)) {
|
IrisContext.Scope ignored = IrisContext.open(generationEngine, lease.sessionId(), null)) {
|
||||||
if (announced.compareAndSet(false, true)) {
|
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());
|
dimensionKey, generationEngine.getDimension().getLoadKey(), pos.x(), pos.z());
|
||||||
}
|
}
|
||||||
int dimMinY = generationEngine.getMinHeight();
|
int dimMinY = generationEngine.getMinHeight();
|
||||||
@@ -763,14 +760,14 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
|
|||||||
return chunk;
|
return chunk;
|
||||||
} catch (GenerationSessionException e) {
|
} catch (GenerationSessionException e) {
|
||||||
if (generationEngine.isClosing() || e.isExpectedTeardown()) {
|
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(
|
throw new IllegalStateException(
|
||||||
"Iris chunk generation was rejected during an engine transition.", e);
|
"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);
|
throw new IllegalStateException("Iris generation failed for chunk " + pos.x() + "," + pos.z(), e);
|
||||||
} catch (Throwable 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);
|
throw new IllegalStateException("Iris generation failed for chunk " + pos.x() + "," + pos.z(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded;
|
package art.arcane.iris.modded;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -32,7 +30,6 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public final class MainWorldService {
|
public final class MainWorldService {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final String MARKER_NAME = "mainworld.pending";
|
private static final String MARKER_NAME = "mainworld.pending";
|
||||||
private static final String PROPERTIES_NAME = "server.properties";
|
private static final String PROPERTIES_NAME = "server.properties";
|
||||||
/**
|
/**
|
||||||
@@ -80,12 +77,12 @@ public final class MainWorldService {
|
|||||||
if (!target.equals(currentType)) {
|
if (!target.equals(currentType)) {
|
||||||
writeLevelProperties(properties, target, config.mainWorldSeed());
|
writeLevelProperties(properties, target, config.mainWorldSeed());
|
||||||
markPending();
|
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);
|
pack, properties, target);
|
||||||
if (config.mainWorldAutoRestart()) {
|
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);
|
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);
|
AUTO_RESTART_EXIT_STATUS);
|
||||||
System.exit(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
|
// bootstrap: there is no prior overworld to move aside, so this is nothing to quarantine, not a
|
||||||
// reason to refuse startup.
|
// reason to refuse startup.
|
||||||
clearPending();
|
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);
|
pack, missing.path(), target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Path recovery = quarantineVanillaDimensions(worldRoot);
|
Path recovery = quarantineVanillaDimensions(worldRoot);
|
||||||
clearPending();
|
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);
|
pack, worldRoot, recovery, target);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Iris main world reconciliation failed", e);
|
ModdedIrisLog.error("Iris main world reconciliation failed", e);
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Iris refused startup after main-world reconciliation failed", e);
|
"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) {
|
public static boolean stage(String packRef, long seed) {
|
||||||
if (ModdedEngineBootstrap.loader().clientEnvironment()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
Path instanceRoot = verifiedInstanceRoot("stage the Iris main world");
|
Path instanceRoot = verifiedInstanceRoot("stage the Iris main world");
|
||||||
@@ -131,7 +128,7 @@ public final class MainWorldService {
|
|||||||
markPending();
|
markPending();
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +137,7 @@ public final class MainWorldService {
|
|||||||
try {
|
try {
|
||||||
clearPending();
|
clearPending();
|
||||||
} catch (IOException e) {
|
} 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))) {
|
if (Files.isRegularFile(workingDirectory.resolve(PROPERTIES_NAME))) {
|
||||||
return workingDirectory;
|
return workingDirectory;
|
||||||
}
|
}
|
||||||
LOGGER.error("Iris refuses to {}: no {} in the server working directory {}", operation, PROPERTIES_NAME, workingDirectory);
|
ModdedIrisLog.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 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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +302,7 @@ public final class MainWorldService {
|
|||||||
return List.of(arguments.get());
|
return List.of(arguments.get());
|
||||||
}
|
}
|
||||||
} catch (RuntimeException unavailable) {
|
} 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
|
// 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
|
// --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.resources.Identifier;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -39,7 +37,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
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 String VANILLA_FALLBACK_KEY = "minecraft:plains";
|
||||||
private static final int MAX_CACHED_IDS = 4096;
|
private static final int MAX_CACHED_IDS = 4096;
|
||||||
/** NUL cannot occur in a pack or registry key, so the composite cache key stays unambiguous. */
|
/** 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;
|
return 0;
|
||||||
}
|
}
|
||||||
if (key == null) {
|
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);
|
return fallbackId(registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +214,7 @@ public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
|||||||
|
|
||||||
private void reportMissingServer(String operation, String fallback) {
|
private void reportMissingServer(String operation, String fallback) {
|
||||||
if (serverMissingReported.compareAndSet(false, true)) {
|
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.item.ItemStack;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public final class ModdedBlockBreakHandler {
|
public final class ModdedBlockBreakHandler {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final ConcurrentHashMap<BreakKey, PendingBreak> PENDING = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<BreakKey, PendingBreak> PENDING = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private ModdedBlockBreakHandler() {
|
private ModdedBlockBreakHandler() {
|
||||||
@@ -72,7 +69,7 @@ public final class ModdedBlockBreakHandler {
|
|||||||
if (scheduler == null) {
|
if (scheduler == null) {
|
||||||
// finishPending is the only thing that evicts an unconsumed entry. With no scheduler there is no
|
// 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.
|
// 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());
|
position.getX(), position.getY(), position.getZ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -150,7 +147,7 @@ public final class ModdedBlockBreakHandler {
|
|||||||
try {
|
try {
|
||||||
return evaluate(level, position, pending);
|
return evaluate(level, position, pending);
|
||||||
} catch (Throwable error) {
|
} 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);
|
level.dimension().identifier(), error);
|
||||||
return Result.empty();
|
return Result.empty();
|
||||||
}
|
}
|
||||||
@@ -182,7 +179,7 @@ public final class ModdedBlockBreakHandler {
|
|||||||
try {
|
try {
|
||||||
return evaluateDrops(level, position, brokenState, engine);
|
return evaluateDrops(level, position, brokenState, engine);
|
||||||
} catch (Throwable error) {
|
} 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);
|
level.dimension().identifier(), error);
|
||||||
return Result.empty();
|
return Result.empty();
|
||||||
}
|
}
|
||||||
@@ -315,7 +312,7 @@ public final class ModdedBlockBreakHandler {
|
|||||||
try {
|
try {
|
||||||
return irisGenerator.commandEngine();
|
return irisGenerator.commandEngine();
|
||||||
} catch (Throwable error) {
|
} 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;
|
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.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.ServerLevelData;
|
import net.minecraft.world.level.storage.ServerLevelData;
|
||||||
import net.minecraft.world.level.storage.WorldData;
|
import net.minecraft.world.level.storage.WorldData;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -60,7 +58,6 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class ModdedDimensionManager {
|
public final class ModdedDimensionManager {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
private static final ConcurrentHashMap<String, Handle> HANDLES = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<String, Handle> HANDLES = new ConcurrentHashMap<>();
|
||||||
private static final TicketType TELEPORT_WARM_TICKET = new TicketType(TicketType.NO_TIMEOUT,
|
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)) {
|
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");
|
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);
|
generator.repointAndBind(present, pack, packDimensionKey, seed);
|
||||||
Handle handle = new Handle(dimensionId, pack, packDimensionKey, seed, present, generator);
|
Handle handle = new Handle(dimensionId, pack, packDimensionKey, seed, present, generator);
|
||||||
HANDLES.put(dimensionId, handle);
|
HANDLES.put(dimensionId, handle);
|
||||||
@@ -147,10 +144,10 @@ public final class ModdedDimensionManager {
|
|||||||
try {
|
try {
|
||||||
Handle handle = inject(server, serverAccess, dimensionId, key, pack, packDimensionKey, seed);
|
Handle handle = inject(server, serverAccess, dimensionId, key, pack, packDimensionKey, seed);
|
||||||
HANDLES.put(dimensionId, handle);
|
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;
|
return handle;
|
||||||
} catch (Throwable e) {
|
} 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);
|
throw new IllegalStateException("Iris runtime dimension injection failed for " + dimensionId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,11 +230,11 @@ public final class ModdedDimensionManager {
|
|||||||
if (wipeStorage) {
|
if (wipeStorage) {
|
||||||
ModdedDimensionStorage.wipe(server, key);
|
ModdedDimensionStorage.wipe(server, key);
|
||||||
}
|
}
|
||||||
LOGGER.info("Iris removed runtime dimension '{}'", dimensionId);
|
ModdedIrisLog.info("Iris removed runtime dimension '{}'", dimensionId);
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
rollbackRemoval(server, serverAccess, key, level, generator, generatorUnbound, 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);
|
throw new IllegalStateException("Iris runtime dimension removal failed for " + dimensionId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,7 +253,7 @@ public final class ModdedDimensionManager {
|
|||||||
if (rollbackFailure != failure) {
|
if (rollbackFailure != failure) {
|
||||||
failure.addSuppressed(rollbackFailure);
|
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);
|
key.identifier(), rollbackFailure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,7 +279,7 @@ public final class ModdedDimensionManager {
|
|||||||
.whenComplete((Object result, Throwable error) -> server.execute(() -> {
|
.whenComplete((Object result, Throwable error) -> server.execute(() -> {
|
||||||
level.getChunkSource().removeTicketWithRadius(TELEPORT_WARM_TICKET, chunkPos, 1);
|
level.getChunkSource().removeTicketWithRadius(TELEPORT_WARM_TICKET, chunkPos, 1);
|
||||||
if (error != null) {
|
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);
|
ServerPlayer target = server.getPlayerList().getPlayer(playerId);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
@@ -325,7 +322,7 @@ public final class ModdedDimensionManager {
|
|||||||
}
|
}
|
||||||
return dimension;
|
return dimension;
|
||||||
} catch (Throwable e) {
|
} 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);
|
pack, packDimensionKey, e);
|
||||||
if (e instanceof Error fatalError) {
|
if (e instanceof Error fatalError) {
|
||||||
throw fatalError;
|
throw fatalError;
|
||||||
@@ -401,19 +398,19 @@ public final class ModdedDimensionManager {
|
|||||||
}
|
}
|
||||||
} catch (Throwable cleanupError) {
|
} catch (Throwable cleanupError) {
|
||||||
failure.addSuppressed(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 {
|
try {
|
||||||
generator.unbindEngine(level);
|
generator.unbindEngine(level);
|
||||||
} catch (Throwable cleanupError) {
|
} catch (Throwable cleanupError) {
|
||||||
failure.addSuppressed(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 {
|
try {
|
||||||
level.close();
|
level.close();
|
||||||
} catch (Throwable cleanupError) {
|
} catch (Throwable cleanupError) {
|
||||||
failure.addSuppressed(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 art.arcane.volmlib.util.json.JSONObject;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
@@ -41,7 +39,6 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public final class ModdedDimensionRegistryStore {
|
public final class ModdedDimensionRegistryStore {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final String FILE_NAME = "iris-dimensions.json";
|
private static final String FILE_NAME = "iris-dimensions.json";
|
||||||
private static final Pattern ID_FIELD = Pattern.compile("\"id\"\\s*:\\s*\"([^\"]+)\"");
|
private static final Pattern ID_FIELD = Pattern.compile("\"id\"\\s*:\\s*\"([^\"]+)\"");
|
||||||
|
|
||||||
@@ -68,13 +65,13 @@ public final class ModdedDimensionRegistryStore {
|
|||||||
try {
|
try {
|
||||||
return load(file);
|
return load(file);
|
||||||
} catch (RuntimeException corrupt) {
|
} 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);
|
file, corrupt);
|
||||||
List<String> lostIds = salvageIds(file);
|
List<String> lostIds = salvageIds(file);
|
||||||
if (lostIds.isEmpty()) {
|
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 {
|
} 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));
|
lostIds.size(), String.join(", ", lostIds));
|
||||||
}
|
}
|
||||||
quarantine(file);
|
quarantine(file);
|
||||||
@@ -93,7 +90,7 @@ public final class ModdedDimensionRegistryStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException | RuntimeException unreadable) {
|
} 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;
|
return ids;
|
||||||
}
|
}
|
||||||
@@ -102,9 +99,9 @@ public final class ModdedDimensionRegistryStore {
|
|||||||
Path broken = file.resolveSibling(FILE_NAME + ".broken-" + System.currentTimeMillis());
|
Path broken = file.resolveSibling(FILE_NAME + ".broken-" + System.currentTimeMillis());
|
||||||
try {
|
try {
|
||||||
Files.move(file, broken, StandardCopyOption.REPLACE_EXISTING);
|
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) {
|
} 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);
|
file, failure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,14 +131,14 @@ public final class ModdedDimensionRegistryStore {
|
|||||||
PersistentDimension previous = deduplicated.putIfAbsent(
|
PersistentDimension previous = deduplicated.putIfAbsent(
|
||||||
id, new PersistentDimension(id, pack, dimension, entry.getLong("seed")));
|
id, new PersistentDimension(id, pack, dimension, entry.getLong("seed")));
|
||||||
if (previous != null) {
|
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);
|
index, file, id);
|
||||||
}
|
}
|
||||||
} catch (RuntimeException invalidEntry) {
|
} catch (RuntimeException invalidEntry) {
|
||||||
if (raw != null) {
|
if (raw != null) {
|
||||||
unparsed.add(raw);
|
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);
|
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.Level;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -35,7 +33,6 @@ import java.util.List;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class ModdedDimensionStorage {
|
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 static final List<String> CHUNK_DATA_FOLDERS = List.of("region", "entities", "poi", "mantle");
|
||||||
|
|
||||||
private ModdedDimensionStorage() {
|
private ModdedDimensionStorage() {
|
||||||
@@ -56,7 +53,7 @@ public final class ModdedDimensionStorage {
|
|||||||
"Iris failed to completely wipe dimension storage at "
|
"Iris failed to completely wipe dimension storage at "
|
||||||
+ storageFolder.getAbsolutePath(), e);
|
+ 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 {
|
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.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import net.minecraft.world.level.storage.LevelData;
|
import net.minecraft.world.level.storage.LevelData;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
public final class ModdedEngineBootstrap {
|
public final class ModdedEngineBootstrap {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final String[] CORE_SELF_TEST_CLASSES = {
|
private static final String[] CORE_SELF_TEST_CLASSES = {
|
||||||
"art.arcane.iris.engine.IrisEngine",
|
"art.arcane.iris.engine.IrisEngine",
|
||||||
"art.arcane.iris.util.common.data.B",
|
"art.arcane.iris.util.common.data.B",
|
||||||
@@ -156,7 +153,7 @@ public final class ModdedEngineBootstrap {
|
|||||||
try {
|
try {
|
||||||
generator.unbindEngine(level);
|
generator.unbindEngine(level);
|
||||||
} catch (Throwable exception) {
|
} 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) {
|
if (exception instanceof RuntimeException runtimeException) {
|
||||||
throw runtimeException;
|
throw runtimeException;
|
||||||
}
|
}
|
||||||
@@ -207,7 +204,7 @@ public final class ModdedEngineBootstrap {
|
|||||||
if (failure != null) {
|
if (failure != null) {
|
||||||
// The shutdown path must not propagate: propagating aborts the remaining loader stop handlers and
|
// 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.
|
// 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();
|
action.run();
|
||||||
return failure;
|
return failure;
|
||||||
} catch (Throwable stageFailure) {
|
} catch (Throwable stageFailure) {
|
||||||
LOGGER.error("Iris modded shutdown stage '{}' failed", stage, stageFailure);
|
ModdedIrisLog.error("Iris modded shutdown stage '{}' failed", stage, stageFailure);
|
||||||
if (failure == null) {
|
if (failure == null) {
|
||||||
return stageFailure;
|
return stageFailure;
|
||||||
}
|
}
|
||||||
@@ -255,7 +252,7 @@ public final class ModdedEngineBootstrap {
|
|||||||
BlockPos position = reconciledSpawnPosition(surfaceY, level.getMinY(), level.getHeight());
|
BlockPos position = reconciledSpawnPosition(surfaceY, level.getMinY(), level.getHeight());
|
||||||
server.setRespawnData(LevelData.RespawnData.of(
|
server.setRespawnData(LevelData.RespawnData.of(
|
||||||
level.dimension(), position, current.yaw(), current.pitch()));
|
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());
|
position.getX(), position.getY(), position.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +318,7 @@ public final class ModdedEngineBootstrap {
|
|||||||
Class.forName(className, true, classLoader);
|
Class.forName(className, true, classLoader);
|
||||||
loadedClasses++;
|
loadedClasses++;
|
||||||
} catch (Throwable error) {
|
} 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);
|
ModdedIrisSplash.print(boundLoader);
|
||||||
} catch (Throwable splashFailure) {
|
} catch (Throwable splashFailure) {
|
||||||
// A cosmetic banner must never roll back the platform bind.
|
// 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();
|
createdServices.enableAll();
|
||||||
runtime = new BoundRuntime(created, createdServices);
|
runtime = new BoundRuntime(created, createdServices);
|
||||||
@@ -413,7 +410,7 @@ public final class ModdedEngineBootstrap {
|
|||||||
} catch (Throwable failure) {
|
} catch (Throwable failure) {
|
||||||
createdServices.rollback(failure);
|
createdServices.rollback(failure);
|
||||||
rollback.restore(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) {
|
if (failure instanceof RuntimeException runtimeException) {
|
||||||
throw 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.Pack;
|
||||||
import net.minecraft.server.packs.repository.PackSource;
|
import net.minecraft.server.packs.repository.PackSource;
|
||||||
import net.minecraft.server.packs.repository.RepositorySource;
|
import net.minecraft.server.packs.repository.RepositorySource;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -67,7 +65,6 @@ import java.util.function.Consumer;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class ModdedForcedDatapack {
|
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_ID = "iris_worldgen";
|
||||||
private static final String PACK_FOLDER = "iris";
|
private static final String PACK_FOLDER = "iris";
|
||||||
private static final String HASH_FILE_NAME = "packs.hash";
|
private static final String HASH_FILE_NAME = "packs.hash";
|
||||||
@@ -111,7 +108,7 @@ public final class ModdedForcedDatapack {
|
|||||||
return requireReadablePack(current.directory());
|
return requireReadablePack(current.directory());
|
||||||
} catch (RuntimeException unreadable) {
|
} catch (RuntimeException unreadable) {
|
||||||
published = null;
|
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);
|
current.directory(), unreadable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,19 +122,19 @@ public final class ModdedForcedDatapack {
|
|||||||
reason = "stale cache (hash changed)";
|
reason = "stale cache (hash changed)";
|
||||||
} else {
|
} else {
|
||||||
if (hash.isEmpty() && STALE_SERVE_LOGGED.compareAndSet(false, true)) {
|
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());
|
state.directory());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return requireReadablePack(state.directory());
|
return requireReadablePack(state.directory());
|
||||||
} catch (RuntimeException unreadable) {
|
} catch (RuntimeException unreadable) {
|
||||||
published = null;
|
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);
|
state.directory(), unreadable);
|
||||||
}
|
}
|
||||||
reason = "unreadable published pack";
|
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();
|
return buildPack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,11 +148,11 @@ public final class ModdedForcedDatapack {
|
|||||||
if (packs.isEmpty()) {
|
if (packs.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOGGER.error("===============================================================");
|
ModdedIrisLog.error("===============================================================");
|
||||||
LOGGER.error("Iris forced datapack '{}' was never loaded by this server.", PACK_ID);
|
ModdedIrisLog.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);
|
ModdedIrisLog.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.");
|
ModdedIrisLog.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("===============================================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path datapackRoot() {
|
public static Path datapackRoot() {
|
||||||
@@ -172,7 +169,7 @@ public final class ModdedForcedDatapack {
|
|||||||
} catch (RuntimeException | Error generationFailure) {
|
} catch (RuntimeException | Error generationFailure) {
|
||||||
Path lastKnownGood = packDirectory();
|
Path lastKnownGood = packDirectory();
|
||||||
if (Files.isRegularFile(lastKnownGood.resolve("pack.mcmeta"))) {
|
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);
|
generationFailure);
|
||||||
return requireReadablePack(lastKnownGood);
|
return requireReadablePack(lastKnownGood);
|
||||||
}
|
}
|
||||||
@@ -201,7 +198,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
return write();
|
return write();
|
||||||
} catch (Throwable e) {
|
} 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) {
|
if (e instanceof RuntimeException runtimeException) {
|
||||||
throw runtimeException;
|
throw runtimeException;
|
||||||
}
|
}
|
||||||
@@ -222,10 +219,10 @@ public final class ModdedForcedDatapack {
|
|||||||
String currentHash = packsHashOrEmpty();
|
String currentHash = packsHashOrEmpty();
|
||||||
PublishedState state = publishedState();
|
PublishedState state = publishedState();
|
||||||
if (state != null && !currentHash.isEmpty() && state.packsHash().equals(currentHash)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
LOGGER.info("Iris regenerating the forced datapack ({})", reason);
|
ModdedIrisLog.info("Iris regenerating the forced datapack ({})", reason);
|
||||||
regenerate();
|
regenerate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -240,7 +237,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
regenerateIfStale(reason);
|
regenerateIfStale(reason);
|
||||||
} catch (Throwable failure) {
|
} 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();
|
ModdedScheduler scheduler = ModdedEngineBootstrap.schedulerOrNull();
|
||||||
@@ -301,7 +298,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
return Files.readString(hashFile, StandardCharsets.UTF_8).trim();
|
return Files.readString(hashFile, StandardCharsets.UTF_8).trim();
|
||||||
} catch (IOException unreadable) {
|
} 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 "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,7 +329,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
hash = packsHash();
|
hash = packsHash();
|
||||||
} catch (IOException | RuntimeException failure) {
|
} 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 = "";
|
hash = "";
|
||||||
}
|
}
|
||||||
packsHashMemo = new HashMemo(hash, now);
|
packsHashMemo = new HashMemo(hash, now);
|
||||||
@@ -412,9 +409,9 @@ public final class ModdedForcedDatapack {
|
|||||||
if (!presetIds.isEmpty()) {
|
if (!presetIds.isEmpty()) {
|
||||||
writeWorldPresetTag(stagingDirectory, presetIds);
|
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) {
|
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 {
|
try {
|
||||||
validation = PackValidator.validateForDatapackBootstrap(sourcePack);
|
validation = PackValidator.validateForDatapackBootstrap(sourcePack);
|
||||||
} catch (Throwable validationFailure) {
|
} 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);
|
sourcePack.getName(), validationFailure);
|
||||||
rethrowIfUnrecoverable(validationFailure);
|
rethrowIfUnrecoverable(validationFailure);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!validation.isLoadable()) {
|
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(),
|
sourcePack.getName(), validation.getBlockingErrors().size(),
|
||||||
validation.getBlockingErrors().getFirst());
|
validation.getBlockingErrors().getFirst());
|
||||||
return false;
|
return false;
|
||||||
@@ -447,7 +444,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
installed = installPack(sourcePack, fixer, packFolders, packBiomes, packPresetIds);
|
installed = installPack(sourcePack, fixer, packFolders, packBiomes, packPresetIds);
|
||||||
} catch (Throwable installationFailure) {
|
} 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);
|
sourcePack.getName(), installationFailure);
|
||||||
rethrowIfUnrecoverable(installationFailure);
|
rethrowIfUnrecoverable(installationFailure);
|
||||||
installed = false;
|
installed = false;
|
||||||
@@ -465,7 +462,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
clean(packStagingDirectory);
|
clean(packStagingDirectory);
|
||||||
} catch (Throwable cleanupFailure) {
|
} 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);
|
sourcePack.getName(), cleanupFailure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -728,7 +725,7 @@ public final class ModdedForcedDatapack {
|
|||||||
try {
|
try {
|
||||||
clean(backupDirectory);
|
clean(backupDirectory);
|
||||||
} catch (Throwable cleanupError) {
|
} 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);
|
backupDirectory, cleanupError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded;
|
package art.arcane.iris.modded;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
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.
|
* missing hop serializes generation on the loader's chunk threads.
|
||||||
*/
|
*/
|
||||||
public final class ModdedGenPool {
|
public final class ModdedGenPool {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final long SHUTDOWN_DRAIN_MILLIS = 2_000L;
|
private static final long SHUTDOWN_DRAIN_MILLIS = 2_000L;
|
||||||
private static final String[] C2ME_MARKERS = {
|
private static final String[] C2ME_MARKERS = {
|
||||||
"com.ishland.c2me.base.ModProperties",
|
"com.ishland.c2me.base.ModProperties",
|
||||||
@@ -116,7 +113,7 @@ public final class ModdedGenPool {
|
|||||||
if (pool.awaitTermination(SHUTDOWN_DRAIN_MILLIS, TimeUnit.MILLISECONDS)) {
|
if (pool.awaitTermination(SHUTDOWN_DRAIN_MILLIS, TimeUnit.MILLISECONDS)) {
|
||||||
return;
|
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) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
@@ -131,7 +128,7 @@ public final class ModdedGenPool {
|
|||||||
if (detected == null) {
|
if (detected == null) {
|
||||||
detected = new ChunkSystem(false, "vanilla");
|
detected = new ChunkSystem(false, "vanilla");
|
||||||
}
|
}
|
||||||
LOGGER.info("Iris chunk system: {} (parallel={}, generation on {})",
|
ModdedIrisLog.info("Iris chunk system: {} (parallel={}, generation on {})",
|
||||||
detected.description(),
|
detected.description(),
|
||||||
detected.parallel() ? "yes" : "no",
|
detected.parallel() ? "yes" : "no",
|
||||||
detected.parallel() ? "loader threads" : "Iris gen pool");
|
detected.parallel() ? "loader threads" : "Iris gen pool");
|
||||||
@@ -182,7 +179,7 @@ public final class ModdedGenPool {
|
|||||||
try {
|
try {
|
||||||
value = field.get(null);
|
value = field.get(null);
|
||||||
} catch (Throwable e) {
|
} 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;
|
continue;
|
||||||
}
|
}
|
||||||
if (value instanceof Boolean flag) {
|
if (value instanceof Boolean flag) {
|
||||||
@@ -209,7 +206,7 @@ public final class ModdedGenPool {
|
|||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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);
|
Method method = declaredMethodOrNull(type, name);
|
||||||
@@ -219,7 +216,7 @@ public final class ModdedGenPool {
|
|||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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();
|
return number.intValue();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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 {
|
try {
|
||||||
pool = field.get(null);
|
pool = field.get(null);
|
||||||
} catch (Throwable e) {
|
} 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;
|
continue;
|
||||||
}
|
}
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
@@ -281,7 +278,7 @@ public final class ModdedGenPool {
|
|||||||
return number.intValue();
|
return number.intValue();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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;
|
return null;
|
||||||
@@ -305,7 +302,7 @@ public final class ModdedGenPool {
|
|||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
return null;
|
return null;
|
||||||
} catch (Throwable e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,7 +315,7 @@ public final class ModdedGenPool {
|
|||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
return null;
|
return null;
|
||||||
} catch (Throwable e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,7 +333,7 @@ public final class ModdedGenPool {
|
|||||||
try {
|
try {
|
||||||
return Class.forName(name, false, ModdedGenPool.class.getClassLoader());
|
return Class.forName(name, false, ModdedGenPool.class.getClassLoader());
|
||||||
} catch (Throwable e) {
|
} 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;
|
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.WorldgenRandom;
|
||||||
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
|
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -76,7 +74,6 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
* {@link #generationSettings} answers exactly what vanilla's default getter answers.
|
* {@link #generationSettings} answers exactly what vanilla's default getter answers.
|
||||||
*/
|
*/
|
||||||
final class ModdedImportedFeatureStage {
|
final class ModdedImportedFeatureStage {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final String CYCLE_MARKER = "Feature order cycle found";
|
private static final String CYCLE_MARKER = "Feature order cycle found";
|
||||||
private static final long NO_GENERATION = Long.MIN_VALUE;
|
private static final long NO_GENERATION = Long.MIN_VALUE;
|
||||||
|
|
||||||
@@ -179,7 +176,7 @@ final class ModdedImportedFeatureStage {
|
|||||||
try {
|
try {
|
||||||
control = NativeFeatureGenerationPolicy.control(engine);
|
control = NativeFeatureGenerationPolicy.control(engine);
|
||||||
} catch (RuntimeException error) {
|
} 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());
|
error.toString());
|
||||||
markInert(generation);
|
markInert(generation);
|
||||||
return;
|
return;
|
||||||
@@ -193,7 +190,7 @@ final class ModdedImportedFeatureStage {
|
|||||||
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
||||||
built = buildTable(engine, control, generation);
|
built = buildTable(engine, control, generation);
|
||||||
} catch (Throwable error) {
|
} 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());
|
dimensionKey(engine), error.toString());
|
||||||
markInert(generation);
|
markInert(generation);
|
||||||
return;
|
return;
|
||||||
@@ -207,7 +204,7 @@ final class ModdedImportedFeatureStage {
|
|||||||
// Arm the worldcheck log watch here, before any chunk decorates: arming from the first pass instead
|
// 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.
|
// missed every far-chunk write the first chunk made. No-op unless -Diris.worldcheck is set.
|
||||||
WorldCheckFeaturePlacement.arm();
|
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(),
|
dimensionKey(engine), built.biomes().size(), built.steps().size(),
|
||||||
built.derivatives().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.
|
// detection depend on JVM hash order and turns a real cycle into an intermittent one.
|
||||||
List<Holder<Biome>> biomes = biomeSource.orderedPossibleBiomes();
|
List<Holder<Biome>> biomes = biomeSource.orderedPossibleBiomes();
|
||||||
if (biomes.isEmpty()) {
|
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));
|
dimensionKey(engine));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -245,7 +242,7 @@ final class ModdedImportedFeatureStage {
|
|||||||
if (message == null || !message.contains(CYCLE_MARKER)) {
|
if (message == null || !message.contains(CYCLE_MARKER)) {
|
||||||
throw error;
|
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"
|
+ " {}. Remove or reorder the conflicting content, or leave"
|
||||||
+ " importedFeatures.enabled false.",
|
+ " importedFeatures.enabled false.",
|
||||||
dimensionKey(engine), message);
|
dimensionKey(engine), message);
|
||||||
@@ -276,7 +273,7 @@ final class ModdedImportedFeatureStage {
|
|||||||
derivative = biomeSource.registeredBiome(derivativeKey);
|
derivative = biomeSource.registeredBiome(derivativeKey);
|
||||||
}
|
}
|
||||||
if (derivative == null) {
|
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",
|
+ " its custom biomes generate no imported features",
|
||||||
derivativeKey, irisBiome.getLoadKey());
|
derivativeKey, irisBiome.getLoadKey());
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -54,18 +54,55 @@ public final class ModdedIrisLog {
|
|||||||
LOGGER.info("[Iris/DEBUG] " + clean(message));
|
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) {
|
public static void info(String message) {
|
||||||
LOGGER.info(clean(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) {
|
public static void warn(String message) {
|
||||||
LOGGER.warn(clean(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) {
|
public static void error(String message) {
|
||||||
LOGGER.error(clean(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) {
|
public static void error(String message, Throwable error) {
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
error(message);
|
error(message);
|
||||||
@@ -79,6 +116,34 @@ public final class ModdedIrisLog {
|
|||||||
return IrisLogging.clean(message);
|
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() {
|
private static boolean debugEnabled() {
|
||||||
try {
|
try {
|
||||||
IrisSettings settings = IrisSettings.settings != null ? IrisSettings.settings : IrisSettings.get();
|
IrisSettings settings = IrisSettings.settings != null ? IrisSettings.settings : IrisSettings.get();
|
||||||
@@ -97,4 +162,7 @@ public final class ModdedIrisLog {
|
|||||||
DEBUG_SETTING_WARNING_LOGGED = true;
|
DEBUG_SETTING_WARNING_LOGGED = true;
|
||||||
LOGGER.warn("Iris debug logging setting could not be read", error);
|
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;
|
package art.arcane.iris.modded;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -40,7 +38,6 @@ import java.util.function.BooleanSupplier;
|
|||||||
* references and is safe on a dedicated server.
|
* references and is safe on a dedicated server.
|
||||||
*/
|
*/
|
||||||
public final class ModdedMixinAudit {
|
public final class ModdedMixinAudit {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final AtomicBoolean AUDITED = new AtomicBoolean(false);
|
private static final AtomicBoolean AUDITED = new AtomicBoolean(false);
|
||||||
|
|
||||||
private static final List<ExpectedMixin> EXPECTED = List.of(
|
private static final List<ExpectedMixin> EXPECTED = List.of(
|
||||||
@@ -95,20 +92,20 @@ public final class ModdedMixinAudit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (missing.isEmpty()) {
|
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));
|
clientEnvironment ? "client" : "server", String.join(", ", applied));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOGGER.error("===============================================================");
|
ModdedIrisLog.error("===============================================================");
|
||||||
LOGGER.error("Iris mixin audit FAILED on {} ({} dist): {} of {} expected mixin(s) were not applied.",
|
ModdedIrisLog.error("Iris mixin audit FAILED on {} ({} dist): {} of {} expected mixin(s) were not applied.",
|
||||||
platform, clientEnvironment ? "client" : "server", missing.size(),
|
platform, clientEnvironment ? "client" : "server", missing.size(),
|
||||||
missing.size() + applied.size());
|
missing.size() + applied.size());
|
||||||
for (String entry : missing) {
|
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).");
|
ModdedIrisLog.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.");
|
ModdedIrisLog.error("Entity persistence, custom mob loot, parallel structure safety, or Iris world-type labels are disabled until this is fixed.");
|
||||||
LOGGER.error("===============================================================");
|
ModdedIrisLog.error("===============================================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isApplied(ExpectedMixin expected) {
|
private static boolean isApplied(ExpectedMixin expected) {
|
||||||
@@ -126,7 +123,7 @@ public final class ModdedMixinAudit {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} catch (ClassNotFoundException | LinkageError unavailable) {
|
} 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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,8 @@ import java.io.IOException;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public final class ModdedModConfig {
|
public final class ModdedModConfig {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
private static volatile ModdedModConfig instance;
|
private static volatile ModdedModConfig instance;
|
||||||
|
|
||||||
@@ -128,7 +125,7 @@ public final class ModdedModConfig {
|
|||||||
json.optLong("mainWorldSeed", defaults.mainWorldSeed),
|
json.optLong("mainWorldSeed", defaults.mainWorldSeed),
|
||||||
json.optBoolean("mainWorldAutoRestart", defaults.mainWorldAutoRestart));
|
json.optBoolean("mainWorldAutoRestart", defaults.mainWorldAutoRestart));
|
||||||
} catch (RuntimeException | IOException e) {
|
} 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;
|
return defaults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +142,7 @@ public final class ModdedModConfig {
|
|||||||
Files.createDirectories(file.getParent());
|
Files.createDirectories(file.getParent());
|
||||||
Files.writeString(file, json.toString(4), StandardCharsets.UTF_8);
|
Files.writeString(file, json.toString(4), StandardCharsets.UTF_8);
|
||||||
} catch (IOException e) {
|
} 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.spi.PlatformBlockState;
|
||||||
import art.arcane.iris.util.project.hunk.Hunk;
|
import art.arcane.iris.util.project.hunk.Hunk;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -48,7 +46,6 @@ import java.util.Map;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
public final class ModdedParityProbe {
|
public final class ModdedParityProbe {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final String DIMENSION_KEY = "overworld";
|
private static final String DIMENSION_KEY = "overworld";
|
||||||
private static final long SEED = 1337L;
|
private static final long SEED = 1337L;
|
||||||
private static final int BIOME_STEP = 4;
|
private static final int BIOME_STEP = 4;
|
||||||
@@ -82,7 +79,7 @@ public final class ModdedParityProbe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (server == null) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,10 +87,10 @@ public final class ModdedParityProbe {
|
|||||||
try {
|
try {
|
||||||
match = run(server, config);
|
match = run(server, config);
|
||||||
} catch (Throwable e) {
|
} 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);
|
server.halt(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +109,7 @@ public final class ModdedParityProbe {
|
|||||||
|
|
||||||
File packSource = new File(packPath);
|
File packSource = new File(packPath);
|
||||||
if (!packSource.isDirectory()) {
|
if (!packSource.isDirectory()) {
|
||||||
LOGGER.error("[parity] pack folder not found: {}", packSource.getAbsolutePath());
|
ModdedIrisLog.error("[parity] pack folder not found: {}", packSource.getAbsolutePath());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,14 +118,14 @@ public final class ModdedParityProbe {
|
|||||||
|
|
||||||
File workRoot = Files.createTempDirectory("iris-parity").toFile();
|
File workRoot = Files.createTempDirectory("iris-parity").toFile();
|
||||||
File pack = clonePack(packSource, workRoot);
|
File pack = clonePack(packSource, workRoot);
|
||||||
LOGGER.info("[parity] pack: {}", packSource.getAbsolutePath());
|
ModdedIrisLog.info("[parity] pack: {}", packSource.getAbsolutePath());
|
||||||
LOGGER.info("[parity] work copy: {}", pack.getAbsolutePath());
|
ModdedIrisLog.info("[parity] work copy: {}", pack.getAbsolutePath());
|
||||||
LOGGER.info("[parity] radius: {} ({} chunks)", radius, (2 * radius + 1) * (2 * radius + 1));
|
ModdedIrisLog.info("[parity] radius: {} ({} chunks)", radius, (2 * radius + 1) * (2 * radius + 1));
|
||||||
|
|
||||||
IrisData data = IrisData.get(pack);
|
IrisData data = IrisData.get(pack);
|
||||||
IrisDimension dimension = data.getDimensionLoader().load(DIMENSION_KEY);
|
IrisDimension dimension = data.getDimensionLoader().load(DIMENSION_KEY);
|
||||||
if (dimension == null) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +144,7 @@ public final class ModdedParityProbe {
|
|||||||
int minY = dimension.getMinHeight();
|
int minY = dimension.getMinHeight();
|
||||||
int maxY = dimension.getMaxHeight();
|
int maxY = dimension.getMaxHeight();
|
||||||
int height = maxY - minY;
|
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<>();
|
Map<String, String> goldenChunks = new HashMap<>();
|
||||||
String goldenCombined = null;
|
String goldenCombined = null;
|
||||||
@@ -173,7 +170,7 @@ public final class ModdedParityProbe {
|
|||||||
goldenChunks.put(line.substring(0, second), line);
|
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();
|
PlatformBlockState airState = IrisPlatforms.get().registries().air();
|
||||||
@@ -198,9 +195,9 @@ public final class ModdedParityProbe {
|
|||||||
|
|
||||||
if (!failures.isEmpty()) {
|
if (!failures.isEmpty()) {
|
||||||
failed++;
|
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) {
|
for (Throwable failure : failures) {
|
||||||
LOGGER.error("[parity] chunk {},{} error", cx, cz, failure);
|
ModdedIrisLog.error("[parity] chunk {},{} error", cx, cz, failure);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -212,9 +209,9 @@ public final class ModdedParityProbe {
|
|||||||
String golden = goldenChunks.get(key);
|
String golden = goldenChunks.get(key);
|
||||||
if (golden != null && !golden.equals(line)) {
|
if (golden != null && !golden.equals(line)) {
|
||||||
mismatches.add(key);
|
mismatches.add(key);
|
||||||
LOGGER.warn("[parity] chunk {} MISMATCH", key);
|
ModdedIrisLog.warn("[parity] chunk {} MISMATCH", key);
|
||||||
LOGGER.warn("[parity] golden: {}", golden);
|
ModdedIrisLog.warn("[parity] golden: {}", golden);
|
||||||
LOGGER.warn("[parity] actual: {}", line);
|
ModdedIrisLog.warn("[parity] actual: {}", line);
|
||||||
if (mismatches.size() == 1) {
|
if (mismatches.size() == 1) {
|
||||||
diffDeep(cx, cz, blocks, height, minY);
|
diffDeep(cx, cz, blocks, height, minY);
|
||||||
}
|
}
|
||||||
@@ -231,9 +228,9 @@ public final class ModdedParityProbe {
|
|||||||
boolean match = goldenChunks.isEmpty() ? combinedMatch : (chunkMatch && (radius != 8 || combinedMatch));
|
boolean match = goldenChunks.isEmpty() ? combinedMatch : (chunkMatch && (radius != 8 || combinedMatch));
|
||||||
|
|
||||||
if (!goldenChunks.isEmpty()) {
|
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());
|
combined.substring(0, 12), expected, match ? "MATCH" : "MISMATCH", body.size() - mismatches.size(), targets.size());
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
@@ -246,7 +243,7 @@ public final class ModdedParityProbe {
|
|||||||
try {
|
try {
|
||||||
Path goldenDump = Path.of(deepDir, cx + "_" + cz + ".txt");
|
Path goldenDump = Path.of(deepDir, cx + "_" + cz + ".txt");
|
||||||
if (!Files.exists(goldenDump)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
List<String> golden = Files.readAllLines(goldenDump, StandardCharsets.UTF_8);
|
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 g = i < golden.size() ? golden.get(i) : "<missing>";
|
||||||
String a = i < actual.size() ? actual.get(i) : "<missing>";
|
String a = i < actual.size() ? actual.get(i) : "<missing>";
|
||||||
if (!g.equals(a)) {
|
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++;
|
shown++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File out = new File(IrisPlatforms.get().dataFolder("parity"), "deep-" + cx + "_" + cz + ".txt");
|
File out = new File(IrisPlatforms.get().dataFolder("parity"), "deep-" + cx + "_" + cz + ".txt");
|
||||||
Files.write(out.toPath(), actual, StandardCharsets.UTF_8);
|
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) {
|
} 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 {
|
} else {
|
||||||
for (Throwable error : batch) {
|
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();
|
quietSince = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -21,8 +21,6 @@ package art.arcane.iris.modded;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -31,7 +29,6 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public final class ModdedPrimaryWorldRouter {
|
public final class ModdedPrimaryWorldRouter {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int TICK_INTERVAL = 20;
|
private static final int TICK_INTERVAL = 20;
|
||||||
|
|
||||||
private static final Set<UUID> routed = ConcurrentHashMap.newKeySet();
|
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());
|
ModdedDimensionManager.teleport(player, server, primary, player.getX(), Double.MIN_VALUE, player.getZ());
|
||||||
routed.add(id);
|
routed.add(id);
|
||||||
} catch (Throwable e) {
|
} 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;
|
package art.arcane.iris.modded;
|
||||||
|
|
||||||
import art.arcane.iris.core.protocol.EngineResolver;
|
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.IrisProtocolServer;
|
||||||
import art.arcane.iris.core.protocol.IrisSession;
|
import art.arcane.iris.core.protocol.IrisSession;
|
||||||
import art.arcane.iris.core.protocol.IrisSessionRegistry;
|
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.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -43,7 +42,6 @@ public final class ModdedProtocolHandler {
|
|||||||
| IrisProtocol.CAPABILITY_CURSOR
|
| IrisProtocol.CAPABILITY_CURSOR
|
||||||
| IrisProtocol.CAPABILITY_STUDIO;
|
| IrisProtocol.CAPABILITY_STUDIO;
|
||||||
private static final int DIMENSION_SYNC_INTERVAL_TICKS = 5;
|
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, Engine> SESSION_ENGINES = new ConcurrentHashMap<>();
|
||||||
private static final ConcurrentHashMap<String, String> SESSION_LEVELS = 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 IrisSessionRegistry registry;
|
||||||
private static volatile IrisProtocolServer protocolServer;
|
private static volatile IrisProtocolServer protocolServer;
|
||||||
private static volatile ModdedProtocolTransport transport;
|
private static volatile ModdedProtocolTransport transport;
|
||||||
|
private static volatile IrisCursorRequestService cursorRequests;
|
||||||
private static volatile IrisVisionRequestService visionRequests;
|
private static volatile IrisVisionRequestService visionRequests;
|
||||||
private static int dimensionSyncTicks;
|
private static int dimensionSyncTicks;
|
||||||
|
|
||||||
@@ -80,11 +79,14 @@ public final class ModdedProtocolHandler {
|
|||||||
return engine == null || engine.isClosed() ? null : engine;
|
return engine == null || engine.isClosed() ? null : engine;
|
||||||
};
|
};
|
||||||
protocol.setEngineResolver(engineResolver);
|
protocol.setEngineResolver(engineResolver);
|
||||||
|
IrisCursorRequestService cursorService = IrisCursorRequestService.create(engineResolver, sessionRegistry);
|
||||||
|
protocol.setCursorInfoHandler(cursorService);
|
||||||
IrisVisionRequestService visionService = IrisVisionRequestService.create(engineResolver, sessionRegistry);
|
IrisVisionRequestService visionService = IrisVisionRequestService.create(engineResolver, sessionRegistry);
|
||||||
protocol.setVisionTileHandler(visionService);
|
protocol.setVisionTileHandler(visionService);
|
||||||
registry = sessionRegistry;
|
registry = sessionRegistry;
|
||||||
transport = serverTransport;
|
transport = serverTransport;
|
||||||
protocolServer = protocol;
|
protocolServer = protocol;
|
||||||
|
cursorRequests = cursorService;
|
||||||
visionRequests = visionService;
|
visionRequests = visionService;
|
||||||
IrisServices.register(IrisProtocolServer.class, protocol);
|
IrisServices.register(IrisProtocolServer.class, protocol);
|
||||||
if (server.getPlayerList() == null) {
|
if (server.getPlayerList() == null) {
|
||||||
@@ -98,10 +100,14 @@ public final class ModdedProtocolHandler {
|
|||||||
public static void stop() {
|
public static void stop() {
|
||||||
IrisServices.remove(IrisProtocolServer.class);
|
IrisServices.remove(IrisProtocolServer.class);
|
||||||
IrisSessionRegistry current = registry;
|
IrisSessionRegistry current = registry;
|
||||||
|
IrisCursorRequestService cursor = cursorRequests;
|
||||||
IrisVisionRequestService vision = visionRequests;
|
IrisVisionRequestService vision = visionRequests;
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
for (IrisSession session : current.all()) {
|
for (IrisSession session : current.all()) {
|
||||||
current.unregister(session.id());
|
current.unregister(session.id());
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.clearSession(session.id());
|
||||||
|
}
|
||||||
if (vision != null) {
|
if (vision != null) {
|
||||||
vision.clearSession(session.id());
|
vision.clearSession(session.id());
|
||||||
}
|
}
|
||||||
@@ -114,6 +120,7 @@ public final class ModdedProtocolHandler {
|
|||||||
registry = null;
|
registry = null;
|
||||||
protocolServer = null;
|
protocolServer = null;
|
||||||
transport = null;
|
transport = null;
|
||||||
|
cursorRequests = null;
|
||||||
visionRequests = null;
|
visionRequests = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +154,10 @@ public final class ModdedProtocolHandler {
|
|||||||
if (current != null) {
|
if (current != null) {
|
||||||
current.unregister(sessionId);
|
current.unregister(sessionId);
|
||||||
}
|
}
|
||||||
|
IrisCursorRequestService cursor = cursorRequests;
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.clearSession(sessionId);
|
||||||
|
}
|
||||||
IrisVisionRequestService vision = visionRequests;
|
IrisVisionRequestService vision = visionRequests;
|
||||||
if (vision != null) {
|
if (vision != null) {
|
||||||
vision.clearSession(sessionId);
|
vision.clearSession(sessionId);
|
||||||
@@ -229,7 +240,7 @@ public final class ModdedProtocolHandler {
|
|||||||
Engine engine = generator.engineIfBound();
|
Engine engine = generator.engineIfBound();
|
||||||
return engine == null || engine.isClosed() ? null : engine;
|
return engine == null || engine.isClosed() ? null : engine;
|
||||||
} catch (Throwable failure) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ package art.arcane.iris.modded;
|
|||||||
import art.arcane.iris.spi.PlatformScheduler;
|
import art.arcane.iris.spi.PlatformScheduler;
|
||||||
import art.arcane.iris.spi.PlatformWorld;
|
import art.arcane.iris.spi.PlatformWorld;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -41,7 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public final class ModdedScheduler implements PlatformScheduler {
|
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 int ASYNC_MAX_THREADS = Math.max(4, Runtime.getRuntime().availableProcessors());
|
||||||
private static final long ASYNC_KEEP_ALIVE_SECONDS = 30L;
|
private static final long ASYNC_KEEP_ALIVE_SECONDS = 30L;
|
||||||
private static final int ASYNC_BACKLOG_WARN = 8192;
|
private static final int ASYNC_BACKLOG_WARN = 8192;
|
||||||
@@ -85,10 +82,10 @@ public final class ModdedScheduler implements PlatformScheduler {
|
|||||||
rejectionAwareTask.reject();
|
rejectionAwareTask.reject();
|
||||||
}
|
}
|
||||||
if (executor.isShutdown()) {
|
if (executor.isShutdown()) {
|
||||||
LOGGER.debug("Iris async task dropped: scheduler is shut down");
|
ModdedIrisLog.debug("Iris async task dropped: scheduler is shut down");
|
||||||
return;
|
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());
|
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)) {
|
if (now - last < ASYNC_BACKLOG_WARN_INTERVAL_MILLIS || !lastBacklogWarnAt.compareAndSet(last, now)) {
|
||||||
return;
|
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() {
|
private void drain() {
|
||||||
@@ -262,7 +259,7 @@ public final class ModdedScheduler implements PlatformScheduler {
|
|||||||
try {
|
try {
|
||||||
task.run();
|
task.run();
|
||||||
} catch (Throwable error) {
|
} 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.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ConcurrentModificationException;
|
import java.util.ConcurrentModificationException;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -35,7 +33,6 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public final class ModdedServerLevels implements ModdedServerAccess {
|
public final class ModdedServerLevels implements ModdedServerAccess {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int CAPTURE_ATTEMPTS = 16;
|
private static final int CAPTURE_ATTEMPTS = 16;
|
||||||
private static volatile Snapshot snapshot;
|
private static volatile Snapshot snapshot;
|
||||||
|
|
||||||
@@ -125,7 +122,7 @@ public final class ModdedServerLevels implements ModdedServerAccess {
|
|||||||
Thread.onSpinWait();
|
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;
|
Snapshot current = snapshot;
|
||||||
return current != null && current.server() == server ? current : null;
|
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.ModdedService;
|
||||||
import art.arcane.iris.modded.service.ModdedTickableService;
|
import art.arcane.iris.modded.service.ModdedTickableService;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public final class ModdedServiceManager {
|
public final class ModdedServiceManager {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
|
|
||||||
private final Map<Class<? extends ModdedService>, ModdedService> services = new LinkedHashMap<>();
|
private final Map<Class<? extends ModdedService>, ModdedService> services = new LinkedHashMap<>();
|
||||||
private boolean enabled = false;
|
private boolean enabled = false;
|
||||||
@@ -103,7 +100,7 @@ public final class ModdedServiceManager {
|
|||||||
service.onDisable();
|
service.onDisable();
|
||||||
} catch (Throwable serviceFailure) {
|
} catch (Throwable serviceFailure) {
|
||||||
failed++;
|
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) {
|
if (failure == null) {
|
||||||
failure = serviceFailure;
|
failure = serviceFailure;
|
||||||
} else if (serviceFailure != failure) {
|
} else if (serviceFailure != failure) {
|
||||||
@@ -113,7 +110,7 @@ public final class ModdedServiceManager {
|
|||||||
}
|
}
|
||||||
enabled = false;
|
enabled = false;
|
||||||
if (failure != null) {
|
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 {
|
try {
|
||||||
service.onServerTick(server);
|
service.onServerTick(server);
|
||||||
} catch (Throwable error) {
|
} 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) {
|
if (cleanupError != failure) {
|
||||||
failure.addSuppressed(cleanupError);
|
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) {
|
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) {
|
if (failure instanceof RuntimeException runtimeException) {
|
||||||
return runtimeException;
|
return runtimeException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ import net.minecraft.commands.Commands;
|
|||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -43,7 +41,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class ModdedStartup {
|
public final class ModdedStartup {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final AtomicBoolean PREPARED = new AtomicBoolean(false);
|
private static final AtomicBoolean PREPARED = new AtomicBoolean(false);
|
||||||
private static final AtomicBoolean STARTED = new AtomicBoolean(false);
|
private static final AtomicBoolean STARTED = new AtomicBoolean(false);
|
||||||
|
|
||||||
@@ -76,7 +73,7 @@ public final class ModdedStartup {
|
|||||||
}
|
}
|
||||||
if (!PackDirectoryResolver.listVisiblePackDirectories(legacy).isEmpty()) {
|
if (!PackDirectoryResolver.listVisiblePackDirectories(legacy).isEmpty()) {
|
||||||
File real = art.arcane.iris.spi.IrisPlatforms.get().packsFolderNoCreate();
|
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());
|
legacy.getAbsolutePath(), real.getAbsolutePath());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -85,7 +82,7 @@ public final class ModdedStartup {
|
|||||||
legacy.delete();
|
legacy.delete();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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 {
|
try {
|
||||||
ModdedForcedDatapack.regenerateIfStale("boot");
|
ModdedForcedDatapack.regenerateIfStale("boot");
|
||||||
} catch (Throwable failure) {
|
} 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);
|
List<File> packDirs = PackDirectoryResolver.listVisiblePackDirectories(packsRoot);
|
||||||
PackValidationRegistry.clear();
|
PackValidationRegistry.clear();
|
||||||
if (packDirs.isEmpty()) {
|
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());
|
packsRoot.getAbsolutePath());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -142,19 +139,19 @@ public final class ModdedStartup {
|
|||||||
PackValidationResult result = PackValidator.validate(packDir);
|
PackValidationResult result = PackValidator.validate(packDir);
|
||||||
PackValidationRegistry.publish(result);
|
PackValidationRegistry.publish(result);
|
||||||
if (!result.isLoadable()) {
|
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.getPackName(), result.getBlockingErrors().size(),
|
||||||
result.getBlockingErrors().getFirst());
|
result.getBlockingErrors().getFirst());
|
||||||
} else if (!result.getWarnings().isEmpty()) {
|
} 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()) {
|
for (String warning : result.getWarnings()) {
|
||||||
LOGGER.warn(" [{}] {}", result.getPackName(), warning);
|
ModdedIrisLog.warn(" [{}] {}", result.getPackName(), warning);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Iris pack '{}' validated.", result.getPackName());
|
ModdedIrisLog.info("Iris pack '{}' validated.", result.getPackName());
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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();
|
String detail = e.getMessage();
|
||||||
if (detail == null || detail.isBlank()) {
|
if (detail == null || detail.isBlank()) {
|
||||||
detail = e.getClass().getSimpleName();
|
detail = e.getClass().getSimpleName();
|
||||||
@@ -190,7 +187,7 @@ public final class ModdedStartup {
|
|||||||
} catch (BrokenPackException e) {
|
} catch (BrokenPackException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Throwable 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();
|
String detail = e.getMessage();
|
||||||
if (detail == null || detail.isBlank()) {
|
if (detail == null || detail.isBlank()) {
|
||||||
detail = e.getClass().getSimpleName();
|
detail = e.getClass().getSimpleName();
|
||||||
@@ -220,17 +217,17 @@ public final class ModdedStartup {
|
|||||||
try {
|
try {
|
||||||
ModdedDimensionManager.create(server, dimension.id(), dimension.pack(), dimension.dimension(), dimension.seed());
|
ModdedDimensionManager.create(server, dimension.id(), dimension.pack(), dimension.dimension(), dimension.seed());
|
||||||
injected++;
|
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(),
|
index, dimensions.size(), dimension.id(), dimension.pack(), dimension.dimension(),
|
||||||
System.currentTimeMillis() - dimensionStartedAt);
|
System.currentTimeMillis() - dimensionStartedAt);
|
||||||
} catch (Throwable e) {
|
} 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) {
|
if (e instanceof OutOfMemoryError outOfMemory) {
|
||||||
throw 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);
|
injected, dimensions.size(), System.currentTimeMillis() - startedAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +242,7 @@ public final class ModdedStartup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException | RuntimeException unreadable) {
|
} 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 Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
return newest;
|
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.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
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_TIMEOUT_MILLIS = 600000L;
|
||||||
private static final long SERVER_WAIT_INTERVAL_MILLIS = 250L;
|
private static final long SERVER_WAIT_INTERVAL_MILLIS = 250L;
|
||||||
private static final long SERVER_TASK_TIMEOUT_MILLIS = 900000L;
|
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
|
// 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.
|
// 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;
|
private static final ProcessExit PROCESS_EXIT = Runtime.getRuntime()::halt;
|
||||||
@@ -100,7 +97,7 @@ public final class ModdedWorldCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (server == null) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,15 +112,15 @@ public final class ModdedWorldCheck {
|
|||||||
}
|
}
|
||||||
)).get(SERVER_TASK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
)).get(SERVER_TASK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOGGER.error("[worldcheck] coordinator interrupted", e);
|
ModdedIrisLog.error("[worldcheck] coordinator interrupted", e);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (TimeoutException e) {
|
} 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) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("[worldcheck] check failed", e);
|
ModdedIrisLog.error("[worldcheck] check failed", e);
|
||||||
} finally {
|
} finally {
|
||||||
int resultCode = exitCode;
|
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;
|
MinecraftServer serverRef = server;
|
||||||
if (serverRef != null && stopRequested.get()) {
|
if (serverRef != null && stopRequested.get()) {
|
||||||
awaitStopAndExit(() -> serverRef.halt(true), resultCode, processExit);
|
awaitStopAndExit(() -> serverRef.halt(true), resultCode, processExit);
|
||||||
@@ -138,12 +135,12 @@ public final class ModdedWorldCheck {
|
|||||||
try {
|
try {
|
||||||
exitCode = check.getAsBoolean() ? EXIT_PASS : EXIT_FAILURE;
|
exitCode = check.getAsBoolean() ? EXIT_PASS : EXIT_FAILURE;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("[worldcheck] check failed", e);
|
ModdedIrisLog.error("[worldcheck] check failed", e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
requestStop.run();
|
requestStop.run();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("[worldcheck] server stop request failed", e);
|
ModdedIrisLog.error("[worldcheck] server stop request failed", e);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
return exitCode;
|
return exitCode;
|
||||||
@@ -159,7 +156,7 @@ public final class ModdedWorldCheck {
|
|||||||
awaitStop.run();
|
awaitStop.run();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
exitCode = EXIT_FAILURE;
|
exitCode = EXIT_FAILURE;
|
||||||
LOGGER.error("[worldcheck] waiting for server shutdown failed", e);
|
ModdedIrisLog.error("[worldcheck] waiting for server shutdown failed", e);
|
||||||
} finally {
|
} finally {
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
@@ -171,25 +168,25 @@ public final class ModdedWorldCheck {
|
|||||||
private static WorldCheckPreparation run(MinecraftServer server) {
|
private static WorldCheckPreparation run(MinecraftServer server) {
|
||||||
ServerLevel level = targetLevel(server);
|
ServerLevel level = targetLevel(server);
|
||||||
if (level == null) {
|
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,
|
return new WorldCheckPreparation(false, false, false, false,
|
||||||
new NativeStructureGate(false, 0, false, null));
|
new NativeStructureGate(false, 0, false, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
String levelId = level.dimension().identifier().toString();
|
String levelId = level.dimension().identifier().toString();
|
||||||
String generatorClass = level.getChunkSource().getGenerator().getClass().getName();
|
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
|
IrisModdedChunkGenerator generator = level.getChunkSource().getGenerator() instanceof IrisModdedChunkGenerator iris
|
||||||
? iris : null;
|
? iris : null;
|
||||||
boolean irisGenerator = generator != null;
|
boolean irisGenerator = generator != null;
|
||||||
if (!irisGenerator) {
|
if (!irisGenerator) {
|
||||||
LOGGER.error("[worldcheck] {} is NOT using IrisModdedChunkGenerator", levelId);
|
ModdedIrisLog.error("[worldcheck] {} is NOT using IrisModdedChunkGenerator", levelId);
|
||||||
}
|
}
|
||||||
boolean dimensionTypeOk = generator != null
|
boolean dimensionTypeOk = generator != null
|
||||||
&& WorldCheckDimensionContract.checkDimensionType(level, generator);
|
&& WorldCheckDimensionContract.checkDimensionType(level, generator);
|
||||||
|
|
||||||
BlockPos spawn = level.getRespawnData().pos();
|
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();
|
MessageDigest digest = WorldCheckPredicates.sha256();
|
||||||
List<String> samples = new ArrayList<>();
|
List<String> samples = new ArrayList<>();
|
||||||
@@ -210,9 +207,9 @@ public final class ModdedWorldCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < Math.min(6, samples.size()); i++) {
|
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);
|
HexFormat.of().formatHex(digest.digest()).substring(0, 12), samples.size(), surfaceKeys.size(), surfaceKeys);
|
||||||
|
|
||||||
ChunkAccess zeroChunk = level.getChunk(0, 0);
|
ChunkAccess zeroChunk = level.getChunk(0, 0);
|
||||||
@@ -230,16 +227,16 @@ public final class ModdedWorldCheck {
|
|||||||
columnKeys.add(BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString());
|
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);
|
nonEmptySections, zeroChunk.getSections().length, columnKeys);
|
||||||
|
|
||||||
boolean sectionsOk = nonEmptySections >= 4;
|
boolean sectionsOk = nonEmptySections >= 4;
|
||||||
boolean varietyOk = columnKeys.size() >= 2 || surfaceKeys.size() >= 2;
|
boolean varietyOk = columnKeys.size() >= 2 || surfaceKeys.size() >= 2;
|
||||||
if (!sectionsOk) {
|
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) {
|
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);
|
boolean entityMixinsOk = WorldCheckDimensionContract.checkEntityMixins(level);
|
||||||
@@ -262,7 +259,7 @@ public final class ModdedWorldCheck {
|
|||||||
WorldCheckPredicates.qaEvent("village_poi_metric", "village", poiOk,
|
WorldCheckPredicates.qaEvent("village_poi_metric", "village", poiOk,
|
||||||
"inBounds=" + poi.inBounds() + ",outOfBounds=" + poi.outOfBounds());
|
"inBounds=" + poi.inBounds() + ",outOfBounds=" + poi.outOfBounds());
|
||||||
if (!poiOk) {
|
if (!poiOk) {
|
||||||
LOGGER.error("[worldcheck] village POI audit failed: inBounds={} outOfBounds={}",
|
ModdedIrisLog.error("[worldcheck] village POI audit failed: inBounds={} outOfBounds={}",
|
||||||
poi.inBounds(), poi.outOfBounds());
|
poi.inBounds(), poi.outOfBounds());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -271,12 +268,12 @@ public final class ModdedWorldCheck {
|
|||||||
int passed = structureGate.nonVillagePassed()
|
int passed = structureGate.nonVillagePassed()
|
||||||
+ (structureGate.villagePassBeforePoi() && poiOk ? 1 : 0);
|
+ (structureGate.villagePassBeforePoi() && poiOk ? 1 : 0);
|
||||||
boolean structurePass = structureGate.passBeforePoi() && poiOk;
|
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());
|
WorldCheckStructureAudit.STRUCTURE_CHECKS.size());
|
||||||
WorldCheckPredicates.qaEvent("structure_aggregate", "all", structurePass,
|
WorldCheckPredicates.qaEvent("structure_aggregate", "all", structurePass,
|
||||||
"passed=" + passed + ",total=" + WorldCheckStructureAudit.STRUCTURE_CHECKS.size());
|
"passed=" + passed + ",total=" + WorldCheckStructureAudit.STRUCTURE_CHECKS.size());
|
||||||
boolean pass = preparation.nonStructurePass() && structurePass;
|
boolean pass = preparation.nonStructurePass() && structurePass;
|
||||||
LOGGER.info("[worldcheck] {}", pass ? "PASS" : "FAIL");
|
ModdedIrisLog.info("[worldcheck] {}", pass ? "PASS" : "FAIL");
|
||||||
WorldCheckPredicates.qaEvent("worldcheck_final", "all", pass,
|
WorldCheckPredicates.qaEvent("worldcheck_final", "all", pass,
|
||||||
"structures=" + WorldCheckStructureAudit.STRUCTURE_CHECKS.size()
|
"structures=" + WorldCheckStructureAudit.STRUCTURE_CHECKS.size()
|
||||||
+ ",terrain=" + preparation.terrainOk()
|
+ ",terrain=" + preparation.terrainOk()
|
||||||
@@ -295,7 +292,7 @@ public final class ModdedWorldCheck {
|
|||||||
if (requested != null) {
|
if (requested != null) {
|
||||||
return requested;
|
return requested;
|
||||||
}
|
}
|
||||||
LOGGER.error("[worldcheck] requested dimension '{}' is not loaded", target);
|
ModdedIrisLog.error("[worldcheck] requested dimension '{}' is not loaded", target);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-14
@@ -31,8 +31,6 @@ import art.arcane.iris.modded.command.ModdedGuiHost;
|
|||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -42,7 +40,6 @@ import java.util.Objects;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public final class ModdedWorldEngines {
|
public final class ModdedWorldEngines {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final ConcurrentHashMap<ServerLevel, Engine> ENGINES = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<ServerLevel, Engine> ENGINES = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private ModdedWorldEngines() {
|
private ModdedWorldEngines() {
|
||||||
@@ -64,7 +61,7 @@ public final class ModdedWorldEngines {
|
|||||||
try {
|
try {
|
||||||
evictOrThrow(level);
|
evictOrThrow(level);
|
||||||
} catch (Throwable e) {
|
} 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.
|
// The GUI host holds strong Engine/ServerLevel references with no other remove path.
|
||||||
ModdedGuiHost.unbind(removed[0]);
|
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) {
|
static Engine prepareReplacement(ServerLevel level, String pack, String dimensionKey, long seedOverride) {
|
||||||
@@ -111,7 +108,7 @@ public final class ModdedWorldEngines {
|
|||||||
IrisData data = IrisData.openRuntime(packDir);
|
IrisData data = IrisData.openRuntime(packDir);
|
||||||
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
|
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
|
||||||
if (dimension == null) {
|
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);
|
pack, packDir.getAbsolutePath(), dimensionKey, dimensionKey);
|
||||||
throw new IllegalStateException("Iris dimension '" + dimensionKey + "' missing from pack " + packDir.getAbsolutePath());
|
throw new IllegalStateException("Iris dimension '" + dimensionKey + "' missing from pack " + packDir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
@@ -142,7 +139,7 @@ public final class ModdedWorldEngines {
|
|||||||
throw failure;
|
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());
|
level.dimension().identifier(), packDir.getAbsolutePath(), dimension.getLoadKey(), seed, dimension.getMinHeight(), dimension.getMaxHeight());
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
@@ -182,11 +179,11 @@ public final class ModdedWorldEngines {
|
|||||||
return packDir;
|
return packDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.error("===============================================================");
|
ModdedIrisLog.error("===============================================================");
|
||||||
LOGGER.error("Iris pack '{}' is not installed.", pack);
|
ModdedIrisLog.error("Iris pack '{}' is not installed.", pack);
|
||||||
LOGGER.error("Expected a pack folder at: {}", packDir.getAbsolutePath());
|
ModdedIrisLog.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);
|
ModdedIrisLog.error("Install an Iris pack there (the folder must contain dimensions/{}.json) and restart the server.", dimensionKey);
|
||||||
LOGGER.error("===============================================================");
|
ModdedIrisLog.error("===============================================================");
|
||||||
throw new IllegalStateException("Iris pack not installed: " + packDir.getAbsolutePath());
|
throw new IllegalStateException("Iris pack not installed: " + packDir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,9 +212,9 @@ public final class ModdedWorldEngines {
|
|||||||
+ level.dimension().identifier());
|
+ level.dimension().identifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOGGER.info("Iris engine closed for {}", level.dimension().identifier());
|
ModdedIrisLog.info("Iris engine closed for {}", level.dimension().identifier());
|
||||||
} catch (Throwable e) {
|
} 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) {
|
if (failure == null) {
|
||||||
failure = e;
|
failure = e;
|
||||||
} else if (e != failure) {
|
} 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.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
final class WorldCheckDimensionContract {
|
final class WorldCheckDimensionContract {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
|
|
||||||
private WorldCheckDimensionContract() {
|
private WorldCheckDimensionContract() {
|
||||||
}
|
}
|
||||||
@@ -44,13 +41,13 @@ final class WorldCheckDimensionContract {
|
|||||||
+ ",levelMinY=" + level.getMinY() + ",levelHeight=" + level.getHeight();
|
+ ",levelMinY=" + level.getMinY() + ",levelHeight=" + level.getHeight();
|
||||||
WorldCheckPredicates.qaEvent("dimension_type", dimension.getLoadKey(), pass, detail);
|
WorldCheckPredicates.qaEvent("dimension_type", dimension.getLoadKey(), pass, detail);
|
||||||
if (!pass) {
|
if (!pass) {
|
||||||
LOGGER.error("[worldcheck] dimension type mismatch for {}: {}", dimension.getLoadKey(), detail);
|
ModdedIrisLog.error("[worldcheck] dimension type mismatch for {}: {}", dimension.getLoadKey(), detail);
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("[worldcheck] dimension type contract: {}", detail);
|
ModdedIrisLog.info("[worldcheck] dimension type contract: {}", detail);
|
||||||
}
|
}
|
||||||
return pass;
|
return pass;
|
||||||
} catch (Throwable error) {
|
} 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,
|
WorldCheckPredicates.qaEvent("dimension_type", generator.activeDimensionKey(), false,
|
||||||
"validationError=" + error.getClass().getSimpleName() + ":" + error.getMessage());
|
"validationError=" + error.getClass().getSimpleName() + ":" + error.getMessage());
|
||||||
return false;
|
return false;
|
||||||
@@ -102,7 +99,7 @@ final class WorldCheckDimensionContract {
|
|||||||
WorldCheckPredicates.qaEvent("entity_mixin", "persistence", pass,
|
WorldCheckPredicates.qaEvent("entity_mixin", "persistence", pass,
|
||||||
"vanilla=" + vanillaSave + ",suppressed=" + suppressed + ",restored=" + restored);
|
"vanilla=" + vanillaSave + ",suppressed=" + suppressed + ",restored=" + restored);
|
||||||
if (!pass) {
|
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;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -20,14 +20,11 @@ package art.arcane.iris.modded;
|
|||||||
|
|
||||||
import art.arcane.iris.engine.framework.StructureVerticalBounds;
|
import art.arcane.iris.engine.framework.StructureVerticalBounds;
|
||||||
import art.arcane.iris.modded.WorldCheckStructureAudit.StructureCheck;
|
import art.arcane.iris.modded.WorldCheckStructureAudit.StructureCheck;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
final class WorldCheckPredicates {
|
final class WorldCheckPredicates {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
|
|
||||||
private WorldCheckPredicates() {
|
private WorldCheckPredicates() {
|
||||||
}
|
}
|
||||||
@@ -39,7 +36,7 @@ final class WorldCheckPredicates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void qaEvent(String event, String structure, boolean pass, String detail) {
|
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) {
|
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.ConcentricRingsStructurePlacement;
|
||||||
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
|
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -77,7 +75,6 @@ final class WorldCheckStructureAudit {
|
|||||||
private static final int MAX_FOOTPRINT_CHUNKS = 96;
|
private static final int MAX_FOOTPRINT_CHUNKS = 96;
|
||||||
private static final int MAX_START_REFERENCE_CHUNKS = 16;
|
private static final int MAX_START_REFERENCE_CHUNKS = 16;
|
||||||
private static final int MAX_STRUCTURE_CANDIDATES = 1024;
|
private static final int MAX_STRUCTURE_CANDIDATES = 1024;
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
|
|
||||||
private WorldCheckStructureAudit() {
|
private WorldCheckStructureAudit() {
|
||||||
}
|
}
|
||||||
@@ -123,13 +120,13 @@ final class WorldCheckStructureAudit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean registryOk = registered.size() == check.registryKeys().size();
|
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);
|
check.registryKeys().size(), registeredKeys);
|
||||||
WorldCheckPredicates.qaEvent("structure_registry", check.label(), registryOk,
|
WorldCheckPredicates.qaEvent("structure_registry", check.label(), registryOk,
|
||||||
"resolved=" + registered.size() + ",expected=" + check.registryKeys().size()
|
"resolved=" + registered.size() + ",expected=" + check.registryKeys().size()
|
||||||
+ ",keys=" + String.join("|", registeredKeys));
|
+ ",keys=" + String.join("|", registeredKeys));
|
||||||
if (!registryOk) {
|
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",
|
WorldCheckPredicates.emitSkipped(check, "registry", "structure_reachability", "structure_locate",
|
||||||
"structure_start_reference", "structure_footprint", "structure_material",
|
"structure_start_reference", "structure_footprint", "structure_material",
|
||||||
"structure_block_entity");
|
"structure_block_entity");
|
||||||
@@ -149,12 +146,12 @@ final class WorldCheckStructureAudit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean reachableOk = !reachable.isEmpty();
|
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,
|
WorldCheckPredicates.qaEvent("structure_reachability", check.label(), reachableOk,
|
||||||
"reachable=" + reachable.size() + ",registered=" + registered.size()
|
"reachable=" + reachable.size() + ",registered=" + registered.size()
|
||||||
+ ",keys=" + String.join("|", reachableKeys));
|
+ ",keys=" + String.join("|", reachableKeys));
|
||||||
if (!reachableOk) {
|
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",
|
WorldCheckPredicates.emitSkipped(check, "reachability", "structure_locate", "structure_start_reference",
|
||||||
"structure_footprint", "structure_material", "structure_block_entity");
|
"structure_footprint", "structure_material", "structure_block_entity");
|
||||||
return new StructureCheckResult(false, null);
|
return new StructureCheckResult(false, null);
|
||||||
@@ -170,7 +167,7 @@ final class WorldCheckStructureAudit {
|
|||||||
"method=placement_candidates,millis=" + locateMillis + ",radius=" + check.locateRadius()
|
"method=placement_candidates,millis=" + locateMillis + ",radius=" + check.locateRadius()
|
||||||
+ ",result=" + (foundKey == null ? "none" : foundKey));
|
+ ",result=" + (foundKey == null ? "none" : foundKey));
|
||||||
if (found == null) {
|
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);
|
check.label(), check.locateRadius(), locateMillis);
|
||||||
WorldCheckPredicates.emitSkipped(check, "locate", "structure_start_reference", "structure_footprint",
|
WorldCheckPredicates.emitSkipped(check, "locate", "structure_start_reference", "structure_footprint",
|
||||||
"structure_material", "structure_block_entity");
|
"structure_material", "structure_block_entity");
|
||||||
@@ -178,11 +175,11 @@ final class WorldCheckStructureAudit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BlockPos position = found.getFirst();
|
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.label(), position.getX(), position.getY(), position.getZ(), locateMillis,
|
||||||
check.locateRadius(), foundKey);
|
check.locateRadius(), foundKey);
|
||||||
if (!locateOk) {
|
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",
|
WorldCheckPredicates.emitSkipped(check, "locate", "structure_start_reference", "structure_footprint",
|
||||||
"structure_material", "structure_block_entity");
|
"structure_material", "structure_block_entity");
|
||||||
return new StructureCheckResult(false, null);
|
return new StructureCheckResult(false, null);
|
||||||
@@ -196,13 +193,13 @@ final class WorldCheckStructureAudit {
|
|||||||
boolean validStart = start != null && start.isValid();
|
boolean validStart = start != null && start.isValid();
|
||||||
int references = targetChunk.getReferencesForStructure(structure).size();
|
int references = targetChunk.getReferencesForStructure(structure).size();
|
||||||
boolean startReferenceOk = WorldCheckPredicates.hasNativeStructureEvidence(validStart, references);
|
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);
|
check.label(), chunkX, chunkZ, validStart, references);
|
||||||
WorldCheckPredicates.qaEvent("structure_start_reference", check.label(), startReferenceOk,
|
WorldCheckPredicates.qaEvent("structure_start_reference", check.label(), startReferenceOk,
|
||||||
"chunk=" + chunkX + "," + chunkZ + ",validStart=" + validStart
|
"chunk=" + chunkX + "," + chunkZ + ",validStart=" + validStart
|
||||||
+ ",references=" + references);
|
+ ",references=" + references);
|
||||||
if (!startReferenceOk || !validStart) {
|
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);
|
check.label(), chunkX, chunkZ);
|
||||||
WorldCheckPredicates.emitSkipped(check, "start_reference", "structure_footprint", "structure_material",
|
WorldCheckPredicates.emitSkipped(check, "start_reference", "structure_footprint", "structure_material",
|
||||||
"structure_block_entity");
|
"structure_block_entity");
|
||||||
@@ -221,7 +218,7 @@ final class WorldCheckStructureAudit {
|
|||||||
"configured=" + decision.yShift() + ",applied="
|
"configured=" + decision.yShift() + ",applied="
|
||||||
+ (appliedShift == null ? "unrecorded" : appliedShift));
|
+ (appliedShift == null ? "unrecorded" : appliedShift));
|
||||||
if (!verticalShiftOk) {
|
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);
|
check.label(), decision.yShift(), appliedShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +226,7 @@ final class WorldCheckStructureAudit {
|
|||||||
boolean footprintOk = footprint.inspectedChunks() > 0
|
boolean footprintOk = footprint.inspectedChunks() > 0
|
||||||
&& footprint.evidenceChunks() == footprint.inspectedChunks()
|
&& footprint.evidenceChunks() == footprint.inspectedChunks()
|
||||||
&& footprint.coveredPieces() == footprint.totalPieces();
|
&& footprint.coveredPieces() == footprint.totalPieces();
|
||||||
LOGGER.info("[worldcheck] {} footprint: chunks={}/{} evidence={} pieces={}/{}",
|
ModdedIrisLog.info("[worldcheck] {} footprint: chunks={}/{} evidence={} pieces={}/{}",
|
||||||
check.label(), footprint.inspectedChunks(), footprint.availableChunks(),
|
check.label(), footprint.inspectedChunks(), footprint.availableChunks(),
|
||||||
footprint.evidenceChunks(), footprint.coveredPieces(), footprint.totalPieces());
|
footprint.evidenceChunks(), footprint.coveredPieces(), footprint.totalPieces());
|
||||||
WorldCheckPredicates.qaEvent("structure_footprint", check.label(), footprintOk,
|
WorldCheckPredicates.qaEvent("structure_footprint", check.label(), footprintOk,
|
||||||
@@ -239,7 +236,7 @@ final class WorldCheckStructureAudit {
|
|||||||
|
|
||||||
boolean materialOk = WorldCheckPredicates.hasCharacteristicMaterialEvidence(footprint.characteristicBlocks(),
|
boolean materialOk = WorldCheckPredicates.hasCharacteristicMaterialEvidence(footprint.characteristicBlocks(),
|
||||||
footprint.characteristicChunks(), footprint.materialScannedChunks());
|
footprint.characteristicChunks(), footprint.materialScannedChunks());
|
||||||
LOGGER.info("[worldcheck] {} material: blocks={} chunks={}/{}",
|
ModdedIrisLog.info("[worldcheck] {} material: blocks={} chunks={}/{}",
|
||||||
check.label(), footprint.characteristicBlocks(), footprint.characteristicChunks(),
|
check.label(), footprint.characteristicBlocks(), footprint.characteristicChunks(),
|
||||||
footprint.materialScannedChunks());
|
footprint.materialScannedChunks());
|
||||||
WorldCheckPredicates.qaEvent("structure_material", check.label(), materialOk,
|
WorldCheckPredicates.qaEvent("structure_material", check.label(), materialOk,
|
||||||
@@ -250,7 +247,7 @@ final class WorldCheckStructureAudit {
|
|||||||
if (check.label().equals("mansion")) {
|
if (check.label().equals("mansion")) {
|
||||||
boolean overlap = footprint.vegetationBlocks() > 0;
|
boolean overlap = footprint.vegetationBlocks() > 0;
|
||||||
vegetationOk = WorldCheckPredicates.mansionVegetationPass(footprint.vegetationBlocks());
|
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);
|
footprint.vegetationBlocks(), footprint.vegetationColumns(), overlap);
|
||||||
WorldCheckPredicates.qaEvent("mansion_vegetation_metric", check.label(), vegetationOk,
|
WorldCheckPredicates.qaEvent("mansion_vegetation_metric", check.label(), vegetationOk,
|
||||||
"remainingLogsOrLeaves=" + footprint.vegetationBlocks() + ",columns="
|
"remainingLogsOrLeaves=" + footprint.vegetationBlocks() + ",columns="
|
||||||
@@ -261,7 +258,7 @@ final class WorldCheckStructureAudit {
|
|||||||
PendingVillagePoi pendingPoi = null;
|
PendingVillagePoi pendingPoi = null;
|
||||||
if (check.label().equals("village")) {
|
if (check.label().equals("village")) {
|
||||||
foundationOk = WorldCheckPredicates.villageFoundationPass(footprint.foundationGapColumns());
|
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.foundationBaseColumns(), footprint.foundationBlocks(),
|
||||||
footprint.foundationColumns(), footprint.foundationGapColumns());
|
footprint.foundationColumns(), footprint.foundationGapColumns());
|
||||||
WorldCheckPredicates.qaEvent("village_foundation_metric", check.label(), foundationOk,
|
WorldCheckPredicates.qaEvent("village_foundation_metric", check.label(), foundationOk,
|
||||||
@@ -272,26 +269,26 @@ final class WorldCheckStructureAudit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean blockEntityOk = footprint.blockEntityStates() == footprint.blockEntitiesPresent();
|
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(),
|
check.label(), footprint.blockEntityStates(), footprint.blockEntitiesPresent(),
|
||||||
footprint.blockEntityStates() - footprint.blockEntitiesPresent());
|
footprint.blockEntityStates() - footprint.blockEntitiesPresent());
|
||||||
WorldCheckPredicates.qaEvent("structure_block_entity", check.label(), blockEntityOk,
|
WorldCheckPredicates.qaEvent("structure_block_entity", check.label(), blockEntityOk,
|
||||||
"states=" + footprint.blockEntityStates() + ",present=" + footprint.blockEntitiesPresent()
|
"states=" + footprint.blockEntityStates() + ",present=" + footprint.blockEntitiesPresent()
|
||||||
+ ",missing=" + (footprint.blockEntityStates() - footprint.blockEntitiesPresent()));
|
+ ",missing=" + (footprint.blockEntityStates() - footprint.blockEntitiesPresent()));
|
||||||
if (!footprintOk) {
|
if (!footprintOk) {
|
||||||
LOGGER.error("[worldcheck] {} structure footprint is incomplete", check.label());
|
ModdedIrisLog.error("[worldcheck] {} structure footprint is incomplete", check.label());
|
||||||
}
|
}
|
||||||
if (!materialOk) {
|
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) {
|
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) {
|
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) {
|
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
|
boolean pass = verticalShiftOk && footprintOk && materialOk && blockEntityOk
|
||||||
&& vegetationOk && foundationOk;
|
&& vegetationOk && foundationOk;
|
||||||
|
|||||||
+16
-18
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.api;
|
package art.arcane.iris.modded.api;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.modded.ModdedBlockResolution;
|
import art.arcane.iris.modded.ModdedBlockResolution;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@@ -25,8 +26,6 @@ import net.minecraft.resources.Identifier;
|
|||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -57,7 +56,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
* next provider.
|
* next provider.
|
||||||
*/
|
*/
|
||||||
public final class ModdedCustomContentRegistry {
|
public final class ModdedCustomContentRegistry {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final List<ModdedDataProvider> PROVIDERS = new CopyOnWriteArrayList<>();
|
private static final List<ModdedDataProvider> PROVIDERS = new CopyOnWriteArrayList<>();
|
||||||
private static final Map<String, BlockState> CUSTOM_BLOCKS = new ConcurrentHashMap<>();
|
private static final Map<String, BlockState> CUSTOM_BLOCKS = new ConcurrentHashMap<>();
|
||||||
private static volatile boolean scanned = false;
|
private static volatile boolean scanned = false;
|
||||||
@@ -77,14 +75,14 @@ public final class ModdedCustomContentRegistry {
|
|||||||
}
|
}
|
||||||
Identifier identifier = Identifier.tryParse(namespace + ":" + key);
|
Identifier identifier = Identifier.tryParse(namespace + ":" + key);
|
||||||
if (identifier == null) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
BlockState parsed;
|
BlockState parsed;
|
||||||
try {
|
try {
|
||||||
parsed = ModdedBlockResolution.strictParse(state).handle();
|
parsed = ModdedBlockResolution.strictParse(state).handle();
|
||||||
} catch (Throwable error) {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
DiscoveryBatch activeBatch = discoveryBatch;
|
DiscoveryBatch activeBatch = discoveryBatch;
|
||||||
@@ -93,7 +91,7 @@ public final class ModdedCustomContentRegistry {
|
|||||||
} else {
|
} else {
|
||||||
activeBatch.customBlocks.put(identifier.toString(), parsed);
|
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) {
|
for (ModdedDataProvider existing : PROVIDERS) {
|
||||||
if (existing.modId().equals(provider.modId())) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,9 +118,9 @@ public final class ModdedCustomContentRegistry {
|
|||||||
try {
|
try {
|
||||||
provider.init();
|
provider.init();
|
||||||
} catch (Throwable error) {
|
} 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);
|
CUSTOM_BLOCKS.putAll(batch.customBlocks);
|
||||||
scanned = true;
|
scanned = true;
|
||||||
for (ModdedDataProvider provider : batch.additions) {
|
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,
|
return new Discovery(previousProviders, previousCustomBlocks,
|
||||||
previousDiscoveryComplete, true);
|
previousDiscoveryComplete, true);
|
||||||
@@ -171,7 +169,7 @@ public final class ModdedCustomContentRegistry {
|
|||||||
failure.addSuppressed(rollbackFailure);
|
failure.addSuppressed(rollbackFailure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOGGER.warn("Iris custom content provider discovery failed at {}",
|
ModdedIrisLog.warn("Iris custom content provider discovery failed at {}",
|
||||||
providerIdentity(failingProvider), failure);
|
providerIdentity(failingProvider), failure);
|
||||||
if (failure instanceof RuntimeException runtimeException) {
|
if (failure instanceof RuntimeException runtimeException) {
|
||||||
throw runtimeException;
|
throw runtimeException;
|
||||||
@@ -242,7 +240,7 @@ public final class ModdedCustomContentRegistry {
|
|||||||
try {
|
try {
|
||||||
types = provider.getTypes(type);
|
types = provider.getTypes(type);
|
||||||
} catch (Throwable error) {
|
} 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;
|
continue;
|
||||||
}
|
}
|
||||||
if (types == null) {
|
if (types == null) {
|
||||||
@@ -288,7 +286,7 @@ public final class ModdedCustomContentRegistry {
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
} catch (Throwable error) {
|
} 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;
|
return null;
|
||||||
@@ -302,7 +300,7 @@ public final class ModdedCustomContentRegistry {
|
|||||||
public static void processBlockPlacement(Engine engine, ServerLevel level, BlockPos position, String key) {
|
public static void processBlockPlacement(Engine engine, ServerLevel level, BlockPos position, String key) {
|
||||||
Identifier base = parseIdentifier(key);
|
Identifier base = parseIdentifier(key);
|
||||||
if (base == null) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, String> state = parseState(key);
|
Map<String, String> state = parseState(key);
|
||||||
@@ -314,11 +312,11 @@ public final class ModdedCustomContentRegistry {
|
|||||||
provider.processBlockPlacement(new ModdedBlockPlacementContext(
|
provider.processBlockPlacement(new ModdedBlockPlacementContext(
|
||||||
engine, level, position.immutable(), base, state, level.getBlockState(position)));
|
engine, level, position.immutable(), base, state, level.getBlockState(position)));
|
||||||
} catch (Throwable error) {
|
} 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;
|
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;
|
return entity;
|
||||||
}
|
}
|
||||||
} catch (Throwable error) {
|
} 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;
|
return null;
|
||||||
@@ -439,7 +437,7 @@ public final class ModdedCustomContentRegistry {
|
|||||||
"Iris custom content provider returned a null mod id");
|
"Iris custom content provider returned a null mod id");
|
||||||
for (ModdedDataProvider existing : providers) {
|
for (ModdedDataProvider existing : providers) {
|
||||||
if (modId.equals(existing.modId())) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-9
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.IrisMessages;
|
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.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -67,7 +66,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
|
|
||||||
public final class IrisModdedCommands {
|
public final class IrisModdedCommands {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final long DOWNLOAD_SHUTDOWN_POLL_SECONDS = 15L;
|
private static final long DOWNLOAD_SHUTDOWN_POLL_SECONDS = 15L;
|
||||||
private static final Object DOWNLOAD_MONITOR = new Object();
|
private static final Object DOWNLOAD_MONITOR = new Object();
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ public final class IrisModdedCommands {
|
|||||||
LiteralCommandNode<CommandSourceStack> root = dispatcher.register(ModdedCommandTree.rootTree());
|
LiteralCommandNode<CommandSourceStack> root = dispatcher.register(ModdedCommandTree.rootTree());
|
||||||
dispatcher.register(Commands.literal("ir").redirect(root));
|
dispatcher.register(Commands.literal("ir").redirect(root));
|
||||||
dispatcher.register(Commands.literal("irs").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() {
|
public static void openDownloadAdmission() {
|
||||||
@@ -108,7 +106,7 @@ public final class IrisModdedCommands {
|
|||||||
try {
|
try {
|
||||||
if (!execution.await(DOWNLOAD_SHUTDOWN_POLL_SECONDS, TimeUnit.SECONDS) && !warned) {
|
if (!execution.await(DOWNLOAD_SHUTDOWN_POLL_SECONDS, TimeUnit.SECONDS) && !warned) {
|
||||||
warned = true;
|
warned = true;
|
||||||
LOGGER.warn(execution.isPublishing()
|
ModdedIrisLog.warn(execution.isPublishing()
|
||||||
? "Waiting for atomic pack publication to finish before Iris shutdown."
|
? "Waiting for atomic pack publication to finish before Iris shutdown."
|
||||||
: "Waiting for the active pack download to cancel 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);
|
accepted = scheduler.asyncIfRunning(execution, execution::cancel);
|
||||||
} catch (Throwable error) {
|
} catch (Throwable error) {
|
||||||
execution.cancel();
|
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(
|
fail(source, IrisLanguage.plain(
|
||||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||||
MessageArgument.untrusted("pack", target),
|
MessageArgument.untrusted("pack", target),
|
||||||
@@ -363,7 +361,7 @@ public final class IrisModdedCommands {
|
|||||||
}
|
}
|
||||||
if (!accepted) {
|
if (!accepted) {
|
||||||
execution.cancel();
|
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(
|
fail(source, IrisLanguage.plain(
|
||||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||||
MessageArgument.untrusted("pack", target),
|
MessageArgument.untrusted("pack", target),
|
||||||
@@ -416,7 +414,7 @@ public final class IrisModdedCommands {
|
|||||||
dispatchDownloadFeedback(source, () -> fail(source, error.getMessage()));
|
dispatchDownloadFeedback(source, () -> fail(source, error.getMessage()));
|
||||||
return;
|
return;
|
||||||
} catch (IOException | RuntimeException error) {
|
} 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(
|
dispatchDownloadFeedback(source, () -> fail(source, IrisLanguage.plain(
|
||||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||||
@@ -512,7 +510,7 @@ public final class IrisModdedCommands {
|
|||||||
try {
|
try {
|
||||||
return irisGenerator.commandEngine();
|
return irisGenerator.commandEngine();
|
||||||
} catch (Throwable e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
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.resources.Identifier;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
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> PACK_NAMES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestPackNames(context, builder);
|
||||||
static final SuggestionProvider<CommandSourceStack> DIMENSION_NAMES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestDimensionNames(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 int TAB_FAILURE_KEYS_MAX = 256;
|
||||||
private static final Set<String> REPORTED_TAB_FAILURES = ConcurrentHashMap.newKeySet();
|
private static final Set<String> REPORTED_TAB_FAILURES = ConcurrentHashMap.newKeySet();
|
||||||
private static final long PACK_NAME_CACHE_TTL_MS = 3_000L;
|
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) {
|
if (REPORTED_TAB_FAILURES.size() > TAB_FAILURE_KEYS_MAX) {
|
||||||
REPORTED_TAB_FAILURES.clear();
|
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) {
|
private static String tabOrigin(CommandSourceStack source) {
|
||||||
|
|||||||
+5
-7
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
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.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
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.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedDatapackCommands {
|
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 Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
private static final String WORLD_PACK_NAME = "iris";
|
private static final String WORLD_PACK_NAME = "iris";
|
||||||
|
|
||||||
@@ -170,7 +168,7 @@ public final class ModdedDatapackCommands {
|
|||||||
try {
|
try {
|
||||||
json = dimension.getDimensionType().toJson(DataVersion.getLatest().get());
|
json = dimension.getDimensionType().toJson(DataVersion.getLatest().get());
|
||||||
} catch (Throwable e) {
|
} 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()))));
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -180,7 +178,7 @@ public final class ModdedDatapackCommands {
|
|||||||
Files.writeString(output.toPath(), json, StandardCharsets.UTF_8);
|
Files.writeString(output.toPath(), json, StandardCharsets.UTF_8);
|
||||||
written.add(output.getPath());
|
written.add(output.getPath());
|
||||||
} catch (IOException e) {
|
} 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()))));
|
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);
|
Files.writeString(mcmeta.toPath(), meta, StandardCharsets.UTF_8);
|
||||||
written.add(mcmeta.getPath());
|
written.add(mcmeta.getPath());
|
||||||
} catch (IOException e) {
|
} 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()))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -237,7 +235,7 @@ public final class ModdedDatapackCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
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.iris.core.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
final class ModdedDeveloperCommands {
|
final class ModdedDeveloperCommands {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|
||||||
private ModdedDeveloperCommands() {
|
private ModdedDeveloperCommands() {
|
||||||
@@ -71,7 +69,7 @@ final class ModdedDeveloperCommands {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
} catch (SocketException error) {
|
} 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())));
|
ModdedCommandFeedback.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_DEVELOPER_COMMANDS_NETWORK_SCAN_FAILED, MessageArgument.untrusted("value", error.getClass().getSimpleName())));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-6
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
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.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
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.SoundEvents;
|
||||||
import net.minecraft.sounds.SoundSource;
|
import net.minecraft.sounds.SoundSource;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -62,7 +61,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public final class ModdedDustRevealer {
|
public final class ModdedDustRevealer {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int MAX_HITS = 2_048;
|
private static final int MAX_HITS = 2_048;
|
||||||
private static final int PARTICLE_BATCH_SIZE = 64;
|
private static final int PARTICLE_BATCH_SIZE = 64;
|
||||||
private static final DustParticleOptions REVEAL_DUST = new DustParticleOptions(0xFFD24A, 1.2F);
|
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) {
|
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(() -> {
|
scheduler.global(() -> {
|
||||||
if (ACTIVE_RUNS.remove(run.playerId(), run)) {
|
if (ACTIVE_RUNS.remove(run.playerId(), run)) {
|
||||||
run.player().sendSystemMessage(Component.literal(
|
run.player().sendSystemMessage(Component.literal(
|
||||||
@@ -415,7 +413,7 @@ public final class ModdedDustRevealer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable error) {
|
} 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);
|
x, relativeY + minHeight, z, error);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -458,7 +456,7 @@ public final class ModdedDustRevealer {
|
|||||||
try {
|
try {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
} catch (Throwable error) {
|
} catch (Throwable error) {
|
||||||
LOGGER.error("Iris dust {} failed", operation, error);
|
ModdedIrisLog.error("Iris dust {} failed", operation, error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.gui.GuiHost;
|
import art.arcane.iris.core.gui.GuiHost;
|
||||||
import art.arcane.iris.core.loader.IrisRegistrant;
|
import art.arcane.iris.core.loader.IrisRegistrant;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
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.commands.CommandSourceStack;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.awt.Desktop;
|
import java.awt.Desktop;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
final class ModdedEditCommands {
|
final class ModdedEditCommands {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
|
|
||||||
private ModdedEditCommands() {
|
private ModdedEditCommands() {
|
||||||
}
|
}
|
||||||
@@ -123,7 +121,7 @@ final class ModdedEditCommands {
|
|||||||
try {
|
try {
|
||||||
Desktop.getDesktop().open(file);
|
Desktop.getDesktop().open(file);
|
||||||
} catch (Throwable e) {
|
} 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())));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.runtime.GoldenHashEngine;
|
import art.arcane.iris.core.runtime.GoldenHashEngine;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.modded.ModdedBlockBuffer;
|
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.commands.CommandSourceStack;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -47,7 +46,6 @@ public final class ModdedGoldenHash {
|
|||||||
VERIFY
|
VERIFY
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final AtomicBoolean ACTIVE = new AtomicBoolean(false);
|
private static final AtomicBoolean ACTIVE = new AtomicBoolean(false);
|
||||||
|
|
||||||
private final CommandSourceStack source;
|
private final CommandSourceStack source;
|
||||||
@@ -96,7 +94,7 @@ public final class ModdedGoldenHash {
|
|||||||
MessageArgument.trusted("threads", Math.max(1, threads)),
|
MessageArgument.trusted("threads", Math.max(1, threads)),
|
||||||
MessageArgument.untrusted("mode", mode)
|
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());
|
engine.getDimension().getLoadKey(), engine.getSeedManager().getSeed(), boundedRadius, Math.max(1, threads), mode, scan.hashEngine.getGoldenFile().getName());
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
@@ -182,7 +180,7 @@ public final class ModdedGoldenHash {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkFailed(int chunkX, int chunkZ, Throwable error) {
|
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(
|
ModdedGoldenHash.this.fail(IrisLanguage.plain(
|
||||||
RuntimeProgressMessages.GOLDEN_CHUNK_FAILED,
|
RuntimeProgressMessages.GOLDEN_CHUNK_FAILED,
|
||||||
MessageArgument.trusted("x", chunkX),
|
MessageArgument.trusted("x", chunkX),
|
||||||
|
|||||||
+4
-6
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
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.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
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.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -64,7 +63,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
final class ModdedLocateCommands {
|
final class ModdedLocateCommands {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final long LOCATE_TIMEOUT_MS = 120000L;
|
private static final long LOCATE_TIMEOUT_MS = 120000L;
|
||||||
private static final int NATIVE_STRUCTURE_LOCATE_RADIUS = 100;
|
private static final int NATIVE_STRUCTURE_LOCATE_RADIUS = 100;
|
||||||
private static final ConcurrentHashMap<UUID, CompletableFuture<Position2>> ACTIVE_LOCATE_REQUESTS = new ConcurrentHashMap<>();
|
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,
|
server.execute(() -> teleportToStructure(source, level, player, targetX, targetY, targetZ,
|
||||||
"Iris-placed structure " + key));
|
"Iris-placed structure " + key));
|
||||||
} catch (Throwable e) {
|
} 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()))));
|
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCH_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()))));
|
||||||
}
|
}
|
||||||
}, "Iris Structure Locator");
|
}, "Iris Structure Locator");
|
||||||
@@ -302,7 +300,7 @@ final class ModdedLocateCommands {
|
|||||||
teleportToStructure(source, level, player, targetX, targetY, targetZ,
|
teleportToStructure(source, level, player, targetX, targetY, targetZ,
|
||||||
"native structure " + target.key());
|
"native structure " + target.key());
|
||||||
} catch (Throwable e) {
|
} 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())));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (failure != null) {
|
if (failure != null) {
|
||||||
LOGGER.error("Iris locate failed for {}", label, failure);
|
ModdedIrisLog.error("Iris locate failed for {}", label, failure);
|
||||||
server.execute(() -> {
|
server.execute(() -> {
|
||||||
if (ACTIVE_LOCATE_REQUESTS.remove(playerId, search)) {
|
if (ACTIVE_LOCATE_REQUESTS.remove(playerId, search)) {
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCH_FAILED_2, MessageArgument.untrusted("failure", failure)));
|
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;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.tools.TreePlausibilizeBatch;
|
import art.arcane.iris.core.tools.TreePlausibilizeBatch;
|
||||||
import art.arcane.iris.core.tools.TreePlausibilizer;
|
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.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
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.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedObjectCommands {
|
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 Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
private static final long MAX_SAVE_VOLUME = 500000L;
|
private static final long MAX_SAVE_VOLUME = 500000L;
|
||||||
private static final long MAX_AUTOSELECT_VOLUME = 100000L;
|
private static final long MAX_AUTOSELECT_VOLUME = 100000L;
|
||||||
@@ -313,7 +311,7 @@ public final class ModdedObjectCommands {
|
|||||||
try {
|
try {
|
||||||
object.write(file);
|
object.write(file);
|
||||||
} catch (IOException e) {
|
} 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) {
|
if (finalClaimed) {
|
||||||
// Never leave a 0-byte claim file permanently blocking non-overwrite saves.
|
// Never leave a 0-byte claim file permanently blocking non-overwrite saves.
|
||||||
file.delete();
|
file.delete();
|
||||||
@@ -332,7 +330,7 @@ public final class ModdedObjectCommands {
|
|||||||
tileNote.append(" (").append(tilesSkipped[0]).append(" tile state(s) could not be captured)");
|
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))));
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -378,7 +376,7 @@ public final class ModdedObjectCommands {
|
|||||||
String blockKey = BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
|
String blockKey = BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
|
||||||
return ModdedTileData.capture(blockKey, snbt);
|
return ModdedTileData.capture(blockKey, snbt);
|
||||||
} catch (Throwable e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,7 +389,7 @@ public final class ModdedObjectCommands {
|
|||||||
try {
|
try {
|
||||||
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
||||||
} catch (Throwable e) {
|
} 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) {
|
if (object == null || object.getBlocks().size() == 0) {
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_EMPTY_OBJECT, MessageArgument.untrusted("key", key)));
|
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 {
|
try {
|
||||||
object.place(target.getX(), target.getY() + object.getCenter().getY(), target.getZ(), placer, placement, new RNG(), null);
|
object.place(target.getX(), target.getY() + object.getCenter().getY(), target.getZ(), placer, placement, new RNG(), null);
|
||||||
} catch (Throwable e) {
|
} 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());
|
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())));
|
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_PASTE_FAILED_PARTIAL_CHANGES_RECORDED_UNDO, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -428,7 +426,7 @@ public final class ModdedObjectCommands {
|
|||||||
ModdedObjectUndo.record(owner, level, placer.undoSnapshot());
|
ModdedObjectUndo.record(owner, level, placer.undoSnapshot());
|
||||||
String tileNote = tileNote(placer);
|
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)));
|
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());
|
key, target.getX(), target.getY(), target.getZ(), rotation, placer.writes(), placer.nonAirWrites(), placer.restoredTiles(), placer.skippedTiles());
|
||||||
return placer.writes() > 0 ? 1 : 0;
|
return placer.writes() > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
@@ -608,7 +606,7 @@ public final class ModdedObjectCommands {
|
|||||||
try {
|
try {
|
||||||
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Iris object load failed for {}", key, e);
|
ModdedIrisLog.error("Iris object load failed for {}", key, e);
|
||||||
}
|
}
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_OBJECT, MessageArgument.untrusted("key", key)));
|
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_OBJECT, MessageArgument.untrusted("key", key)));
|
||||||
@@ -648,7 +646,7 @@ public final class ModdedObjectCommands {
|
|||||||
try {
|
try {
|
||||||
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
object = IrisData.loadAnyObject(key, engine == null ? null : engine.getData());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Iris object load failed for {}", key, e);
|
ModdedIrisLog.error("Iris object load failed for {}", key, e);
|
||||||
}
|
}
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_UNKNOWN_OBJECT_2, MessageArgument.untrusted("key", key)));
|
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 {
|
try {
|
||||||
object.write(file);
|
object.write(file);
|
||||||
} catch (IOException e) {
|
} 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()))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.object.IObjectPlacer;
|
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.block.state.BlockState;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
final class ModdedObjectPlacer implements IObjectPlacer {
|
final class ModdedObjectPlacer implements IObjectPlacer {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int DEFAULT_FLUID_HEIGHT = 63;
|
private static final int DEFAULT_FLUID_HEIGHT = 63;
|
||||||
|
|
||||||
private final ServerLevel level;
|
private final ServerLevel level;
|
||||||
@@ -199,7 +197,7 @@ final class ModdedObjectPlacer implements IObjectPlacer {
|
|||||||
}
|
}
|
||||||
restoredTiles++;
|
restoredTiles++;
|
||||||
} catch (Throwable e) {
|
} 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++;
|
skippedTiles++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -18,13 +18,12 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
@@ -34,7 +33,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public final class ModdedObjectUndo {
|
public final class ModdedObjectUndo {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int MAX_ENTRIES_PER_OWNER = 32;
|
private static final int MAX_ENTRIES_PER_OWNER = 32;
|
||||||
private static final ConcurrentHashMap<UUID, Deque<Entry>> UNDOS = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<UUID, Deque<Entry>> UNDOS = new ConcurrentHashMap<>();
|
||||||
private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
|
private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
|
||||||
@@ -48,7 +46,7 @@ public final class ModdedObjectUndo {
|
|||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
if (INITIALIZED.compareAndSet(false, true)) {
|
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.
|
// dimension id must never have blocks replayed into the dead ServerLevel.
|
||||||
MinecraftServer server = entry.level().getServer();
|
MinecraftServer server = entry.level().getServer();
|
||||||
if (server == null || server.getLevel(entry.level().dimension()) != entry.level()) {
|
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());
|
entry.level().dimension().identifier());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -103,10 +101,10 @@ public final class ModdedObjectUndo {
|
|||||||
entry.level().setBlock(block.getKey(), block.getValue(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
|
entry.level().setBlock(block.getKey(), block.getValue(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
|
||||||
writes++;
|
writes++;
|
||||||
} catch (Throwable e) {
|
} 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++;
|
reverted++;
|
||||||
}
|
}
|
||||||
return reverted;
|
return reverted;
|
||||||
|
|||||||
+2
-4
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||||
import art.arcane.iris.core.pack.PackResourceCleanup;
|
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.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
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.iris.core.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedPackCommands {
|
public final class ModdedPackCommands {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|
||||||
private ModdedPackCommands() {
|
private ModdedPackCommands() {
|
||||||
@@ -139,7 +137,7 @@ public final class ModdedPackCommands {
|
|||||||
}
|
}
|
||||||
server.execute(() -> report(source, result));
|
server.execute(() -> report(source, result));
|
||||||
} catch (Throwable e) {
|
} 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())))));
|
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++;
|
broken++;
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-20
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.pregenerator.PregenListener;
|
import art.arcane.iris.core.pregenerator.PregenListener;
|
||||||
import art.arcane.iris.core.pregenerator.PregenMantleBackpressure;
|
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.ServerLevel;
|
||||||
import net.minecraft.server.level.TicketType;
|
import net.minecraft.server.level.TicketType;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@@ -48,7 +47,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public final class ModdedPregenMethod implements PregeneratorMethod {
|
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 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 int ADAPTIVE_TIMEOUT_STEP = 3;
|
||||||
private static final long ADAPTIVE_RECOVERY_INTERVAL = 64L;
|
private static final long ADAPTIVE_RECOVERY_INTERVAL = 64L;
|
||||||
@@ -106,7 +104,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
pauseGuard.suspend();
|
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(),
|
level.dimension().identifier(),
|
||||||
sync ? "sync" : "async",
|
sync ? "sync" : "async",
|
||||||
sync ? 1 : maxInFlight,
|
sync ? 1 : maxInFlight,
|
||||||
@@ -114,7 +112,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
describeWorkerPool(),
|
describeWorkerPool(),
|
||||||
ModdedGenPool.describeChunkSystem());
|
ModdedGenPool.describeChunkSystem());
|
||||||
if (!sync && !ModdedGenPool.parallelChunkSystem()) {
|
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();
|
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());
|
level.dimension().identifier(), completed.get(), inFlightPeak.get(), adaptiveLimit.get());
|
||||||
if (deferFinalSaveIfRequested()) {
|
if (deferFinalSaveIfRequested()) {
|
||||||
return;
|
return;
|
||||||
@@ -245,7 +243,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
long remainingNanos = deadline - System.nanoTime();
|
long remainingNanos = deadline - System.nanoTime();
|
||||||
if (remainingNanos <= 0L) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
long waitMillis = Math.max(1L, Math.min(FINAL_SAVE_POLL_MILLIS,
|
long waitMillis = Math.max(1L, Math.min(FINAL_SAVE_POLL_MILLIS,
|
||||||
@@ -260,7 +258,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
continue;
|
continue;
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
Throwable cause = e.getCause() == null ? e : e.getCause();
|
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 "
|
throw new IllegalStateException("Iris pregen level save failed for "
|
||||||
+ level.dimension().identifier(), cause);
|
+ level.dimension().identifier(), cause);
|
||||||
}
|
}
|
||||||
@@ -337,7 +335,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
try {
|
try {
|
||||||
Object result = loadFuture.get(timeoutSeconds, TimeUnit.SECONDS);
|
Object result = loadFuture.get(timeoutSeconds, TimeUnit.SECONDS);
|
||||||
if (result instanceof ChunkResult<?> chunkResult && !chunkResult.isSuccess()) {
|
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);
|
listener.onChunkFailed(x, z);
|
||||||
return;
|
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.
|
// this abort the pregen thread spins hot against the dead chunk source until the JVM dies.
|
||||||
if (level.getServer().isStopped() || !level.getServer().isRunning()) {
|
if (level.getServer().isStopped() || !level.getServer().isRunning()) {
|
||||||
if (SERVER_DEAD_LOGGED.compareAndSet(false, true)) {
|
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);
|
listener.onChunkFailed(x, z);
|
||||||
ModdedPregenJob.stop();
|
ModdedPregenJob.stop();
|
||||||
@@ -401,7 +399,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result instanceof ChunkResult<?> chunkResult && !chunkResult.isSuccess()) {
|
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);
|
listener.onChunkFailed(x, z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -425,10 +423,10 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
private void logChunkFailure(int x, int z, Throwable failure) {
|
private void logChunkFailure(int x, int z, Throwable failure) {
|
||||||
Throwable cause = unwrap(failure);
|
Throwable cause = unwrap(failure);
|
||||||
if (failureDetailLogged.compareAndSet(false, true)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
LOGGER.warn("Iris pregen chunk {},{} failed: {}", x, z, cause.toString());
|
ModdedIrisLog.warn("Iris pregen chunk {},{} failed: {}", x, z, cause.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markFinished() {
|
private void markFinished() {
|
||||||
@@ -500,7 +498,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
try {
|
try {
|
||||||
engine.getMantle().forceCleanupChunk(x, z);
|
engine.getMantle().forceCleanupChunk(x, z);
|
||||||
} catch (Throwable e) {
|
} 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 {
|
try {
|
||||||
current = dedicated.pauseWhenEmptySeconds();
|
current = dedicated.pauseWhenEmptySeconds();
|
||||||
} catch (Throwable e) {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
if (current <= 0) {
|
if (current <= 0) {
|
||||||
@@ -591,7 +589,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
suspendedFrom.set(current);
|
suspendedFrom.set(current);
|
||||||
armCrashRestore();
|
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() {
|
private void restore() {
|
||||||
@@ -606,9 +604,9 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
dedicated.setPauseWhenEmptySeconds(previous);
|
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) {
|
} 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);
|
previous, e.toString(), previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -655,11 +653,11 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
|
|||||||
if (!pauseStillArmed()) {
|
if (!pauseStillArmed()) {
|
||||||
return;
|
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) {
|
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);
|
current, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-10
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.tools.WorldMaintenance;
|
import art.arcane.iris.core.tools.WorldMaintenance;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.mantle.EngineMantle;
|
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.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||||
public final class ModdedRegen {
|
public final class ModdedRegen {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int APPLY_AHEAD = 8;
|
private static final int APPLY_AHEAD = 8;
|
||||||
private static final long CHUNK_SLOT_TIMEOUT_MILLIS = 120000L;
|
private static final long CHUNK_SLOT_TIMEOUT_MILLIS = 120000L;
|
||||||
private static final long FINAL_APPLY_TIMEOUT_MILLIS = 300000L;
|
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);
|
ModdedRegen job = new ModdedRegen(source, level, generator, engine, centerX, centerZ, radius);
|
||||||
int chunks = (job.radius * 2 + 1) * (job.radius * 2 + 1);
|
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.");
|
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);
|
level.dimension().identifier(), centerX, centerZ, job.radius, chunks);
|
||||||
Thread thread = new Thread(job::run, "Iris Regenerate");
|
Thread thread = new Thread(job::run, "Iris Regenerate");
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
@@ -117,11 +115,11 @@ public final class ModdedRegen {
|
|||||||
List<int[]> targets = ChunkSpiral.centerOut(centerX, centerZ, radius);
|
List<int[]> targets = ChunkSpiral.centerOut(centerX, centerZ, radius);
|
||||||
int applied = regenerate(targets);
|
int applied = regenerate(targets);
|
||||||
ok("Regen finished: " + applied + "/" + targets.size() + " chunk(s) in " + Form.duration(M.ms() - startedAt, 2));
|
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) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Iris regen failed", e);
|
ModdedIrisLog.error("Iris regen failed", e);
|
||||||
fail("Regen failed: " + e);
|
fail("Regen failed: " + e);
|
||||||
} finally {
|
} finally {
|
||||||
WorldMaintenance.endWorldMaintenance(worldIdentity, "regen");
|
WorldMaintenance.endWorldMaintenance(worldIdentity, "regen");
|
||||||
@@ -155,7 +153,7 @@ public final class ModdedRegen {
|
|||||||
int chunkZ = target[1];
|
int chunkZ = target[1];
|
||||||
if (!inFlight.tryAcquire(CHUNK_SLOT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
|
if (!inFlight.tryAcquire(CHUNK_SLOT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
|
||||||
aborted.set(true);
|
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);
|
chunkX, chunkZ, CHUNK_SLOT_TIMEOUT_MILLIS, completed.get(), total);
|
||||||
fail("Regen aborted: apply pipeline stalled at " + completed.get() + "/" + total + " chunk(s)");
|
fail("Regen aborted: apply pipeline stalled at " + completed.get() + "/" + total + " chunk(s)");
|
||||||
break;
|
break;
|
||||||
@@ -173,7 +171,7 @@ public final class ModdedRegen {
|
|||||||
try {
|
try {
|
||||||
engine.generate(chunkX << 4, chunkZ << 4, blocks, biomes, false);
|
engine.generate(chunkX << 4, chunkZ << 4, blocks, biomes, false);
|
||||||
} catch (Throwable e) {
|
} 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());
|
fail("Chunk " + chunkX + "," + chunkZ + " generation FAILED: " + e.getClass().getSimpleName());
|
||||||
completed.incrementAndGet();
|
completed.incrementAndGet();
|
||||||
inFlight.release();
|
inFlight.release();
|
||||||
@@ -190,7 +188,7 @@ public final class ModdedRegen {
|
|||||||
success = true;
|
success = true;
|
||||||
applied.incrementAndGet();
|
applied.incrementAndGet();
|
||||||
} catch (Throwable e) {
|
} 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());
|
fail("Chunk " + chunkX + "," + chunkZ + " apply FAILED: " + e.getClass().getSimpleName());
|
||||||
} finally {
|
} finally {
|
||||||
int done = completed.incrementAndGet();
|
int done = completed.incrementAndGet();
|
||||||
@@ -212,7 +210,7 @@ public final class ModdedRegen {
|
|||||||
if (!allApplied.await(FINAL_APPLY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
|
if (!allApplied.await(FINAL_APPLY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
|
||||||
aborted.set(true);
|
aborted.set(true);
|
||||||
long outstanding = allApplied.getCount();
|
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);
|
outstanding, total, FINAL_APPLY_TIMEOUT_MILLIS);
|
||||||
fail("Regen aborted: " + outstanding + " of " + total + " chunk(s) never finished");
|
fail("Regen aborted: " + outstanding + " of " + total + " chunk(s) never finished");
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.structure.StructureIndexService;
|
import art.arcane.iris.core.structure.StructureIndexService;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
@@ -40,8 +41,6 @@ import net.minecraft.commands.Commands;
|
|||||||
import net.minecraft.commands.SharedSuggestionProvider;
|
import net.minecraft.commands.SharedSuggestionProvider;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
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.iris.core.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedStructureCommands {
|
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 Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|
||||||
private static final SuggestionProvider<CommandSourceStack> IRIS_STRUCTURE_KEYS = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestIrisStructureKeys(context, builder);
|
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);
|
piece.getObject().place(piece.getX(), piece.getY(), piece.getZ(), placer, config, rng, null, null, data);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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());
|
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())));
|
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STRUCTURE_COMMANDS_PLACE_FAILED_PARTIAL_CHANGES_RECORDED_UNDO, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+23
-23
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.gui.GuiHost;
|
import art.arcane.iris.core.gui.GuiHost;
|
||||||
import art.arcane.iris.core.gui.NoiseExplorerGUI;
|
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.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Relative;
|
import net.minecraft.world.entity.Relative;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
|
|
||||||
import java.awt.Desktop;
|
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.iris.core.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedStudioCommands {
|
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 Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
private static final Pattern PROJECT_NAME = Pattern.compile("[a-z0-9_-]+");
|
private static final Pattern PROJECT_NAME = Pattern.compile("[a-z0-9_-]+");
|
||||||
private static final Pattern STUDIO_ID_SANITIZER = 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 {
|
try {
|
||||||
workspace = ModdedWorkspaceGenerator.writeWorkspace(IrisData.get(folder), folder, open);
|
workspace = ModdedWorkspaceGenerator.writeWorkspace(IrisData.get(folder), folder, open);
|
||||||
} catch (Throwable e) {
|
} 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()))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -299,7 +297,7 @@ public final class ModdedStudioCommands {
|
|||||||
try {
|
try {
|
||||||
Desktop.getDesktop().open(workspace);
|
Desktop.getDesktop().open(workspace);
|
||||||
} catch (Throwable e) {
|
} 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())));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -380,8 +378,9 @@ public final class ModdedStudioCommands {
|
|||||||
try {
|
try {
|
||||||
File packFolder = new File(ModdedPackCommands.packsRoot(), pack);
|
File packFolder = new File(ModdedPackCommands.packsRoot(), pack);
|
||||||
if (!new File(packFolder, "dimensions/" + pack + ".json").isFile()) {
|
if (!new File(packFolder, "dimensions/" + pack + ".json").isFile()) {
|
||||||
server.execute(() -> IrisModdedCommands.fail(source, "Pack '" + pack
|
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
+ "' is not installed. Use /iris download pack=overworld or pack=underworld, then restart."));
|
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||||
|
MessageArgument.untrusted("pack", pack))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrisData data = IrisData.get(packFolder);
|
IrisData data = IrisData.get(packFolder);
|
||||||
@@ -393,7 +392,7 @@ public final class ModdedStudioCommands {
|
|||||||
try {
|
try {
|
||||||
ModdedWorkspaceGenerator.writeWorkspace(data, packFolder, true);
|
ModdedWorkspaceGenerator.writeWorkspace(data, packFolder, true);
|
||||||
} catch (Throwable workspaceError) {
|
} 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(
|
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_FAILED_WRITE_WORKSPACE,
|
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_FAILED_WRITE_WORKSPACE,
|
||||||
MessageArgument.untrusted("value", packFolder.getAbsolutePath()),
|
MessageArgument.untrusted("value", packFolder.getAbsolutePath()),
|
||||||
@@ -407,7 +406,7 @@ public final class ModdedStudioCommands {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Throwable e) {
|
} 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)))));
|
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 {
|
try {
|
||||||
handle = ModdedDimensionManager.create(server, dimensionId, pack, pack, seed);
|
handle = ModdedDimensionManager.create(server, dimensionId, pack, pack, seed);
|
||||||
} catch (Throwable e) {
|
} 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))));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -430,7 +429,7 @@ public final class ModdedStudioCommands {
|
|||||||
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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_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)));
|
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 {
|
try {
|
||||||
handle = ModdedDimensionManager.create(server, dimensionId, pack, pack, seed);
|
handle = ModdedDimensionManager.create(server, dimensionId, pack, pack, seed);
|
||||||
} catch (Throwable e) {
|
} 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))));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -460,7 +459,7 @@ public final class ModdedStudioCommands {
|
|||||||
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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);
|
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)));
|
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 {
|
try {
|
||||||
ModdedDimensionManager.remove(server, dimensionId, true);
|
ModdedDimensionManager.remove(server, dimensionId, true);
|
||||||
} catch (Throwable e) {
|
} 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))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -553,7 +552,7 @@ public final class ModdedStudioCommands {
|
|||||||
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
surface = engine.getMinHeight() + engine.getHeight(8, 8, false) + 2;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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);
|
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)));
|
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 {
|
try {
|
||||||
File templateFolder = new File(packsRoot, template);
|
File templateFolder = new File(packsRoot, template);
|
||||||
if (!new File(templateFolder, "dimensions/" + template + ".json").isFile()) {
|
if (!new File(templateFolder, "dimensions/" + template + ".json").isFile()) {
|
||||||
server.execute(() -> IrisModdedCommands.fail(source, "Template pack '" + template
|
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
+ "' is not installed. Install its zip with /iris download link=<zip-url>, then restart."));
|
ModdedCommandMessages.MODDED_STUDIO_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||||
|
MessageArgument.untrusted("pack", template))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrisProjectCopier.copyProject(templateFolder, target, template, name);
|
IrisProjectCopier.copyProject(templateFolder, target, template, name);
|
||||||
try {
|
try {
|
||||||
ModdedWorkspaceGenerator.writeWorkspace(IrisData.get(target), target);
|
ModdedWorkspaceGenerator.writeWorkspace(IrisData.get(target), target);
|
||||||
} catch (IOException e) {
|
} 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(() -> {
|
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_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)));
|
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) {
|
} 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)))));
|
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");
|
}, "Iris Studio Create");
|
||||||
@@ -630,7 +630,7 @@ public final class ModdedStudioCommands {
|
|||||||
File result = compilePackage(folder, dimKey);
|
File result = compilePackage(folder, dimKey);
|
||||||
server.execute(() -> IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PACKAGE_COMPILED, MessageArgument.untrusted("value", result.getAbsolutePath()))));
|
server.execute(() -> IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PACKAGE_COMPILED, MessageArgument.untrusted("value", result.getAbsolutePath()))));
|
||||||
} catch (Throwable e) {
|
} 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)))));
|
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");
|
}, "Iris Studio Package");
|
||||||
@@ -728,7 +728,7 @@ public final class ModdedStudioCommands {
|
|||||||
IO.copyFile(objectFile, new File(folder, "objects/" + objectKey + ".iob"));
|
IO.copyFile(objectFile, new File(folder, "objects/" + objectKey + ".iob"));
|
||||||
hashes.append(IO.hash(objectFile));
|
hashes.append(IO.hash(objectFile));
|
||||||
} catch (Throwable e) {
|
} 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);
|
IO.writeAll(new File(folder, category + "/" + key + ".json"), json);
|
||||||
return IO.hash(json);
|
return IO.hash(json);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Iris package failed to write {}/{}", category, key, e);
|
ModdedIrisLog.error("Iris package failed to write {}/{}", category, key, e);
|
||||||
return "";
|
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))));
|
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) {
|
} 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()))));
|
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_REGION_SAMPLING_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()))));
|
||||||
}
|
}
|
||||||
}, "Iris Region Sampler");
|
}, "Iris Region Sampler");
|
||||||
|
|||||||
+5
-7
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
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.Engine;
|
||||||
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
||||||
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
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.resources.Identifier;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -44,7 +43,6 @@ import java.util.TreeMap;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
final class ModdedUnregisteredStructures {
|
final class ModdedUnregisteredStructures {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
|
|
||||||
private ModdedUnregisteredStructures() {
|
private ModdedUnregisteredStructures() {
|
||||||
}
|
}
|
||||||
@@ -67,13 +65,13 @@ final class ModdedUnregisteredStructures {
|
|||||||
.filter((ExcludedStructure entry) -> entry.status() == ReportStatus.UNPLACED)
|
.filter((ExcludedStructure entry) -> entry.status() == ReportStatus.UNPLACED)
|
||||||
.count();
|
.count();
|
||||||
long hidden = excluded.size() - unregistered - unplaced;
|
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);
|
excluded.size(), dimension);
|
||||||
for (ExcludedStructure entry : excluded) {
|
for (ExcludedStructure entry : excluded) {
|
||||||
LOGGER.info("[Iris goto unregistered] [{}] {} - {}",
|
ModdedIrisLog.info("[Iris goto unregistered] [{}] {} - {}",
|
||||||
entry.status().label(), entry.key(), entry.reason());
|
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 "
|
+ "nativeStructures placements, and structureLoader editable resources. This is deterministic "
|
||||||
+ "eligibility analysis and performs no chunk search; absent unmanaged datapack resources "
|
+ "eligibility analysis and performs no chunk search; absent unmanaged datapack resources "
|
||||||
+ "cannot be inferred after registry loading.");
|
+ "cannot be inferred after registry loading.");
|
||||||
@@ -82,7 +80,7 @@ final class ModdedUnregisteredStructures {
|
|||||||
+ unregistered + " unregistered, " + unplaced + " unplaced).");
|
+ unregistered + " unregistered, " + unplaced + " unplaced).");
|
||||||
return 1;
|
return 1;
|
||||||
} catch (Throwable error) {
|
} 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);
|
level.dimension().identifier(), error);
|
||||||
IrisModdedCommands.fail(source,
|
IrisModdedCommands.fail(source,
|
||||||
"Iris could not build the excluded structure report; see the server console.");
|
"Iris could not build the excluded structure report; see the server console.");
|
||||||
|
|||||||
+2
-4
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
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.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
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.ItemLore;
|
||||||
import net.minecraft.world.item.component.TooltipDisplay;
|
import net.minecraft.world.item.component.TooltipDisplay;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -52,7 +51,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public final class ModdedWandService {
|
public final class ModdedWandService {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final ConcurrentHashMap<UUID, Selection> SELECTIONS = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<UUID, Selection> SELECTIONS = new ConcurrentHashMap<>();
|
||||||
private static final String WAND_TAG = "iris_wand";
|
private static final String WAND_TAG = "iris_wand";
|
||||||
private static final String DUST_TAG = "iris_dust";
|
private static final String DUST_TAG = "iris_dust";
|
||||||
@@ -213,7 +211,7 @@ public final class ModdedWandService {
|
|||||||
draw(player.level(), player, selection);
|
draw(player.level(), player, selection);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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;
|
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.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.IrisMessages;
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
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.level.storage.loot.LootTable;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -77,7 +76,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public final class ModdedWhatCommands {
|
public final class ModdedWhatCommands {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final Predicate<CommandSourceStack> GATE =
|
private static final Predicate<CommandSourceStack> GATE =
|
||||||
Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
private static final SuggestionProvider<CommandSourceStack> MARKER_TYPES =
|
private static final SuggestionProvider<CommandSourceStack> MARKER_TYPES =
|
||||||
@@ -343,7 +341,7 @@ public final class ModdedWhatCommands {
|
|||||||
MessageArgument.untrusted("object", object)));
|
MessageArgument.untrusted("object", object)));
|
||||||
}
|
}
|
||||||
} catch (Throwable error) {
|
} 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);
|
pos.getX(), pos.getY(), pos.getZ(), error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,7 +484,7 @@ public final class ModdedWhatCommands {
|
|||||||
|
|
||||||
private static void markerFailure(CommandSourceStack source,
|
private static void markerFailure(CommandSourceStack source,
|
||||||
ModdedScheduler scheduler, MarkerRun run, Throwable error) {
|
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(() -> {
|
scheduler.global(() -> {
|
||||||
if (ACTIVE_MARKER_RUNS.remove(run.playerId(), run)) {
|
if (ACTIVE_MARKER_RUNS.remove(run.playerId(), run)) {
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
@@ -514,7 +512,7 @@ public final class ModdedWhatCommands {
|
|||||||
private static void logLookupFailure(CommandSourceStack source,
|
private static void logLookupFailure(CommandSourceStack source,
|
||||||
String operation, Throwable error,
|
String operation, Throwable error,
|
||||||
TextKey message) {
|
TextKey message) {
|
||||||
LOGGER.error("Iris /what {} lookup failed in {}", operation,
|
ModdedIrisLog.error("Iris /what {} lookup failed in {}", operation,
|
||||||
source.getLevel().dimension().identifier(), error);
|
source.getLevel().dimension().identifier(), error);
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
message,
|
message,
|
||||||
|
|||||||
+11
-11
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.pack.BrokenPackException;
|
import art.arcane.iris.core.pack.BrokenPackException;
|
||||||
import art.arcane.iris.core.pack.PackValidationRegistry;
|
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.commands.arguments.IdentifierArgument;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
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.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedWorldCommands {
|
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 Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
private static final String DEFAULT_NAMESPACE = "irisworldgen";
|
private static final String DEFAULT_NAMESPACE = "irisworldgen";
|
||||||
private static final long DEFAULT_SEED = 1337L;
|
private static final long DEFAULT_SEED = 1337L;
|
||||||
@@ -174,8 +172,9 @@ public final class ModdedWorldCommands {
|
|||||||
if (packFolder.isDirectory()) {
|
if (packFolder.isDirectory()) {
|
||||||
return enableInstalled(source, server, dimensionId, pack, packDimension, seed);
|
return enableInstalled(source, server, dimensionId, pack, packDimension, seed);
|
||||||
}
|
}
|
||||||
IrisModdedCommands.fail(source, "Pack '" + pack
|
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
+ "' is not installed. Use /iris download pack=overworld or pack=underworld, then restart.");
|
ModdedCommandMessages.MODDED_WORLD_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||||
|
MessageArgument.untrusted("pack", pack)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +188,7 @@ public final class ModdedWorldCommands {
|
|||||||
try {
|
try {
|
||||||
ModdedDimensionManager.createPersistent(server, dimensionId, pack, packDimension, seed);
|
ModdedDimensionManager.createPersistent(server, dimensionId, pack, packDimension, seed);
|
||||||
} catch (Throwable e) {
|
} 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))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -220,7 +219,7 @@ public final class ModdedWorldCommands {
|
|||||||
try {
|
try {
|
||||||
ModdedDimensionManager.createPersistent(server, dimensionId, pack, packDimension, seed);
|
ModdedDimensionManager.createPersistent(server, dimensionId, pack, packDimension, seed);
|
||||||
} catch (Throwable e) {
|
} 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))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -265,8 +264,9 @@ public final class ModdedWorldCommands {
|
|||||||
if (packFolder.isDirectory()) {
|
if (packFolder.isDirectory()) {
|
||||||
return applyMainWorld(source, pack, packDimension, packRaw, seed);
|
return applyMainWorld(source, pack, packDimension, packRaw, seed);
|
||||||
}
|
}
|
||||||
IrisModdedCommands.fail(source, "Pack '" + pack
|
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||||
+ "' is not installed. Use /iris download pack=overworld or pack=underworld, then restart.");
|
ModdedCommandMessages.MODDED_WORLD_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||||
|
MessageArgument.untrusted("pack", pack)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ public final class ModdedWorldCommands {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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) {
|
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)));
|
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;
|
return 0;
|
||||||
@@ -384,7 +384,7 @@ public final class ModdedWorldCommands {
|
|||||||
try {
|
try {
|
||||||
removed = ModdedDimensionManager.removePersistent(server, dimensionId, wipeStorage);
|
removed = ModdedDimensionManager.removePersistent(server, dimensionId, wipeStorage);
|
||||||
} catch (Throwable e) {
|
} 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))));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-10
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.service;
|
package art.arcane.iris.modded.service;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.service.EngineMaintenance;
|
import art.arcane.iris.core.service.EngineMaintenance;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
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.spi.IrisLogging;
|
||||||
import art.arcane.iris.util.project.context.IrisContext;
|
import art.arcane.iris.util.project.context.IrisContext;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -42,7 +41,6 @@ import java.util.concurrent.ThreadFactory;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class ModdedEngineMaintenanceService implements ModdedTickableService {
|
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 MAINTENANCE_PERIOD_MILLIS = 2_000L;
|
||||||
private static final long SAVE_PERIOD_MILLIS = 60_000L;
|
private static final long SAVE_PERIOD_MILLIS = 60_000L;
|
||||||
private static final long SHUTDOWN_TIMEOUT_SECONDS = 30L;
|
private static final long SHUTDOWN_TIMEOUT_SECONDS = 30L;
|
||||||
@@ -120,7 +118,7 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
|||||||
} catch (RejectedExecutionException exception) {
|
} catch (RejectedExecutionException exception) {
|
||||||
inFlight.remove(engine);
|
inFlight.remove(engine);
|
||||||
if (active == service && !active.isShutdown()) {
|
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);
|
EngineMaintenance.Outcome outcome = EngineMaintenance.run(engine);
|
||||||
if (outcome.unloadedTectonicPlates() > 0) {
|
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));
|
outcome.unloadedTectonicPlates(), outcome.unloadDurationMillis(), engineName(engine));
|
||||||
}
|
}
|
||||||
} catch (GenerationSessionException exception) {
|
} catch (GenerationSessionException exception) {
|
||||||
@@ -156,13 +154,13 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrisLogging.reportError(exception);
|
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) {
|
} catch (Throwable exception) {
|
||||||
if (EngineMaintenance.isMantleClosed(exception)) {
|
if (EngineMaintenance.isMantleClosed(exception)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrisLogging.reportError(exception);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
IrisLogging.reportError(exception);
|
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(
|
IllegalStateException failure = new IllegalStateException(
|
||||||
"Iris engine maintenance workers did not stop after shutdownNow");
|
"Iris engine maintenance workers did not stop after shutdownNow");
|
||||||
IrisLogging.reportError(failure);
|
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;
|
return false;
|
||||||
} catch (InterruptedException exception) {
|
} catch (InterruptedException exception) {
|
||||||
active.shutdownNow();
|
active.shutdownNow();
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
IrisLogging.reportError(exception);
|
IrisLogging.reportError(exception);
|
||||||
LOGGER.error("Interrupted while draining Iris engine maintenance", exception);
|
ModdedIrisLog.error("Interrupted while draining Iris engine maintenance", exception);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -18,11 +18,10 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.service;
|
package art.arcane.iris.modded.service;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.engine.framework.MeteredCache;
|
import art.arcane.iris.engine.framework.MeteredCache;
|
||||||
import art.arcane.iris.engine.framework.PreservationRegistry;
|
import art.arcane.iris.engine.framework.PreservationRegistry;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -31,7 +30,6 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public final class ModdedPreservationService implements ModdedService, PreservationRegistry {
|
public final class ModdedPreservationService implements ModdedService, PreservationRegistry {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final long DEREFERENCE_INTERVAL_MILLIS = 60000L;
|
private static final long DEREFERENCE_INTERVAL_MILLIS = 60000L;
|
||||||
|
|
||||||
private final List<Thread> threads = new CopyOnWriteArrayList<>();
|
private final List<Thread> threads = new CopyOnWriteArrayList<>();
|
||||||
@@ -107,17 +105,17 @@ public final class ModdedPreservationService implements ModdedService, Preservat
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
thread.interrupt();
|
thread.interrupt();
|
||||||
LOGGER.info("Iris preservation interrupted thread {}", thread.getName());
|
ModdedIrisLog.info("Iris preservation interrupted thread {}", thread.getName());
|
||||||
} catch (Throwable error) {
|
} 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) {
|
for (ExecutorService service : services) {
|
||||||
try {
|
try {
|
||||||
service.shutdownNow();
|
service.shutdownNow();
|
||||||
LOGGER.info("Iris preservation shut down executor {}", service);
|
ModdedIrisLog.info("Iris preservation shut down executor {}", service);
|
||||||
} catch (Throwable error) {
|
} 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() {
|
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;
|
package art.arcane.iris.modded.service;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.gui.PregeneratorJob;
|
import art.arcane.iris.core.gui.PregeneratorJob;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.tools.WorldMaintenance;
|
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.io.ReactiveFolder;
|
||||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -52,7 +51,6 @@ import java.util.concurrent.RejectedExecutionException;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public final class ModdedStudioHotloadService implements ModdedTickableService, EnginePlatformHooks {
|
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 String STUDIO_DIMENSION_PREFIX = "irisworldgen:studio_";
|
||||||
private static final long POLL_MILLIS = 250L;
|
private static final long POLL_MILLIS = 250L;
|
||||||
private static final long CHECK_LATCH_MILLIS = 1_000L;
|
private static final long CHECK_LATCH_MILLIS = 1_000L;
|
||||||
@@ -237,7 +235,7 @@ public final class ModdedStudioHotloadService implements ModdedTickableService,
|
|||||||
folder.check();
|
folder.check();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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 {
|
try {
|
||||||
engine.hotloadSilently();
|
engine.hotloadSilently();
|
||||||
generator.onHotload();
|
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) {
|
} 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);
|
throw new IllegalStateException("Iris studio hotload failed for " + dimensionId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,7 +273,7 @@ public final class ModdedStudioHotloadService implements ModdedTickableService,
|
|||||||
IrisData data = engine.getData();
|
IrisData data = engine.getData();
|
||||||
ModdedWorkspaceGenerator.writeWorkspace(data, data.getDataFolder());
|
ModdedWorkspaceGenerator.writeWorkspace(data, data.getDataFolder());
|
||||||
} catch (Throwable e) {
|
} 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;
|
package art.arcane.iris.modded.service;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||||
import art.arcane.iris.modded.ModdedScheduler;
|
import art.arcane.iris.modded.ModdedScheduler;
|
||||||
import net.minecraft.core.BlockPos;
|
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.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -21,7 +20,6 @@ import java.util.List;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
final class ModdedTreeFellerPresentation {
|
final class ModdedTreeFellerPresentation {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
|
||||||
private static final int MIN_BLOCKS_PER_PULSE = 4;
|
private static final int MIN_BLOCKS_PER_PULSE = 4;
|
||||||
private static final int MAX_BLOCKS_PER_PULSE = 64;
|
private static final int MAX_BLOCKS_PER_PULSE = 64;
|
||||||
private static final int TARGET_EROSION_PULSES = 60;
|
private static final int TARGET_EROSION_PULSES = 60;
|
||||||
@@ -215,13 +213,13 @@ final class ModdedTreeFellerPresentation {
|
|||||||
|
|
||||||
private void reportEffectFailure(Throwable error) {
|
private void reportEffectFailure(Throwable error) {
|
||||||
if (effectFailureReported.compareAndSet(false, true)) {
|
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) {
|
private void reportDeliveryFailure(Throwable error) {
|
||||||
if (deliveryFailureReported.compareAndSet(false, true)) {
|
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;
|
package art.arcane.iris.modded.service;
|
||||||
|
|
||||||
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.service.tree.TreeDefinitionIndex;
|
import art.arcane.iris.core.service.tree.TreeDefinitionIndex;
|
||||||
import art.arcane.iris.core.service.tree.TreeMarkerTraversal;
|
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.Block;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -38,7 +37,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
public final class ModdedTreeFellerService implements ModdedTickableService {
|
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 static final ThreadLocal<Integer> BREAK_PROBE_DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||||
|
|
||||||
private final AtomicBoolean enabled = new AtomicBoolean();
|
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)
|
(x, y, z) -> markerAt(prepared.engine(), prepared.minimumY(), x, y, z)
|
||||||
);
|
);
|
||||||
} catch (Throwable error) {
|
} 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);
|
discovery = new TreeMarkerTraversal.Discovery(List.of(), false);
|
||||||
}
|
}
|
||||||
TreeMarkerTraversal.Discovery resolved = discovery;
|
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.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
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;
|
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));
|
String body = source.substring(router, source.indexOf("public static void debug(", router));
|
||||||
assertTrue(body, body.contains("default -> info(message);"));
|
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");
|
File iris = new File(temporaryFolder.getRoot(), "iris");
|
||||||
|
|
||||||
assertEquals(iris, platform.dataFolder());
|
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"));
|
assertEquals(new File(iris, "parity"), platform.dataFolder("parity"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,13 +85,12 @@ public class IrisSettings {
|
|||||||
|
|
||||||
private static IrisSettings read() {
|
private static IrisSettings read() {
|
||||||
IrisSettings loaded = new IrisSettings();
|
IrisSettings loaded = new IrisSettings();
|
||||||
File s = IrisPlatforms.get().dataFile("settings.json");
|
File s = IrisPlatforms.get().dataFile("iris.json");
|
||||||
|
|
||||||
if (!s.exists()) {
|
if (!s.exists()) {
|
||||||
try {
|
try {
|
||||||
IO.writeAll(s, new JSONObject(new Gson().toJson(loaded)).toString(4));
|
IO.writeAll(s, new JSONObject(new Gson().toJson(loaded)).toString(4));
|
||||||
} catch (JSONException | IOException e) {
|
} catch (JSONException | IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,32 +105,18 @@ public class IrisSettings {
|
|||||||
loaded = parsed;
|
loaded = parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
migrateLegacyKeys(loaded, ss);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IO.writeAll(s, new JSONObject(new Gson().toJson(loaded)).toString(4));
|
IO.writeAll(s, new JSONObject(new Gson().toJson(loaded)).toString(4));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
} catch (Throwable ee) {
|
} catch (Throwable ee) {
|
||||||
// IrisLogging.reportError(ee); causes a self-reference & stackoverflow
|
// IrisLogging.reportError(ee); causes a self-reference & stackoverflow
|
||||||
IrisLogging.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage());
|
IrisLogging.error("Configuration Error in iris.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void migrateLegacyKeys(IrisSettings target, String rawJson) {
|
|
||||||
JSONObject root = new JSONObject(rawJson);
|
|
||||||
JSONObject worldObject = root.optJSONObject("world");
|
|
||||||
if (worldObject == null || !worldObject.has("anbientEntitySpawningSystem")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
target.getWorld().setAmbientEntitySpawningSystem(worldObject.optBoolean("anbientEntitySpawningSystem", target.getWorld().isAmbientEntitySpawningSystem()));
|
|
||||||
IrisLogging.info("Migrated legacy settings key world.anbientEntitySpawningSystem -> world.ambientEntitySpawningSystem");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void invalidate() {
|
public static void invalidate() {
|
||||||
synchronized (SETTINGS_LOCK) {
|
synchronized (SETTINGS_LOCK) {
|
||||||
settings = null;
|
settings = null;
|
||||||
@@ -169,7 +154,6 @@ public class IrisSettings {
|
|||||||
if (parsed == null) {
|
if (parsed == null) {
|
||||||
throw new IllegalArgumentException("Iris settings snapshot did not contain an object");
|
throw new IllegalArgumentException("Iris settings snapshot did not contain an object");
|
||||||
}
|
}
|
||||||
migrateLegacyKeys(parsed, rawJson);
|
|
||||||
} catch (RuntimeException failure) {
|
} catch (RuntimeException failure) {
|
||||||
throw new IllegalArgumentException("Iris settings snapshot is invalid", failure);
|
throw new IllegalArgumentException("Iris settings snapshot is invalid", failure);
|
||||||
}
|
}
|
||||||
@@ -179,12 +163,11 @@ public class IrisSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void forceSave() {
|
public void forceSave() {
|
||||||
File s = IrisPlatforms.get().dataFile("settings.json");
|
File s = IrisPlatforms.get().dataFile("iris.json");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IO.writeAll(s, new JSONObject(new Gson().toJson(this)).toString(4));
|
IO.writeAll(s, new JSONObject(new Gson().toJson(this)).toString(4));
|
||||||
} catch (JSONException | IOException e) {
|
} catch (JSONException | IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,17 +304,18 @@ public class IrisSettings {
|
|||||||
@Data
|
@Data
|
||||||
public static class IrisSettingsGeneral {
|
public static class IrisSettingsGeneral {
|
||||||
public String language = "en_US";
|
public String language = "en_US";
|
||||||
|
public boolean metrics = true;
|
||||||
public boolean commandSounds = true;
|
public boolean commandSounds = true;
|
||||||
public boolean debug = false;
|
public boolean debug = false;
|
||||||
public boolean dumpMantleOnError = false;
|
public boolean dumpMantleOnError = false;
|
||||||
public boolean disableNMS = false;
|
public boolean disableNMS = false;
|
||||||
public boolean pluginMetrics = true;
|
|
||||||
public boolean splashLogoStartup = true;
|
public boolean splashLogoStartup = true;
|
||||||
public boolean useConsoleCustomColors = true;
|
public boolean useConsoleCustomColors = true;
|
||||||
public boolean useCustomColorsIngame = true;
|
public boolean useCustomColorsIngame = true;
|
||||||
/**
|
/**
|
||||||
* Boss bar progress loaders for jobs, studio opens, world creation, chunk jobs and pack
|
* Boss bars for jobs, Studio opens, chunk jobs, and pack downloads. Ordinary
|
||||||
* downloads. Turning this off keeps the action bar progress line; only the bar goes away.
|
* world creation uses only its action-bar lifecycle meter; creation-time
|
||||||
|
* pregeneration retains its dedicated long-running boss bar.
|
||||||
*/
|
*/
|
||||||
public boolean progressBossBar = true;
|
public boolean progressBossBar = true;
|
||||||
public boolean adjustVanillaHeight = false;
|
public boolean adjustVanillaHeight = false;
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.file.AtomicMoveNotSupportedException;
|
import java.nio.file.AtomicMoveNotSupportedException;
|
||||||
@@ -281,11 +283,7 @@ public class ServerConfigurator {
|
|||||||
IrisLogging.error("Unable to install datapacks, fixer is null!");
|
IrisLogging.error("Unable to install datapacks, fixer is null!");
|
||||||
return DatapackInstallResult.failedResult();
|
return DatapackInstallResult.failedResult();
|
||||||
}
|
}
|
||||||
if (fullInstall) {
|
IrisLogging.debug("Checking Data Packs...");
|
||||||
IrisLogging.info("Checking Data Packs...");
|
|
||||||
} else {
|
|
||||||
IrisLogging.debug("Checking Data Packs...");
|
|
||||||
}
|
|
||||||
List<File> packRoots;
|
List<File> packRoots;
|
||||||
List<IrisGeneratorBinding> bindings;
|
List<IrisGeneratorBinding> bindings;
|
||||||
try {
|
try {
|
||||||
@@ -349,11 +347,7 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fullInstall) {
|
IrisLogging.debug("Data Packs Setup!");
|
||||||
IrisLogging.info("Data Packs Setup!");
|
|
||||||
} else {
|
|
||||||
IrisLogging.debug("Data Packs Setup!");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean verifiedRestartRequired = fullInstall && verifyDataPacksPost();
|
boolean verifiedRestartRequired = fullInstall && verifyDataPacksPost();
|
||||||
boolean restartRequired = fullInstall && (reapply.changed() || verifiedRestartRequired);
|
boolean restartRequired = fullInstall && (reapply.changed() || verifiedRestartRequired);
|
||||||
@@ -1026,12 +1020,21 @@ public class ServerConfigurator {
|
|||||||
? "Iris startup validation requires a restart."
|
? "Iris startup validation requires a restart."
|
||||||
: reason.trim();
|
: reason.trim();
|
||||||
IrisLogging.warn(restartReason + " Restarting server before default worlds are loaded.");
|
IrisLogging.warn(restartReason + " Restarting server before default worlds are loaded.");
|
||||||
|
boolean restartInvoked = false;
|
||||||
try {
|
try {
|
||||||
Bukkit.restart();
|
restartInvoked = invokeImmediateRestartIfSupported(Bukkit.class);
|
||||||
} catch (Throwable failure) {
|
} catch (ReflectiveOperationException | RuntimeException | LinkageError failure) {
|
||||||
IrisLogging.reportError("Unable to restart the server at the Iris startup boundary.", failure);
|
Throwable cause = failure instanceof InvocationTargetException invocationFailure
|
||||||
|
&& invocationFailure.getCause() != null
|
||||||
|
? invocationFailure.getCause()
|
||||||
|
: failure;
|
||||||
|
IrisLogging.reportError("Unable to restart the server at the Iris startup boundary.", cause);
|
||||||
|
}
|
||||||
|
if (restartInvoked) {
|
||||||
|
IrisLogging.error("The immediate Iris startup restart returned unexpectedly; stopping the server instead.");
|
||||||
|
} else {
|
||||||
|
IrisLogging.warn("This server has no immediate restart API; stopping at the Iris startup boundary instead.");
|
||||||
}
|
}
|
||||||
IrisLogging.error("The immediate Iris startup restart returned unexpectedly; stopping the server instead.");
|
|
||||||
try {
|
try {
|
||||||
Bukkit.shutdown();
|
Bukkit.shutdown();
|
||||||
} catch (Throwable failure) {
|
} catch (Throwable failure) {
|
||||||
@@ -1039,6 +1042,17 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean invokeImmediateRestartIfSupported(Class<?> bukkitApi) throws ReflectiveOperationException {
|
||||||
|
Method restartMethod;
|
||||||
|
try {
|
||||||
|
restartMethod = Objects.requireNonNull(bukkitApi, "Bukkit API class").getMethod("restart");
|
||||||
|
} catch (NoSuchMethodException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
restartMethod.invoke(null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
|
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
|
||||||
KSet<String> keys = new KSet<>();
|
KSet<String> keys = new KSet<>();
|
||||||
boolean warn = false;
|
boolean warn = false;
|
||||||
@@ -1056,11 +1070,9 @@ public class ServerConfigurator {
|
|||||||
|
|
||||||
if (!INMS.get().supportsDataPacks()) {
|
if (!INMS.get().supportsDataPacks()) {
|
||||||
if (!keys.isEmpty()) {
|
if (!keys.isEmpty()) {
|
||||||
IrisLogging.warn("===================================================================================");
|
|
||||||
IrisLogging.warn("Pack " + key + " has " + keys.size() + " custom biome(s). ");
|
IrisLogging.warn("Pack " + key + " has " + keys.size() + " custom biome(s). ");
|
||||||
IrisLogging.warn("Your server version does not yet support datapacks for iris.");
|
IrisLogging.warn("Your server version does not yet support datapacks for iris.");
|
||||||
IrisLogging.warn("The world will generate these biomes as backup biomes.");
|
IrisLogging.warn("The world will generate these biomes as backup biomes.");
|
||||||
IrisLogging.warn("====================================================================================");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ public final class SettingsHotloadWatch implements AutoCloseable {
|
|||||||
} catch (RuntimeException failure) {
|
} catch (RuntimeException failure) {
|
||||||
IrisLogging.error("Iris settings and locale hotload watcher failed: " + failureDetail(failure));
|
IrisLogging.error("Iris settings and locale hotload watcher failed: " + failureDetail(failure));
|
||||||
IrisLogging.reportError(failure);
|
IrisLogging.reportError(failure);
|
||||||
failure.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +112,7 @@ public final class SettingsHotloadWatch implements AutoCloseable {
|
|||||||
boolean missing = "missing".equals(snapshot.signature());
|
boolean missing = "missing".equals(snapshot.signature());
|
||||||
if (isSettingsFile(file)) {
|
if (isSettingsFile(file)) {
|
||||||
if (missing) {
|
if (missing) {
|
||||||
IrisLogging.warn("settings.json was removed; retaining the last valid runtime settings.");
|
IrisLogging.warn("iris.json was removed; retaining the last valid runtime settings.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (snapshot.normalizedContent() == null) {
|
if (snapshot.normalizedContent() == null) {
|
||||||
@@ -210,7 +209,6 @@ public final class SettingsHotloadWatch implements AutoCloseable {
|
|||||||
} catch (RuntimeException failure) {
|
} catch (RuntimeException failure) {
|
||||||
IrisLogging.error("Rejected invalid settings hotload from " + file.getAbsolutePath() + ": " + failureDetail(failure));
|
IrisLogging.error("Rejected invalid settings hotload from " + file.getAbsolutePath() + ": " + failureDetail(failure));
|
||||||
IrisLogging.reportError(failure);
|
IrisLogging.reportError(failure);
|
||||||
failure.printStackTrace();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +219,6 @@ public final class SettingsHotloadWatch implements AutoCloseable {
|
|||||||
} catch (RuntimeException failure) {
|
} catch (RuntimeException failure) {
|
||||||
IrisLogging.error("Rejected invalid locale hotload from " + file.getAbsolutePath() + ": " + failureDetail(failure));
|
IrisLogging.error("Rejected invalid locale hotload from " + file.getAbsolutePath() + ": " + failureDetail(failure));
|
||||||
IrisLogging.reportError(failure);
|
IrisLogging.reportError(failure);
|
||||||
failure.printStackTrace();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +248,6 @@ public final class SettingsHotloadWatch implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
IrisLogging.error("Failed to read watched Iris file " + path + ": " + failureDetail(failure));
|
IrisLogging.error("Failed to read watched Iris file " + path + ": " + failureDetail(failure));
|
||||||
IrisLogging.reportError(failure);
|
IrisLogging.reportError(failure);
|
||||||
failure.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearCaptureFailure(File file) {
|
private void clearCaptureFailure(File file) {
|
||||||
@@ -262,12 +258,12 @@ public final class SettingsHotloadWatch implements AutoCloseable {
|
|||||||
File file = delta.file();
|
File file = delta.file();
|
||||||
if (isSettingsFile(file)) {
|
if (isSettingsFile(file)) {
|
||||||
if (delta.after() != null) {
|
if (delta.after() != null) {
|
||||||
IrisLogging.info("Hotloaded settings.json");
|
IrisLogging.debug("Hotloaded iris.json");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (IrisLanguage.isActiveOverrideFile(file)) {
|
if (IrisLanguage.isActiveOverrideFile(file)) {
|
||||||
IrisLogging.info("Hotloaded locale override " + file.getName());
|
IrisLogging.debug("Hotloaded locale override " + file.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -983,8 +983,8 @@ public final class VisionGUI extends JPanel implements MouseWheelListener, KeyLi
|
|||||||
notifyUser(IrisLanguage.plain(DesktopUiMessages.VISION_NO_PLAYER));
|
notifyUser(IrisLanguage.plain(DesktopUiMessages.VISION_NO_PLAYER));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int worldX = (int) screenToWorldX(point.x);
|
int worldX = floorWorldCoordinate(screenToWorldX(point.x));
|
||||||
int worldZ = (int) screenToWorldZ(point.y);
|
int worldZ = floorWorldCoordinate(screenToWorldZ(point.y));
|
||||||
overlay.teleport(worldX, worldZ);
|
overlay.teleport(worldX, worldZ);
|
||||||
notifyUser(IrisLanguage.plain(
|
notifyUser(IrisLanguage.plain(
|
||||||
DesktopUiMessages.VISION_TELEPORTING,
|
DesktopUiMessages.VISION_TELEPORTING,
|
||||||
@@ -1009,6 +1009,10 @@ public final class VisionGUI extends JPanel implements MouseWheelListener, KeyLi
|
|||||||
controller.close();
|
controller.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int floorWorldCoordinate(double coordinate) {
|
||||||
|
return (int) StrictMath.floor(coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
private static String modeName(RenderType type) {
|
private static String modeName(RenderType type) {
|
||||||
return IrisLanguage.plain(modeKey(type));
|
return IrisLanguage.plain(modeKey(type));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -944,7 +944,7 @@ public final class IrisWorldRemovalService {
|
|||||||
PlatformChunkGenerator generator = null;
|
PlatformChunkGenerator generator = null;
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
Path loadedDirectory = world.getWorldFolder().toPath().toAbsolutePath().normalize();
|
Path loadedDirectory = world.getWorldFolder().toPath().toAbsolutePath().normalize();
|
||||||
WorldRemovalPathPolicy.validateStoragePath(target.levelRoot(), target.worldKey(), loadedDirectory);
|
WorldRemovalPathPolicy.validateStorageRoot(target.levelRoot(), target.worldKey(), loadedDirectory);
|
||||||
generator = IrisToolbelt.access(world);
|
generator = IrisToolbelt.access(world);
|
||||||
}
|
}
|
||||||
boolean registryManaged = IrisWorlds.get().getWorlds().containsKey(target.worldKey().toString());
|
boolean registryManaged = IrisWorlds.get().getWorlds().containsKey(target.worldKey().toString());
|
||||||
|
|||||||
@@ -208,9 +208,11 @@ public final class WorldLifecycleService {
|
|||||||
return worldsProviderBackend;
|
return worldsProviderBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.studio() && capabilities.serverFamily().isPaperLike()) {
|
if (capabilities.regionizedRuntime()
|
||||||
|
|| capabilities.serverFamily() == ServerFamily.FOLIA
|
||||||
|
|| (request.studio() && capabilities.serverFamily().isPaperLike())) {
|
||||||
if (!paperLikeRuntimeBackend.supports(request, capabilities)) {
|
if (!paperLikeRuntimeBackend.supports(request, capabilities)) {
|
||||||
throw new IllegalStateException("World lifecycle backend paper_like_runtime is unavailable for studio create on "
|
throw new IllegalStateException("World lifecycle backend paper_like_runtime is unavailable for runtime create on "
|
||||||
+ capabilities.serverFamily().id() + ": " + capabilities.paperLikeResolution());
|
+ capabilities.serverFamily().id() + ": " + capabilities.paperLikeResolution());
|
||||||
}
|
}
|
||||||
return paperLikeRuntimeBackend;
|
return paperLikeRuntimeBackend;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import art.arcane.iris.util.common.scheduling.J;
|
|||||||
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.scheduling.FoliaScheduler;
|
import art.arcane.volmlib.util.scheduling.FoliaScheduler;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
@@ -472,12 +471,8 @@ final class WorldLifecycleSupport {
|
|||||||
) {
|
) {
|
||||||
String worldName = world.getName();
|
String worldName = world.getName();
|
||||||
try {
|
try {
|
||||||
try {
|
if (capabilities.minecraftServer() == null || capabilities.removeLevelMethod() == null) {
|
||||||
return CompletableFuture.completedFuture(Bukkit.unloadWorld(world, save));
|
return CompletableFuture.completedFuture(Bukkit.unloadWorld(world, save));
|
||||||
} catch (UnsupportedOperationException unsupported) {
|
|
||||||
if (capabilities.minecraftServer() == null || capabilities.removeLevelMethod() == null) {
|
|
||||||
return CompletableFuture.failedFuture(unsupported);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!announceManualWorldUnload(world)) {
|
if (!announceManualWorldUnload(world)) {
|
||||||
@@ -489,8 +484,9 @@ final class WorldLifecycleSupport {
|
|||||||
}
|
}
|
||||||
Method getHandleMethod = world.getClass().getMethod("getHandle");
|
Method getHandleMethod = world.getClass().getMethod("getHandle");
|
||||||
Object serverLevel = getHandleMethod.invoke(world);
|
Object serverLevel = getHandleMethod.invoke(world);
|
||||||
CompletableFuture<Boolean> operation = closeServerLevelAsync(world, serverLevel)
|
CompletableFuture<Boolean> operation = detachServerLevelAsync(capabilities, serverLevel, world)
|
||||||
.thenCompose(unused -> detachServerLevelAsync(capabilities, serverLevel, world))
|
.thenCompose(unused -> drainChunkTasksAsync(world, serverLevel))
|
||||||
|
.thenCompose(unused -> closeServerLevelAsync(world, serverLevel))
|
||||||
.thenApply(unused -> WorldIdentity.resolve(WorldIdentity.key(world)).isEmpty());
|
.thenApply(unused -> WorldIdentity.resolve(WorldIdentity.key(world)).isEmpty());
|
||||||
return contextualizeUnloadFailure(worldName, operation);
|
return contextualizeUnloadFailure(worldName, operation);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -527,7 +523,13 @@ final class WorldLifecycleSupport {
|
|||||||
boolean save
|
boolean save
|
||||||
) {
|
) {
|
||||||
CompletableFuture<Boolean> callbackFuture = new CompletableFuture<>();
|
CompletableFuture<Boolean> callbackFuture = new CompletableFuture<>();
|
||||||
Consumer<Boolean> callback = unloaded -> callbackFuture.complete(Boolean.TRUE.equals(unloaded));
|
Consumer<Object> callback = unloaded -> {
|
||||||
|
try {
|
||||||
|
callbackFuture.complete(asyncUnloadSucceeded(unloaded));
|
||||||
|
} catch (Throwable failure) {
|
||||||
|
callbackFuture.completeExceptionally(unwrap(failure));
|
||||||
|
}
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
unloadWorldAsyncMethod.invoke(bukkitServer, world, save, callback);
|
unloadWorldAsyncMethod.invoke(bukkitServer, world, save, callback);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -536,6 +538,17 @@ final class WorldLifecycleSupport {
|
|||||||
return callbackFuture;
|
return callbackFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean asyncUnloadSucceeded(Object result) throws ReflectiveOperationException {
|
||||||
|
if (result instanceof Boolean unloaded) {
|
||||||
|
return unloaded;
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Method isSuccessMethod = result.getClass().getMethod("isSuccess");
|
||||||
|
return Boolean.TRUE.equals(isSuccessMethod.invoke(result));
|
||||||
|
}
|
||||||
|
|
||||||
private static CompletableFuture<Boolean> contextualizeUnloadFailure(
|
private static CompletableFuture<Boolean> contextualizeUnloadFailure(
|
||||||
String worldName,
|
String worldName,
|
||||||
CompletableFuture<Boolean> operation
|
CompletableFuture<Boolean> operation
|
||||||
@@ -569,33 +582,59 @@ final class WorldLifecycleSupport {
|
|||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!J.isFolia()) {
|
Runnable closeTask = () -> {
|
||||||
try {
|
try {
|
||||||
closeMethod.invoke(serverLevel);
|
closeMethod.invoke(serverLevel);
|
||||||
return CompletableFuture.completedFuture(null);
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return CompletableFuture.failedFuture(unwrap(e));
|
throw new RuntimeException(unwrap(e));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
return runGlobalAsync(closeTask).orTimeout(90L, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CompletableFuture<Void> drainChunkTasksAsync(World world, Object serverLevel) {
|
||||||
|
Method schedulerMethod;
|
||||||
|
try {
|
||||||
|
schedulerMethod = CapabilityResolution.resolveMethod(
|
||||||
|
serverLevel.getClass(),
|
||||||
|
"moonrise$getChunkTaskScheduler",
|
||||||
|
method -> method.getParameterCount() == 0
|
||||||
|
);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return CompletableFuture.failedFuture(unwrap(e));
|
||||||
|
}
|
||||||
|
if (schedulerMethod == null) {
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Location spawn = world.getSpawnLocation();
|
return J.afut(() -> {
|
||||||
int chunkX = spawn == null ? 0 : spawn.getBlockX() >> 4;
|
|
||||||
int chunkZ = spawn == null ? 0 : spawn.getBlockZ() >> 4;
|
|
||||||
CompletableFuture<Void> closeFuture = new CompletableFuture<>();
|
|
||||||
boolean scheduled = J.runRegion(world, chunkX, chunkZ, () -> {
|
|
||||||
try {
|
try {
|
||||||
closeMethod.invoke(serverLevel);
|
Object scheduler = schedulerMethod.invoke(serverLevel);
|
||||||
closeFuture.complete(null);
|
Method haltMethod = CapabilityResolution.resolveMethod(
|
||||||
|
scheduler.getClass(),
|
||||||
|
"halt",
|
||||||
|
method -> {
|
||||||
|
Class<?>[] parameters = method.getParameterTypes();
|
||||||
|
return parameters.length == 2
|
||||||
|
&& boolean.class.equals(parameters[0])
|
||||||
|
&& long.class.equals(parameters[1]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (haltMethod == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object halted = haltMethod.invoke(
|
||||||
|
scheduler,
|
||||||
|
true,
|
||||||
|
TimeUnit.SECONDS.toNanos(90L));
|
||||||
|
if (halted instanceof Boolean complete && !complete) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Chunk scheduler drain timed out for world \"" + world.getName() + "\".");
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
closeFuture.completeExceptionally(unwrap(e));
|
throw new RuntimeException(unwrap(e));
|
||||||
}
|
}
|
||||||
});
|
}).orTimeout(90L, TimeUnit.SECONDS);
|
||||||
if (!scheduled) {
|
|
||||||
return CompletableFuture.failedFuture(new IllegalStateException(
|
|
||||||
"Failed to schedule region close task for world \"" + world.getName() + "\"."
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return closeFuture.orTimeout(90L, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public class WorldEditLink {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (errorThrottle.flip()) {
|
if (errorThrottle.flip()) {
|
||||||
IrisLogging.error("Could not get selection");
|
IrisLogging.error("Could not get selection");
|
||||||
e.printStackTrace();
|
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
}
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import art.arcane.iris.core.nms.container.BlockProperty;
|
|||||||
import art.arcane.iris.core.nms.container.Pair;
|
import art.arcane.iris.core.nms.container.Pair;
|
||||||
import art.arcane.iris.core.service.ExternalDataSVC;
|
import art.arcane.iris.core.service.ExternalDataSVC;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
import art.arcane.iris.util.common.data.IrisCustomData;
|
import art.arcane.iris.util.common.data.IrisCustomData;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
@@ -82,7 +83,7 @@ public class NexoDataProvider extends ExternalDataProvider {
|
|||||||
try {
|
try {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
IrisLogging.reportError("Failed to build Nexo item data for " + itemId + ".", e);
|
||||||
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,7 +278,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -450,7 +449,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
return r;
|
return r;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
IrisLogging.error("Failed to create loader! " + registrant.getCanonicalName());
|
IrisLogging.error("Failed to create loader! " + registrant.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,7 +559,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
IrisLogging.reportError(failure);
|
IrisLogging.reportError(failure);
|
||||||
failure.printStackTrace();
|
|
||||||
throw failure;
|
throw failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,7 +727,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
.map(s -> s.split("\\Q.\\E")[0])
|
.map(s -> s.split("\\Q.\\E")[0])
|
||||||
.forEach(s -> l.add("snippet/" + s));
|
.forEach(s -> l.add("snippet/" + s));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
IrisLogging.reportError("Failed to scan Iris snippets in " + snippetFolder + ".", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
|
|||||||
-35
@@ -183,10 +183,6 @@ public final class BukkitCommandMessagesExtended {
|
|||||||
"iris.bukkit.commandiris.install_pack_and_restart",
|
"iris.bukkit.commandiris.install_pack_and_restart",
|
||||||
C.YELLOW + "Install it with " + C.AQUA + "{command}" + C.YELLOW + " and restart the server."
|
C.YELLOW + "Install it with " + C.AQUA + "{command}" + C.YELLOW + " and restart the server."
|
||||||
);
|
);
|
||||||
public static final TextKey COMMAND_IRIS_WORLD_STAGING_COMPLETED_RESTARTING_SERVER_GENERATE_LOAD = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.world_staging_completed_restarting_server_generate_load",
|
|
||||||
C.GREEN + "World staging completed. Iris is restarting the server to generate/load \"" + "{worldName}" + "\"."
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_EXCEPTION_RAISED_DURING_CREATION_SEE_CONSOLE_MORE_DETAILS = TextKey.of(
|
public static final TextKey COMMAND_IRIS_EXCEPTION_RAISED_DURING_CREATION_SEE_CONSOLE_MORE_DETAILS = TextKey.of(
|
||||||
"iris.bukkit.commandiris.exception_raised_during_creation_see_console_more_details",
|
"iris.bukkit.commandiris.exception_raised_during_creation_see_console_more_details",
|
||||||
C.RED + "Exception raised during creation. See the console for more details."
|
C.RED + "Exception raised during creation. See the console for more details."
|
||||||
@@ -195,26 +191,6 @@ public final class BukkitCommandMessagesExtended {
|
|||||||
"iris.bukkit.commandiris.successfully_created_your_world",
|
"iris.bukkit.commandiris.successfully_created_your_world",
|
||||||
C.GREEN + "Successfully created your world!"
|
C.GREEN + "Successfully created your world!"
|
||||||
);
|
);
|
||||||
public static final TextKey COMMAND_IRIS_RUNTIME_WORLD_CREATION_IS_DISABLED_ON_FOLIA = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.runtime_world_creation_is_disabled_on_folia",
|
|
||||||
C.YELLOW + "Runtime world creation is disabled on Folia."
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_PREPARING_WORLD_FILES_BUKKIT_YML_NEXT_STARTUP = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.preparing_world_files_bukkit_yml_next_startup",
|
|
||||||
C.YELLOW + "Preparing world files and bukkit.yml for next startup..."
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_FAILED_STAGE_WORLD_FILES_DIMENSION = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.failed_stage_world_files_dimension",
|
|
||||||
C.RED + "Failed to stage world files for dimension \"" + "{value}" + "\"."
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_STAGED_IRIS_WORLD_WITH_GENERATOR_IRIS_SEED = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.staged_iris_world_with_generator_iris_seed",
|
|
||||||
C.GREEN + "Staged Iris world \"" + "{name}" + "\" with generator Iris:" + "{value}" + " and seed " + "{seed}" + "."
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_FAILED_UPDATE_BUKKIT_YML = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.failed_update_bukkit_yml",
|
|
||||||
C.RED + "Failed to update bukkit.yml: " + "{value}"
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_SPECIFIED_PLAYER_DOES_NOT_EXIST = TextKey.of(
|
public static final TextKey COMMAND_IRIS_SPECIFIED_PLAYER_DOES_NOT_EXIST = TextKey.of(
|
||||||
"iris.bukkit.commandiris.specified_player_does_not_exist",
|
"iris.bukkit.commandiris.specified_player_does_not_exist",
|
||||||
C.RED + "The specified player does not exist."
|
C.RED + "The specified player does not exist."
|
||||||
@@ -327,10 +303,6 @@ public final class BukkitCommandMessagesExtended {
|
|||||||
"iris.bukkit.commandiris.loading_world",
|
"iris.bukkit.commandiris.loading_world",
|
||||||
C.GREEN + "Loading world: " + "{logicalWorldName}"
|
C.GREEN + "Loading world: " + "{logicalWorldName}"
|
||||||
);
|
);
|
||||||
public static final TextKey COMMAND_IRIS_FOLIA_CANNOT_LOAD_NEW_WORLDS_AT_RUNTIME_RESTART_SERVER_LOAD = TextKey.of(
|
|
||||||
"iris.bukkit.commandiris.folia_cannot_load_new_worlds_at_runtime_restart_server_load",
|
|
||||||
C.YELLOW + "Folia cannot load new worlds at runtime. Restart the server to load \"" + "{logicalWorldName}" + "\"."
|
|
||||||
);
|
|
||||||
public static final TextKey COMMAND_IRIS_LOADED_SUCCESSFULLY = TextKey.of(
|
public static final TextKey COMMAND_IRIS_LOADED_SUCCESSFULLY = TextKey.of(
|
||||||
"iris.bukkit.commandiris.loaded_successfully",
|
"iris.bukkit.commandiris.loaded_successfully",
|
||||||
C.GREEN + "{logicalWorldName}" + " loaded successfully."
|
C.GREEN + "{logicalWorldName}" + " loaded successfully."
|
||||||
@@ -874,14 +846,8 @@ public final class BukkitCommandMessagesExtended {
|
|||||||
COMMAND_IRIS_TRY_ONE_OVERWORLD_VANILLA_FLAT_THEEND,
|
COMMAND_IRIS_TRY_ONE_OVERWORLD_VANILLA_FLAT_THEEND,
|
||||||
COMMAND_IRIS_DIMENSION_NOT_FOUND,
|
COMMAND_IRIS_DIMENSION_NOT_FOUND,
|
||||||
COMMAND_IRIS_INSTALL_PACK_AND_RESTART,
|
COMMAND_IRIS_INSTALL_PACK_AND_RESTART,
|
||||||
COMMAND_IRIS_WORLD_STAGING_COMPLETED_RESTARTING_SERVER_GENERATE_LOAD,
|
|
||||||
COMMAND_IRIS_EXCEPTION_RAISED_DURING_CREATION_SEE_CONSOLE_MORE_DETAILS,
|
COMMAND_IRIS_EXCEPTION_RAISED_DURING_CREATION_SEE_CONSOLE_MORE_DETAILS,
|
||||||
COMMAND_IRIS_SUCCESSFULLY_CREATED_YOUR_WORLD,
|
COMMAND_IRIS_SUCCESSFULLY_CREATED_YOUR_WORLD,
|
||||||
COMMAND_IRIS_RUNTIME_WORLD_CREATION_IS_DISABLED_ON_FOLIA,
|
|
||||||
COMMAND_IRIS_PREPARING_WORLD_FILES_BUKKIT_YML_NEXT_STARTUP,
|
|
||||||
COMMAND_IRIS_FAILED_STAGE_WORLD_FILES_DIMENSION,
|
|
||||||
COMMAND_IRIS_STAGED_IRIS_WORLD_WITH_GENERATOR_IRIS_SEED,
|
|
||||||
COMMAND_IRIS_FAILED_UPDATE_BUKKIT_YML,
|
|
||||||
COMMAND_IRIS_SPECIFIED_PLAYER_DOES_NOT_EXIST,
|
COMMAND_IRIS_SPECIFIED_PLAYER_DOES_NOT_EXIST,
|
||||||
COMMAND_IRIS_IRIS_V_BY_VOLMIT_SOFTWARE,
|
COMMAND_IRIS_IRIS_V_BY_VOLMIT_SOFTWARE,
|
||||||
COMMAND_IRIS_TO,
|
COMMAND_IRIS_TO,
|
||||||
@@ -910,7 +876,6 @@ public final class BukkitCommandMessagesExtended {
|
|||||||
COMMAND_IRIS_IS_NOT_IRIS_WORLD,
|
COMMAND_IRIS_IS_NOT_IRIS_WORLD,
|
||||||
COMMAND_IRIS_COULD_NOT_DETERMINE_IRIS_DIMENSION,
|
COMMAND_IRIS_COULD_NOT_DETERMINE_IRIS_DIMENSION,
|
||||||
COMMAND_IRIS_LOADING_WORLD,
|
COMMAND_IRIS_LOADING_WORLD,
|
||||||
COMMAND_IRIS_FOLIA_CANNOT_LOAD_NEW_WORLDS_AT_RUNTIME_RESTART_SERVER_LOAD,
|
|
||||||
COMMAND_IRIS_LOADED_SUCCESSFULLY,
|
COMMAND_IRIS_LOADED_SUCCESSFULLY,
|
||||||
COMMAND_IRIS_THIS_IS_NOT_IRIS_WORLD_IRIS_WORLDS_3,
|
COMMAND_IRIS_THIS_IS_NOT_IRIS_WORLD_IRIS_WORLDS_3,
|
||||||
COMMAND_IRIS_EVACUATING_WORLD,
|
COMMAND_IRIS_EVACUATING_WORLD,
|
||||||
|
|||||||
@@ -406,10 +406,6 @@ public final class BukkitRuntimeMessages {
|
|||||||
"iris.bukkit.runtime.irisconverter.some_schematics_failed_convert_check_console_details",
|
"iris.bukkit.runtime.irisconverter.some_schematics_failed_convert_check_console_details",
|
||||||
C.RED + "Some schematics failed to convert. Check the console for details."
|
C.RED + "Some schematics failed to convert. Check the console for details."
|
||||||
);
|
);
|
||||||
public static final TextKey STUDIO_S_V_C_INSTALLING_PACKAGE = TextKey.of(
|
|
||||||
"iris.bukkit.runtime.studiosvc.installing_package",
|
|
||||||
C.GOLD + "World pack " + C.AQUA + "{name}" + ":" + "{loadKey}" + C.GRAY + " | " + C.WHITE + "Publishing snapshot"
|
|
||||||
);
|
|
||||||
public static final TextKey STUDIO_S_V_C_PACK_COPY_REQUIRES_ASYNC_THREAD = TextKey.of(
|
public static final TextKey STUDIO_S_V_C_PACK_COPY_REQUIRES_ASYNC_THREAD = TextKey.of(
|
||||||
"iris.bukkit.runtime.studiosvc.pack_copy_requires_async_thread",
|
"iris.bukkit.runtime.studiosvc.pack_copy_requires_async_thread",
|
||||||
C.RED + "Iris refused to copy the world pack on the Bukkit primary thread."
|
C.RED + "Iris refused to copy the world pack on the Bukkit primary thread."
|
||||||
@@ -708,7 +704,6 @@ public final class BukkitRuntimeMessages {
|
|||||||
IRIS_CONVERTER_FAILED_CONVERT,
|
IRIS_CONVERTER_FAILED_CONVERT,
|
||||||
IRIS_CONVERTER_CONVERTED_3,
|
IRIS_CONVERTER_CONVERTED_3,
|
||||||
IRIS_CONVERTER_SOME_SCHEMATICS_FAILED_CONVERT_CHECK_CONSOLE_DETAILS,
|
IRIS_CONVERTER_SOME_SCHEMATICS_FAILED_CONVERT_CHECK_CONSOLE_DETAILS,
|
||||||
STUDIO_S_V_C_INSTALLING_PACKAGE,
|
|
||||||
STUDIO_S_V_C_PACK_COPY_REQUIRES_ASYNC_THREAD,
|
STUDIO_S_V_C_PACK_COPY_REQUIRES_ASYNC_THREAD,
|
||||||
STUDIO_S_V_C_PACK_INSTALL_FAILED,
|
STUDIO_S_V_C_PACK_INSTALL_FAILED,
|
||||||
STUDIO_S_V_C_LOOKING_PACKAGE,
|
STUDIO_S_V_C_LOOKING_PACKAGE,
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ public final class IrisLanguage {
|
|||||||
dataFolder = resolvedRoot;
|
dataFolder = resolvedRoot;
|
||||||
IrisLogging.error("Rejected locale setting '" + locale + "'; continuing with " + activeLocale + ".");
|
IrisLogging.error("Rejected locale setting '" + locale + "'; continuing with " + activeLocale + ".");
|
||||||
IrisLogging.reportError(exception);
|
IrisLogging.reportError(exception);
|
||||||
exception.printStackTrace();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +158,6 @@ public final class IrisLanguage {
|
|||||||
} catch (RuntimeException exception) {
|
} catch (RuntimeException exception) {
|
||||||
IrisLogging.error("Rejected locale setting '" + configured + "'; continuing with " + activeLocale + ".");
|
IrisLogging.error("Rejected locale setting '" + configured + "'; continuing with " + activeLocale + ".");
|
||||||
IrisLogging.reportError(exception);
|
IrisLogging.reportError(exception);
|
||||||
exception.printStackTrace();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +212,7 @@ public final class IrisLanguage {
|
|||||||
|
|
||||||
activeLocale = requestedLocale;
|
activeLocale = requestedLocale;
|
||||||
int warnings = result.validation().warnings().size();
|
int warnings = result.validation().warnings().size();
|
||||||
IrisLogging.info("Loaded locale " + requestedLocale + " with " + warnings + " fallback "
|
IrisLogging.debug("Loaded locale " + requestedLocale + " with " + warnings + " fallback "
|
||||||
+ (warnings == 1 ? "entry" : "entries") + ".");
|
+ (warnings == 1 ? "entry" : "entries") + ".");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -228,7 +226,6 @@ public final class IrisLanguage {
|
|||||||
+ failure.getClass().getSimpleName()
|
+ failure.getClass().getSimpleName()
|
||||||
+ (failure.getMessage() == null ? "" : " - " + failure.getMessage()));
|
+ (failure.getMessage() == null ? "" : " - " + failure.getMessage()));
|
||||||
IrisLogging.reportError(failure);
|
IrisLogging.reportError(failure);
|
||||||
failure.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -641,7 +638,6 @@ public final class IrisLanguage {
|
|||||||
}
|
}
|
||||||
if (result.failure() != null) {
|
if (result.failure() != null) {
|
||||||
IrisLogging.reportError(result.failure());
|
IrisLogging.reportError(result.failure());
|
||||||
result.failure().printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1043,13 +1043,9 @@ public final class ModdedCommandMessages {
|
|||||||
"iris.modded.moddedstudiocommands.creating_project_from_template",
|
"iris.modded.moddedstudiocommands.creating_project_from_template",
|
||||||
"Creating project '" + "{name}" + "' from template '" + "{template}" + "'..."
|
"Creating project '" + "{name}" + "' from template '" + "{template}" + "'..."
|
||||||
);
|
);
|
||||||
public static final TextKey MODDED_STUDIO_COMMANDS_TEMPLATE_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS = TextKey.of(
|
public static final TextKey MODDED_STUDIO_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART = TextKey.of(
|
||||||
"iris.modded.moddedstudiocommands.template_is_not_installed_downloading_irisdimensions",
|
"iris.modded.moddedstudiocommands.required_pack_is_not_installed_install_then_restart",
|
||||||
"Template '" + "{template}" + "' is not installed; downloading IrisDimensions/" + "{template2}" + "..."
|
"Required pack '" + "{pack}" + "' is not installed. Install it with /iris download, then restart."
|
||||||
);
|
|
||||||
public static final TextKey MODDED_STUDIO_COMMANDS_TEMPLATE_COULD_NOT_BE_DOWNLOADED_INSTALL_PACK_WITH_DIMENSIONS_JSON = TextKey.of(
|
|
||||||
"iris.modded.moddedstudiocommands.template_could_not_be_downloaded_install_pack_with_dimensions_json",
|
|
||||||
"Template '" + "{template}" + "' could not be downloaded; install a pack with dimensions/" + "{template2}" + ".json first."
|
|
||||||
);
|
);
|
||||||
public static final TextKey MODDED_STUDIO_COMMANDS_CREATED_PROJECT_AT = TextKey.of(
|
public static final TextKey MODDED_STUDIO_COMMANDS_CREATED_PROJECT_AT = TextKey.of(
|
||||||
"iris.modded.moddedstudiocommands.created_project_at",
|
"iris.modded.moddedstudiocommands.created_project_at",
|
||||||
@@ -1095,13 +1091,9 @@ public final class ModdedCommandMessages {
|
|||||||
"iris.modded.moddedstudiocommands.region_sampling_failed",
|
"iris.modded.moddedstudiocommands.region_sampling_failed",
|
||||||
"Region sampling failed: " + "{value}"
|
"Region sampling failed: " + "{value}"
|
||||||
);
|
);
|
||||||
public static final TextKey MODDED_WORLD_COMMANDS_PACK_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS = TextKey.of(
|
public static final TextKey MODDED_WORLD_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART = TextKey.of(
|
||||||
"iris.modded.moddedworldcommands.pack_is_not_installed_downloading_irisdimensions",
|
"iris.modded.moddedworldcommands.required_pack_is_not_installed_install_then_restart",
|
||||||
"Pack '" + "{pack}" + "' is not installed; downloading IrisDimensions/" + "{pack2}" + "..."
|
"Required pack '" + "{pack}" + "' is not installed. Install it with /iris download, then restart."
|
||||||
);
|
|
||||||
public static final TextKey MODDED_WORLD_COMMANDS_PACK_COULD_NOT_BE_DOWNLOADED_CHECK_NAME_INSTALL_IT_WITH = TextKey.of(
|
|
||||||
"iris.modded.moddedworldcommands.pack_could_not_be_downloaded_check_name_install_it_with",
|
|
||||||
"Pack '" + "{pack}" + "' could not be downloaded; check the name or install it with /iris download " + "{pack2}" + "."
|
|
||||||
);
|
);
|
||||||
public static final TextKey MODDED_WORLD_COMMANDS_FAILED_INJECT_IRIS_WORLD = TextKey.of(
|
public static final TextKey MODDED_WORLD_COMMANDS_FAILED_INJECT_IRIS_WORLD = TextKey.of(
|
||||||
"iris.modded.moddedworldcommands.failed_inject_iris_world",
|
"iris.modded.moddedworldcommands.failed_inject_iris_world",
|
||||||
@@ -1139,14 +1131,6 @@ public final class ModdedCommandMessages {
|
|||||||
"iris.modded.moddedworldcommands.invalid_seed_use_number_random",
|
"iris.modded.moddedworldcommands.invalid_seed_use_number_random",
|
||||||
"Invalid seed '" + "{seedRaw}" + "'. Use a number or 'random'."
|
"Invalid seed '" + "{seedRaw}" + "'. Use a number or 'random'."
|
||||||
);
|
);
|
||||||
public static final TextKey MODDED_WORLD_COMMANDS_PACK_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS_2 = TextKey.of(
|
|
||||||
"iris.modded.moddedworldcommands.pack_is_not_installed_downloading_irisdimensions_2",
|
|
||||||
"Pack '" + "{pack}" + "' is not installed; downloading IrisDimensions/" + "{pack2}" + "..."
|
|
||||||
);
|
|
||||||
public static final TextKey MODDED_WORLD_COMMANDS_PACK_COULD_NOT_BE_DOWNLOADED_CHECK_NAME_INSTALL_IT_WITH_2 = TextKey.of(
|
|
||||||
"iris.modded.moddedworldcommands.pack_could_not_be_downloaded_check_name_install_it_with_2",
|
|
||||||
"Pack '" + "{pack}" + "' could not be downloaded; check the name or install it with /iris download " + "{pack2}" + "."
|
|
||||||
);
|
|
||||||
public static final TextKey MODDED_WORLD_COMMANDS_PACK_IS_NOT_READY_YET_STILL_LOADING_VALIDATING_TRY_COMMAND = TextKey.of(
|
public static final TextKey MODDED_WORLD_COMMANDS_PACK_IS_NOT_READY_YET_STILL_LOADING_VALIDATING_TRY_COMMAND = TextKey.of(
|
||||||
"iris.modded.moddedworldcommands.pack_is_not_ready_yet_still_loading_validating_try_command",
|
"iris.modded.moddedworldcommands.pack_is_not_ready_yet_still_loading_validating_try_command",
|
||||||
"Pack '" + "{pack}" + "' is not ready yet (still loading or validating). Try the command again in a moment."
|
"Pack '" + "{pack}" + "' is not ready yet (still loading or validating). Try the command again in a moment."
|
||||||
@@ -1512,8 +1496,7 @@ public final class ModdedCommandMessages {
|
|||||||
MODDED_STUDIO_COMMANDS_INVALID_PROJECT_NAME_ALLOWED_Z_0_9,
|
MODDED_STUDIO_COMMANDS_INVALID_PROJECT_NAME_ALLOWED_Z_0_9,
|
||||||
MODDED_STUDIO_COMMANDS_PACK_ALREADY_EXISTS_AT,
|
MODDED_STUDIO_COMMANDS_PACK_ALREADY_EXISTS_AT,
|
||||||
MODDED_STUDIO_COMMANDS_CREATING_PROJECT_FROM_TEMPLATE,
|
MODDED_STUDIO_COMMANDS_CREATING_PROJECT_FROM_TEMPLATE,
|
||||||
MODDED_STUDIO_COMMANDS_TEMPLATE_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS,
|
MODDED_STUDIO_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||||
MODDED_STUDIO_COMMANDS_TEMPLATE_COULD_NOT_BE_DOWNLOADED_INSTALL_PACK_WITH_DIMENSIONS_JSON,
|
|
||||||
MODDED_STUDIO_COMMANDS_CREATED_PROJECT_AT,
|
MODDED_STUDIO_COMMANDS_CREATED_PROJECT_AT,
|
||||||
MODDED_STUDIO_COMMANDS_EDIT_DIMENSIONS_JSON_REST_PACK_VSCODE_WORKSPACE_WITH_JSON_SCHEMA,
|
MODDED_STUDIO_COMMANDS_EDIT_DIMENSIONS_JSON_REST_PACK_VSCODE_WORKSPACE_WITH_JSON_SCHEMA,
|
||||||
MODDED_STUDIO_COMMANDS_PROJECT_CREATION_FAILED,
|
MODDED_STUDIO_COMMANDS_PROJECT_CREATION_FAILED,
|
||||||
@@ -1525,8 +1508,7 @@ public final class ModdedCommandMessages {
|
|||||||
MODDED_STUDIO_COMMANDS_SAMPLING_REGION_DISTRIBUTION_X_CHUNKS_AROUND_YOU,
|
MODDED_STUDIO_COMMANDS_SAMPLING_REGION_DISTRIBUTION_X_CHUNKS_AROUND_YOU,
|
||||||
MODDED_STUDIO_COMMANDS_RARITY,
|
MODDED_STUDIO_COMMANDS_RARITY,
|
||||||
MODDED_STUDIO_COMMANDS_REGION_SAMPLING_FAILED,
|
MODDED_STUDIO_COMMANDS_REGION_SAMPLING_FAILED,
|
||||||
MODDED_WORLD_COMMANDS_PACK_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS,
|
MODDED_WORLD_COMMANDS_REQUIRED_PACK_IS_NOT_INSTALLED_INSTALL_THEN_RESTART,
|
||||||
MODDED_WORLD_COMMANDS_PACK_COULD_NOT_BE_DOWNLOADED_CHECK_NAME_INSTALL_IT_WITH,
|
|
||||||
MODDED_WORLD_COMMANDS_FAILED_INJECT_IRIS_WORLD,
|
MODDED_WORLD_COMMANDS_FAILED_INJECT_IRIS_WORLD,
|
||||||
MODDED_WORLD_COMMANDS_CREATED_IRIS_WORLD_FROM_PACK_DIMENSION_SEED,
|
MODDED_WORLD_COMMANDS_CREATED_IRIS_WORLD_FROM_PACK_DIMENSION_SEED,
|
||||||
MODDED_WORLD_COMMANDS_IT_IS_LIVE_NOW_RE_INJECTED_ON_EVERY_STARTUP_TELEPORT,
|
MODDED_WORLD_COMMANDS_IT_IS_LIVE_NOW_RE_INJECTED_ON_EVERY_STARTUP_TELEPORT,
|
||||||
@@ -1536,8 +1518,6 @@ public final class ModdedCommandMessages {
|
|||||||
MODDED_WORLD_COMMANDS_INSTEAD_IS_NOW_CONFIGURED_PRIMARY_WORLD_PLAYERS_VANILLA_OVERWORLD_ARE,
|
MODDED_WORLD_COMMANDS_INSTEAD_IS_NOW_CONFIGURED_PRIMARY_WORLD_PLAYERS_VANILLA_OVERWORLD_ARE,
|
||||||
MODDED_WORLD_COMMANDS_IRIS_MAIN_WORLD_OVERRIDE_CLEARED_OVERWORLD_KEEPS_ITS_CURRENT_GENERATOR,
|
MODDED_WORLD_COMMANDS_IRIS_MAIN_WORLD_OVERRIDE_CLEARED_OVERWORLD_KEEPS_ITS_CURRENT_GENERATOR,
|
||||||
MODDED_WORLD_COMMANDS_INVALID_SEED_USE_NUMBER_RANDOM,
|
MODDED_WORLD_COMMANDS_INVALID_SEED_USE_NUMBER_RANDOM,
|
||||||
MODDED_WORLD_COMMANDS_PACK_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS_2,
|
|
||||||
MODDED_WORLD_COMMANDS_PACK_COULD_NOT_BE_DOWNLOADED_CHECK_NAME_INSTALL_IT_WITH_2,
|
|
||||||
MODDED_WORLD_COMMANDS_PACK_IS_NOT_READY_YET_STILL_LOADING_VALIDATING_TRY_COMMAND,
|
MODDED_WORLD_COMMANDS_PACK_IS_NOT_READY_YET_STILL_LOADING_VALIDATING_TRY_COMMAND,
|
||||||
MODDED_WORLD_COMMANDS_FAILED_WRITE_SERVER_PROPERTIES_CHECK_FILE_PERMISSIONS_SET_LEVEL_TYPE,
|
MODDED_WORLD_COMMANDS_FAILED_WRITE_SERVER_PROPERTIES_CHECK_FILE_PERMISSIONS_SET_LEVEL_TYPE,
|
||||||
MODDED_WORLD_COMMANDS_IRIS_MAIN_WORLD_SET_PRESET_SEED,
|
MODDED_WORLD_COMMANDS_IRIS_MAIN_WORLD_SET_PRESET_SEED,
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ public final class ModdedHelpMessages {
|
|||||||
);
|
);
|
||||||
public static final TextKey COMMAND_DEBUG_TOGGLE_IRIS_DEBUG_LOGGING_AND_SAVE_SETTINGS_JSON = TextKey.of(
|
public static final TextKey COMMAND_DEBUG_TOGGLE_IRIS_DEBUG_LOGGING_AND_SAVE_SETTINGS_JSON = TextKey.of(
|
||||||
"iris.modded.help.entry.command.debug",
|
"iris.modded.help.entry.command.debug",
|
||||||
"Toggle Iris debug logging and save settings.json"
|
"Toggle Iris debug logging and save iris.json"
|
||||||
);
|
);
|
||||||
public static final TextKey COMMAND_RELOAD_RELOAD_SETTINGS_JSON_ALSO_HOTLOADED_AUTOMATICALLY_EVERY_3S = TextKey.of(
|
public static final TextKey COMMAND_RELOAD_RELOAD_SETTINGS_JSON_ALSO_HOTLOADED_AUTOMATICALLY_EVERY_3S = TextKey.of(
|
||||||
"iris.modded.help.entry.command.reload",
|
"iris.modded.help.entry.command.reload",
|
||||||
"Reload settings.json (also hotloaded automatically every 3s)"
|
"Reload iris.json (also hotloaded automatically every 3s)"
|
||||||
);
|
);
|
||||||
public static final TextKey COMMAND_DOWNLOAD_DOWNLOAD_A_PACK_PROJECT = TextKey.of(
|
public static final TextKey COMMAND_DOWNLOAD_DOWNLOAD_A_PACK_PROJECT = TextKey.of(
|
||||||
"iris.modded.help.entry.command.download",
|
"iris.modded.help.entry.command.download",
|
||||||
|
|||||||
@@ -25,16 +25,10 @@ public final class RuntimeProgressMessages {
|
|||||||
public static final TextKey STUDIO_STAGE_CREATE_WORLD = TextKey.of("iris.runtime.studio.stage.create_world", "Creating world");
|
public static final TextKey STUDIO_STAGE_CREATE_WORLD = TextKey.of("iris.runtime.studio.stage.create_world", "Creating world");
|
||||||
public static final TextKey STUDIO_STAGE_APPLY_WORLD_RULES = TextKey.of("iris.runtime.studio.stage.apply_world_rules", "Applying world rules");
|
public static final TextKey STUDIO_STAGE_APPLY_WORLD_RULES = TextKey.of("iris.runtime.studio.stage.apply_world_rules", "Applying world rules");
|
||||||
public static final TextKey STUDIO_STAGE_PREPARE_GENERATOR = TextKey.of("iris.runtime.studio.stage.prepare_generator", "Preparing generator");
|
public static final TextKey STUDIO_STAGE_PREPARE_GENERATOR = TextKey.of("iris.runtime.studio.stage.prepare_generator", "Preparing generator");
|
||||||
public static final TextKey STUDIO_STAGE_REQUEST_ENTRY_CHUNK = TextKey.of("iris.runtime.studio.stage.request_entry_chunk", "Loading entry chunk");
|
|
||||||
public static final TextKey STUDIO_STAGE_RESOLVE_SAFE_ENTRY = TextKey.of("iris.runtime.studio.stage.resolve_safe_entry", "Finding safe spawn");
|
|
||||||
public static final TextKey STUDIO_STAGE_TELEPORT_PLAYER = TextKey.of("iris.runtime.studio.stage.teleport_player", "Teleporting");
|
public static final TextKey STUDIO_STAGE_TELEPORT_PLAYER = TextKey.of("iris.runtime.studio.stage.teleport_player", "Teleporting");
|
||||||
public static final TextKey STUDIO_STAGE_FINALIZE_OPEN = TextKey.of("iris.runtime.studio.stage.finalize_open", "Finalizing");
|
public static final TextKey STUDIO_STAGE_FINALIZE_OPEN = TextKey.of("iris.runtime.studio.stage.finalize_open", "Finalizing");
|
||||||
public static final TextKey STUDIO_STAGE_CLEANUP = TextKey.of("iris.runtime.studio.stage.cleanup", "Cleaning up");
|
public static final TextKey STUDIO_STAGE_CLEANUP = TextKey.of("iris.runtime.studio.stage.cleanup", "Cleaning up");
|
||||||
public static final TextKey WORLD_CREATE_TELEPORT_FAILED = TextKey.of("iris.runtime.world_create.teleport_failed", C.YELLOW + "The world was created, but automatic teleport failed. Try /iris teleport world={world}");
|
public static final TextKey WORLD_CREATE_TELEPORT_FAILED = TextKey.of("iris.runtime.world_create.teleport_failed", C.YELLOW + "The world was created, but automatic teleport failed. Try /iris teleport world={world}");
|
||||||
public static final TextKey WORLD_CREATE_BOSSBAR_WORKING = TextKey.of("iris.runtime.world_create.bossbar.working", C.GOLD + "World " + C.AQUA + "{world}" + C.GRAY + " | " + C.WHITE + "Starting");
|
|
||||||
public static final TextKey WORLD_CREATE_BOSSBAR_PROGRESS = TextKey.of("iris.runtime.world_create.bossbar.progress", C.GOLD + "World " + C.AQUA + "{world}" + C.GRAY + " | " + C.YELLOW + "{percent}% " + C.WHITE + "{stage}");
|
|
||||||
public static final TextKey WORLD_CREATE_BOSSBAR_FAILED = TextKey.of("iris.runtime.world_create.bossbar.failed", C.GOLD + "World " + C.AQUA + "{world}" + C.GRAY + " | " + C.RED + "FAILED " + C.DARK_GRAY + "{percent}%");
|
|
||||||
public static final TextKey WORLD_CREATE_BOSSBAR_READY = TextKey.of("iris.runtime.world_create.bossbar.ready", C.GOLD + "World " + C.AQUA + "{world}" + C.GRAY + " | " + C.GREEN + "READY 100%");
|
|
||||||
public static final TextKey WORLD_CREATE_LIFECYCLE_ACTION = TextKey.of("iris.runtime.world_create.lifecycle.action", "{bar}" + C.GRAY + " " + C.YELLOW + "{percent}%" + C.GRAY + " | " + C.WHITE + "{stage}{detail}" + C.DARK_GRAY + " {elapsed}");
|
public static final TextKey WORLD_CREATE_LIFECYCLE_ACTION = TextKey.of("iris.runtime.world_create.lifecycle.action", "{bar}" + C.GRAY + " " + C.YELLOW + "{percent}%" + C.GRAY + " | " + C.WHITE + "{stage}{detail}" + C.DARK_GRAY + " {elapsed}");
|
||||||
public static final TextKey WORLD_CREATE_LIFECYCLE_ACTION_FAILED = TextKey.of("iris.runtime.world_create.lifecycle.action.failed", "{bar}" + C.GRAY + " " + C.RED + "FAILED" + C.GRAY + " | " + C.WHITE + "{stage}{detail}" + C.DARK_GRAY + " {elapsed}");
|
public static final TextKey WORLD_CREATE_LIFECYCLE_ACTION_FAILED = TextKey.of("iris.runtime.world_create.lifecycle.action.failed", "{bar}" + C.GRAY + " " + C.RED + "FAILED" + C.GRAY + " | " + C.WHITE + "{stage}{detail}" + C.DARK_GRAY + " {elapsed}");
|
||||||
public static final TextKey WORLD_CREATE_LIFECYCLE_ACTION_READY = TextKey.of("iris.runtime.world_create.lifecycle.action.ready", "{bar}" + C.GRAY + " " + C.GREEN + "100%" + C.GRAY + " | " + C.GREEN + "World ready" + C.DARK_GRAY + " {elapsed}");
|
public static final TextKey WORLD_CREATE_LIFECYCLE_ACTION_READY = TextKey.of("iris.runtime.world_create.lifecycle.action.ready", "{bar}" + C.GRAY + " " + C.GREEN + "100%" + C.GRAY + " | " + C.GREEN + "World ready" + C.DARK_GRAY + " {elapsed}");
|
||||||
@@ -49,7 +43,7 @@ public final class RuntimeProgressMessages {
|
|||||||
public static final TextKey WORLD_CREATE_STAGE_PREPARE_GENERATOR = TextKey.of("iris.runtime.world_create.stage.prepare_generator", "Preparing generator");
|
public static final TextKey WORLD_CREATE_STAGE_PREPARE_GENERATOR = TextKey.of("iris.runtime.world_create.stage.prepare_generator", "Preparing generator");
|
||||||
public static final TextKey WORLD_CREATE_STAGE_CREATE_WORLD = TextKey.of("iris.runtime.world_create.stage.create_world", "Generating spawn");
|
public static final TextKey WORLD_CREATE_STAGE_CREATE_WORLD = TextKey.of("iris.runtime.world_create.stage.create_world", "Generating spawn");
|
||||||
public static final TextKey WORLD_CREATE_STAGE_REGISTER_WORLD = TextKey.of("iris.runtime.world_create.stage.register_world", "Registering world");
|
public static final TextKey WORLD_CREATE_STAGE_REGISTER_WORLD = TextKey.of("iris.runtime.world_create.stage.register_world", "Registering world");
|
||||||
public static final TextKey WORLD_CREATE_STAGE_TELEPORT_PLAYER = TextKey.of("iris.runtime.world_create.stage.teleport_player", "Finding safe entry");
|
public static final TextKey WORLD_CREATE_STAGE_TELEPORT_PLAYER = TextKey.of("iris.runtime.world_create.stage.teleport_player", "Entering world");
|
||||||
public static final TextKey WORLD_CREATE_STAGE_PREGENERATE = TextKey.of("iris.runtime.world_create.stage.pregenerate", "Pregenerating");
|
public static final TextKey WORLD_CREATE_STAGE_PREGENERATE = TextKey.of("iris.runtime.world_create.stage.pregenerate", "Pregenerating");
|
||||||
public static final TextKey WORLD_CREATE_STAGE_FINALIZE = TextKey.of("iris.runtime.world_create.stage.finalize", "Finalizing");
|
public static final TextKey WORLD_CREATE_STAGE_FINALIZE = TextKey.of("iris.runtime.world_create.stage.finalize", "Finalizing");
|
||||||
public static final TextKey WORLD_CREATE_STAGE_COMPLETE = TextKey.of("iris.runtime.world_create.stage.complete", "World ready");
|
public static final TextKey WORLD_CREATE_STAGE_COMPLETE = TextKey.of("iris.runtime.world_create.stage.complete", "World ready");
|
||||||
@@ -124,16 +118,10 @@ public final class RuntimeProgressMessages {
|
|||||||
STUDIO_STAGE_CREATE_WORLD,
|
STUDIO_STAGE_CREATE_WORLD,
|
||||||
STUDIO_STAGE_APPLY_WORLD_RULES,
|
STUDIO_STAGE_APPLY_WORLD_RULES,
|
||||||
STUDIO_STAGE_PREPARE_GENERATOR,
|
STUDIO_STAGE_PREPARE_GENERATOR,
|
||||||
STUDIO_STAGE_REQUEST_ENTRY_CHUNK,
|
|
||||||
STUDIO_STAGE_RESOLVE_SAFE_ENTRY,
|
|
||||||
STUDIO_STAGE_TELEPORT_PLAYER,
|
STUDIO_STAGE_TELEPORT_PLAYER,
|
||||||
STUDIO_STAGE_FINALIZE_OPEN,
|
STUDIO_STAGE_FINALIZE_OPEN,
|
||||||
STUDIO_STAGE_CLEANUP,
|
STUDIO_STAGE_CLEANUP,
|
||||||
WORLD_CREATE_TELEPORT_FAILED,
|
WORLD_CREATE_TELEPORT_FAILED,
|
||||||
WORLD_CREATE_BOSSBAR_WORKING,
|
|
||||||
WORLD_CREATE_BOSSBAR_PROGRESS,
|
|
||||||
WORLD_CREATE_BOSSBAR_FAILED,
|
|
||||||
WORLD_CREATE_BOSSBAR_READY,
|
|
||||||
WORLD_CREATE_LIFECYCLE_ACTION,
|
WORLD_CREATE_LIFECYCLE_ACTION,
|
||||||
WORLD_CREATE_LIFECYCLE_ACTION_FAILED,
|
WORLD_CREATE_LIFECYCLE_ACTION_FAILED,
|
||||||
WORLD_CREATE_LIFECYCLE_ACTION_READY,
|
WORLD_CREATE_LIFECYCLE_ACTION_READY,
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class INMS {
|
|||||||
private static INMSBinding bind() {
|
private static INMSBinding bind() {
|
||||||
boolean disableNms = IrisSettings.get().getGeneral().isDisableNMS();
|
boolean disableNms = IrisSettings.get().getGeneral().isDisableNMS();
|
||||||
if (disableNms) {
|
if (disableNms) {
|
||||||
IrisLogging.info("Craftbukkit BUKKIT <-> " + NMSBinding1X.class.getSimpleName() + " Successfully Bound");
|
IrisLogging.debug("Craftbukkit BUKKIT <-> " + NMSBinding1X.class.getSimpleName() + " Successfully Bound");
|
||||||
IrisLogging.warn("NMS support is disabled. Iris world creation is unavailable until general.disableNMS=false.");
|
IrisLogging.warn("NMS support is disabled. Iris world creation is unavailable until general.disableNMS=false.");
|
||||||
return new NMSBinding1X();
|
return new NMSBinding1X();
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,6 @@ public class INMS {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
IrisLogging.error("Failed to determine server minecraft version!");
|
IrisLogging.error("Failed to determine server minecraft version!");
|
||||||
e.printStackTrace();
|
|
||||||
if (e instanceof IllegalStateException illegalStateException) {
|
if (e instanceof IllegalStateException illegalStateException) {
|
||||||
throw illegalStateException;
|
throw illegalStateException;
|
||||||
}
|
}
|
||||||
@@ -96,19 +95,18 @@ public class INMS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static INMSBinding bindExact(String code) {
|
private static INMSBinding bindExact(String code) {
|
||||||
IrisLogging.info("Locating exact NMS Binding for " + code);
|
IrisLogging.debug("Locating exact NMS Binding for " + code);
|
||||||
try {
|
try {
|
||||||
Class<?> clazz = Class.forName("art.arcane.iris.core.nms." + code + ".NMSBinding");
|
Class<?> clazz = Class.forName("art.arcane.iris.core.nms." + code + ".NMSBinding");
|
||||||
Object candidate = clazz.getConstructor().newInstance();
|
Object candidate = clazz.getConstructor().newInstance();
|
||||||
if (candidate instanceof INMSBinding binding) {
|
if (candidate instanceof INMSBinding binding) {
|
||||||
IrisLogging.info("Craftbukkit " + code + " <-> " + candidate.getClass().getSimpleName() + " Successfully Bound");
|
IrisLogging.debug("Craftbukkit " + code + " <-> " + candidate.getClass().getSimpleName() + " Successfully Bound");
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Exact NMS binding class for " + code
|
throw new IllegalStateException("Exact NMS binding class for " + code
|
||||||
+ " does not implement " + INMSBinding.class.getName());
|
+ " does not implement " + INMSBinding.class.getName());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
if (e instanceof IllegalStateException illegalStateException) {
|
if (e instanceof IllegalStateException illegalStateException) {
|
||||||
throw illegalStateException;
|
throw illegalStateException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ import org.bukkit.generator.ChunkGenerator;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -272,14 +270,6 @@ public interface INMSBinding {
|
|||||||
default void uninjectBukkit() {
|
default void uninjectBukkit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
default void writeCurrentPaperWorldData(
|
|
||||||
Path sourceWorldDirectory,
|
|
||||||
Path targetWorldDirectory,
|
|
||||||
long seed
|
|
||||||
) throws IOException {
|
|
||||||
throw new UnsupportedOperationException("The active NMS binding does not support current Paper world data staging.");
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean awaitServerShutdownBoundary(long timeout, TimeUnit unit) {
|
default boolean awaitServerShutdownBoundary(long timeout, TimeUnit unit) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ public final class ContentKeyValidator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether unresolved pack content keys are blocking errors instead of warnings. Enabled by
|
* Whether unresolved pack content keys are blocking errors instead of warnings. Enabled by
|
||||||
* {@code -Diris.strictContent} or {@code general.strictContentKeys} in settings.json; the system property wins.
|
* {@code -Diris.strictContent} or {@code general.strictContentKeys} in iris.json; the system property wins.
|
||||||
*/
|
*/
|
||||||
public static boolean strictContent() {
|
public static boolean strictContent() {
|
||||||
String property = System.getProperty(STRICT_PROPERTY);
|
String property = System.getProperty(STRICT_PROPERTY);
|
||||||
|
|||||||
@@ -223,7 +223,6 @@ public class IrisPack {
|
|||||||
IO.writeAll(ws, generateWorkspaceConfig());
|
IO.writeAll(ws, generateWorkspaceConfig());
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
IrisLogging.reportError(e1);
|
IrisLogging.reportError(e1);
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package art.arcane.iris.core.pack;
|
|||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.core.service.StudioSVC;
|
import art.arcane.iris.core.service.StudioSVC;
|
||||||
import art.arcane.volmlib.util.format.Form;
|
import art.arcane.volmlib.util.format.Form;
|
||||||
@@ -126,7 +127,7 @@ public class IrisPackRepository {
|
|||||||
try {
|
try {
|
||||||
FileUtils.copyDirectory(work.listFiles()[0], pack);
|
FileUtils.copyDirectory(work.listFiles()[0], pack);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
IrisLogging.reportError("Failed to install Iris pack into " + pack + ".", e);
|
||||||
}
|
}
|
||||||
})).execute(sender, whenComplete);
|
})).execute(sender, whenComplete);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -94,7 +94,15 @@ final class PackRiverValidator {
|
|||||||
validateWater(path + ".water", water, errors);
|
validateWater(path + ".water", water, errors);
|
||||||
}
|
}
|
||||||
if (biomes != null) {
|
if (biomes != null) {
|
||||||
validateBiomePools(packFolder, path + ".biomes", biomes, false, errors, warnings);
|
validateBiomePools(
|
||||||
|
packFolder,
|
||||||
|
path + ".biomes",
|
||||||
|
biomes,
|
||||||
|
false,
|
||||||
|
usesOverworldNativeStructureRoles(context),
|
||||||
|
errors,
|
||||||
|
warnings
|
||||||
|
);
|
||||||
}
|
}
|
||||||
boolean sinkholeTerminal = terrain != null
|
boolean sinkholeTerminal = terrain != null
|
||||||
&& "SINKHOLE_GROTTO".equals(stringValue(terrain, "terminalMode", "DRY_CHANNEL"));
|
&& "SINKHOLE_GROTTO".equals(stringValue(terrain, "terminalMode", "DRY_CHANNEL"));
|
||||||
@@ -108,7 +116,7 @@ final class PackRiverValidator {
|
|||||||
if (Double.isFinite(meanderStrength) && meanderStrength > cellSize) {
|
if (Double.isFinite(meanderStrength) && meanderStrength > cellSize) {
|
||||||
warnings.add(path + ".terrain.meanderStrength exceeds topology.cellSize; reaches may require large cache halos.");
|
warnings.add(path + ".terrain.meanderStrength exceeds topology.cellSize; reaches may require large cache halos.");
|
||||||
}
|
}
|
||||||
validateTopologyComplexity(path, topology, terrain, errors);
|
validateTopologyComplexity(packFolder, path, topology, terrain, errors);
|
||||||
}
|
}
|
||||||
if (sinkholeTerminal && caves != null) {
|
if (sinkholeTerminal && caves != null) {
|
||||||
validateSinkholeCapability(
|
validateSinkholeCapability(
|
||||||
@@ -130,8 +138,14 @@ final class PackRiverValidator {
|
|||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "minimumSourcesPerTile", 0, 64, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "minimumSourcesPerTile", 0, 64, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "sinkSearchReaches", 0, 7, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "sinkSearchReaches", 0, 7, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "routingBasinCells", 8, 256, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "routingBasinCells", 8, 256, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "routingDeviationScaleCells", 8, 256, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "routingDeviationStrengthCells", 0D, 32D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "routingPlateauHeight", 1D, 64D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "routingPlateauHeight", 1D, 64D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "routingNoiseWeight", 0D, 1024D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "routingNoiseWeight", 0D, 1024D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "flowAlignmentWeight", 0D, 1024D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "confluenceWeight", 0D, 1024D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, topology, "branchSoftCap", 1, 8, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "branchChildShrinkFactor", 0D, 1D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "terrainHeightWeight", 0D, 16D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "terrainHeightWeight", 0D, 16D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "terrainSlopeWeight", 0D, 16D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "terrainSlopeWeight", 0D, 16D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "oceanAttraction", 0D, 16D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, topology, "oceanAttraction", 0D, 16D, errors);
|
||||||
@@ -155,6 +169,7 @@ final class PackRiverValidator {
|
|||||||
validateStyledRange(packFolder, terrain, "channelWidth", path, 1D, 2048D, errors, warnings);
|
validateStyledRange(packFolder, terrain, "channelWidth", path, 1D, 2048D, errors, warnings);
|
||||||
validateStyledRange(packFolder, terrain, "bankWidth", path, 0D, 2048D, errors, warnings);
|
validateStyledRange(packFolder, terrain, "bankWidth", path, 0D, 2048D, errors, warnings);
|
||||||
validateStyledRange(packFolder, terrain, "depth", path, 1D, 512D, errors, warnings);
|
validateStyledRange(packFolder, terrain, "depth", path, 1D, 512D, errors, warnings);
|
||||||
|
validateStyledRange(packFolder, terrain, "tunnelWidthMultiplier", path, 1D, 8D, errors, warnings);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "maxChannelWidth", 1D, 2048D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "maxChannelWidth", 1D, 2048D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "maxBankWidth", 0D, 2048D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "maxBankWidth", 0D, 2048D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "maxDepth", 1D, 512D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "maxDepth", 1D, 512D, errors);
|
||||||
@@ -162,6 +177,9 @@ final class PackRiverValidator {
|
|||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "orderDepthFactor", 0D, 8D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "orderDepthFactor", 0D, 8D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, terrain, "maxIncision", 0, 512, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, terrain, "maxIncision", 0, 512, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "bankExponent", 0.125D, 16D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "bankExponent", 0.125D, 16D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "tunnelMouthBlend", 0D, 16D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "tunnelFloorVariation", 0D, 8D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "tunnelRoofVariation", 0D, 16D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "meanderStrength", 0D, 1024D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "meanderStrength", 0D, 1024D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, terrain, "meanderSubdivisions", 1, 64, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, terrain, "meanderSubdivisions", 1, 64, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "bedRoughness", 0D, 8D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "bedRoughness", 0D, 8D, errors);
|
||||||
@@ -169,8 +187,32 @@ final class PackRiverValidator {
|
|||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, terrain, "terminalTaper", 8, 1024, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, terrain, "terminalTaper", 8, 1024, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "dryContinuationChance", 0D, 1D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, terrain, "dryContinuationChance", 0D, 1D, errors);
|
||||||
validateNoiseChance(packFolder, terrain, "incision", path, errors);
|
validateNoiseChance(packFolder, terrain, "incision", path, errors);
|
||||||
|
validateStyle(packFolder, terrain, "tunnelFloorStyle", path, errors);
|
||||||
|
validateStyle(packFolder, terrain, "tunnelRoofStyle", path, errors);
|
||||||
validateStyle(packFolder, terrain, "meanderStyle", path, errors);
|
validateStyle(packFolder, terrain, "meanderStyle", path, errors);
|
||||||
validateStyle(packFolder, terrain, "bedRoughnessStyle", path, errors);
|
validateStyle(packFolder, terrain, "bedRoughnessStyle", path, errors);
|
||||||
|
double maximumChannelWidth = doubleValue(terrain, "maxChannelWidth", 10D);
|
||||||
|
double maximumTunnelWidthMultiplier = styledRangeMaximum(
|
||||||
|
packFolder,
|
||||||
|
terrain,
|
||||||
|
"tunnelWidthMultiplier",
|
||||||
|
path,
|
||||||
|
1D
|
||||||
|
);
|
||||||
|
double tunnelMouthBlend = doubleValue(terrain, "tunnelMouthBlend", 2D);
|
||||||
|
if (Double.isFinite(maximumChannelWidth) && maximumChannelWidth >= 1D && maximumChannelWidth <= 2048D
|
||||||
|
&& Double.isFinite(maximumTunnelWidthMultiplier)
|
||||||
|
&& maximumTunnelWidthMultiplier >= 1D && maximumTunnelWidthMultiplier <= 8D
|
||||||
|
&& Double.isFinite(tunnelMouthBlend) && tunnelMouthBlend >= 0D && tunnelMouthBlend <= 16D) {
|
||||||
|
String violation = RiverTopologyComplexity.tunnelPlanViolation(
|
||||||
|
maximumChannelWidth,
|
||||||
|
maximumTunnelWidthMultiplier,
|
||||||
|
tunnelMouthBlend
|
||||||
|
);
|
||||||
|
if (violation != null) {
|
||||||
|
errors.add(path + " exceeds the safe derived hydrology budget. " + violation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateWater(String path, JSONObject water, List<String> errors) {
|
private static void validateWater(String path, JSONObject water, List<String> errors) {
|
||||||
@@ -188,6 +230,7 @@ final class PackRiverValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void validateTopologyComplexity(
|
private static void validateTopologyComplexity(
|
||||||
|
File packFolder,
|
||||||
String path,
|
String path,
|
||||||
JSONObject topology,
|
JSONObject topology,
|
||||||
JSONObject terrain,
|
JSONObject terrain,
|
||||||
@@ -201,6 +244,14 @@ final class PackRiverValidator {
|
|||||||
int meanderSubdivisions = integerValue(terrain, "meanderSubdivisions", 8);
|
int meanderSubdivisions = integerValue(terrain, "meanderSubdivisions", 8);
|
||||||
double maximumChannelWidth = doubleValue(terrain, "maxChannelWidth", 10D);
|
double maximumChannelWidth = doubleValue(terrain, "maxChannelWidth", 10D);
|
||||||
double maximumBankWidth = doubleValue(terrain, "maxBankWidth", 4D);
|
double maximumBankWidth = doubleValue(terrain, "maxBankWidth", 4D);
|
||||||
|
double maximumTunnelWidthMultiplier = styledRangeMaximum(
|
||||||
|
packFolder,
|
||||||
|
terrain,
|
||||||
|
"tunnelWidthMultiplier",
|
||||||
|
path,
|
||||||
|
1D
|
||||||
|
);
|
||||||
|
double tunnelMouthBlend = doubleValue(terrain, "tunnelMouthBlend", 2D);
|
||||||
if (cellSize < 64 || cellSize > 4096
|
if (cellSize < 64 || cellSize > 4096
|
||||||
|| tileCells < 1 || tileCells > 64
|
|| tileCells < 1 || tileCells > 64
|
||||||
|| !Double.isFinite(siteJitter) || siteJitter < 0D || siteJitter > 0.49D
|
|| !Double.isFinite(siteJitter) || siteJitter < 0D || siteJitter > 0.49D
|
||||||
@@ -208,10 +259,16 @@ final class PackRiverValidator {
|
|||||||
|| !Double.isFinite(meanderStrength) || meanderStrength < 0D || meanderStrength > 1024D
|
|| !Double.isFinite(meanderStrength) || meanderStrength < 0D || meanderStrength > 1024D
|
||||||
|| meanderSubdivisions < 1 || meanderSubdivisions > 64
|
|| meanderSubdivisions < 1 || meanderSubdivisions > 64
|
||||||
|| !Double.isFinite(maximumChannelWidth) || maximumChannelWidth < 1D || maximumChannelWidth > 2048D
|
|| !Double.isFinite(maximumChannelWidth) || maximumChannelWidth < 1D || maximumChannelWidth > 2048D
|
||||||
|| !Double.isFinite(maximumBankWidth) || maximumBankWidth < 0D || maximumBankWidth > 2048D) {
|
|| !Double.isFinite(maximumBankWidth) || maximumBankWidth < 0D || maximumBankWidth > 2048D
|
||||||
|
|| !Double.isFinite(maximumTunnelWidthMultiplier)
|
||||||
|
|| maximumTunnelWidthMultiplier < 1D || maximumTunnelWidthMultiplier > 8D
|
||||||
|
|| !Double.isFinite(tunnelMouthBlend) || tunnelMouthBlend < 0D || tunnelMouthBlend > 16D) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
double maximumReachRadius = maximumChannelWidth * 0.5D + maximumBankWidth;
|
double maximumSurfaceRadius = maximumChannelWidth * 0.5D + maximumBankWidth;
|
||||||
|
double maximumTunnelRadius = maximumChannelWidth * 0.5D * maximumTunnelWidthMultiplier
|
||||||
|
+ tunnelMouthBlend;
|
||||||
|
double maximumReachRadius = Math.max(maximumSurfaceRadius, maximumTunnelRadius);
|
||||||
RiverTopologyComplexity.Estimate estimate = RiverTopologyComplexity.estimate(
|
RiverTopologyComplexity.Estimate estimate = RiverTopologyComplexity.estimate(
|
||||||
cellSize,
|
cellSize,
|
||||||
tileCells,
|
tileCells,
|
||||||
@@ -239,6 +296,7 @@ final class PackRiverValidator {
|
|||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "grottoHorizontalRadius", 2, 128, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "grottoHorizontalRadius", 2, 128, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "grottoVerticalRadius", 2, 128, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "grottoVerticalRadius", 2, 128, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, caves, "grottoWarpStrength", 0D, 32D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, caves, "grottoWarpStrength", 0D, 32D, errors);
|
||||||
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, caves, "parentBiomeInheritance", 0D, 1D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "maxFloodRadius", 4, 256, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "maxFloodRadius", 4, 256, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "maxFloodDepth", 4, 256, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "maxFloodDepth", 4, 256, errors);
|
||||||
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "maxFloodVolume", 64, 1048576, errors);
|
PackJsonFieldChecks.validateOptionalIntegerRange(path, caves, "maxFloodVolume", 64, 1048576, errors);
|
||||||
@@ -525,12 +583,18 @@ final class PackRiverValidator {
|
|||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, override, "continuationChanceMultiplier", 0D, 16D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, override, "continuationChanceMultiplier", 0D, 16D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalDoubleRange(path, override, "caveEntryMultiplier", 0D, 16D, errors);
|
PackJsonFieldChecks.validateOptionalDoubleRange(path, override, "caveEntryMultiplier", 0D, 16D, errors);
|
||||||
PackJsonFieldChecks.validateOptionalEnum(path, override, "terminalMode", TERMINAL_MODES, errors);
|
PackJsonFieldChecks.validateOptionalEnum(path, override, "terminalMode", TERMINAL_MODES, errors);
|
||||||
validateBiomePool(packFolder, path, override, "channelBiomes", RiverBiomeRole.CHANNEL, true, errors, warnings);
|
boolean validateSuitability = reachesOverworldNativeStructureRoles(
|
||||||
validateBiomePool(packFolder, path, override, "bankBiomes", RiverBiomeRole.BANK, true, errors, warnings);
|
packFolder, resourceKey, resourceType, contexts);
|
||||||
validateBiomePool(packFolder, path, override, "mouthBiomes", RiverBiomeRole.MOUTH, true, errors, warnings);
|
validateBiomePool(packFolder, path, override, "channelBiomes", RiverBiomeRole.CHANNEL, true,
|
||||||
validateBiomePool(packFolder, path, override, "dryBiomes", RiverBiomeRole.DRY, true, errors, warnings);
|
validateSuitability, errors, warnings);
|
||||||
|
validateBiomePool(packFolder, path, override, "bankBiomes", RiverBiomeRole.BANK, true,
|
||||||
|
validateSuitability, errors, warnings);
|
||||||
|
validateBiomePool(packFolder, path, override, "mouthBiomes", RiverBiomeRole.MOUTH, true,
|
||||||
|
validateSuitability, errors, warnings);
|
||||||
|
validateBiomePool(packFolder, path, override, "dryBiomes", RiverBiomeRole.DRY, true,
|
||||||
|
validateSuitability, errors, warnings);
|
||||||
validateBiomePool(packFolder, path, override, "floodedCaveBiomes", RiverBiomeRole.FLOODED_CAVE, true,
|
validateBiomePool(packFolder, path, override, "floodedCaveBiomes", RiverBiomeRole.FLOODED_CAVE, true,
|
||||||
errors, warnings);
|
validateSuitability, errors, warnings);
|
||||||
if ("SINKHOLE_GROTTO".equals(stringValue(override, "terminalMode", null))) {
|
if ("SINKHOLE_GROTTO".equals(stringValue(override, "terminalMode", null))) {
|
||||||
validateOverrideSinkhole(
|
validateOverrideSinkhole(
|
||||||
packFolder,
|
packFolder,
|
||||||
@@ -545,18 +609,24 @@ final class PackRiverValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void validateBiomePools(File packFolder, String path, JSONObject biomes, boolean allowNull,
|
private static void validateBiomePools(File packFolder, String path, JSONObject biomes, boolean allowNull,
|
||||||
|
boolean validateSuitability,
|
||||||
List<String> errors, List<String> warnings) {
|
List<String> errors, List<String> warnings) {
|
||||||
validateStyle(packFolder, biomes, "selectionStyle", path, errors);
|
validateStyle(packFolder, biomes, "selectionStyle", path, errors);
|
||||||
validateBiomePool(packFolder, path, biomes, "channel", RiverBiomeRole.CHANNEL, allowNull, errors, warnings);
|
validateBiomePool(packFolder, path, biomes, "channel", RiverBiomeRole.CHANNEL, allowNull,
|
||||||
validateBiomePool(packFolder, path, biomes, "bank", RiverBiomeRole.BANK, allowNull, errors, warnings);
|
validateSuitability, errors, warnings);
|
||||||
validateBiomePool(packFolder, path, biomes, "mouth", RiverBiomeRole.MOUTH, allowNull, errors, warnings);
|
validateBiomePool(packFolder, path, biomes, "bank", RiverBiomeRole.BANK, allowNull,
|
||||||
validateBiomePool(packFolder, path, biomes, "dry", RiverBiomeRole.DRY, allowNull, errors, warnings);
|
validateSuitability, errors, warnings);
|
||||||
|
validateBiomePool(packFolder, path, biomes, "mouth", RiverBiomeRole.MOUTH, allowNull,
|
||||||
|
validateSuitability, errors, warnings);
|
||||||
|
validateBiomePool(packFolder, path, biomes, "dry", RiverBiomeRole.DRY, allowNull,
|
||||||
|
validateSuitability, errors, warnings);
|
||||||
validateBiomePool(packFolder, path, biomes, "floodedCave", RiverBiomeRole.FLOODED_CAVE, allowNull,
|
validateBiomePool(packFolder, path, biomes, "floodedCave", RiverBiomeRole.FLOODED_CAVE, allowNull,
|
||||||
errors, warnings);
|
validateSuitability, errors, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateBiomePool(File packFolder, String path, JSONObject owner, String field,
|
private static void validateBiomePool(File packFolder, String path, JSONObject owner, String field,
|
||||||
RiverBiomeRole role, boolean allowNull,
|
RiverBiomeRole role, boolean allowNull,
|
||||||
|
boolean validateSuitability,
|
||||||
List<String> errors, List<String> warnings) {
|
List<String> errors, List<String> warnings) {
|
||||||
if (!owner.has(field)) {
|
if (!owner.has(field)) {
|
||||||
return;
|
return;
|
||||||
@@ -588,10 +658,36 @@ final class PackRiverValidator {
|
|||||||
errors.add(entryPath + " references missing biome '" + key + "'.");
|
errors.add(entryPath + " references missing biome '" + key + "'.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
validateBiomeSuitability(entryPath, key, role, PackValidationIo.readJson(biomeFile), warnings);
|
if (validateSuitability) {
|
||||||
|
validateBiomeSuitability(entryPath, key, role, PackValidationIo.readJson(biomeFile), warnings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean usesOverworldNativeStructureRoles(DimensionRiverContext context) {
|
||||||
|
return "NORMAL".equals(stringValue(context.dimension(), "environment", "NORMAL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean reachesOverworldNativeStructureRoles(
|
||||||
|
File packFolder,
|
||||||
|
String resourceKey,
|
||||||
|
String resourceType,
|
||||||
|
List<DimensionRiverContext> contexts
|
||||||
|
) {
|
||||||
|
for (DimensionRiverContext context : contexts) {
|
||||||
|
if (!usesOverworldNativeStructureRoles(context)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean reachable = "Region".equals(resourceType)
|
||||||
|
? context.regionKeys().contains(resourceKey)
|
||||||
|
: referencedSurfaceBiomes(packFolder, context.regionKeys()).contains(resourceKey);
|
||||||
|
if (reachable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateBiomeSuitability(String path, String biomeKey, RiverBiomeRole role,
|
private static void validateBiomeSuitability(String path, String biomeKey, RiverBiomeRole role,
|
||||||
JSONObject biome, List<String> warnings) {
|
JSONObject biome, List<String> warnings) {
|
||||||
if (biome == null || role == RiverBiomeRole.DRY || role == RiverBiomeRole.FLOODED_CAVE) {
|
if (biome == null || role == RiverBiomeRole.DRY || role == RiverBiomeRole.FLOODED_CAVE) {
|
||||||
@@ -661,6 +757,26 @@ final class PackRiverValidator {
|
|||||||
validateStyle(packFolder, range, "style", rangePath, errors);
|
validateStyle(packFolder, range, "style", rangePath, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static double styledRangeMaximum(
|
||||||
|
File packFolder,
|
||||||
|
JSONObject owner,
|
||||||
|
String field,
|
||||||
|
String path,
|
||||||
|
double fallback
|
||||||
|
) {
|
||||||
|
if (!owner.has(field)) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
JSONObject range = resolveObject(
|
||||||
|
packFolder,
|
||||||
|
owner.opt(field),
|
||||||
|
"snippet/style-range/",
|
||||||
|
path + "." + field,
|
||||||
|
new ArrayList<>()
|
||||||
|
);
|
||||||
|
return range == null ? fallback : doubleValue(range, "max", fallback);
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateStyle(File packFolder, JSONObject owner, String field, String path,
|
private static void validateStyle(File packFolder, JSONObject owner, String field, String path,
|
||||||
List<String> errors) {
|
List<String> errors) {
|
||||||
if (!owner.has(field)) {
|
if (!owner.has(field)) {
|
||||||
|
|||||||
-2
@@ -173,7 +173,6 @@ public class PregenCacheImpl implements PregenCache {
|
|||||||
return readPlate(x, z, input);
|
return readPlate(x, z, input);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
IrisLogging.error("Failed to read pregen cache " + file);
|
IrisLogging.error("Failed to read pregen cache " + file);
|
||||||
e.printStackTrace();
|
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +194,6 @@ public class PregenCacheImpl implements PregenCache {
|
|||||||
plate.dirty = false;
|
plate.dirty = false;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.error("Failed to write pregen cache " + (file != null ? file : "c." + plate.x + "." + plate.z));
|
IrisLogging.error("Failed to write pregen cache " + (file != null ? file : "c." + plate.x + "." + plate.z));
|
||||||
e.printStackTrace();
|
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -464,7 +464,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
|
|
||||||
IrisLogging.reportError(throwable);
|
IrisLogging.reportError(throwable);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -489,7 +488,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
markFinished(success);
|
markFinished(success);
|
||||||
@@ -520,7 +518,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
String suppressedText = suppressed <= 0 ? "" : " suppressed=" + suppressed;
|
String suppressedText = suppressed <= 0 ? "" : " suppressed=" + suppressed;
|
||||||
// Slow chunk loads are what the adaptive in flight limit exists to absorb, and this line is already
|
// Slow chunk loads are what the adaptive in flight limit exists to absorb, and this line is already
|
||||||
// interval throttled with a suppression count. It reports the throttle working, not a fault.
|
// interval throttled with a suppression count. It reports the throttle working, not a fault.
|
||||||
IrisLogging.info("Async pregen chunk load at " + x + "," + z
|
IrisLogging.debug("Async pregen chunk load at " + x + "," + z
|
||||||
+ " is still pending after " + slowRequestWarningSeconds + "s."
|
+ " is still pending after " + slowRequestWarningSeconds + "s."
|
||||||
+ " adaptiveLimit=" + adaptiveInFlightLimit.get()
|
+ " adaptiveLimit=" + adaptiveInFlightLimit.get()
|
||||||
+ suppressedText + " " + metricsSnapshot());
|
+ suppressedText + " " + metricsSnapshot());
|
||||||
@@ -583,7 +581,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lastAdaptiveLogAt.compareAndSet(last, now)) {
|
if (lastAdaptiveLogAt.compareAndSet(last, now)) {
|
||||||
IrisLogging.info("Async pregen adaptive limit " + mode + " -> " + value + " " + metricsSnapshot());
|
IrisLogging.debug("Async pregen adaptive limit " + mode + " -> " + value + " " + metricsSnapshot());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1001,7 +999,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
IrisLogging.warn("For more information see https://docs.papermc.io/paper/reference/global-configuration#chunk_system_worker_threads");
|
IrisLogging.warn("For more information see https://docs.papermc.io/paper/reference/global-configuration#chunk_system_worker_threads");
|
||||||
if (e instanceof InvocationTargetException) {
|
if (e instanceof InvocationTargetException) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1023,7 +1020,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.reportError(e);
|
IrisLogging.reportError(e);
|
||||||
IrisLogging.error("Failed to reset worker threads");
|
IrisLogging.error("Failed to reset worker threads");
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ public class IrisCodeWorkspace {
|
|||||||
IO.writeAll(ws, rendered);
|
IO.writeAll(ws, rendered);
|
||||||
} catch (Throwable e1) {
|
} catch (Throwable e1) {
|
||||||
IrisLogging.reportError(e1);
|
IrisLogging.reportError(e1);
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user