mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 04:37:47 +00:00
d
This commit is contained in:
@@ -97,11 +97,20 @@ public final class IrisClient {
|
||||
}
|
||||
|
||||
public static void onWorldJoin() {
|
||||
clearWorldState();
|
||||
SESSION.sendHello();
|
||||
}
|
||||
|
||||
public static void onDisconnect() {
|
||||
SESSION.reset();
|
||||
clearWorldState();
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
SESSION.tick();
|
||||
}
|
||||
|
||||
private static void clearWorldState() {
|
||||
PREGEN.clear();
|
||||
DIMENSION.clear();
|
||||
TILES.clear();
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.function.LongSupplier;
|
||||
|
||||
public final class IrisClientCursor {
|
||||
private static final long MIN_REQUEST_INTERVAL_MILLIS = 500L;
|
||||
private static final long SAME_POSITION_REFRESH_MILLIS = 2_000L;
|
||||
|
||||
private final ClientPacketSink sink;
|
||||
private final LongSupplier clock;
|
||||
@@ -27,10 +28,11 @@ public final class IrisClientCursor {
|
||||
}
|
||||
|
||||
public synchronized void requestFor(int blockX, int blockZ) {
|
||||
if (requested && blockX == lastRequestedX && blockZ == lastRequestedZ) {
|
||||
long now = clock.getAsLong();
|
||||
boolean samePosition = requested && blockX == lastRequestedX && blockZ == lastRequestedZ;
|
||||
if (samePosition && now - lastRequestMillis < SAME_POSITION_REFRESH_MILLIS) {
|
||||
return;
|
||||
}
|
||||
long now = clock.getAsLong();
|
||||
if (now - lastRequestMillis < MIN_REQUEST_INTERVAL_MILLIS) {
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ public final class IrisClientDimension {
|
||||
if (previous == null) {
|
||||
return true;
|
||||
}
|
||||
return previous.irisWorld() != incoming.irisWorld() || !previous.dimensionKey().equals(incoming.dimensionKey());
|
||||
return !previous.equals(incoming);
|
||||
}
|
||||
|
||||
public IrisMessage.DimensionStatus status() {
|
||||
|
||||
@@ -4,21 +4,35 @@ import art.arcane.iris.spi.protocol.IrisMessage;
|
||||
import art.arcane.iris.spi.protocol.IrisMessageCodec;
|
||||
import art.arcane.iris.spi.protocol.IrisProtocol;
|
||||
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
public final class IrisClientSession {
|
||||
private static final long CLIENT_CAPABILITIES = IrisProtocol.CAPABILITY_PREGEN | IrisProtocol.CAPABILITY_VISION | IrisProtocol.CAPABILITY_CURSOR | IrisProtocol.CAPABILITY_STUDIO;
|
||||
private static final long HELLO_RETRY_MILLIS = 2_000L;
|
||||
private static final int MAX_HELLO_ATTEMPTS = 5;
|
||||
|
||||
private final LongSupplier clock;
|
||||
private volatile State state;
|
||||
private volatile long serverCapabilities;
|
||||
private volatile boolean irisActive;
|
||||
private volatile String serverBrand;
|
||||
private volatile ClientPacketSink sink;
|
||||
private volatile long nextHelloAt;
|
||||
private volatile int helloAttempts;
|
||||
|
||||
public IrisClientSession() {
|
||||
this(System::currentTimeMillis);
|
||||
}
|
||||
|
||||
IrisClientSession(LongSupplier clock) {
|
||||
this.clock = clock;
|
||||
this.state = State.IDLE;
|
||||
this.serverCapabilities = 0L;
|
||||
this.irisActive = false;
|
||||
this.serverBrand = "";
|
||||
this.sink = null;
|
||||
this.nextHelloAt = Long.MAX_VALUE;
|
||||
this.helloAttempts = 0;
|
||||
}
|
||||
|
||||
public void bind(ClientPacketSink boundSink) {
|
||||
@@ -46,16 +60,39 @@ public final class IrisClientSession {
|
||||
}
|
||||
|
||||
public void sendHello() {
|
||||
helloAttempts = 0;
|
||||
state = State.AWAITING_HELLO;
|
||||
sendHelloAttempt();
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if (state != State.AWAITING_HELLO || clock.getAsLong() < nextHelloAt) {
|
||||
return;
|
||||
}
|
||||
if (helloAttempts >= MAX_HELLO_ATTEMPTS) {
|
||||
state = State.UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
sendHelloAttempt();
|
||||
}
|
||||
|
||||
private void sendHelloAttempt() {
|
||||
ClientPacketSink activeSink = sink;
|
||||
if (activeSink == null) {
|
||||
return;
|
||||
}
|
||||
byte[] frame = IrisMessageCodec.encode(new IrisMessage.ClientHello(IrisProtocol.PROTOCOL_VERSION, CLIENT_CAPABILITIES));
|
||||
state = State.AWAITING_HELLO;
|
||||
helloAttempts++;
|
||||
nextHelloAt = clock.getAsLong() + HELLO_RETRY_MILLIS;
|
||||
activeSink.send(frame);
|
||||
}
|
||||
|
||||
public void onServerHello(IrisMessage.ServerHello hello) {
|
||||
if (hello.protocolVersion() != IrisProtocol.PROTOCOL_VERSION) {
|
||||
this.state = State.INCOMPATIBLE;
|
||||
return;
|
||||
}
|
||||
this.serverCapabilities = hello.capabilities();
|
||||
this.irisActive = hello.irisActive();
|
||||
this.serverBrand = hello.serverBrand();
|
||||
@@ -67,11 +104,15 @@ public final class IrisClientSession {
|
||||
this.serverCapabilities = 0L;
|
||||
this.irisActive = false;
|
||||
this.serverBrand = "";
|
||||
this.nextHelloAt = Long.MAX_VALUE;
|
||||
this.helloAttempts = 0;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
IDLE,
|
||||
AWAITING_HELLO,
|
||||
READY
|
||||
READY,
|
||||
UNSUPPORTED,
|
||||
INCOMPATIBLE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public final class IrisVisionScreen extends Screen {
|
||||
private double centerBlockZ;
|
||||
private int zoom;
|
||||
private boolean initialized;
|
||||
private String renderedDimensionKey;
|
||||
private IrisMessage.DimensionStatus renderedDimension;
|
||||
|
||||
public IrisVisionScreen() {
|
||||
super(Component.literal(IrisLanguage.plain(ClientUiMessages.VISION_TITLE)));
|
||||
@@ -54,7 +54,7 @@ public final class IrisVisionScreen extends Screen {
|
||||
this.centerBlockZ = 0.0D;
|
||||
this.zoom = DEFAULT_ZOOM;
|
||||
this.initialized = false;
|
||||
this.renderedDimensionKey = null;
|
||||
this.renderedDimension = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -290,12 +290,12 @@ public final class IrisVisionScreen extends Screen {
|
||||
}
|
||||
|
||||
private void syncWorld(IrisMessage.DimensionStatus status) {
|
||||
if (renderedDimensionKey == null) {
|
||||
renderedDimensionKey = status.dimensionKey();
|
||||
if (renderedDimension == null) {
|
||||
renderedDimension = status;
|
||||
return;
|
||||
}
|
||||
if (!renderedDimensionKey.equals(status.dimensionKey())) {
|
||||
renderedDimensionKey = status.dimensionKey();
|
||||
if (!renderedDimension.equals(status)) {
|
||||
renderedDimension = status;
|
||||
releaseTextures();
|
||||
centerOnPlayer();
|
||||
}
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package art.arcane.iris.client.mixin;
|
||||
|
||||
import art.arcane.iris.modded.IrisModdedChunkGenerator;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
|
||||
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;
|
||||
import net.minecraft.client.gui.screens.worldselection.WorldOpenFlows;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.WorldStem;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.world.level.dimension.LevelStem;
|
||||
import net.minecraft.world.level.levelgen.presets.WorldPreset;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(WorldOpenFlows.class)
|
||||
public abstract class IrisWorldOpenFlowsMixin {
|
||||
@Invoker("openWorldLoadBundledResourcePack")
|
||||
protected abstract void iris$openWorldLoadBundledResourcePack(
|
||||
LevelStorageSource.LevelStorageAccess worldAccess,
|
||||
WorldStem worldStem,
|
||||
PackRepository packRepository,
|
||||
Runnable onCancel);
|
||||
|
||||
@Inject(method = "confirmWorldCreation", at = @At("HEAD"), cancellable = true)
|
||||
private static void iris$confirmWorldCreation(
|
||||
Minecraft minecraft,
|
||||
CreateWorldScreen parent,
|
||||
Lifecycle lifecycle,
|
||||
Runnable task,
|
||||
boolean skipWarning,
|
||||
CallbackInfo info) {
|
||||
if (skipWarning || lifecycle == Lifecycle.stable() || !iris$selectedPresetIsIris(parent)) {
|
||||
return;
|
||||
}
|
||||
task.run();
|
||||
info.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "openWorldCheckWorldStemCompatibility", at = @At("HEAD"), cancellable = true)
|
||||
private void iris$openWorldCheckWorldStemCompatibility(
|
||||
LevelStorageSource.LevelStorageAccess worldAccess,
|
||||
WorldStem worldStem,
|
||||
PackRepository packRepository,
|
||||
Runnable onCancel,
|
||||
CallbackInfo info) {
|
||||
if (!iris$containsIrisGenerator(worldStem)) {
|
||||
return;
|
||||
}
|
||||
iris$openWorldLoadBundledResourcePack(worldAccess, worldStem, packRepository, onCancel);
|
||||
info.cancel();
|
||||
}
|
||||
|
||||
private static boolean iris$selectedPresetIsIris(CreateWorldScreen parent) {
|
||||
WorldCreationUiState.WorldTypeEntry worldType = parent.getUiState().getWorldType();
|
||||
Holder<WorldPreset> preset = worldType.preset();
|
||||
if (preset == null) {
|
||||
return false;
|
||||
}
|
||||
Optional<ResourceKey<WorldPreset>> key = preset.unwrapKey();
|
||||
return key.isPresent() && "irisworldgen".equals(key.get().identifier().getNamespace());
|
||||
}
|
||||
|
||||
private static boolean iris$containsIrisGenerator(WorldStem worldStem) {
|
||||
Registry<LevelStem> dimensions = worldStem.registries()
|
||||
.compositeAccess()
|
||||
.lookupOrThrow(Registries.LEVEL_STEM);
|
||||
for (LevelStem dimension : dimensions) {
|
||||
if (dimension.generator() instanceof IrisModdedChunkGenerator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package art.arcane.iris.client.mixin;
|
||||
|
||||
import art.arcane.iris.modded.ModdedWorldgenIds;
|
||||
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.levelgen.presets.WorldPreset;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(WorldCreationUiState.WorldTypeEntry.class)
|
||||
public class IrisWorldTypeEntryMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private Holder<WorldPreset> preset;
|
||||
|
||||
@Inject(method = "describePreset", at = @At("HEAD"), cancellable = true)
|
||||
private void iris$describePreset(CallbackInfoReturnable<Component> info) {
|
||||
Optional<ResourceKey<WorldPreset>> key = preset == null
|
||||
? Optional.empty()
|
||||
: preset.unwrapKey();
|
||||
if (key.isEmpty() || !"irisworldgen".equals(key.get().identifier().getNamespace())) {
|
||||
return;
|
||||
}
|
||||
String label = ModdedWorldgenIds.displayName(key.get().identifier().getPath());
|
||||
if (label != null) {
|
||||
info.setReturnValue(Component.literal(label));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,10 @@ tasks.named('test').configure {
|
||||
loom {
|
||||
accessWidenerPath = file('src/main/resources/irisworldgen.accesswidener')
|
||||
runs {
|
||||
client {
|
||||
runDir(providers.gradleProperty('irisClientRunDir').getOrElse('run'))
|
||||
vmArg('-Xmx8G')
|
||||
}
|
||||
server {
|
||||
String parity = providers.gradleProperty('irisParity').getOrNull()
|
||||
if (parity != null) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,371 +1,2 @@
|
||||
[19:42:28] [Test worker/INFO]: Iris registered custom content provider 'iris_deferred_test'
|
||||
[19:42:28] [Test worker/ERROR]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: second disable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndAggregatesFailures(ModdedServiceManagerTest.java:55)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[19:42:28] [Test worker/ERROR]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
|
||||
java.lang.RuntimeException: first disable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndAggregatesFailures(ModdedServiceManagerTest.java:54)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[19:42:28] [Test worker/ERROR]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: cleanup failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[19:42:28] [Test worker/ERROR]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: enable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:31)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
Suppressed: java.lang.RuntimeException: cleanup failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32)
|
||||
... 42 more
|
||||
[19:42:28] [Test worker/ERROR]: [worldcheck] server stop request failed
|
||||
java.lang.IllegalStateException: stop request failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$stopRequestFailureForcesNonzeroResult$1(ModdedWorldCheckTest.java:235)
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:179)
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.stopRequestFailureForcesNonzeroResult(ModdedWorldCheckTest.java:232)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[19:42:28] [Test worker/ERROR]: [worldcheck] waiting for server shutdown failed
|
||||
java.lang.IllegalStateException: shutdown wait failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$shutdownWaitFailureForcesNonzeroExit$0(ModdedWorldCheckTest.java:261)
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.awaitStopAndExit(ModdedWorldCheck.java:194)
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.shutdownWaitFailureForcesNonzeroExit(ModdedWorldCheckTest.java:259)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[19:42:28] [Test worker/ERROR]: [worldcheck] check failed
|
||||
java.lang.IllegalStateException: check failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$thrownCheckStillRequestsStop$0(ModdedWorldCheckTest.java:221)
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:174)
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.thrownCheckStillRequestsStop(ModdedWorldCheckTest.java:219)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[19:42:28] [Test worker/INFO]: Iris registered custom content provider 'iris_discovery_success'
|
||||
[19:42:28] [Test worker/ERROR]: Iris custom content provider discovery failed
|
||||
java.lang.RuntimeException: provider init failed
|
||||
at art.arcane.iris.modded.api.ModdedCustomContentRegistryTest.failedDiscoveryPublishesNothingAndPreservesTheCause(ModdedCustomContentRegistryTest.java:39)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
|
||||
[15:08:50] [Test worker/INFO]: Iris object undo service ready (bounded to 32 paste(s) per player)
|
||||
[15:08:50] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
|
||||
|
||||
@@ -45,6 +45,9 @@ public final class IrisFabricClient implements ClientModInitializer {
|
||||
KeyMappingHelper.registerKeyMapping(IrisClientKeybinds.OPEN_MAP);
|
||||
KeyMappingHelper.registerKeyMapping(IrisClientKeybinds.TOGGLE_WHAT);
|
||||
HudElementRegistry.addLast(IrisClient.HUD_ELEMENT_ID, (graphics, delta) -> IrisClientHud.render(graphics));
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> IrisClientKeybinds.pollToggle());
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
IrisClient.tick();
|
||||
IrisClientKeybinds.pollToggle();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+12
-7
@@ -20,17 +20,22 @@ package art.arcane.iris.fabric.mixin;
|
||||
|
||||
import art.arcane.iris.fabric.FabricForcedDatapackSources;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.server.packs.repository.RepositorySource;
|
||||
import net.minecraft.server.packs.repository.ServerPacksSource;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPacksSource.class)
|
||||
public class ServerPacksSourceMixin {
|
||||
@Inject(method = "createPackRepository(Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;)Lnet/minecraft/server/packs/repository/PackRepository;", at = @At("RETURN"))
|
||||
private static void iris$addForcedDatapackSource(LevelStorageSource.LevelStorageAccess storage, CallbackInfoReturnable<PackRepository> info) {
|
||||
FabricForcedDatapackSources.attach(info.getReturnValue());
|
||||
@Mixin(PackRepository.class)
|
||||
public class PackRepositoryMixin {
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void iris$addForcedDatapackSource(RepositorySource[] sources, CallbackInfo info) {
|
||||
for (RepositorySource source : sources) {
|
||||
if (source instanceof ServerPacksSource) {
|
||||
FabricForcedDatapackSources.attach((PackRepository) (Object) this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,14 @@
|
||||
"license": "GPL-3.0",
|
||||
"environment": "*",
|
||||
"accessWidener": "irisworldgen.accesswidener",
|
||||
"mixins": ["irisworldgen.mixins.json", "irisworldgen.entity.mixins.json"],
|
||||
"mixins": [
|
||||
"irisworldgen.mixins.json",
|
||||
"irisworldgen.entity.mixins.json",
|
||||
{
|
||||
"config": "irisworldgen.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"entrypoints": {
|
||||
"main": ["art.arcane.iris.fabric.IrisFabricBootstrap"],
|
||||
"client": ["art.arcane.iris.fabric.IrisFabricClient"]
|
||||
|
||||
@@ -4,4 +4,3 @@ accessible field net/minecraft/server/MinecraftServer executor Ljava/util/concur
|
||||
accessible field net/minecraft/server/MinecraftServer storageSource Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;
|
||||
accessible field net/minecraft/server/packs/repository/PackRepository sources Ljava/util/Set;
|
||||
mutable field net/minecraft/server/packs/repository/PackRepository sources Ljava/util/Set;
|
||||
accessible field net/minecraft/core/MappedRegistry frozen Z
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"mixins": [
|
||||
"BlockItemMixin",
|
||||
"BlockMixin",
|
||||
"ServerPacksSourceMixin"
|
||||
"PackRepositoryMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
@@ -174,6 +174,12 @@ dependencies {
|
||||
minecraft {
|
||||
accessTransformer.from(file('src/main/resources/META-INF/accesstransformer.cfg'))
|
||||
runs {
|
||||
register('client') {
|
||||
workingDir = layout.projectDirectory.dir('run')
|
||||
jvmArgs('-Xmx8G')
|
||||
args('--mixin.config', 'irisworldgen.entity.mixins.json',
|
||||
'--mixin.config', 'irisworldgen.client.mixins.json')
|
||||
}
|
||||
register('server') {
|
||||
workingDir = layout.projectDirectory.dir('run')
|
||||
String parity = providers.gradleProperty('irisParity').getOrNull()
|
||||
@@ -223,7 +229,7 @@ tasks.named('shadowJar', ShadowJar).configure {
|
||||
delete(layout.buildDirectory.file("libs/Iris-${project.version}+mc${minecraftVersion}-forge.jar"))
|
||||
}
|
||||
manifest {
|
||||
attributes('MixinConfigs': 'irisworldgen.entity.mixins.json')
|
||||
attributes('MixinConfigs': 'irisworldgen.entity.mixins.json,irisworldgen.client.mixins.json')
|
||||
}
|
||||
archiveFileName.set(irisArtifactName('Forge', "${minecraftVersion}+${loaderDisplayVersion(forgeVersion)}"))
|
||||
configurations = [project.configurations.named('bundle').get()]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,55 @@
|
||||
[20Jul2026 19:42:36.918] [Test worker/DEBUG] [io.netty.util.internal.logging.InternalLoggerFactory/]: Using SLF4J as the default logging framework
|
||||
[20Jul2026 19:42:36.919] [Test worker/DEBUG] [io.netty.util.ResourceLeakDetector/]: -Dio.netty.leakDetection.level: simple
|
||||
[20Jul2026 19:42:36.919] [Test worker/DEBUG] [io.netty.util.ResourceLeakDetector/]: -Dio.netty.leakDetection.targetRecords: 4
|
||||
[20Jul2026 19:42:38.772] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_deferred_test'
|
||||
[20Jul2026 19:42:38.831] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
[26Jul2026 15:03:10.625] [Test worker/DEBUG] [io.netty.util.internal.logging.InternalLoggerFactory/]: Using SLF4J as the default logging framework
|
||||
[26Jul2026 15:03:10.627] [Test worker/DEBUG] [io.netty.util.ResourceLeakDetector/]: -Dio.netty.leakDetection.level: simple
|
||||
[26Jul2026 15:03:10.627] [Test worker/DEBUG] [io.netty.util.ResourceLeakDetector/]: -Dio.netty.leakDetection.targetRecords: 4
|
||||
[26Jul2026 15:03:12.446] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_deferred_test'
|
||||
[26Jul2026 15:03:12.461] [Test worker/ERROR] [Iris/]: Iris persistent dimension registry entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial9764216152837868358/iris-dimensions.json is invalid; skipping only that entry
|
||||
java.lang.IllegalArgumentException: entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial9764216152837868358/iris-dimensions.json has no dimension
|
||||
at art.arcane.iris.modded.ModdedDimensionRegistryStore.required(ModdedDimensionRegistryStore.java:117) ~[main/:?]
|
||||
at art.arcane.iris.modded.ModdedDimensionRegistryStore.load(ModdedDimensionRegistryStore.java:68) ~[main/:?]
|
||||
at art.arcane.iris.modded.ModdedDimensionRegistryStoreTest.malformedEntryDoesNotDiscardHealthyEntries(ModdedDimensionRegistryStoreTest.java:51) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[?:?]
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53) ~[?:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[?:?]
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88) ~[?:?]
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63) ~[?:?]
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) ~[?:?]
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122) ~[?:?]
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[26Jul2026 15:03:12.522] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: second disable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndAggregatesFailures(ModdedServiceManagerTest.java:55) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -47,7 +94,7 @@ java.lang.RuntimeException: second disable failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.837] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
|
||||
[26Jul2026 15:03:12.524] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
|
||||
java.lang.RuntimeException: first disable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndAggregatesFailures(ModdedServiceManagerTest.java:54) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -92,7 +139,7 @@ java.lang.RuntimeException: first disable failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.840] [Test worker/ERROR] [Iris/]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
[26Jul2026 15:03:12.528] [Test worker/ERROR] [Iris/]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: cleanup failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -137,7 +184,7 @@ java.lang.RuntimeException: cleanup failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.843] [Test worker/ERROR] [Iris/]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
[26Jul2026 15:03:12.531] [Test worker/ERROR] [Iris/]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: enable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:31) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -185,7 +232,7 @@ java.lang.RuntimeException: enable failed
|
||||
Suppressed: java.lang.RuntimeException: cleanup failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32) ~[test/:?]
|
||||
... 42 more
|
||||
[20Jul2026 19:42:38.875] [Test worker/ERROR] [Iris/]: [worldcheck] server stop request failed
|
||||
[26Jul2026 15:03:12.561] [Test worker/ERROR] [Iris/]: [worldcheck] server stop request failed
|
||||
java.lang.IllegalStateException: stop request failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$stopRequestFailureForcesNonzeroResult$1(ModdedWorldCheckTest.java:235) ~[test/:?]
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:179) ~[main/:?]
|
||||
@@ -232,7 +279,7 @@ java.lang.IllegalStateException: stop request failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.878] [Test worker/ERROR] [Iris/]: [worldcheck] waiting for server shutdown failed
|
||||
[26Jul2026 15:03:12.564] [Test worker/ERROR] [Iris/]: [worldcheck] waiting for server shutdown failed
|
||||
java.lang.IllegalStateException: shutdown wait failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$shutdownWaitFailureForcesNonzeroExit$0(ModdedWorldCheckTest.java:261) ~[test/:?]
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.awaitStopAndExit(ModdedWorldCheck.java:194) ~[main/:?]
|
||||
@@ -279,7 +326,7 @@ java.lang.IllegalStateException: shutdown wait failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.883] [Test worker/ERROR] [Iris/]: [worldcheck] check failed
|
||||
[26Jul2026 15:03:12.571] [Test worker/ERROR] [Iris/]: [worldcheck] check failed
|
||||
java.lang.IllegalStateException: check failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$thrownCheckStillRequestsStop$0(ModdedWorldCheckTest.java:221) ~[test/:?]
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:174) ~[main/:?]
|
||||
@@ -326,8 +373,8 @@ java.lang.IllegalStateException: check failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.889] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_discovery_success'
|
||||
[20Jul2026 19:42:38.889] [Test worker/ERROR] [Iris/]: Iris custom content provider discovery failed
|
||||
[26Jul2026 15:03:12.577] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_discovery_success'
|
||||
[26Jul2026 15:03:12.578] [Test worker/ERROR] [Iris/]: Iris custom content provider discovery failed
|
||||
java.lang.RuntimeException: provider init failed
|
||||
at art.arcane.iris.modded.api.ModdedCustomContentRegistryTest.failedDiscoveryPublishesNothingAndPreservesTheCause(ModdedCustomContentRegistryTest.java:39) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -372,3 +419,4 @@ java.lang.RuntimeException: provider init failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[26Jul2026 15:03:12.591] [Test worker/INFO] [Iris/]: Iris object undo service ready (bounded to 32 paste(s) per player)
|
||||
|
||||
@@ -1,5 +1,52 @@
|
||||
[20Jul2026 19:42:38.772] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_deferred_test'
|
||||
[20Jul2026 19:42:38.831] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
[26Jul2026 15:03:12.446] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_deferred_test'
|
||||
[26Jul2026 15:03:12.461] [Test worker/ERROR] [Iris/]: Iris persistent dimension registry entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial9764216152837868358/iris-dimensions.json is invalid; skipping only that entry
|
||||
java.lang.IllegalArgumentException: entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial9764216152837868358/iris-dimensions.json has no dimension
|
||||
at art.arcane.iris.modded.ModdedDimensionRegistryStore.required(ModdedDimensionRegistryStore.java:117) ~[main/:?]
|
||||
at art.arcane.iris.modded.ModdedDimensionRegistryStore.load(ModdedDimensionRegistryStore.java:68) ~[main/:?]
|
||||
at art.arcane.iris.modded.ModdedDimensionRegistryStoreTest.malformedEntryDoesNotDiscardHealthyEntries(ModdedDimensionRegistryStoreTest.java:51) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[?:?]
|
||||
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runners.ParentRunner.run(ParentRunner.java:413) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.junit.runner.JUnitCore.run(JUnitCore.java:115) ~[junit-4.13.2.jar:4.13.2]
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53) ~[?:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[?:?]
|
||||
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) ~[?:?]
|
||||
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88) ~[?:?]
|
||||
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103) ~[?:?]
|
||||
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63) ~[?:?]
|
||||
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) ~[?:?]
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122) ~[?:?]
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[26Jul2026 15:03:12.522] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: second disable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndAggregatesFailures(ModdedServiceManagerTest.java:55) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -44,7 +91,7 @@ java.lang.RuntimeException: second disable failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.837] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
|
||||
[26Jul2026 15:03:12.524] [Test worker/ERROR] [Iris/]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
|
||||
java.lang.RuntimeException: first disable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndAggregatesFailures(ModdedServiceManagerTest.java:54) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -89,7 +136,7 @@ java.lang.RuntimeException: first disable failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.840] [Test worker/ERROR] [Iris/]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
[26Jul2026 15:03:12.528] [Test worker/ERROR] [Iris/]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: cleanup failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -134,7 +181,7 @@ java.lang.RuntimeException: cleanup failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.843] [Test worker/ERROR] [Iris/]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
[26Jul2026 15:03:12.531] [Test worker/ERROR] [Iris/]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
|
||||
java.lang.RuntimeException: enable failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:31) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -182,7 +229,7 @@ java.lang.RuntimeException: enable failed
|
||||
Suppressed: java.lang.RuntimeException: cleanup failed
|
||||
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32) ~[test/:?]
|
||||
... 42 more
|
||||
[20Jul2026 19:42:38.875] [Test worker/ERROR] [Iris/]: [worldcheck] server stop request failed
|
||||
[26Jul2026 15:03:12.561] [Test worker/ERROR] [Iris/]: [worldcheck] server stop request failed
|
||||
java.lang.IllegalStateException: stop request failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$stopRequestFailureForcesNonzeroResult$1(ModdedWorldCheckTest.java:235) ~[test/:?]
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:179) ~[main/:?]
|
||||
@@ -229,7 +276,7 @@ java.lang.IllegalStateException: stop request failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.878] [Test worker/ERROR] [Iris/]: [worldcheck] waiting for server shutdown failed
|
||||
[26Jul2026 15:03:12.564] [Test worker/ERROR] [Iris/]: [worldcheck] waiting for server shutdown failed
|
||||
java.lang.IllegalStateException: shutdown wait failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$shutdownWaitFailureForcesNonzeroExit$0(ModdedWorldCheckTest.java:261) ~[test/:?]
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.awaitStopAndExit(ModdedWorldCheck.java:194) ~[main/:?]
|
||||
@@ -276,7 +323,7 @@ java.lang.IllegalStateException: shutdown wait failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.883] [Test worker/ERROR] [Iris/]: [worldcheck] check failed
|
||||
[26Jul2026 15:03:12.571] [Test worker/ERROR] [Iris/]: [worldcheck] check failed
|
||||
java.lang.IllegalStateException: check failed
|
||||
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$thrownCheckStillRequestsStop$0(ModdedWorldCheckTest.java:221) ~[test/:?]
|
||||
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:174) ~[main/:?]
|
||||
@@ -323,8 +370,8 @@ java.lang.IllegalStateException: check failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[20Jul2026 19:42:38.889] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_discovery_success'
|
||||
[20Jul2026 19:42:38.889] [Test worker/ERROR] [Iris/]: Iris custom content provider discovery failed
|
||||
[26Jul2026 15:03:12.577] [Test worker/INFO] [Iris/]: Iris registered custom content provider 'iris_discovery_success'
|
||||
[26Jul2026 15:03:12.578] [Test worker/ERROR] [Iris/]: Iris custom content provider discovery failed
|
||||
java.lang.RuntimeException: provider init failed
|
||||
at art.arcane.iris.modded.api.ModdedCustomContentRegistryTest.failedDiscoveryPublishesNothingAndPreservesTheCause(ModdedCustomContentRegistryTest.java:39) ~[test/:?]
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[?:?]
|
||||
@@ -369,3 +416,4 @@ java.lang.RuntimeException: provider init failed
|
||||
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72) ~[?:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) [gradle-worker.jar:?]
|
||||
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) [gradle-worker.jar:?]
|
||||
[26Jul2026 15:03:12.591] [Test worker/INFO] [Iris/]: Iris object undo service ready (bounded to 32 paste(s) per player)
|
||||
|
||||
@@ -27,6 +27,7 @@ import net.minecraftforge.client.event.AddGuiOverlayLayersEvent;
|
||||
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
|
||||
import net.minecraftforge.client.event.InputEvent;
|
||||
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.network.Channel;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
@@ -46,6 +47,8 @@ public final class IrisForgeClient {
|
||||
ClientPlayerNetworkEvent.LoggingIn.BUS.addListener((ClientPlayerNetworkEvent.LoggingIn event) -> IrisClient.onWorldJoin());
|
||||
ClientPlayerNetworkEvent.LoggingOut.BUS.addListener((ClientPlayerNetworkEvent.LoggingOut event) -> IrisClient.onDisconnect());
|
||||
InputEvent.Key.BUS.addListener((InputEvent.Key event) -> IrisClientKeybinds.pollToggle());
|
||||
TickEvent.ClientTickEvent.Post.BUS.addListener(
|
||||
(TickEvent.ClientTickEvent.Post event) -> IrisClient.tick());
|
||||
}
|
||||
|
||||
private static void sendToServer(byte[] frame) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
public net.minecraft.server.MinecraftServer levels
|
||||
public net.minecraft.server.MinecraftServer executor
|
||||
public net.minecraft.server.MinecraftServer storageSource
|
||||
public net.minecraft.core.MappedRegistry frozen
|
||||
|
||||
+2
-4
@@ -334,8 +334,7 @@ final class IrisModdedBiomeSource extends BiomeSource {
|
||||
if (customBiome == null) {
|
||||
return fallbackBiome(registry, quartX, quartY, quartZ, sampler);
|
||||
}
|
||||
biomeKey = engine.getDimension().getLoadKey().toLowerCase(Locale.ROOT)
|
||||
+ ":" + customBiome.getId().toLowerCase(Locale.ROOT);
|
||||
biomeKey = ModdedWorldgenIds.biomeRef(engine, customBiome.getId());
|
||||
} else if (resolution.underground()) {
|
||||
biomeKey = resolution.irisBiome().getGroundBiomeKey(
|
||||
resolution.rng(), engine, resolution.blockX(), resolution.blockY(), resolution.blockZ());
|
||||
@@ -514,7 +513,6 @@ final class IrisModdedBiomeSource extends BiomeSource {
|
||||
throw new IllegalStateException("Iris structure biome key lookup has no active engine runtime");
|
||||
}
|
||||
LinkedHashSet<String> possible = new LinkedHashSet<>();
|
||||
String namespace = engine.getDimension().getLoadKey().toLowerCase(Locale.ROOT);
|
||||
for (IrisBiome irisBiome : engine.getAllBiomes()) {
|
||||
String derivative = normalizeKey(irisBiome.getStructureDerivativeKey());
|
||||
if (derivative != null) {
|
||||
@@ -524,7 +522,7 @@ final class IrisModdedBiomeSource extends BiomeSource {
|
||||
continue;
|
||||
}
|
||||
for (IrisBiomeCustom customBiome : irisBiome.getCustomDerivitives()) {
|
||||
possible.add(namespace + ":" + customBiome.getId().toLowerCase(Locale.ROOT));
|
||||
possible.add(ModdedWorldgenIds.biomeRef(engine, customBiome.getId()));
|
||||
}
|
||||
}
|
||||
return Set.copyOf(possible);
|
||||
|
||||
@@ -26,13 +26,11 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class MainWorldService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final String PRESET_NAMESPACE = "irisworldgen";
|
||||
private static final String MARKER_NAME = "mainworld.pending";
|
||||
private static final String[] VANILLA_DIMENSION_FOLDERS = {
|
||||
"region",
|
||||
@@ -54,8 +52,7 @@ public final class MainWorldService {
|
||||
int colon = value.indexOf(':');
|
||||
String pack = colon >= 0 ? value.substring(0, colon) : value;
|
||||
String dimension = colon >= 0 ? value.substring(colon + 1) : value;
|
||||
String presetKey = dimension.equals(pack) ? pack : pack + "_" + dimension;
|
||||
return PRESET_NAMESPACE + ":" + presetKey;
|
||||
return ModdedWorldgenIds.presetRef(pack, dimension);
|
||||
}
|
||||
|
||||
public static void reconcileEarly() {
|
||||
@@ -78,15 +75,22 @@ public final class MainWorldService {
|
||||
return;
|
||||
}
|
||||
String levelName = firstNonBlank(readProperty(properties, "level-name"), "world");
|
||||
wipeVanillaDimensions(instanceRoot().resolve(levelName));
|
||||
Path worldRoot = resolveWorldRoot(levelName);
|
||||
Path recovery = quarantineVanillaDimensions(worldRoot);
|
||||
clearPending();
|
||||
LOGGER.warn("Iris main world '{}' generated fresh: cleared the previous overworld/nether/end so this boot regenerates them as {} (player data kept).", pack, target);
|
||||
LOGGER.warn("Iris main world '{}' generated fresh: moved the prior overworld/nether/end data to {} so this boot regenerates them as {} (player data kept).", pack, recovery, target);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris main world reconciliation failed", e);
|
||||
throw new IllegalStateException(
|
||||
"Iris refused startup after main-world reconciliation failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean stage(String packRef, long seed) {
|
||||
if (ModdedEngineBootstrap.loader().clientEnvironment()) {
|
||||
LOGGER.error("Iris main-world replacement is only available on dedicated servers; use the Create World generator selector in singleplayer");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Path properties = instanceRoot().resolve("server.properties");
|
||||
writeLevelProperties(properties, presetIdFor(packRef), seed);
|
||||
@@ -164,24 +168,53 @@ public final class MainWorldService {
|
||||
lines.add(prefix + value);
|
||||
}
|
||||
|
||||
private static void wipeVanillaDimensions(Path worldRoot) throws IOException {
|
||||
Files.deleteIfExists(worldRoot.resolve("level.dat"));
|
||||
Files.deleteIfExists(worldRoot.resolve("level.dat_old"));
|
||||
for (String folder : VANILLA_DIMENSION_FOLDERS) {
|
||||
deleteRecursively(worldRoot.resolve(folder));
|
||||
private static Path resolveWorldRoot(String levelName) throws IOException {
|
||||
Path root = instanceRoot().toAbsolutePath().normalize();
|
||||
Path worldRoot = root.resolve(levelName).toAbsolutePath().normalize();
|
||||
if (worldRoot.equals(root) || !worldRoot.startsWith(root)) {
|
||||
throw new IOException("Unsafe level-name path outside the server instance: " + levelName);
|
||||
}
|
||||
return worldRoot;
|
||||
}
|
||||
|
||||
private static void deleteRecursively(Path path) throws IOException {
|
||||
if (!Files.exists(path)) {
|
||||
private static Path quarantineVanillaDimensions(Path worldRoot) throws IOException {
|
||||
Path recovery = markerFile().getParent().resolve("mainworld-recovery-" + UUID.randomUUID());
|
||||
List<Path> moved = new ArrayList<>();
|
||||
moveToRecovery(worldRoot, worldRoot.resolve("level.dat"), recovery, moved);
|
||||
moveToRecovery(worldRoot, worldRoot.resolve("level.dat_old"), recovery, moved);
|
||||
for (String folder : VANILLA_DIMENSION_FOLDERS) {
|
||||
moveToRecovery(worldRoot, worldRoot.resolve(folder), recovery, moved);
|
||||
}
|
||||
if (moved.isEmpty()) {
|
||||
Files.deleteIfExists(recovery);
|
||||
}
|
||||
return recovery;
|
||||
}
|
||||
|
||||
private static void moveToRecovery(Path worldRoot, Path source, Path recovery,
|
||||
List<Path> moved) throws IOException {
|
||||
if (!Files.exists(source)) {
|
||||
return;
|
||||
}
|
||||
List<Path> entries = new ArrayList<>();
|
||||
try (Stream<Path> walk = Files.walk(path)) {
|
||||
walk.sorted(Comparator.comparingInt(Path::getNameCount).reversed()).forEach(entries::add);
|
||||
Path relative = worldRoot.relativize(source);
|
||||
Path target = recovery.resolve(relative);
|
||||
Files.createDirectories(target.getParent());
|
||||
try {
|
||||
Files.move(source, target);
|
||||
moved.add(relative);
|
||||
} catch (IOException failure) {
|
||||
for (int index = moved.size() - 1; index >= 0; index--) {
|
||||
Path rollbackRelative = moved.get(index);
|
||||
Path rollbackSource = recovery.resolve(rollbackRelative);
|
||||
Path rollbackTarget = worldRoot.resolve(rollbackRelative);
|
||||
try {
|
||||
Files.createDirectories(rollbackTarget.getParent());
|
||||
Files.move(rollbackSource, rollbackTarget);
|
||||
} catch (IOException rollbackFailure) {
|
||||
failure.addSuppressed(rollbackFailure);
|
||||
}
|
||||
for (Path entry : entries) {
|
||||
Files.deleteIfExists(entry);
|
||||
}
|
||||
throw failure;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisBiomeCustom;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBiomeWriter;
|
||||
import art.arcane.iris.util.project.context.IrisContext;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
@@ -51,7 +52,7 @@ public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
||||
if (registry == null) {
|
||||
return 0;
|
||||
}
|
||||
int direct = idForKey(registry, key);
|
||||
int direct = idForKey(registry, scopedBiomeKey(key));
|
||||
if (direct >= 0) {
|
||||
return direct;
|
||||
}
|
||||
@@ -62,6 +63,19 @@ public final class ModdedBiomeWriter implements PlatformBiomeWriter {
|
||||
return fallbackId(registry);
|
||||
}
|
||||
|
||||
private String scopedBiomeKey(String key) {
|
||||
IrisContext context = IrisContext.get();
|
||||
if (context == null || key == null) {
|
||||
return key;
|
||||
}
|
||||
Engine engine = context.getEngine();
|
||||
String prefix = engine.getDimension().getLoadKey() + ":";
|
||||
if (!key.regionMatches(true, 0, prefix, 0, prefix.length())) {
|
||||
return key;
|
||||
}
|
||||
return ModdedWorldgenIds.biomeRef(engine, key.substring(prefix.length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlatformBiome> allBiomes() {
|
||||
Registry<Biome> registry = biomeRegistry();
|
||||
|
||||
+26
-4
@@ -152,11 +152,21 @@ public final class ModdedDimensionManager {
|
||||
}
|
||||
|
||||
public static Handle createPersistent(MinecraftServer server, String dimensionId, String pack, String packDimensionKey, long seed) {
|
||||
ModdedDimensionRegistryStore.PersistentDimension previous =
|
||||
ModdedDimensionRegistryStore.get(server, dimensionId);
|
||||
ModdedDimensionRegistryStore.put(server, new ModdedDimensionRegistryStore.PersistentDimension(dimensionId, pack, packDimensionKey, seed));
|
||||
try {
|
||||
return create(server, dimensionId, pack, packDimensionKey, seed);
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
if (previous == null) {
|
||||
ModdedDimensionRegistryStore.remove(server, dimensionId);
|
||||
} else {
|
||||
ModdedDimensionRegistryStore.put(server, previous);
|
||||
}
|
||||
} catch (Throwable rollbackFailure) {
|
||||
e.addSuppressed(rollbackFailure);
|
||||
}
|
||||
if (e instanceof RuntimeException runtimeException) {
|
||||
throw runtimeException;
|
||||
}
|
||||
@@ -168,9 +178,21 @@ public final class ModdedDimensionManager {
|
||||
}
|
||||
|
||||
public static boolean removePersistent(MinecraftServer server, String dimensionId, boolean wipeStorage) {
|
||||
boolean removed = remove(server, dimensionId, wipeStorage);
|
||||
ModdedDimensionRegistryStore.PersistentDimension previous =
|
||||
ModdedDimensionRegistryStore.get(server, dimensionId);
|
||||
ModdedDimensionRegistryStore.remove(server, dimensionId);
|
||||
return removed;
|
||||
try {
|
||||
return remove(server, dimensionId, wipeStorage);
|
||||
} catch (Throwable e) {
|
||||
if (previous != null) {
|
||||
try {
|
||||
ModdedDimensionRegistryStore.put(server, previous);
|
||||
} catch (Throwable rollbackFailure) {
|
||||
e.addSuppressed(rollbackFailure);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean remove(MinecraftServer server, String dimensionId, boolean wipeStorage) {
|
||||
@@ -273,10 +295,10 @@ public final class ModdedDimensionManager {
|
||||
private static Holder<DimensionType> resolveDimensionType(RegistryAccess registryAccess, String pack, String packDimensionKey) {
|
||||
Registry<DimensionType> registry = registryAccess.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||
IrisDimension dimension = loadPackDimension(pack, packDimensionKey);
|
||||
String typeRef = ModdedForcedDatapack.dimensionTypeRef(dimension);
|
||||
String typeRef = ModdedWorldgenIds.dimensionTypeRef(pack, packDimensionKey);
|
||||
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, Identifier.parse(typeRef));
|
||||
ModdedRuntimeRegistry.ensureCustomBiomes(registryAccess, dimension, pack);
|
||||
ModdedRuntimeRegistry.ensureDimensionType(registryAccess, registry, typeKey, typeRef, dimension);
|
||||
ModdedRuntimeRegistry.ensureDimensionType(registry, typeKey, typeRef);
|
||||
return ModdedForcedDatapack.requireRegisteredDimensionType(
|
||||
typeRef, registry.get(typeKey), pack, packDimensionKey);
|
||||
}
|
||||
|
||||
+59
-21
@@ -26,10 +26,13 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -43,7 +46,10 @@ public final class ModdedDimensionRegistryStore {
|
||||
}
|
||||
|
||||
public static List<PersistentDimension> load(MinecraftServer server) {
|
||||
Path file = storeFile(server);
|
||||
return load(storeFile(server));
|
||||
}
|
||||
|
||||
static List<PersistentDimension> load(Path file) {
|
||||
if (!Files.isRegularFile(file)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
@@ -51,34 +57,39 @@ public final class ModdedDimensionRegistryStore {
|
||||
JSONObject root = new JSONObject(Files.readString(file, StandardCharsets.UTF_8));
|
||||
JSONArray entries = root.optJSONArray("dimensions");
|
||||
if (entries == null) {
|
||||
return new ArrayList<>();
|
||||
throw new IllegalArgumentException("registry root has no dimensions array");
|
||||
}
|
||||
Map<String, PersistentDimension> deduplicated = new LinkedHashMap<>();
|
||||
for (int index = 0; index < entries.length(); index++) {
|
||||
try {
|
||||
JSONObject entry = entries.getJSONObject(index);
|
||||
String id = entry.optString("id", null);
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
String pack = entry.optString("pack", null);
|
||||
String dimension = entry.optString("dimension", null);
|
||||
if (pack == null || dimension == null) {
|
||||
LOGGER.error("Iris registry entry '{}' in {} has no pack/dimension fields; skipping it. Re-create the world with /iris world enable", id, file);
|
||||
continue;
|
||||
}
|
||||
String id = required(entry, "id", index, file);
|
||||
String pack = required(entry, "pack", index, file);
|
||||
String dimension = required(entry, "dimension", index, file);
|
||||
if (!entry.has("seed")) {
|
||||
LOGGER.warn("Iris registry entry '{}' in {} has no seed; skipping it. Re-create the world with /iris world enable", id, file);
|
||||
continue;
|
||||
throw new IllegalArgumentException("missing seed");
|
||||
}
|
||||
PersistentDimension previous = deduplicated.putIfAbsent(
|
||||
id, new PersistentDimension(id, pack, dimension, entry.getLong("seed")));
|
||||
if (previous != null) {
|
||||
throw new IllegalArgumentException("duplicate id '" + id + "'");
|
||||
}
|
||||
} catch (RuntimeException invalidEntry) {
|
||||
LOGGER.error("Iris persistent dimension registry entry {} in {} is invalid; skipping only that entry",
|
||||
index, file, invalidEntry);
|
||||
}
|
||||
deduplicated.put(id, new PersistentDimension(id, pack, dimension, entry.getLong("seed")));
|
||||
}
|
||||
return new ArrayList<>(deduplicated.values());
|
||||
} catch (RuntimeException | IOException e) {
|
||||
LOGGER.error("Iris persistent dimension registry at {} is invalid; ignoring it", file, e);
|
||||
return new ArrayList<>();
|
||||
throw new IllegalStateException("Iris persistent dimension registry at " + file
|
||||
+ " could not be read; refusing to discard persistent worlds", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PersistentDimension get(MinecraftServer server, String id) {
|
||||
return index(load(server)).get(id);
|
||||
}
|
||||
|
||||
public static synchronized void put(MinecraftServer server, PersistentDimension dimension) {
|
||||
Map<String, PersistentDimension> current = index(load(server));
|
||||
current.put(dimension.id(), dimension);
|
||||
@@ -100,8 +111,19 @@ public final class ModdedDimensionRegistryStore {
|
||||
return map;
|
||||
}
|
||||
|
||||
private static String required(JSONObject entry, String key, int index, Path file) {
|
||||
String value = entry.optString(key, null);
|
||||
if (value == null || value.isBlank()) {
|
||||
throw new IllegalArgumentException("entry " + index + " in " + file + " has no " + key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static void write(MinecraftServer server, List<PersistentDimension> dimensions) {
|
||||
Path file = storeFile(server);
|
||||
write(storeFile(server), dimensions);
|
||||
}
|
||||
|
||||
static void write(Path file, List<PersistentDimension> dimensions) {
|
||||
JSONArray entries = new JSONArray();
|
||||
for (PersistentDimension dimension : dimensions) {
|
||||
JSONObject entry = new JSONObject();
|
||||
@@ -113,13 +135,29 @@ public final class ModdedDimensionRegistryStore {
|
||||
}
|
||||
JSONObject root = new JSONObject();
|
||||
root.put("dimensions", entries);
|
||||
Path temp = file.resolveSibling(FILE_NAME + ".tmp");
|
||||
try {
|
||||
Files.createDirectories(file.getParent());
|
||||
Path temp = file.resolveSibling(FILE_NAME + ".tmp");
|
||||
Files.writeString(temp, root.toString(2), StandardCharsets.UTF_8);
|
||||
Files.move(temp, file, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||
try (FileChannel channel = FileChannel.open(temp, StandardOpenOption.WRITE)) {
|
||||
channel.force(true);
|
||||
}
|
||||
moveReplacing(temp, file);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris failed to write persistent dimension registry at {}", file, e);
|
||||
try {
|
||||
Files.deleteIfExists(temp);
|
||||
} catch (IOException cleanupFailure) {
|
||||
e.addSuppressed(cleanupFailure);
|
||||
}
|
||||
throw new IllegalStateException("Iris failed to write persistent dimension registry at " + file, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void moveReplacing(Path source, Path target) throws IOException {
|
||||
try {
|
||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (AtomicMoveNotSupportedException unsupported) {
|
||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -47,13 +47,19 @@ public final class ModdedDimensionStorage {
|
||||
|
||||
public static void wipe(MinecraftServer server, ResourceKey<Level> dimension) {
|
||||
File storageFolder = storageFolder(server, dimension);
|
||||
try {
|
||||
for (String folder : CHUNK_DATA_FOLDERS) {
|
||||
deleteRecursively(new File(storageFolder, folder).toPath());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(
|
||||
"Iris failed to completely wipe dimension storage at "
|
||||
+ storageFolder.getAbsolutePath(), e);
|
||||
}
|
||||
LOGGER.info("Iris wiped dimension storage at {}", storageFolder.getAbsolutePath());
|
||||
}
|
||||
|
||||
private static void deleteRecursively(Path root) {
|
||||
private static void deleteRecursively(Path root) throws IOException {
|
||||
if (!Files.exists(root)) {
|
||||
return;
|
||||
}
|
||||
@@ -61,8 +67,6 @@ public final class ModdedDimensionStorage {
|
||||
for (Path path : walk.sorted(Comparator.reverseOrder()).toList()) {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Iris failed to wipe dimension storage at {}", root, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,10 @@ public final class ModdedEngineBootstrap {
|
||||
selfTest(moddedLoader.getClass().getClassLoader());
|
||||
bind();
|
||||
IrisLanguage.initialize();
|
||||
ModdedStartup.prefetchDefaultPack();
|
||||
if (!moddedLoader.clientEnvironment()) {
|
||||
MainWorldService.reconcileEarly();
|
||||
}
|
||||
chunkGeneratorRegistration.run();
|
||||
ModdedIrisLog.info("Iris chunk generator registered as irisworldgen:iris");
|
||||
armParityProbe();
|
||||
|
||||
+132
-20
@@ -23,6 +23,9 @@ import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||
import art.arcane.iris.core.nms.datapack.IDataFixer;
|
||||
import art.arcane.iris.core.pack.PackValidationRegistry;
|
||||
import art.arcane.iris.core.pack.PackValidationResult;
|
||||
import art.arcane.iris.core.pack.PackValidator;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisDimensionType;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
@@ -80,8 +83,17 @@ public final class ModdedForcedDatapack {
|
||||
}
|
||||
|
||||
private static Pack buildPack() {
|
||||
Path directory = regenerate();
|
||||
return requireReadablePack(directory);
|
||||
try {
|
||||
return requireReadablePack(regenerate());
|
||||
} catch (RuntimeException | Error generationFailure) {
|
||||
Path published = packDirectory();
|
||||
if (Files.isRegularFile(published.resolve("pack.mcmeta"))) {
|
||||
LOGGER.error("Iris kept the last known-good generated datapack after regeneration failed",
|
||||
generationFailure);
|
||||
return requireReadablePack(published);
|
||||
}
|
||||
throw generationFailure;
|
||||
}
|
||||
}
|
||||
|
||||
private static Pack requireReadablePack(Path directory) {
|
||||
@@ -138,9 +150,6 @@ public final class ModdedForcedDatapack {
|
||||
}
|
||||
|
||||
private static void writeStagedPack(Path stagingDirectory) throws IOException {
|
||||
File packFolder = stagingDirectory.toFile();
|
||||
KList<File> folders = new KList<>();
|
||||
folders.add(packFolder);
|
||||
Map<String, KSet<String>> seenBiomes = new LinkedHashMap<>();
|
||||
IDataFixer fixer = DataVersion.getLatest().get();
|
||||
|
||||
@@ -154,7 +163,7 @@ public final class ModdedForcedDatapack {
|
||||
if (packs != null) {
|
||||
Arrays.sort(packs, Comparator.comparing(File::getName));
|
||||
for (File pack : packs) {
|
||||
if (installPack(pack, fixer, folders, seenBiomes, presetIds)) {
|
||||
if (stagePack(pack, fixer, stagingDirectory, seenBiomes, presetIds)) {
|
||||
packCount++;
|
||||
}
|
||||
}
|
||||
@@ -173,6 +182,88 @@ public final class ModdedForcedDatapack {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean stagePack(File sourcePack, IDataFixer fixer, Path stagingDirectory,
|
||||
Map<String, KSet<String>> seenBiomes,
|
||||
KList<String> presetIds) throws IOException {
|
||||
PackValidationResult validation;
|
||||
try {
|
||||
validation = PackValidator.validate(sourcePack);
|
||||
PackValidationRegistry.publish(validation);
|
||||
} catch (Throwable validationFailure) {
|
||||
LOGGER.error("Iris excluded pack '{}' from Create World because validation failed",
|
||||
sourcePack.getName(), validationFailure);
|
||||
if (validationFailure instanceof Error fatalError) {
|
||||
throw fatalError;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!validation.isLoadable()) {
|
||||
LOGGER.error("Iris excluded pack '{}' from Create World: {} blocking validation error(s); first error: {}",
|
||||
sourcePack.getName(), validation.getBlockingErrors().size(),
|
||||
validation.getBlockingErrors().getFirst());
|
||||
return false;
|
||||
}
|
||||
|
||||
Path packStagingDirectory = Files.createTempDirectory(
|
||||
stagingDirectory.getParent(), PACK_FOLDER + ".pack-" + sourcePack.getName() + "-");
|
||||
Map<String, KSet<String>> packBiomes = new LinkedHashMap<>();
|
||||
KList<String> packPresetIds = new KList<>();
|
||||
KList<File> packFolders = new KList<>();
|
||||
packFolders.add(packStagingDirectory.toFile());
|
||||
boolean installed;
|
||||
try {
|
||||
installed = installPack(sourcePack, fixer, packFolders, packBiomes, packPresetIds);
|
||||
} catch (Throwable installationFailure) {
|
||||
LOGGER.error("Iris excluded pack '{}' from Create World because datapack serialization failed",
|
||||
sourcePack.getName(), installationFailure);
|
||||
if (installationFailure instanceof Error fatalError) {
|
||||
throw fatalError;
|
||||
}
|
||||
installed = false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!installed) {
|
||||
return false;
|
||||
}
|
||||
mergeDirectory(packStagingDirectory, stagingDirectory);
|
||||
mergeBiomes(seenBiomes, packBiomes);
|
||||
presetIds.addAll(packPresetIds);
|
||||
return true;
|
||||
} finally {
|
||||
try {
|
||||
clean(packStagingDirectory);
|
||||
} catch (Throwable cleanupFailure) {
|
||||
LOGGER.warn("Iris could not remove temporary datapack staging for pack '{}'",
|
||||
sourcePack.getName(), cleanupFailure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void mergeDirectory(Path sourceDirectory, Path destinationDirectory) throws IOException {
|
||||
List<Path> entries = new ArrayList<>();
|
||||
try (Stream<Path> walk = Files.walk(sourceDirectory)) {
|
||||
walk.sorted(Comparator.comparingInt(Path::getNameCount)).forEach(entries::add);
|
||||
}
|
||||
for (Path source : entries) {
|
||||
Path relative = sourceDirectory.relativize(source);
|
||||
Path destination = destinationDirectory.resolve(relative);
|
||||
if (Files.isDirectory(source)) {
|
||||
Files.createDirectories(destination);
|
||||
} else if (!Files.exists(destination)) {
|
||||
Files.copy(source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void mergeBiomes(Map<String, KSet<String>> destination,
|
||||
Map<String, KSet<String>> source) {
|
||||
for (Map.Entry<String, KSet<String>> entry : source.entrySet()) {
|
||||
destination.computeIfAbsent(entry.getKey(), ignored -> new KSet<>())
|
||||
.addAll(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean installPack(File packFolder, IDataFixer fixer, KList<File> folders,
|
||||
Map<String, KSet<String>> seenBiomes,
|
||||
KList<String> presetIds) throws IOException {
|
||||
@@ -198,12 +289,15 @@ public final class ModdedForcedDatapack {
|
||||
throw new IllegalStateException("Iris pack '" + packName + "' dimension '"
|
||||
+ dimensionKey + "' did not load while building the forced datapack");
|
||||
}
|
||||
String biomePathPrefix = ModdedWorldgenIds.biomePathPrefix(packName, dimensionKey);
|
||||
dimension.installBiomes(fixer, () -> data, folders, "irisworldgen", biomePathPrefix,
|
||||
biomesForNamespace(seenBiomes, biomePathPrefix));
|
||||
dimension.installBiomes(fixer, () -> data, folders,
|
||||
biomesForNamespace(seenBiomes, dimension.getLoadKey()));
|
||||
writeDimensionType(folders, fixer, dimension);
|
||||
String presetKey = dimensionKey.equals(packName) ? packName : packName + "_" + dimensionKey;
|
||||
writeWorldPreset(folders, dimension, packName, dimensionKey, presetKey);
|
||||
presetIds.add("irisworldgen:" + presetKey);
|
||||
writeDimensionType(folders, fixer, dimension, packName, dimensionKey);
|
||||
String presetRef = ModdedWorldgenIds.presetRef(packName, dimensionKey);
|
||||
writeWorldPreset(folders, packName, dimensionKey, presetRef);
|
||||
presetIds.add(presetRef);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -212,10 +306,6 @@ public final class ModdedForcedDatapack {
|
||||
return biomes.computeIfAbsent(namespace, ignored -> new KSet<>());
|
||||
}
|
||||
|
||||
public static String dimensionTypeRef(IrisDimension dimension) {
|
||||
return "irisworldgen:" + dimension.getDimensionTypeKey();
|
||||
}
|
||||
|
||||
static <T> T requireRegisteredDimensionType(String typeRef, Optional<T> registeredType,
|
||||
String pack, String packDimensionKey) {
|
||||
return registeredType.orElseThrow(() -> new IllegalStateException(
|
||||
@@ -223,13 +313,26 @@ public final class ModdedForcedDatapack {
|
||||
+ packDimensionKey + "' is not loaded. Restart the server so the forced Iris datapack registers it before creating the world."));
|
||||
}
|
||||
|
||||
private static void writeWorldPreset(KList<File> folders, IrisDimension dimension, String packName, String dimensionKey, String presetKey) throws IOException {
|
||||
private static void writeWorldPreset(KList<File> folders, String packName, String dimensionKey,
|
||||
String presetRef) throws IOException {
|
||||
String dimensionRef = dimensionKey.equals(packName) ? packName : packName + ":" + dimensionKey;
|
||||
String json = worldPresetJson(dimensionRef, dimensionTypeRef(dimension));
|
||||
String json = worldPresetJson(dimensionRef,
|
||||
ModdedWorldgenIds.dimensionTypeRef(packName, dimensionKey));
|
||||
String presetPath = presetRef.substring(presetRef.indexOf(':') + 1);
|
||||
for (File datapackRoot : folders) {
|
||||
Path output = datapackRoot.toPath().resolve("data").resolve("irisworldgen").resolve("worldgen").resolve("world_preset").resolve(presetKey + ".json");
|
||||
Path output = datapackRoot.toPath().resolve("data").resolve("irisworldgen")
|
||||
.resolve("worldgen").resolve("world_preset").resolve(presetPath + ".json");
|
||||
Files.createDirectories(output.getParent());
|
||||
Files.writeString(output, json, StandardCharsets.UTF_8);
|
||||
String legacyPresetKey = dimensionKey.equals(packName)
|
||||
? packName
|
||||
: packName + "_" + dimensionKey;
|
||||
Path legacyOutput = datapackRoot.toPath().resolve("data").resolve("irisworldgen")
|
||||
.resolve("worldgen").resolve("world_preset").resolve(legacyPresetKey + ".json");
|
||||
if (!Files.exists(legacyOutput)) {
|
||||
Files.createDirectories(legacyOutput.getParent());
|
||||
Files.writeString(legacyOutput, json, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,14 +394,23 @@ public final class ModdedForcedDatapack {
|
||||
Files.writeString(output, json, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
static void writeDimensionType(KList<File> folders, IDataFixer fixer, IrisDimension dimension) throws IOException {
|
||||
static void writeDimensionType(KList<File> folders, IDataFixer fixer, IrisDimension dimension,
|
||||
String pack, String packDimensionKey) throws IOException {
|
||||
IrisDimensionType type = dimension.getDimensionType();
|
||||
String json = type.toJson(fixer);
|
||||
String typeKey = dimension.getDimensionTypeKey();
|
||||
String typeRef = ModdedWorldgenIds.dimensionTypeRef(pack, packDimensionKey);
|
||||
String typePath = typeRef.substring(typeRef.indexOf(':') + 1);
|
||||
for (File datapackRoot : folders) {
|
||||
Path output = datapackRoot.toPath().resolve("data").resolve("irisworldgen").resolve("dimension_type").resolve(typeKey + ".json");
|
||||
Path output = datapackRoot.toPath().resolve("data").resolve("irisworldgen")
|
||||
.resolve("dimension_type").resolve(typePath + ".json");
|
||||
Files.createDirectories(output.getParent());
|
||||
Files.writeString(output, json, StandardCharsets.UTF_8);
|
||||
Path legacyOutput = datapackRoot.toPath().resolve("data").resolve("irisworldgen")
|
||||
.resolve("dimension_type").resolve(dimension.getDimensionTypeKey() + ".json");
|
||||
if (!Files.exists(legacyOutput)) {
|
||||
Files.createDirectories(legacyOutput.getParent());
|
||||
Files.writeString(legacyOutput, json, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-3
@@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -35,11 +36,13 @@ public final class ModdedPackInstaller {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Pattern PACK_NAME = Pattern.compile("[a-z0-9_-]+");
|
||||
private static final Pattern BRANCH_NAME = Pattern.compile("[A-Za-z0-9._-]+");
|
||||
private static final ConcurrentHashMap<String, Object> INSTALL_LOCKS = new ConcurrentHashMap<>();
|
||||
|
||||
private ModdedPackInstaller() {
|
||||
}
|
||||
|
||||
public static boolean install(Path configDir, String pack, String branch, Consumer<String> feedback) {
|
||||
public static boolean install(Path configDir, String pack, String branch,
|
||||
boolean forceOverwrite, Consumer<String> feedback) {
|
||||
if (pack == null || !PACK_NAME.matcher(pack).matches()) {
|
||||
feedback.accept(IrisLanguage.plain(PackDownloadMessages.INVALID_PACK_NAME, MessageArgument.untrusted("pack", String.valueOf(pack))));
|
||||
return false;
|
||||
@@ -49,12 +52,22 @@ public final class ModdedPackInstaller {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object installLock = INSTALL_LOCKS.computeIfAbsent(pack, key -> new Object());
|
||||
synchronized (installLock) {
|
||||
File packs = configDir.resolve("irisworldgen").resolve("packs").toFile();
|
||||
try {
|
||||
if (PackDownloader.isDefaultOverworld(pack)) {
|
||||
return PackDownloader.downloadDefaultOverworld(packs, true, feedback) != null;
|
||||
return PackDownloader.downloadDefaultOverworld(
|
||||
packs, forceOverwrite, feedback) != null;
|
||||
}
|
||||
return PackDownloader.download(packs, "IrisDimensions/" + pack, branch, true, false, feedback) != null;
|
||||
return PackDownloader.download(
|
||||
packs,
|
||||
"IrisDimensions/" + pack,
|
||||
branch,
|
||||
forceOverwrite,
|
||||
false,
|
||||
feedback
|
||||
) != null;
|
||||
} catch (IOException error) {
|
||||
LOGGER.error("Iris pack download failed for IrisDimensions/{} ({})", pack, branch, error);
|
||||
feedback.accept(IrisLanguage.plain(
|
||||
@@ -66,3 +79,4 @@ public final class ModdedPackInstaller {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ public final class ModdedPlatform implements IrisPlatform {
|
||||
|
||||
public ModdedPlatform(ModdedLoader loader) {
|
||||
this.loader = loader;
|
||||
this.registries = new ModdedRegistries(loader::currentServer);
|
||||
this.registries = new ModdedRegistries(ModdedEngineBootstrap::currentServer);
|
||||
this.scheduler = new ModdedScheduler();
|
||||
this.structureHooks = new ModdedStructureHooks(loader::currentServer);
|
||||
this.biomeWriter = new ModdedBiomeWriter(loader::currentServer);
|
||||
this.structureHooks = new ModdedStructureHooks(ModdedEngineBootstrap::currentServer);
|
||||
this.biomeWriter = new ModdedBiomeWriter(ModdedEngineBootstrap::currentServer);
|
||||
}
|
||||
|
||||
public static void errorSink(Consumer<Throwable> sink) {
|
||||
@@ -63,7 +63,7 @@ public final class ModdedPlatform implements IrisPlatform {
|
||||
}
|
||||
|
||||
public MinecraftServer server() {
|
||||
return loader.currentServer();
|
||||
return ModdedEngineBootstrap.currentServer();
|
||||
}
|
||||
|
||||
public ModdedScheduler moddedScheduler() {
|
||||
@@ -137,7 +137,7 @@ public final class ModdedPlatform implements IrisPlatform {
|
||||
|
||||
@Override
|
||||
public void dispatchConsoleCommand(String command) {
|
||||
ModdedServerCommands.dispatch(loader.currentServer(), command);
|
||||
ModdedServerCommands.dispatch(ModdedEngineBootstrap.currentServer(), command);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -64,6 +64,7 @@ public final class ModdedProtocolHandler {
|
||||
}
|
||||
SESSION_ENGINES.clear();
|
||||
SESSION_LEVELS.clear();
|
||||
dimensionSyncTicks = 0;
|
||||
IrisSessionRegistry sessionRegistry = new IrisSessionRegistry();
|
||||
ModdedProtocolTransport serverTransport = new ModdedProtocolTransport(server, boundChannel);
|
||||
IrisProtocolServer protocol = new IrisProtocolServer(sessionRegistry, SERVER_CAPABILITIES, brand(), true);
|
||||
@@ -95,6 +96,7 @@ public final class ModdedProtocolHandler {
|
||||
}
|
||||
SESSION_ENGINES.clear();
|
||||
SESSION_LEVELS.clear();
|
||||
dimensionSyncTicks = 0;
|
||||
registry = null;
|
||||
protocolServer = null;
|
||||
transport = null;
|
||||
|
||||
+15
-66
@@ -19,53 +19,35 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||
import art.arcane.iris.core.nms.datapack.IDataFixer;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisBiomeCustom;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.util.common.data.DataProvider;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.core.RegistrationInfo;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ModdedRuntimeRegistry {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
private ModdedRuntimeRegistry() {
|
||||
}
|
||||
|
||||
static void ensureDimensionType(RegistryAccess registryAccess, Registry<DimensionType> registry,
|
||||
ResourceKey<DimensionType> typeKey, String typeRef, IrisDimension dimension) {
|
||||
static void ensureDimensionType(Registry<DimensionType> registry,
|
||||
ResourceKey<DimensionType> typeKey, String typeRef) {
|
||||
if (registry.get(typeKey).isPresent()) {
|
||||
return;
|
||||
}
|
||||
IDataFixer fixer = DataVersion.getLatest().get();
|
||||
String json = dimension.getDimensionType().toJson(fixer);
|
||||
DimensionType type = decode(registryAccess, DimensionType.DIRECT_CODEC, json, typeRef);
|
||||
registerIntoFrozen(registry, typeKey, type, typeRef);
|
||||
LOGGER.info("Iris registered runtime dimension type '{}'", typeRef);
|
||||
throw new IllegalStateException("Iris dimension type '" + typeRef
|
||||
+ "' is not synchronized. Restart after installing the pack before creating its world.");
|
||||
}
|
||||
|
||||
static void ensureCustomBiomes(RegistryAccess registryAccess, IrisDimension dimension, String pack) {
|
||||
@@ -76,10 +58,8 @@ public final class ModdedRuntimeRegistry {
|
||||
Registry<Biome> registry = registryAccess.lookupOrThrow(Registries.BIOME);
|
||||
IrisData data = IrisData.get(packFolder);
|
||||
DataProvider provider = () -> data;
|
||||
IDataFixer fixer = DataVersion.getLatest().get();
|
||||
String namespace = dimension.getLoadKey().toLowerCase(Locale.ROOT);
|
||||
Set<String> seen = new HashSet<>();
|
||||
int registered = 0;
|
||||
List<String> missing = new ArrayList<>();
|
||||
for (IrisBiome irisBiome : dimension.getAllBiomes(provider)) {
|
||||
if (!irisBiome.isCustom()) {
|
||||
continue;
|
||||
@@ -89,48 +69,17 @@ public final class ModdedRuntimeRegistry {
|
||||
if (!seen.add(biomeId)) {
|
||||
continue;
|
||||
}
|
||||
String biomeRef = namespace + ":" + biomeId;
|
||||
String biomeRef = ModdedWorldgenIds.biomeRef(pack, dimension.getLoadKey(), biomeId);
|
||||
ResourceKey<Biome> biomeKey = ResourceKey.create(Registries.BIOME, Identifier.parse(biomeRef));
|
||||
if (registry.get(biomeKey).isPresent()) {
|
||||
continue;
|
||||
}
|
||||
String json = customBiome.generateJson(fixer);
|
||||
Biome biome = decode(registryAccess, Biome.DIRECT_CODEC, json, biomeRef);
|
||||
registerIntoFrozen(registry, biomeKey, biome, biomeRef);
|
||||
registered++;
|
||||
}
|
||||
}
|
||||
if (registered > 0) {
|
||||
LOGGER.info("Iris registered {} runtime biome(s) for pack '{}'", registered, pack);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T decode(RegistryAccess registryAccess, Codec<T> codec, String json, String ref) {
|
||||
JsonElement element = JsonParser.parseString(json);
|
||||
RegistryOps<JsonElement> ops = RegistryOps.create(JsonOps.INSTANCE, registryAccess);
|
||||
return codec.parse(ops, element).getOrThrow((String message) ->
|
||||
new IllegalStateException("Iris could not decode runtime registry entry '" + ref + "': " + message));
|
||||
}
|
||||
|
||||
private static <T> Holder.Reference<T> registerIntoFrozen(Registry<T> registry, ResourceKey<T> key, T value, String ref) {
|
||||
if (!(registry instanceof MappedRegistry<T> mapped)) {
|
||||
throw new IllegalStateException("Iris cannot register '" + ref + "' at runtime: "
|
||||
+ registry.getClass().getName() + " is not a MappedRegistry");
|
||||
}
|
||||
synchronized (LOCK) {
|
||||
Optional<Holder.Reference<T>> raced = registry.get(key);
|
||||
if (raced.isPresent()) {
|
||||
return raced.get();
|
||||
}
|
||||
boolean wasFrozen = mapped.frozen;
|
||||
mapped.frozen = false;
|
||||
try {
|
||||
return mapped.register(key, value, RegistrationInfo.BUILT_IN);
|
||||
} finally {
|
||||
if (wasFrozen) {
|
||||
mapped.freeze();
|
||||
if (registry.get(biomeKey).isEmpty()) {
|
||||
missing.add(biomeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!missing.isEmpty()) {
|
||||
throw new IllegalStateException("Iris pack '" + pack + "' has " + missing.size()
|
||||
+ " unsynchronized custom biome(s). Restart before creating its world. First missing entry: "
|
||||
+ missing.getFirst());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -90,7 +90,6 @@ public final class ModdedServiceManager {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
enabled = false;
|
||||
Throwable failure = null;
|
||||
ModdedService[] ordered = services.values().toArray(new ModdedService[0]);
|
||||
for (int i = ordered.length - 1; i >= 0; i--) {
|
||||
@@ -109,6 +108,7 @@ public final class ModdedServiceManager {
|
||||
if (failure != null) {
|
||||
throw new IllegalStateException("One or more Iris services failed to disable", failure);
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
synchronized void rollback(Throwable failure) {
|
||||
|
||||
@@ -95,10 +95,9 @@ public final class ModdedStartup {
|
||||
PackValidationResult result = PackValidator.validate(packDir);
|
||||
PackValidationRegistry.publish(result);
|
||||
if (!result.isLoadable()) {
|
||||
LOGGER.error("Iris pack '{}' FAILED validation - world/studio creation will be refused. Reasons:", result.getPackName());
|
||||
for (String reason : result.getBlockingErrors()) {
|
||||
LOGGER.error(" - {}", reason);
|
||||
}
|
||||
LOGGER.error("Iris pack '{}' FAILED validation with {} blocking error(s); world/studio creation will be refused. First error: {}",
|
||||
result.getPackName(), result.getBlockingErrors().size(),
|
||||
result.getBlockingErrors().getFirst());
|
||||
} else if (!result.getWarnings().isEmpty()) {
|
||||
LOGGER.info("Iris pack '{}' validated ({} warning(s)).", result.getPackName(), result.getWarnings().size());
|
||||
for (String warning : result.getWarnings()) {
|
||||
@@ -168,8 +167,6 @@ public final class ModdedStartup {
|
||||
if (e instanceof Error fatalError) {
|
||||
throw fatalError;
|
||||
}
|
||||
throw new IllegalStateException("Iris failed to re-inject persistent dimension '"
|
||||
+ dimension.id() + "' from pack '" + dimension.pack() + "'", e);
|
||||
}
|
||||
}
|
||||
LOGGER.info("Iris re-injected {} persistent dimension(s) at startup", injected);
|
||||
@@ -187,9 +184,11 @@ public final class ModdedStartup {
|
||||
if (new File(packFolder, "dimensions/" + pack + ".json").isFile()) {
|
||||
return;
|
||||
}
|
||||
String source = PackDownloader.isDefaultOverworld(pack) ? "beta release" : "master branch";
|
||||
String source = "master branch";
|
||||
LOGGER.info("Iris default pack '{}' missing; downloading IrisDimensions/{} ({})", pack, pack, source);
|
||||
boolean installed = ModdedPackInstaller.install(configDir, pack, "master", (String line) -> LOGGER.info("Iris: {}", line));
|
||||
boolean installed = ModdedPackInstaller.install(
|
||||
configDir, pack, "master", false,
|
||||
(String line) -> LOGGER.info("Iris: {}", line));
|
||||
if (!installed) {
|
||||
LOGGER.warn("Iris default pack '{}' could not be downloaded; install it with /iris download {}", pack, pack);
|
||||
}
|
||||
|
||||
+12
-3
@@ -111,7 +111,7 @@ public final class ModdedWorldEngines {
|
||||
}
|
||||
|
||||
long seed = seedOverride == Long.MIN_VALUE ? level.getSeed() : seedOverride;
|
||||
validateDimensionContract(dimension, level);
|
||||
validateDimensionContract(pack, dimensionKey, dimension, level);
|
||||
File worldFolder = DimensionType.getStorageFolder(level.dimension(), level.getServer().getWorldPath(LevelResource.ROOT)).toFile();
|
||||
IrisWorld world = IrisWorld.builder()
|
||||
.platformIdentity(level.dimension().identifier().toString())
|
||||
@@ -139,12 +139,21 @@ public final class ModdedWorldEngines {
|
||||
return engine;
|
||||
}
|
||||
|
||||
private static void validateDimensionContract(IrisDimension dimension, ServerLevel level) {
|
||||
private static void validateDimensionContract(String pack, String dimensionKey,
|
||||
IrisDimension dimension, ServerLevel level) {
|
||||
DimensionType actualType = level.dimensionType();
|
||||
String actualTypeKey = level.dimensionTypeRegistration().unwrapKey()
|
||||
.map(key -> key.identifier().toString())
|
||||
.orElse("<unregistered>");
|
||||
IrisDimensionRuntimeContract expected = IrisDimensionRuntimeContract.expected(dimension, "irisworldgen");
|
||||
String legacyTypeKey = "irisworldgen:" + dimension.getDimensionTypeKey();
|
||||
String expectedTypeKey = legacyTypeKey.equals(actualTypeKey)
|
||||
? legacyTypeKey
|
||||
: ModdedWorldgenIds.dimensionTypeRef(pack, dimensionKey);
|
||||
IrisDimensionRuntimeContract expected = new IrisDimensionRuntimeContract(
|
||||
expectedTypeKey,
|
||||
dimension.getMinHeight(),
|
||||
dimension.getMaxHeight() - dimension.getMinHeight(),
|
||||
dimension.getLogicalHeight());
|
||||
IrisDimensionRuntimeContract actual = new IrisDimensionRuntimeContract(
|
||||
actualTypeKey,
|
||||
actualType.minY(),
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class ModdedWorldgenIds {
|
||||
private static final String NAMESPACE = "irisworldgen";
|
||||
|
||||
private ModdedWorldgenIds() {
|
||||
}
|
||||
|
||||
public static String presetRef(String pack, String dimension) {
|
||||
return NAMESPACE + ":" + scopedPath(pack, dimension) + "/preset";
|
||||
}
|
||||
|
||||
public static String dimensionTypeRef(String pack, String dimension) {
|
||||
return NAMESPACE + ":" + scopedPath(pack, dimension) + "/dimension_type";
|
||||
}
|
||||
|
||||
public static String biomePathPrefix(String pack, String dimension) {
|
||||
return scopedPath(pack, dimension) + "/biomes";
|
||||
}
|
||||
|
||||
public static String biomeRef(String pack, String dimension, String biome) {
|
||||
return NAMESPACE + ":" + biomePathPrefix(pack, dimension) + "/"
|
||||
+ biome.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public static String biomeRef(Engine engine, String biome) {
|
||||
return biomeRef(engine.getData().getDataFolder().getName(),
|
||||
engine.getDimension().getLoadKey(), biome);
|
||||
}
|
||||
|
||||
public static String displayName(String presetPath) {
|
||||
String[] parts = presetPath.split("/");
|
||||
if (parts.length != 5 || !"packs".equals(parts[0])
|
||||
|| !"dimensions".equals(parts[2]) || !"preset".equals(parts[4])) {
|
||||
return null;
|
||||
}
|
||||
String pack = decode(parts[1]);
|
||||
String dimension = decode(parts[3]);
|
||||
if (pack == null || dimension == null) {
|
||||
return null;
|
||||
}
|
||||
String packLabel = title(pack);
|
||||
return pack.equalsIgnoreCase(dimension)
|
||||
? "IRIS:" + packLabel
|
||||
: "IRIS:" + packLabel + " / " + title(dimension);
|
||||
}
|
||||
|
||||
public static String generatorIdentity(String packDimension) {
|
||||
int separator = packDimension.indexOf(':');
|
||||
String pack = separator >= 0 ? packDimension.substring(0, separator) : packDimension;
|
||||
String dimension = separator >= 0 ? packDimension.substring(separator + 1) : packDimension;
|
||||
return "iris:" + (pack.equalsIgnoreCase(dimension)
|
||||
? pack.toLowerCase(Locale.ROOT)
|
||||
: pack.toLowerCase(Locale.ROOT) + "/" + dimension.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
private static String scopedPath(String pack, String dimension) {
|
||||
return "packs/" + encode(pack) + "/dimensions/" + encode(dimension);
|
||||
}
|
||||
|
||||
private static String encode(String value) {
|
||||
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
StringBuilder encoded = new StringBuilder(bytes.length * 2);
|
||||
for (byte current : bytes) {
|
||||
encoded.append(Character.forDigit((current >>> 4) & 0xF, 16));
|
||||
encoded.append(Character.forDigit(current & 0xF, 16));
|
||||
}
|
||||
return encoded.toString();
|
||||
}
|
||||
|
||||
private static String decode(String value) {
|
||||
if ((value.length() & 1) != 0) {
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = new byte[value.length() / 2];
|
||||
try {
|
||||
for (int index = 0; index < bytes.length; index++) {
|
||||
int high = Character.digit(value.charAt(index * 2), 16);
|
||||
int low = Character.digit(value.charAt(index * 2 + 1), 16);
|
||||
if (high < 0 || low < 0) {
|
||||
return null;
|
||||
}
|
||||
bytes[index] = (byte) ((high << 4) | low);
|
||||
}
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (RuntimeException invalid) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String title(String value) {
|
||||
String normalized = value.replace('_', ' ').replace('-', ' ').trim();
|
||||
if (normalized.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return Character.toUpperCase(normalized.charAt(0)) + normalized.substring(1);
|
||||
}
|
||||
}
|
||||
+148
-211
@@ -33,22 +33,21 @@ import art.arcane.iris.engine.framework.WrongEngineBroException;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
|
||||
import art.arcane.iris.engine.object.NativeStructureGenerationStatus;
|
||||
import art.arcane.iris.engine.object.IrisPosition;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.modded.IrisModdedChunkGenerator;
|
||||
import art.arcane.iris.modded.ModdedBlockState;
|
||||
import art.arcane.iris.modded.ModdedDimensionManager;
|
||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||
import art.arcane.iris.modded.ModdedLoader;
|
||||
import art.arcane.iris.modded.ModdedPackInstaller;
|
||||
import art.arcane.iris.modded.ModdedScheduler;
|
||||
import art.arcane.iris.modded.ModdedWorldgenIds;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.project.context.IrisContext;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.volmlib.util.math.Position2;
|
||||
import art.arcane.volmlib.util.matter.MatterMarker;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.LongArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
@@ -70,7 +69,6 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -79,13 +77,9 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Relative;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -123,8 +117,6 @@ public final class IrisModdedCommands {
|
||||
private static final SuggestionProvider<CommandSourceStack> OBJECT_KEYS = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestObjectKeys(context, builder);
|
||||
private static final SuggestionProvider<CommandSourceStack> STRUCTURE_KEYS = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestStructureKeys(context, builder);
|
||||
private static final SuggestionProvider<CommandSourceStack> POI_TYPES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> SharedSuggestionProvider.suggest(List.of("buried_treasure"), builder);
|
||||
private static final SuggestionProvider<CommandSourceStack> MARKER_TYPES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> SharedSuggestionProvider.suggest(List.of("cave_floor", "cave_ceiling", "object"), builder);
|
||||
private static final DustParticleOptions MARKER_DUST = new DustParticleOptions(0x5A8CFF, 1.2F);
|
||||
static final SuggestionProvider<CommandSourceStack> PACK_NAMES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestPackNames(context, builder);
|
||||
private static final SuggestionProvider<CommandSourceStack> DIMENSION_NAMES = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestDimensionNames(context, builder);
|
||||
|
||||
@@ -152,21 +144,10 @@ public final class IrisModdedCommands {
|
||||
.then(Commands.argument("dimension", StringArgumentType.greedyString()).suggests(DIMENSION_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> info(context.getSource(), StringArgumentType.getString(context, "dimension")))));
|
||||
|
||||
root.then(Commands.literal("what").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> what(context.getSource()))
|
||||
.then(Commands.literal("block")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> whatBlock(context.getSource())))
|
||||
.then(Commands.literal("hand")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> whatHand(context.getSource())))
|
||||
.then(Commands.literal("markers")
|
||||
.then(Commands.argument("marker", StringArgumentType.greedyString()).suggests(MARKER_TYPES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> whatMarkers(context.getSource(), StringArgumentType.getString(context, "marker"))))));
|
||||
root.then(ModdedWhatCommands.tree());
|
||||
|
||||
root.then(Commands.literal("tp").requires(GATE)
|
||||
.then(Commands.argument("dimension", DimensionArgument.dimension()).suggests(DIMENSION_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> tp(context.getSource(), DimensionArgument.getDimension(context, "dimension"), null))
|
||||
.then(Commands.argument("player", EntityArgument.player())
|
||||
.executes((CommandContext<CommandSourceStack> context) -> tp(context.getSource(), DimensionArgument.getDimension(context, "dimension"), EntityArgument.getPlayer(context, "player"))))));
|
||||
root.then(teleportTree("teleport"));
|
||||
root.then(teleportTree("tp"));
|
||||
|
||||
root.then(Commands.literal("evacuate").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> evacuate(context.getSource(), null))
|
||||
@@ -178,6 +159,12 @@ public final class IrisModdedCommands {
|
||||
|
||||
root.then(Commands.literal("reload").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> reload(context.getSource())));
|
||||
root.then(Commands.literal("height").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> height(context.getSource())));
|
||||
root.then(Commands.literal("worlds").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> info(context.getSource(), null)));
|
||||
root.then(Commands.literal("accesslist").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> info(context.getSource(), null)));
|
||||
|
||||
root.then(gotoTree("goto"));
|
||||
root.then(gotoTree("find"));
|
||||
@@ -202,11 +189,16 @@ public final class IrisModdedCommands {
|
||||
|
||||
root.then(Commands.literal("wand").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedObjectCommands.giveWand(context.getSource())));
|
||||
root.then(Commands.literal("dust").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedObjectCommands.giveDust(context.getSource())));
|
||||
root.then(Commands.literal("d").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedObjectCommands.giveDust(context.getSource())));
|
||||
root.then(ModdedObjectCommands.tree("object"));
|
||||
root.then(ModdedObjectCommands.tree("o"));
|
||||
root.then(editTree());
|
||||
|
||||
root.then(createTree());
|
||||
root.then(createTree("create"));
|
||||
root.then(createTree("c"));
|
||||
|
||||
root.then(ModdedStudioCommands.tree("studio"));
|
||||
root.then(ModdedStudioCommands.tree("std"));
|
||||
@@ -227,9 +219,15 @@ public final class IrisModdedCommands {
|
||||
return root;
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> createTree() {
|
||||
return Commands.literal("create").requires(GATE)
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> createTree(String name) {
|
||||
return Commands.literal(name).requires(GATE)
|
||||
.then(Commands.argument("name", StringArgumentType.word())
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
ModdedWorldCommands.createWorld(
|
||||
context.getSource(),
|
||||
StringArgumentType.getString(context, "name"),
|
||||
"overworld",
|
||||
1337L))
|
||||
.then(Commands.argument("pack", StringArgumentType.string()).suggests(PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedWorldCommands.createWorld(context.getSource(),
|
||||
StringArgumentType.getString(context, "name"),
|
||||
@@ -242,6 +240,17 @@ public final class IrisModdedCommands {
|
||||
LongArgumentType.getLong(context, "seed"))))));
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> teleportTree(String name) {
|
||||
return Commands.literal(name).requires(GATE)
|
||||
.then(Commands.argument("dimension", DimensionArgument.dimension()).suggests(DIMENSION_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
tp(context.getSource(), DimensionArgument.getDimension(context, "dimension"), null))
|
||||
.then(Commands.argument("player", EntityArgument.player())
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
tp(context.getSource(), DimensionArgument.getDimension(context, "dimension"),
|
||||
EntityArgument.getPlayer(context, "player")))));
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> helpTree() {
|
||||
return Commands.literal("help")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedCommandHelp.send(context.getSource(), ""))
|
||||
@@ -252,9 +261,34 @@ public final class IrisModdedCommands {
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> downloadTree(String name) {
|
||||
return Commands.literal(name).requires(GATE)
|
||||
.then(Commands.argument("pack", StringArgumentType.word()).suggests(PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> download(context.getSource(), StringArgumentType.getString(context, "pack"), "stable"))
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
download(context.getSource(),
|
||||
StringArgumentType.getString(context, "pack"), "stable", false))
|
||||
.then(Commands.literal("force")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
download(context.getSource(),
|
||||
StringArgumentType.getString(context, "pack"), "stable", true)))
|
||||
.then(Commands.argument("overwrite", BoolArgumentType.bool())
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
download(context.getSource(),
|
||||
StringArgumentType.getString(context, "pack"), "stable",
|
||||
BoolArgumentType.getBool(context, "overwrite"))))
|
||||
.then(Commands.argument("branch", StringArgumentType.word())
|
||||
.executes((CommandContext<CommandSourceStack> context) -> download(context.getSource(), StringArgumentType.getString(context, "pack"), StringArgumentType.getString(context, "branch")))));
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
download(context.getSource(),
|
||||
StringArgumentType.getString(context, "pack"),
|
||||
StringArgumentType.getString(context, "branch"), false))
|
||||
.then(Commands.literal("force")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
download(context.getSource(),
|
||||
StringArgumentType.getString(context, "pack"),
|
||||
StringArgumentType.getString(context, "branch"), true)))
|
||||
.then(Commands.argument("overwrite", BoolArgumentType.bool())
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
download(context.getSource(),
|
||||
StringArgumentType.getString(context, "pack"),
|
||||
StringArgumentType.getString(context, "branch"),
|
||||
BoolArgumentType.getBool(context, "overwrite"))))));
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> metricsTree(String name) {
|
||||
@@ -380,11 +414,21 @@ public final class IrisModdedCommands {
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editBiome(context.getSource(), null))
|
||||
.then(Commands.argument("key", StringArgumentType.greedyString()).suggests(BIOME_KEYS)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editBiome(context.getSource(), StringArgumentType.getString(context, "key")))))
|
||||
.then(Commands.literal("b")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editBiome(context.getSource(), null))
|
||||
.then(Commands.argument("key", StringArgumentType.greedyString()).suggests(BIOME_KEYS)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editBiome(context.getSource(), StringArgumentType.getString(context, "key")))))
|
||||
.then(Commands.literal("region")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editRegion(context.getSource(), null))
|
||||
.then(Commands.argument("key", StringArgumentType.greedyString()).suggests(REGION_KEYS)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editRegion(context.getSource(), StringArgumentType.getString(context, "key")))))
|
||||
.then(Commands.literal("r")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editRegion(context.getSource(), null))
|
||||
.then(Commands.argument("key", StringArgumentType.greedyString()).suggests(REGION_KEYS)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editRegion(context.getSource(), StringArgumentType.getString(context, "key")))))
|
||||
.then(Commands.literal("dimension")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editDimension(context.getSource())))
|
||||
.then(Commands.literal("d")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> editDimension(context.getSource())));
|
||||
}
|
||||
|
||||
@@ -540,21 +584,18 @@ public final class IrisModdedCommands {
|
||||
MessageArgument.untrusted("locale", IrisSettings.get().getGeneral().getLanguage()),
|
||||
MessageArgument.trusted("activeLocale", IrisLanguage.activeLocale())
|
||||
));
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int whatHand(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_IT_INSPECTS));
|
||||
return 0;
|
||||
}
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
if (stack.isEmpty()) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_YOUR_MAIN_HAND_IS_EMPTY));
|
||||
return 0;
|
||||
}
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_HAND_X, MessageArgument.untrusted("value", BuiltInRegistries.ITEM.getKey(stack.getItem())), MessageArgument.untrusted("value2", stack.getCount())));
|
||||
private static int height(CommandSourceStack source) {
|
||||
ServerLevel level = source.getLevel();
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WORLD_HEIGHT_RANGE,
|
||||
MessageArgument.trusted("minY", level.getMinY()),
|
||||
MessageArgument.trusted("maxY", level.getMaxY())));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WORLD_HEIGHT_TOTAL,
|
||||
MessageArgument.trusted("height", level.getHeight())));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -662,15 +703,20 @@ public final class IrisModdedCommands {
|
||||
}
|
||||
iris++;
|
||||
String dimensionId = level.dimension().identifier().toString();
|
||||
if (filter != null && !dimensionId.contains(filter) && !irisGenerator.dimensionKey().contains(filter)) {
|
||||
String irisIdentity = ModdedWorldgenIds.generatorIdentity(irisGenerator.dimensionKey());
|
||||
if (filter != null && !dimensionId.contains(filter)
|
||||
&& !irisIdentity.contains(filter)
|
||||
&& !irisGenerator.dimensionKey().contains(filter)) {
|
||||
continue;
|
||||
}
|
||||
Engine engine = irisGenerator.engineIfBound();
|
||||
if (engine == null) {
|
||||
lines.add(dimensionId + ": pack=" + irisGenerator.dimensionKey() + " (engine not started yet)");
|
||||
lines.add(irisIdentity + ": pack=" + irisGenerator.dimensionKey()
|
||||
+ " world=" + dimensionId + " (engine not started yet)");
|
||||
continue;
|
||||
}
|
||||
lines.add(dimensionId + ": pack=" + engine.getDimension().getLoadKey()
|
||||
lines.add(irisIdentity + ": pack=" + engine.getDimension().getLoadKey()
|
||||
+ " world=" + dimensionId
|
||||
+ " seed=" + level.getSeed()
|
||||
+ " height=" + engine.getMinHeight() + ".." + engine.getMaxHeight()
|
||||
+ " generated=" + engine.getGenerated()
|
||||
@@ -691,154 +737,6 @@ public final class IrisModdedCommands {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int what(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_2));
|
||||
return 0;
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
Engine engine = engineFor(level);
|
||||
if (engine == null) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_6));
|
||||
return 0;
|
||||
}
|
||||
BlockPos pos = player.blockPosition();
|
||||
int relativeY = pos.getY() - engine.getMinHeight();
|
||||
try {
|
||||
IrisBiome biome = engine.getBiome(pos.getX(), relativeY, pos.getZ());
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_BIOME, MessageArgument.untrusted("value", biome.getLoadKey()), MessageArgument.untrusted("value2", biome.getName())));
|
||||
} catch (Throwable e) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_BIOME_LOOKUP_FAILED_2, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||
}
|
||||
try {
|
||||
IrisRegion region = engine.getRegion(pos.getX(), pos.getZ());
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_REGION, MessageArgument.untrusted("value", region.getLoadKey()), MessageArgument.untrusted("value2", region.getName())));
|
||||
} catch (Throwable e) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_REGION_LOOKUP_FAILED_2, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||
}
|
||||
try {
|
||||
IrisBiome cave = engine.getCaveBiome(pos.getX(), relativeY, pos.getZ());
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_CAVE_BIOME, MessageArgument.untrusted("value", cave == null ? IrisLanguage.plain(RuntimeUiMessages.STATUS_NONE) : cave.getLoadKey())));
|
||||
} catch (Throwable e) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_CAVE_BIOME_LOOKUP_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName())));
|
||||
}
|
||||
int surfaceY = level.getHeight(Heightmap.Types.WORLD_SURFACE, pos.getX(), pos.getZ());
|
||||
BlockState surface = level.getBlockState(new BlockPos(pos.getX(), surfaceY - 1, pos.getZ()));
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SURFACE_BLOCK_Y, MessageArgument.untrusted("value", BuiltInRegistries.BLOCK.getKey(surface.getBlock())), MessageArgument.untrusted("value2", (surfaceY - 1))));
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_POSITION_CHUNK, MessageArgument.untrusted("value", pos.getX()), MessageArgument.untrusted("value2", pos.getY()), MessageArgument.untrusted("value3", pos.getZ()), MessageArgument.untrusted("value4", (pos.getX() >> 4)), MessageArgument.untrusted("value5", (pos.getZ() >> 4))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int whatBlock(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_IT_INSPECTS_2));
|
||||
return 0;
|
||||
}
|
||||
HitResult hit = player.pick(128.0D, 1.0F, false);
|
||||
if (hit.getType() != HitResult.Type.BLOCK || !(hit instanceof BlockHitResult blockHit)) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_LOOK_AT_BLOCK_NOT_SKY));
|
||||
return 0;
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
BlockPos pos = blockHit.getBlockPos();
|
||||
BlockState state = level.getBlockState(pos);
|
||||
PlatformBlockState platform = ModdedBlockState.of(state, null);
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_BLOCK_Y, MessageArgument.untrusted("value", platform.key()), MessageArgument.untrusted("value2", pos.getY())));
|
||||
List<String> flags = new ArrayList<>();
|
||||
if (platform.isSolid()) {
|
||||
flags.add("solid");
|
||||
}
|
||||
if (platform.isFluid()) {
|
||||
flags.add("fluid");
|
||||
}
|
||||
if (platform.isWater()) {
|
||||
flags.add("water");
|
||||
}
|
||||
if (platform.isWaterLogged()) {
|
||||
flags.add("waterlogged");
|
||||
}
|
||||
if (platform.isStorage()) {
|
||||
flags.add("storage (loot capable)");
|
||||
}
|
||||
if (platform.isLit()) {
|
||||
flags.add("lit");
|
||||
}
|
||||
if (platform.isFoliage()) {
|
||||
flags.add("foliage");
|
||||
}
|
||||
if (platform.isFoliagePlantable()) {
|
||||
flags.add("plantable foliage");
|
||||
}
|
||||
if (platform.isDecorant()) {
|
||||
flags.add("decorant");
|
||||
}
|
||||
if (platform.isOre()) {
|
||||
flags.add("ore");
|
||||
}
|
||||
if (platform.hasTileEntity()) {
|
||||
flags.add("tile entity");
|
||||
}
|
||||
if (flags.isEmpty()) {
|
||||
ok(source, IrisLanguage.plain(IrisMessages.MODDED_PROPERTIES_NONE));
|
||||
return 1;
|
||||
}
|
||||
ok(source, IrisLanguage.plain(
|
||||
IrisMessages.MODDED_PROPERTIES,
|
||||
MessageArgument.untrusted("properties", String.join(", ", flags))
|
||||
));
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int whatMarkers(CommandSourceStack source, String markerRaw) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_MARKERS_RENDER));
|
||||
return 0;
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
Engine engine = engineFor(level);
|
||||
if (engine == null) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_7));
|
||||
return 0;
|
||||
}
|
||||
String marker = markerRaw.trim();
|
||||
BlockPos origin = player.blockPosition();
|
||||
int chunkX = origin.getX() >> 4;
|
||||
int chunkZ = origin.getZ() >> 4;
|
||||
MinecraftServer server = source.getServer();
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SCANNING_MARKERS_AROUND_YOU, MessageArgument.untrusted("marker", marker)));
|
||||
Thread thread = new Thread(() -> {
|
||||
List<int[]> hits = new ArrayList<>();
|
||||
MatterMarker matterMarker = new MatterMarker(marker);
|
||||
try {
|
||||
for (int cx = chunkX - 4; cx <= chunkX + 4; cx++) {
|
||||
for (int cz = chunkZ - 4; cz <= chunkZ + 4; cz++) {
|
||||
for (IrisPosition position : engine.getMantle().findMarkers(cx, cz, matterMarker)) {
|
||||
hits.add(new int[]{position.getX(), position.getY(), position.getZ()});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris marker scan failed for {}", marker, e);
|
||||
server.execute(() -> fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_MARKER_SCAN_FAILED, MessageArgument.untrusted("value", e.getClass().getSimpleName()))));
|
||||
return;
|
||||
}
|
||||
server.execute(() -> {
|
||||
for (int[] hit : hits) {
|
||||
level.sendParticles(player, MARKER_DUST, true, true,
|
||||
hit[0] + 0.5D, hit[1] + 1.0D, hit[2] + 0.5D,
|
||||
3, 0.2D, 0.2D, 0.2D, 0.0D);
|
||||
}
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_FOUND_NEARBY_MARKER_S, MessageArgument.untrusted("value", hits.size()), MessageArgument.untrusted("marker", marker)));
|
||||
});
|
||||
}, "Iris Marker Scan");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int gotoBiome(CommandSourceStack source, String key) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
@@ -1255,7 +1153,24 @@ public final class IrisModdedCommands {
|
||||
try (GenerationSessionLease lease = engine.acquireGenerationLease("modded_locator_teleport");
|
||||
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
||||
int blockY = engine.getMinHeight() + engine.getHeight(blockX, blockZ, false) + 2;
|
||||
player.teleportTo(level, blockX + 0.5D, blockY, blockZ + 0.5D, Set.<Relative>of(), player.getYRot(), player.getXRot(), false);
|
||||
boolean teleported = player.teleportTo(
|
||||
level,
|
||||
blockX + 0.5D,
|
||||
blockY,
|
||||
blockZ + 0.5D,
|
||||
Set.<Relative>of(),
|
||||
player.getYRot(),
|
||||
player.getXRot(),
|
||||
false);
|
||||
if (!teleported) {
|
||||
fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_FOUND_AT_BUT_TELEPORTATION_FAILED,
|
||||
MessageArgument.untrusted("label", label),
|
||||
MessageArgument.trusted("targetX", blockX),
|
||||
MessageArgument.trusted("clampedY", blockY),
|
||||
MessageArgument.trusted("targetZ", blockZ)));
|
||||
return;
|
||||
}
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_TELEPORTED_AT_2, MessageArgument.untrusted("label", label), MessageArgument.untrusted("blockX", blockX), MessageArgument.untrusted("blockY", blockY), MessageArgument.untrusted("blockZ", blockZ)));
|
||||
} catch (GenerationSessionException e) {
|
||||
fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_ENGINE_CHANGED_WHILE_LOCATING_TRY_AGAIN, MessageArgument.untrusted("label", label)));
|
||||
@@ -1294,22 +1209,32 @@ public final class IrisModdedCommands {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int download(CommandSourceStack source, String pack, String branch) {
|
||||
MinecraftServer server = source.getServer();
|
||||
private static int download(CommandSourceStack source, String pack,
|
||||
String branch, boolean forceOverwrite) {
|
||||
boolean defaultOverworld = PackDownloader.isDefaultOverworld(pack);
|
||||
String downloadSource = defaultOverworld ? "beta release" : "branch " + branch;
|
||||
String baseDownloadSource = defaultOverworld ? "beta release" : "branch " + branch;
|
||||
String downloadSource = forceOverwrite
|
||||
? baseDownloadSource + IrisLanguage.plain(RuntimeUiMessages.DOWNLOAD_OVERWRITE_SUFFIX)
|
||||
: baseDownloadSource;
|
||||
ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_DOWNLOADING_IRISDIMENSIONS, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("downloadSource", downloadSource)));
|
||||
Thread thread = new Thread(() -> {
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, branch,
|
||||
(String message) -> server.execute(() -> ok(source, message)));
|
||||
if (installed) {
|
||||
server.execute(() -> ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_INSTALLED_ITS_EXACT_DIMENSION_TYPES_CUSTOM_BIOMES_JOIN_FORCED, MessageArgument.untrusted("pack", pack))));
|
||||
} else {
|
||||
server.execute(() -> fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("downloadSource", downloadSource))));
|
||||
ModdedScheduler scheduler = ModdedEngineBootstrap.schedulerOrNull();
|
||||
if (scheduler == null) {
|
||||
fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE,
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("downloadSource", downloadSource)));
|
||||
return 0;
|
||||
}
|
||||
}, "Iris Pack Download");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
scheduler.async(() -> {
|
||||
boolean installed = ModdedPackInstaller.install(
|
||||
ModdedEngineBootstrap.loader().configDir(), pack, branch, forceOverwrite,
|
||||
(String message) -> scheduler.global(() -> ok(source, message)));
|
||||
if (installed) {
|
||||
scheduler.global(() -> ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_INSTALLED_ITS_EXACT_DIMENSION_TYPES_CUSTOM_BIOMES_JOIN_FORCED, MessageArgument.untrusted("pack", pack))));
|
||||
} else {
|
||||
scheduler.global(() -> fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_PACK_DOWNLOAD_FAILED_SEE_CONSOLE, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("downloadSource", downloadSource))));
|
||||
}
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1416,15 +1341,27 @@ public final class IrisModdedCommands {
|
||||
|
||||
private static CompletableFuture<Suggestions> suggestPackNames(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) {
|
||||
ModdedCommandFeedback.tab(context.getSource());
|
||||
List<String> names = new ArrayList<>();
|
||||
Set<String> names = new TreeSet<>();
|
||||
names.add("overworld");
|
||||
try {
|
||||
File packs = ModdedEngineBootstrap.loader().configDir().resolve("irisworldgen").resolve("packs").toFile();
|
||||
File[] children = packs.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
if (child.isDirectory() && !names.contains(child.getName())) {
|
||||
names.add(child.getName());
|
||||
if (!child.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
String packName = child.getName();
|
||||
names.add(packName);
|
||||
File dimensions = new File(child, "dimensions");
|
||||
File[] dimensionFiles = dimensions.listFiles(
|
||||
(File directory, String name) -> name.endsWith(".json"));
|
||||
if (dimensionFiles == null) {
|
||||
continue;
|
||||
}
|
||||
for (File dimensionFile : dimensionFiles) {
|
||||
String fileName = dimensionFile.getName();
|
||||
names.add(packName + ":" + fileName.substring(0, fileName.length() - 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-17
@@ -18,18 +18,18 @@
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.IrisMessages;
|
||||
import art.arcane.iris.core.localization.ModdedHelpMessages;
|
||||
import art.arcane.volmlib.util.director.help.DirectorHelpMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import art.arcane.volmlib.util.localization.TextKey;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import art.arcane.iris.core.localization.IrisMessages;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.ModdedHelpMessages;
|
||||
import art.arcane.volmlib.util.director.help.DirectorHelpMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import art.arcane.volmlib.util.localization.TextKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -60,21 +60,24 @@ final class ModdedCommandHelp {
|
||||
SECTIONS.put("", List.of(
|
||||
Entry.command("version", "", ModdedHelpMessages.COMMAND_VERSION_PRINT_VERSION_INFORMATION),
|
||||
Entry.command("info", "[dimension]", ModdedHelpMessages.COMMAND_INFO_LIST_LOADED_IRIS_DIMENSIONS_AND_PACK_DETAILS),
|
||||
Entry.command("what", "[block|hand|markers]", ModdedHelpMessages.COMMAND_WHAT_INSPECT_THE_IRIS_BIOME_REGION_CAVE_BIOME_SURFACE_AND_CHUNK_AT_YOUR),
|
||||
Entry.command("what", "[here|biome|region|block|hand|markers]", ModdedHelpMessages.COMMAND_WHAT_INSPECT_THE_IRIS_BIOME_REGION_CAVE_BIOME_SURFACE_AND_CHUNK_AT_YOUR),
|
||||
Entry.group("find", ModdedHelpMessages.GROUP_FIND_FIND_AND_TELEPORT_TO_IRIS_BIOMES_REGIONS_OBJECTS_IRIS_STRUCTURES_NATIVE_STRUCTURES, "goto"),
|
||||
Entry.command("tp", "<dimension> [player]", ModdedHelpMessages.COMMAND_TP_TELEPORT_YOURSELF_OR_A_NAMED_PLAYER_INTO_A_LOADED_IRIS_DIMENSION),
|
||||
Entry.command("teleport", "<dimension> [player]", ModdedHelpMessages.COMMAND_TP_TELEPORT_YOURSELF_OR_A_NAMED_PLAYER_INTO_A_LOADED_IRIS_DIMENSION, "tp"),
|
||||
Entry.command("evacuate", "[dimension]", ModdedHelpMessages.COMMAND_EVACUATE_TELEPORT_EVERY_PLAYER_OUT_OF_AN_IRIS_DIMENSION_TO_THE_PRIMARY_WORLD),
|
||||
Entry.command("seed", "", ModdedHelpMessages.COMMAND_SEED_PRINT_WORLD_AND_ENGINE_SEED_INFORMATION),
|
||||
Entry.command("debug", "", ModdedHelpMessages.COMMAND_DEBUG_TOGGLE_IRIS_DEBUG_LOGGING_AND_SAVE_SETTINGS_JSON),
|
||||
Entry.command("reload", "", ModdedHelpMessages.COMMAND_RELOAD_RELOAD_SETTINGS_JSON_ALSO_HOTLOADED_AUTOMATICALLY_EVERY_3S),
|
||||
Entry.command("download", "<pack> [branch]", ModdedHelpMessages.COMMAND_DOWNLOAD_DOWNLOAD_A_PACK_PROJECT, "dl"),
|
||||
Entry.command("download", "<pack> [branch] [overwrite]", ModdedHelpMessages.COMMAND_DOWNLOAD_DOWNLOAD_A_PACK_PROJECT, "dl"),
|
||||
Entry.command("metrics", "", ModdedHelpMessages.COMMAND_METRICS_PRINT_GENERATION_METRICS_FOR_YOUR_CURRENT_IRIS_DIMENSION, "measure"),
|
||||
Entry.command("regen", "[radius]", ModdedHelpMessages.COMMAND_REGEN_DELETE_AND_REGENERATE_NEARBY_CHUNKS_IN_PLACE, "rg"),
|
||||
Entry.group("pregen", ModdedHelpMessages.GROUP_PREGEN_PREGENERATE_AN_IRIS_DIMENSION, "pregenerate"),
|
||||
Entry.command("wand", "", ModdedHelpMessages.COMMAND_WAND_GET_AN_IRIS_OBJECT_WAND),
|
||||
Entry.command("dust", "", ModdedHelpMessages.COMMAND_DUST_GET_DUST_THAT_REVEALS_OBJECT_PLACEMENTS, "d"),
|
||||
Entry.group("object", ModdedHelpMessages.GROUP_OBJECT_OBJECT_WAND_SAVE_PASTE_ANALYZE_AND_UNDO_TOOLS, "o"),
|
||||
Entry.group("edit", ModdedHelpMessages.GROUP_EDIT_OPEN_PACK_BIOME_REGION_AND_DIMENSION_JSON_FILES_IN_YOUR_DESKTOP_EDITOR),
|
||||
Entry.command("create", "<name> <pack|pack:dimensionKey> [seed]", ModdedHelpMessages.COMMAND_CREATE_CREATE_AND_INJECT_A_PERSISTENT_IRIS_DIMENSION_QUOTE_PACK_DIMENSIONKEY_TO_PICK),
|
||||
Entry.command("create", "<name> [pack|pack:dimensionKey] [seed]", ModdedHelpMessages.COMMAND_CREATE_CREATE_AND_INJECT_A_PERSISTENT_IRIS_DIMENSION_QUOTE_PACK_DIMENSIONKEY_TO_PICK, "c"),
|
||||
Entry.command("height", "", ModdedHelpMessages.COMMAND_HEIGHT_PRINT_WORLD_HEIGHT),
|
||||
Entry.command("worlds", "", ModdedHelpMessages.COMMAND_WORLDS_LIST_WORLD_ACCESS, "accesslist"),
|
||||
Entry.group("studio", ModdedHelpMessages.GROUP_STUDIO_PACK_PROJECT_CREATION_PACKAGING_AND_REPORTS, "std", "s"),
|
||||
Entry.group("pack", ModdedHelpMessages.GROUP_PACK_PACK_VALIDATION_AND_MAINTENANCE, "pk"),
|
||||
Entry.group("world", ModdedHelpMessages.GROUP_WORLD_RUNTIME_IRIS_DIMENSION_CREATION_REMOVAL_AND_STATUS, "w"),
|
||||
@@ -83,6 +86,14 @@ final class ModdedCommandHelp {
|
||||
Entry.command("goldenhash", "[radius] [threads] [capture|verify]", ModdedHelpMessages.COMMAND_GOLDENHASH_GENERATE_DETERMINISTIC_BLOCK_HASHES_FOR_PARITY_TESTING, "gold"),
|
||||
Entry.group("developer", ModdedHelpMessages.GROUP_DEVELOPER_DEVELOPER_DIAGNOSTICS_SENTRY_TEST_NETWORK_INTERFACES_REGION_FILE_SCAN, "dev")
|
||||
));
|
||||
SECTIONS.put("what", List.of(
|
||||
Entry.command("here", "", ModdedHelpMessages.COMMAND_WHAT_HERE_INSPECT_CURRENT_IRIS_CONTEXT),
|
||||
Entry.command("biome", "", ModdedHelpMessages.COMMAND_WHAT_BIOME_INSPECT_CURRENT_BIOME),
|
||||
Entry.command("region", "", ModdedHelpMessages.COMMAND_WHAT_REGION_INSPECT_CURRENT_REGION),
|
||||
Entry.command("block", "", ModdedHelpMessages.COMMAND_WHAT_BLOCK_INSPECT_TARGET_BLOCK),
|
||||
Entry.command("hand", "", ModdedHelpMessages.COMMAND_WHAT_HAND_INSPECT_HELD_ITEM),
|
||||
Entry.command("markers", "<marker>", ModdedHelpMessages.COMMAND_WHAT_MARKERS_REVEAL_NEARBY_MARKERS)
|
||||
));
|
||||
SECTIONS.put("find", List.of(
|
||||
Entry.command("biome", "<key>", ModdedHelpMessages.COMMAND_BIOME_FIND_AN_IRIS_BIOME),
|
||||
Entry.command("region", "<key>", ModdedHelpMessages.COMMAND_REGION_FIND_AN_IRIS_REGION),
|
||||
@@ -92,9 +103,9 @@ final class ModdedCommandHelp {
|
||||
));
|
||||
SECTIONS.put("goto", SECTIONS.get("find"));
|
||||
SECTIONS.put("edit", List.of(
|
||||
Entry.command("biome", "[key]", ModdedHelpMessages.COMMAND_BIOME_OPEN_A_BIOME_JSON_IN_YOUR_DESKTOP_EDITOR_NO_KEY_OPENS_THE),
|
||||
Entry.command("region", "[key]", ModdedHelpMessages.COMMAND_REGION_OPEN_A_REGION_JSON_IN_YOUR_DESKTOP_EDITOR_NO_KEY_OPENS_THE),
|
||||
Entry.command("dimension", "", ModdedHelpMessages.COMMAND_DIMENSION_OPEN_THE_CURRENT_PACK_S_DIMENSION_JSON_IN_YOUR_DESKTOP_EDITOR)
|
||||
Entry.command("biome", "[key]", ModdedHelpMessages.COMMAND_BIOME_OPEN_A_BIOME_JSON_IN_YOUR_DESKTOP_EDITOR_NO_KEY_OPENS_THE, "b"),
|
||||
Entry.command("region", "[key]", ModdedHelpMessages.COMMAND_REGION_OPEN_A_REGION_JSON_IN_YOUR_DESKTOP_EDITOR_NO_KEY_OPENS_THE, "r"),
|
||||
Entry.command("dimension", "", ModdedHelpMessages.COMMAND_DIMENSION_OPEN_THE_CURRENT_PACK_S_DIMENSION_JSON_IN_YOUR_DESKTOP_EDITOR, "d")
|
||||
));
|
||||
SECTIONS.put("pregen", List.of(
|
||||
Entry.command("start", "<radius> [dimension] [at] [x] [z] [gui] [sync] [nocache]", ModdedHelpMessages.COMMAND_START_START_PREGENERATION_RADIUS_IN_BLOCKS_RESUMABLE_CHECKPOINT_CACHE_ON_BY_DEFAULT_CENTER),
|
||||
@@ -118,12 +129,15 @@ final class ModdedCommandHelp {
|
||||
Entry.command("analyze", "<key>", ModdedHelpMessages.COMMAND_ANALYZE_SHOW_OBJECT_COMPOSITION),
|
||||
Entry.command("shrink", "<key>", ModdedHelpMessages.COMMAND_SHRINK_SHRINK_AN_OBJECT_TO_ITS_MINIMUM_SIZE),
|
||||
Entry.command("plausibilize", "<key|prefix/> [dryrun=true] [reach=N]", ModdedHelpMessages.COMMAND_PLAUSIBILIZE_GROW_BRANCHES_SO_TREE_LEAVES_SURVIVE_VANILLA_DECAY),
|
||||
Entry.command("undo", "[amount]", ModdedHelpMessages.COMMAND_UNDO_UNDO_PASTED_OBJECTS, "u")
|
||||
Entry.command("undo", "[amount]", ModdedHelpMessages.COMMAND_UNDO_UNDO_PASTED_OBJECTS, "u"),
|
||||
Entry.command("we", "", ModdedHelpMessages.COMMAND_OBJECT_WE_BUKKIT_ONLY),
|
||||
Entry.command("studio", "", ModdedHelpMessages.COMMAND_OBJECT_STUDIO_BUKKIT_ONLY),
|
||||
Entry.command("convert", "", ModdedHelpMessages.COMMAND_OBJECT_CONVERT_BUKKIT_ONLY)
|
||||
));
|
||||
SECTIONS.put("o", SECTIONS.get("object"));
|
||||
SECTIONS.put("studio", List.of(
|
||||
Entry.command("create", "<name> [template]", ModdedHelpMessages.COMMAND_CREATE_CREATE_A_NEW_PACK_PROJECT, "+"),
|
||||
Entry.command("package", "[pack]", ModdedHelpMessages.COMMAND_PACKAGE_PACKAGE_A_DIMENSION_INTO_A_COMPRESSED_FORMAT),
|
||||
Entry.command("create", "[name] [template]", ModdedHelpMessages.COMMAND_CREATE_CREATE_A_NEW_PACK_PROJECT, "+"),
|
||||
Entry.command("package", "[pack]", ModdedHelpMessages.COMMAND_PACKAGE_PACKAGE_A_DIMENSION_INTO_A_COMPRESSED_FORMAT, "pkg"),
|
||||
Entry.command("version", "[pack]", ModdedHelpMessages.COMMAND_VERSION_PRINT_A_PACK_VERSION),
|
||||
Entry.command("regions", "[radius]", ModdedHelpMessages.COMMAND_REGIONS_CALCULATE_NEARBY_REGION_DISTRIBUTION),
|
||||
Entry.command("open", "<pack> [seed]", ModdedHelpMessages.COMMAND_OPEN_OPEN_A_TEMPORARY_STUDIO_DIMENSION_FOR_A_PACK, "o"),
|
||||
@@ -134,7 +148,11 @@ final class ModdedCommandHelp {
|
||||
Entry.command("map", "", ModdedHelpMessages.COMMAND_MAP_OPEN_THE_VISION_MAP_GUI_ON_THE_SERVER_DISPLAY, "render"),
|
||||
Entry.command("vscode", "[pack]", ModdedHelpMessages.COMMAND_VSCODE_REGENERATE_THE_CODE_WORKSPACE_FOR_A_PACK_AND_OPEN_IT_IN_YOUR, "vsc"),
|
||||
Entry.command("update", "[pack]", ModdedHelpMessages.COMMAND_UPDATE_REGENERATE_THE_CODE_WORKSPACE_FOR_A_PACK),
|
||||
Entry.command("importvanilla", "", ModdedHelpMessages.COMMAND_IMPORTVANILLA_EXPLAIN_VANILLA_IMPORT_WORKFLOW, "importv", "iv")
|
||||
Entry.command("importvanilla", "", ModdedHelpMessages.COMMAND_IMPORTVANILLA_EXPLAIN_VANILLA_IMPORT_WORKFLOW, "importv", "iv"),
|
||||
Entry.command("loot", "", ModdedHelpMessages.COMMAND_STUDIO_LOOT_BUKKIT_ONLY),
|
||||
Entry.command("profile", "", ModdedHelpMessages.COMMAND_STUDIO_PROFILE_BUKKIT_ONLY),
|
||||
Entry.command("spawn", "", ModdedHelpMessages.COMMAND_STUDIO_SPAWN_BUKKIT_ONLY, "summon"),
|
||||
Entry.command("objects", "", ModdedHelpMessages.COMMAND_STUDIO_OBJECTS_BUKKIT_ONLY, "find-objects")
|
||||
));
|
||||
SECTIONS.put("std", SECTIONS.get("studio"));
|
||||
SECTIONS.put("s", SECTIONS.get("studio"));
|
||||
@@ -148,6 +166,7 @@ final class ModdedCommandHelp {
|
||||
SECTIONS.put("world", List.of(
|
||||
Entry.command("enable", "<dimension> <pack|pack:dimensionKey> [seed|random]", ModdedHelpMessages.COMMAND_ENABLE_CREATE_AND_INJECT_A_PERSISTENT_IRIS_DIMENSION_AT_RUNTIME_DOWNLOADS_THE_PACK, "create"),
|
||||
Entry.command("replace-overworld", "<pack|pack:dimensionKey> [seed|random]", ModdedHelpMessages.COMMAND_REPLACE_OVERWORLD_INJECT_AN_IRIS_PRIMARY_WORLD_AND_ROUTE_PLAYERS_THERE_INSTEAD_OF_THE),
|
||||
Entry.command("mainworld", "<pack|pack:dimensionKey|off> [seed|random]", ModdedHelpMessages.COMMAND_MAINWORLD_CONFIGURE_PRIMARY_WORLD_PRESET),
|
||||
Entry.command("disable", "<dimension>", ModdedHelpMessages.COMMAND_DISABLE_EVACUATE_AND_UNLOAD_AN_IRIS_DIMENSION_WORLD_DATA_ON_DISK_IS_KEPT),
|
||||
Entry.command("delete", "<dimension>", ModdedHelpMessages.COMMAND_DELETE_DISABLE_AN_IRIS_DIMENSION_AND_WIPE_ITS_CHUNK_AND_MANTLE_DATA_FROM, "remove", "rm"),
|
||||
Entry.command("list", "", ModdedHelpMessages.COMMAND_LIST_LIST_LOADED_IRIS_DIMENSIONS, "ls"),
|
||||
@@ -183,6 +202,24 @@ final class ModdedCommandHelp {
|
||||
private ModdedCommandHelp() {
|
||||
}
|
||||
|
||||
static boolean documents(String section, String command) {
|
||||
List<Entry> entries = SECTIONS.get(section);
|
||||
if (entries == null) {
|
||||
return false;
|
||||
}
|
||||
for (Entry entry : entries) {
|
||||
if (entry.name().equals(command)) {
|
||||
return true;
|
||||
}
|
||||
for (String alias : entry.aliases()) {
|
||||
if (alias.equals(command)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int send(CommandSourceStack source, String path) {
|
||||
Request request = parse(path);
|
||||
List<Entry> entries = SECTIONS.get(request.section());
|
||||
|
||||
+353
-96
@@ -21,16 +21,31 @@ package art.arcane.iris.modded.command;
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.GenerationSessionException;
|
||||
import art.arcane.iris.engine.framework.GenerationSessionLease;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.modded.ModdedBlockState;
|
||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||
import art.arcane.iris.modded.ModdedScheduler;
|
||||
import art.arcane.iris.util.project.context.IrisContext;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -40,12 +55,18 @@ import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class ModdedDustRevealer {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final int MAX_HITS = 2048;
|
||||
private static final int MAX_HITS = 2_048;
|
||||
private static final int PARTICLE_BATCH_SIZE = 64;
|
||||
private static final DustParticleOptions REVEAL_DUST = new DustParticleOptions(0xFFD24A, 1.2F);
|
||||
private static final ConcurrentHashMap<UUID, RevealRun> ACTIVE_RUNS = new ConcurrentHashMap<>();
|
||||
|
||||
private ModdedDustRevealer() {
|
||||
}
|
||||
@@ -53,51 +74,91 @@ public final class ModdedDustRevealer {
|
||||
public static void reveal(ServerPlayer player, ServerLevel level, BlockPos pos) {
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
player.sendSystemMessage(Component.literal(IrisLanguage.plain(RuntimeUiMessages.DUST_IRIS_WORLD_REQUIRED)));
|
||||
player.sendSystemMessage(Component.literal(
|
||||
IrisLanguage.plain(RuntimeUiMessages.DUST_IRIS_WORLD_REQUIRED)));
|
||||
return;
|
||||
}
|
||||
describe(player, level, engine, pos);
|
||||
|
||||
int relativeY = pos.getY() - engine.getMinHeight();
|
||||
String key = safe(() -> engine.getObjectPlacementKey(pos.getX(), relativeY, pos.getZ()));
|
||||
String key = safe(
|
||||
"object lookup at " + coordinates(pos),
|
||||
() -> engine.getObjectPlacementKey(pos.getX(), relativeY, pos.getZ()));
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
ModdedScheduler scheduler = ModdedEngineBootstrap.schedulerOrNull();
|
||||
if (scheduler == null) {
|
||||
player.sendSystemMessage(Component.literal(
|
||||
IrisLanguage.plain(RuntimeUiMessages.DUST_REVEAL_FAILED)));
|
||||
return;
|
||||
}
|
||||
level.playSound(null, pos, SoundEvents.LODESTONE_COMPASS_LOCK,
|
||||
SoundSource.PLAYERS, 1.0F, 0.1F);
|
||||
player.sendSystemMessage(Component.literal(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_FOUND_OBJECT,
|
||||
MessageArgument.untrusted("object", key)
|
||||
)));
|
||||
MinecraftServer server = level.getServer();
|
||||
BlockPos origin = pos.immutable();
|
||||
Thread thread = new Thread(() -> {
|
||||
List<BlockPos> hits = collect(engine, level, origin, key);
|
||||
server.execute(() -> {
|
||||
for (BlockPos hit : hits) {
|
||||
level.sendParticles(player, REVEAL_DUST, true, true,
|
||||
hit.getX() + 0.5D, hit.getY() + 0.5D, hit.getZ() + 0.5D,
|
||||
3, 0.25D, 0.25D, 0.25D, 0.0D);
|
||||
|
||||
RevealRun run = new RevealRun(
|
||||
player.getUUID(),
|
||||
player,
|
||||
level,
|
||||
engine,
|
||||
pos.immutable(),
|
||||
key,
|
||||
level.getMinY(),
|
||||
level.getMaxY(),
|
||||
new AtomicBoolean());
|
||||
RevealRun previous = ACTIVE_RUNS.put(player.getUUID(), run);
|
||||
if (previous != null) {
|
||||
previous.cancelled().set(true);
|
||||
}
|
||||
player.sendSystemMessage(Component.literal(IrisLanguage.plain(
|
||||
hits.size() >= MAX_HITS ? RuntimeUiMessages.DUST_REVEALED_CAPPED : RuntimeUiMessages.DUST_REVEALED,
|
||||
MessageArgument.trusted("count", hits.size()),
|
||||
MessageArgument.untrusted("object", key)
|
||||
)));
|
||||
});
|
||||
}, "Iris Dust Revealer");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
scheduler.async(() -> discover(scheduler, run));
|
||||
}
|
||||
|
||||
private static List<BlockPos> collect(Engine engine, ServerLevel level, BlockPos origin, String key) {
|
||||
static void clear() {
|
||||
for (RevealRun run : ACTIVE_RUNS.values()) {
|
||||
run.cancelled().set(true);
|
||||
}
|
||||
ACTIVE_RUNS.clear();
|
||||
}
|
||||
|
||||
private static void discover(ModdedScheduler scheduler, RevealRun run) {
|
||||
try (GenerationSessionLease lease = run.engine().acquireGenerationLease("modded_dust_reveal");
|
||||
IrisContext.Scope ignored = IrisContext.open(run.engine(), lease.sessionId(), null)) {
|
||||
List<BlockPos> hits = collect(run);
|
||||
if (!run.cancelled().get()) {
|
||||
scheduler.global(() -> revealBatch(scheduler, run, hits, 0));
|
||||
}
|
||||
} catch (GenerationSessionException error) {
|
||||
revealFailure(scheduler, run, error);
|
||||
} catch (Throwable error) {
|
||||
revealFailure(scheduler, run, error);
|
||||
}
|
||||
}
|
||||
|
||||
static List<BlockPos> collect(RevealRun run) {
|
||||
return collect(
|
||||
run.origin(),
|
||||
run.key(),
|
||||
run.engine().getMinHeight(),
|
||||
run.minY(),
|
||||
run.maxY(),
|
||||
run.cancelled(),
|
||||
(int x, int relativeY, int z) ->
|
||||
run.engine().getObjectPlacementKey(x, relativeY, z));
|
||||
}
|
||||
|
||||
static List<BlockPos> collect(BlockPos origin, String key, int engineMinY,
|
||||
int minY, int maxY, AtomicBoolean cancelled,
|
||||
ObjectPlacementLookup lookup) {
|
||||
List<BlockPos> hits = new ArrayList<>();
|
||||
Set<BlockPos> visited = new HashSet<>();
|
||||
Deque<BlockPos> frontier = new ArrayDeque<>();
|
||||
frontier.add(origin);
|
||||
visited.add(origin);
|
||||
int minY = level.getMinY();
|
||||
int maxY = minY + level.getHeight();
|
||||
try {
|
||||
while (!frontier.isEmpty() && hits.size() < MAX_HITS) {
|
||||
while (!frontier.isEmpty() && hits.size() < MAX_HITS && !cancelled.get()) {
|
||||
BlockPos current = frontier.poll();
|
||||
hits.add(current);
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
@@ -107,11 +168,13 @@ public final class ModdedDustRevealer {
|
||||
continue;
|
||||
}
|
||||
BlockPos next = current.offset(dx, dy, dz);
|
||||
if (next.getY() < minY || next.getY() >= maxY || visited.contains(next)) {
|
||||
if (next.getY() < minY
|
||||
|| next.getY() >= maxY
|
||||
|| !visited.add(next)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(next);
|
||||
String nextKey = engine.getObjectPlacementKey(next.getX(), next.getY() - engine.getMinHeight(), next.getZ());
|
||||
String nextKey = lookup.at(
|
||||
next.getX(), next.getY() - engineMinY, next.getZ());
|
||||
if (key.equals(nextKey)) {
|
||||
frontier.add(next);
|
||||
}
|
||||
@@ -119,10 +182,59 @@ public final class ModdedDustRevealer {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Iris dust reveal BFS failed for {}", key, e);
|
||||
return List.copyOf(hits);
|
||||
}
|
||||
return hits;
|
||||
|
||||
private static void revealBatch(ModdedScheduler scheduler, RevealRun run,
|
||||
List<BlockPos> hits, int from) {
|
||||
if (!active(run)) {
|
||||
return;
|
||||
}
|
||||
int to = Math.min(hits.size(), from + PARTICLE_BATCH_SIZE);
|
||||
for (int index = from; index < to; index++) {
|
||||
BlockPos hit = hits.get(index);
|
||||
run.level().sendParticles(run.player(), REVEAL_DUST, true, true,
|
||||
hit.getX() + 0.5D, hit.getY() + 0.5D, hit.getZ() + 0.5D,
|
||||
3, 0.25D, 0.25D, 0.25D, 0.0D);
|
||||
}
|
||||
if (to > from) {
|
||||
BlockPos soundAt = hits.get(from);
|
||||
run.level().playSound(null, soundAt, SoundEvents.AMETHYST_BLOCK_CHIME,
|
||||
SoundSource.PLAYERS, 0.5F,
|
||||
ThreadLocalRandom.current().nextFloat(0.2F, 2.0F));
|
||||
}
|
||||
if (to < hits.size()) {
|
||||
scheduler.laterGlobal(() -> revealBatch(scheduler, run, hits, to), 1);
|
||||
return;
|
||||
}
|
||||
ACTIVE_RUNS.remove(run.playerId(), run);
|
||||
run.player().sendSystemMessage(Component.literal(IrisLanguage.plain(
|
||||
hits.size() >= MAX_HITS
|
||||
? RuntimeUiMessages.DUST_REVEALED_CAPPED
|
||||
: RuntimeUiMessages.DUST_REVEALED,
|
||||
MessageArgument.trusted("count", hits.size()),
|
||||
MessageArgument.untrusted("object", run.key())
|
||||
)));
|
||||
}
|
||||
|
||||
private static boolean active(RevealRun run) {
|
||||
return !run.cancelled().get()
|
||||
&& ACTIVE_RUNS.get(run.playerId()) == run
|
||||
&& !run.player().hasDisconnected()
|
||||
&& !run.player().isRemoved()
|
||||
&& run.player().level() == run.level()
|
||||
&& !run.engine().isClosing()
|
||||
&& !run.engine().isClosed();
|
||||
}
|
||||
|
||||
private static void revealFailure(ModdedScheduler scheduler, RevealRun run, Throwable error) {
|
||||
LOGGER.error("Iris dust reveal failed for {} at {}", run.key(), coordinates(run.origin()), error);
|
||||
scheduler.global(() -> {
|
||||
if (ACTIVE_RUNS.remove(run.playerId(), run)) {
|
||||
run.player().sendSystemMessage(Component.literal(
|
||||
IrisLanguage.plain(RuntimeUiMessages.DUST_REVEAL_FAILED)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void describe(ServerPlayer player, ServerLevel level, Engine engine, BlockPos pos) {
|
||||
@@ -131,103 +243,248 @@ public final class ModdedDustRevealer {
|
||||
int z = pos.getZ();
|
||||
int minHeight = engine.getMinHeight();
|
||||
int relativeY = y - minHeight;
|
||||
int surfaceRelative = safeInt(() -> engine.getHeight(x, z, true));
|
||||
int surfaceY = surfaceRelative + minHeight;
|
||||
int offset = y - surfaceY;
|
||||
Integer surfaceRelative = safe(
|
||||
"surface height lookup at " + coordinates(pos),
|
||||
() -> engine.getHeight(x, z, true));
|
||||
Integer surfaceY = surfaceRelative == null ? null : surfaceRelative + minHeight;
|
||||
Integer offset = surfaceY == null ? null : y - surfaceY;
|
||||
|
||||
String objectKey = safe(() -> engine.getObjectPlacementKey(x, relativeY, z));
|
||||
IrisBiome surfaceBiome = safe(() -> engine.getSurfaceBiome(x, z));
|
||||
IrisBiome biomeHere = safe(() -> engine.getBiome(x, relativeY, z));
|
||||
IrisBiome caveBiome = safe(() -> engine.getCaveOrMantleBiome(x, relativeY, z));
|
||||
IrisRegion region = safe(() -> engine.getRegion(x, z));
|
||||
String objectKey = safe(
|
||||
"object lookup at " + coordinates(pos),
|
||||
() -> engine.getObjectPlacementKey(x, relativeY, z));
|
||||
IrisBiome surfaceBiome = safe(
|
||||
"surface biome lookup at " + x + ", " + z,
|
||||
() -> engine.getSurfaceBiome(x, z));
|
||||
IrisBiome biomeHere = safe(
|
||||
"biome lookup at " + coordinates(pos),
|
||||
() -> engine.getBiome(x, relativeY, z));
|
||||
IrisBiome caveBiome = safe(
|
||||
"cave biome lookup at " + coordinates(pos),
|
||||
() -> engine.getCaveOrMantleBiome(x, relativeY, z));
|
||||
IrisRegion region = safe(
|
||||
"region lookup at " + x + ", " + z,
|
||||
() -> engine.getRegion(x, z));
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add(IrisLanguage.plain(
|
||||
List<DustLine> lines = new ArrayList<>();
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_HEADER,
|
||||
MessageArgument.trusted("x", x),
|
||||
MessageArgument.trusted("y", y),
|
||||
MessageArgument.trusted("z", z)
|
||||
));
|
||||
lines.add(IrisLanguage.plain(
|
||||
), false));
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_BLOCK,
|
||||
MessageArgument.untrusted("block", ModdedBlockState.serialize(level.getBlockState(pos)))
|
||||
));
|
||||
if (offset > 0) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_POSITION_ABOVE,
|
||||
MessageArgument.trusted("offset", offset),
|
||||
MessageArgument.trusted("surfaceY", surfaceY)
|
||||
));
|
||||
} else if (offset < 0) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_POSITION_BELOW,
|
||||
MessageArgument.trusted("offset", -offset),
|
||||
MessageArgument.trusted("surfaceY", surfaceY)
|
||||
));
|
||||
} else {
|
||||
lines.add(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_POSITION_AT,
|
||||
MessageArgument.trusted("surfaceY", surfaceY)
|
||||
));
|
||||
), false));
|
||||
if (offset != null && surfaceY != null) {
|
||||
lines.add(new DustLine(positionLine(offset, surfaceY), true));
|
||||
lines.add(new DustLine(
|
||||
placementLine(offset, surfaceRelative, relativeY, objectKey), true));
|
||||
}
|
||||
lines.add(IrisLanguage.plain(
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_OBJECT_AT_BLOCK,
|
||||
MessageArgument.untrusted(
|
||||
"object",
|
||||
objectKey == null ? IrisLanguage.plain(RuntimeUiMessages.DUST_NONE) : objectKey
|
||||
)
|
||||
));
|
||||
if (surfaceBiome != null) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_SURFACE_BIOME,
|
||||
MessageArgument.untrusted("biome", surfaceBiome.getLoadKey())
|
||||
));
|
||||
objectKey == null
|
||||
? IrisLanguage.plain(RuntimeUiMessages.DUST_NONE)
|
||||
: objectKey)
|
||||
), false));
|
||||
if (objectKey == null) {
|
||||
String columnObject = findColumnObject(engine, x, relativeY, z, minHeight);
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
columnObject == null
|
||||
? RuntimeUiMessages.DUST_COLUMN_OBJECT_NONE
|
||||
: RuntimeUiMessages.DUST_COLUMN_OBJECT,
|
||||
MessageArgument.trusted(
|
||||
columnObject == null ? "detail" : "object",
|
||||
columnObject == null
|
||||
? IrisLanguage.plain(RuntimeUiMessages.DUST_COLUMN_NONE)
|
||||
: columnObject)
|
||||
), false));
|
||||
}
|
||||
if (biomeHere != null && (surfaceBiome == null || !biomeHere.getLoadKey().equals(surfaceBiome.getLoadKey()))) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
if (surfaceBiome != null) {
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_SURFACE_BIOME_DETAIL,
|
||||
MessageArgument.untrusted("biome", surfaceBiome.getLoadKey()),
|
||||
MessageArgument.untrusted("derivative", surfaceBiome.getDerivativeKey())
|
||||
), false));
|
||||
}
|
||||
if (biomeHere != null
|
||||
&& (surfaceBiome == null
|
||||
|| !biomeHere.getLoadKey().equals(surfaceBiome.getLoadKey()))) {
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_BIOME_AT_Y,
|
||||
MessageArgument.untrusted("biome", biomeHere.getLoadKey())
|
||||
));
|
||||
), false));
|
||||
}
|
||||
if (caveBiome != null && (surfaceBiome == null || !caveBiome.getLoadKey().equals(surfaceBiome.getLoadKey()))) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
if (caveBiome != null
|
||||
&& (surfaceBiome == null
|
||||
|| !caveBiome.getLoadKey().equals(surfaceBiome.getLoadKey()))) {
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_CAVE_BIOME,
|
||||
MessageArgument.untrusted("biome", caveBiome.getLoadKey())
|
||||
));
|
||||
), false));
|
||||
}
|
||||
NativeBiome nativeBiome = nativeBiome(level, pos);
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_SERVER_BIOME,
|
||||
MessageArgument.untrusted("biome", nativeBiome.key()),
|
||||
MessageArgument.trusted("id", nativeBiome.id())
|
||||
), false));
|
||||
if (region != null) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_REGION,
|
||||
MessageArgument.untrusted("region", region.getLoadKey()),
|
||||
MessageArgument.untrusted("name", region.getName())
|
||||
));
|
||||
), false));
|
||||
}
|
||||
Set<String> objects = safe(() -> engine.getObjectsAt(x >> 4, z >> 4));
|
||||
Set<String> objects = safe(
|
||||
"chunk object lookup at " + (x >> 4) + ", " + (z >> 4),
|
||||
() -> engine.getObjectsAt(x >> 4, z >> 4));
|
||||
if (objects != null && !objects.isEmpty()) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
lines.add(new DustLine(IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_OBJECTS_IN_CHUNK,
|
||||
MessageArgument.untrusted("objects", objects)
|
||||
));
|
||||
}
|
||||
for (String line : lines) {
|
||||
player.sendSystemMessage(Component.literal(line));
|
||||
MessageArgument.untrusted("objects", objects.stream().sorted().toList())
|
||||
), false));
|
||||
}
|
||||
sendReport(player, lines);
|
||||
}
|
||||
|
||||
private static <T> T safe(Supplier<T> supplier) {
|
||||
static String positionLine(int offset, int surfaceY) {
|
||||
if (offset > 0) {
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_POSITION_ABOVE,
|
||||
MessageArgument.trusted("offset", offset),
|
||||
MessageArgument.trusted("surfaceY", surfaceY));
|
||||
}
|
||||
if (offset < 0) {
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_POSITION_BELOW,
|
||||
MessageArgument.trusted("offset", -offset),
|
||||
MessageArgument.trusted("surfaceY", surfaceY));
|
||||
}
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_POSITION_AT,
|
||||
MessageArgument.trusted("surfaceY", surfaceY));
|
||||
}
|
||||
|
||||
static String placementLine(int offset, int surfaceRelative,
|
||||
int relativeY, String objectKey) {
|
||||
if (offset > 0) {
|
||||
return objectKey == null
|
||||
? IrisLanguage.plain(RuntimeUiMessages.DUST_PLACED_BY_DECORATION_ABOVE)
|
||||
: IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_PLACED_BY_OBJECT_ABOVE,
|
||||
MessageArgument.untrusted("object", objectKey));
|
||||
}
|
||||
if (objectKey != null) {
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_PLACED_BY_BURIED_OBJECT,
|
||||
MessageArgument.untrusted("object", objectKey));
|
||||
}
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_PLACED_BY_TERRAIN,
|
||||
MessageArgument.trusted("depth", Math.max(0, surfaceRelative - relativeY)));
|
||||
}
|
||||
|
||||
private static String findColumnObject(Engine engine, int x, int relativeY,
|
||||
int z, int minHeight) {
|
||||
int maxRelativeY = engine.getMaxHeight() - minHeight - 1;
|
||||
try {
|
||||
for (int dy = 1; dy <= 64; dy++) {
|
||||
if (relativeY + dy <= maxRelativeY) {
|
||||
String up = engine.getObjectPlacementKey(x, relativeY + dy, z);
|
||||
if (up != null) {
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_COLUMN_ABOVE,
|
||||
MessageArgument.untrusted("object", up),
|
||||
MessageArgument.trusted("y", relativeY + dy + minHeight));
|
||||
}
|
||||
}
|
||||
if (relativeY - dy >= 0) {
|
||||
String down = engine.getObjectPlacementKey(x, relativeY - dy, z);
|
||||
if (down != null) {
|
||||
return IrisLanguage.plain(
|
||||
RuntimeUiMessages.DUST_COLUMN_BELOW,
|
||||
MessageArgument.untrusted("object", down),
|
||||
MessageArgument.trusted("y", relativeY - dy + minHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris dust column-object lookup failed at {}, {}, {}",
|
||||
x, relativeY + minHeight, z, error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static NativeBiome nativeBiome(ServerLevel level, BlockPos pos) {
|
||||
Holder<Biome> holder = level.getBiome(pos);
|
||||
String key = holder.unwrapKey()
|
||||
.map((ResourceKey<Biome> resourceKey) -> resourceKey.identifier().toString())
|
||||
.orElse(IrisLanguage.plain(RuntimeUiMessages.STATUS_UNREGISTERED));
|
||||
Registry<Biome> registry = level.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
return new NativeBiome(key, registry.getId(holder.value()));
|
||||
}
|
||||
|
||||
private static void sendReport(ServerPlayer player, List<DustLine> lines) {
|
||||
StringBuilder payload = new StringBuilder();
|
||||
for (int index = 0; index < lines.size(); index++) {
|
||||
DustLine line = lines.get(index);
|
||||
ChatFormatting color = index == 0
|
||||
? ChatFormatting.GOLD
|
||||
: line.emphasis() ? ChatFormatting.YELLOW : ChatFormatting.WHITE;
|
||||
player.sendSystemMessage(Component.literal(line.text()).withStyle(color));
|
||||
if (index > 0) {
|
||||
payload.append('\n');
|
||||
}
|
||||
payload.append(line.text());
|
||||
}
|
||||
MutableComponent hover = Component.literal(
|
||||
IrisLanguage.plain(RuntimeUiMessages.DUST_COPY_HOVER));
|
||||
MutableComponent button = Component.literal(
|
||||
IrisLanguage.plain(RuntimeUiMessages.DUST_COPY_BUTTON))
|
||||
.withStyle(ChatFormatting.GREEN)
|
||||
.withStyle(style -> style
|
||||
.withClickEvent(new ClickEvent.CopyToClipboard(payload.toString()))
|
||||
.withHoverEvent(new HoverEvent.ShowText(hover)));
|
||||
player.sendSystemMessage(button);
|
||||
}
|
||||
|
||||
private static <T> T safe(String operation, Supplier<T> supplier) {
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (Throwable e) {
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris dust {} failed", operation, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static int safeInt(Supplier<Integer> supplier) {
|
||||
try {
|
||||
Integer value = supplier.get();
|
||||
return value == null ? 0 : value;
|
||||
} catch (Throwable e) {
|
||||
return 0;
|
||||
}
|
||||
private static String coordinates(BlockPos pos) {
|
||||
return pos.getX() + ", " + pos.getY() + ", " + pos.getZ();
|
||||
}
|
||||
|
||||
private record DustLine(String text, boolean emphasis) {
|
||||
}
|
||||
|
||||
private record NativeBiome(String key, int id) {
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ObjectPlacementLookup {
|
||||
String at(int x, int relativeY, int z);
|
||||
}
|
||||
|
||||
static record RevealRun(
|
||||
UUID playerId,
|
||||
ServerPlayer player,
|
||||
ServerLevel level,
|
||||
Engine engine,
|
||||
BlockPos origin,
|
||||
String key,
|
||||
int minY,
|
||||
int maxY,
|
||||
AtomicBoolean cancelled
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -233,7 +233,7 @@ public final class ModdedObjectCommands {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int giveDust(CommandSourceStack source) {
|
||||
static int giveDust(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_OBJECT_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_DUST_IS));
|
||||
|
||||
+30
-16
@@ -115,21 +115,11 @@ public final class ModdedStudioCommands {
|
||||
|
||||
root.executes((CommandContext<CommandSourceStack> context) -> ModdedCommandHelp.send(context.getSource(), name));
|
||||
|
||||
root.then(Commands.literal("create")
|
||||
.then(Commands.argument("name", StringArgumentType.word())
|
||||
.executes((CommandContext<CommandSourceStack> context) -> create(context.getSource(), StringArgumentType.getString(context, "name"), DEFAULT_TEMPLATE))
|
||||
.then(Commands.argument("template", StringArgumentType.word()).suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> create(context.getSource(), StringArgumentType.getString(context, "name"), StringArgumentType.getString(context, "template"))))));
|
||||
root.then(Commands.literal("+")
|
||||
.then(Commands.argument("name", StringArgumentType.word())
|
||||
.executes((CommandContext<CommandSourceStack> context) -> create(context.getSource(), StringArgumentType.getString(context, "name"), DEFAULT_TEMPLATE))
|
||||
.then(Commands.argument("template", StringArgumentType.word()).suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> create(context.getSource(), StringArgumentType.getString(context, "name"), StringArgumentType.getString(context, "template"))))));
|
||||
root.then(createTree("create"));
|
||||
root.then(createTree("+"));
|
||||
|
||||
root.then(Commands.literal("package")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> pkg(context.getSource(), null))
|
||||
.then(Commands.argument("pack", StringArgumentType.word()).suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> pkg(context.getSource(), StringArgumentType.getString(context, "pack")))));
|
||||
root.then(packageTree("package"));
|
||||
root.then(packageTree("pkg"));
|
||||
|
||||
root.then(Commands.literal("version")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> version(context.getSource(), null))
|
||||
@@ -173,6 +163,30 @@ public final class ModdedStudioCommands {
|
||||
return root;
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> createTree(String name) {
|
||||
return Commands.literal(name)
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
create(context.getSource(), "studio", DEFAULT_TEMPLATE))
|
||||
.then(Commands.argument("name", StringArgumentType.word())
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
create(context.getSource(), StringArgumentType.getString(context, "name"), DEFAULT_TEMPLATE))
|
||||
.then(Commands.argument("template", StringArgumentType.word())
|
||||
.suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
create(context.getSource(),
|
||||
StringArgumentType.getString(context, "name"),
|
||||
StringArgumentType.getString(context, "template")))));
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder<CommandSourceStack> packageTree(String name) {
|
||||
return Commands.literal(name)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> pkg(context.getSource(), null))
|
||||
.then(Commands.argument("pack", StringArgumentType.word())
|
||||
.suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
pkg(context.getSource(), StringArgumentType.getString(context, "pack"))));
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
STUDIOS.clear();
|
||||
}
|
||||
@@ -368,7 +382,7 @@ public final class ModdedStudioCommands {
|
||||
File packFolder = new File(ModdedPackCommands.packsRoot(), pack);
|
||||
if (!new File(packFolder, "dimensions/" + pack + ".json").isFile()) {
|
||||
server.execute(() -> IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PACK_MISSING_DOWNLOADING_IRISDIMENSIONS, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("pack2", pack))));
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, "master",
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, "master", false,
|
||||
(String line) -> server.execute(() -> IrisModdedCommands.ok(source, line)));
|
||||
if (!installed || !new File(packFolder, "dimensions/" + pack + ".json").isFile()) {
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_PACK_COULD_NOT_BE_DOWNLOADED_CHECK_NAME_TRY_IRIS_DOWNLOAD, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("pack2", pack))));
|
||||
@@ -573,7 +587,7 @@ public final class ModdedStudioCommands {
|
||||
File templateFolder = new File(packsRoot, template);
|
||||
if (!new File(templateFolder, "dimensions/" + template + ".json").isFile()) {
|
||||
server.execute(() -> IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_TEMPLATE_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS, MessageArgument.untrusted("template", template), MessageArgument.untrusted("template2", template))));
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), template, "master",
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), template, "master", false,
|
||||
(String line) -> server.execute(() -> IrisModdedCommands.ok(source, line)));
|
||||
if (!installed || !new File(templateFolder, "dimensions/" + template + ".json").isFile()) {
|
||||
server.execute(() -> IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_STUDIO_COMMANDS_TEMPLATE_COULD_NOT_BE_DOWNLOADED_INSTALL_PACK_WITH_DIMENSIONS_JSON, MessageArgument.untrusted("template", template), MessageArgument.untrusted("template2", template))));
|
||||
|
||||
+7
@@ -40,6 +40,7 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.component.ItemLore;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -88,6 +89,8 @@ public final class ModdedWandService {
|
||||
stack.set(DataComponents.UNBREAKABLE, Unit.INSTANCE);
|
||||
stack.set(DataComponents.ENCHANTMENT_GLINT_OVERRIDE, Boolean.TRUE);
|
||||
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(flagTag(WAND_TAG)));
|
||||
stack.set(DataComponents.TOOLTIP_DISPLAY,
|
||||
TooltipDisplay.DEFAULT.withHidden(DataComponents.UNBREAKABLE, true));
|
||||
return stack;
|
||||
}
|
||||
|
||||
@@ -99,6 +102,8 @@ public final class ModdedWandService {
|
||||
stack.set(DataComponents.UNBREAKABLE, Unit.INSTANCE);
|
||||
stack.set(DataComponents.ENCHANTMENT_GLINT_OVERRIDE, Boolean.TRUE);
|
||||
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(flagTag(DUST_TAG)));
|
||||
stack.set(DataComponents.TOOLTIP_DISPLAY,
|
||||
TooltipDisplay.DEFAULT.withHidden(DataComponents.UNBREAKABLE, true));
|
||||
return stack;
|
||||
}
|
||||
|
||||
@@ -187,6 +192,8 @@ public final class ModdedWandService {
|
||||
|
||||
public static void clearAll() {
|
||||
SELECTIONS.clear();
|
||||
ModdedDustRevealer.clear();
|
||||
ModdedWhatCommands.clear();
|
||||
}
|
||||
|
||||
public static void serverTick(MinecraftServer server) {
|
||||
|
||||
+535
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.IrisMessages;
|
||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.GenerationSessionException;
|
||||
import art.arcane.iris.engine.framework.GenerationSessionLease;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisPosition;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.modded.ModdedBlockState;
|
||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||
import art.arcane.iris.modded.ModdedScheduler;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.project.context.IrisContext;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import art.arcane.volmlib.util.localization.TextKey;
|
||||
import art.arcane.volmlib.util.matter.MatterMarker;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.RandomizableContainer;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class ModdedWhatCommands {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
private static final Predicate<CommandSourceStack> GATE =
|
||||
Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||
private static final SuggestionProvider<CommandSourceStack> MARKER_TYPES =
|
||||
(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) ->
|
||||
SharedSuggestionProvider.suggest(
|
||||
List.of("cave_floor", "cave_ceiling", "object"), builder);
|
||||
private static final DustParticleOptions MARKER_DUST = new DustParticleOptions(0x5A8CFF, 1.2F);
|
||||
private static final int MAX_MARKERS = 8_192;
|
||||
private static final int MARKER_BATCH_SIZE = 128;
|
||||
private static final ConcurrentHashMap<UUID, MarkerRun> ACTIVE_MARKER_RUNS = new ConcurrentHashMap<>();
|
||||
|
||||
private ModdedWhatCommands() {
|
||||
}
|
||||
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> tree() {
|
||||
return Commands.literal("what").requires(GATE)
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectHere(context.getSource()))
|
||||
.then(Commands.literal("here")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectHere(context.getSource())))
|
||||
.then(Commands.literal("biome")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectBiome(context.getSource())))
|
||||
.then(Commands.literal("region")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectRegion(context.getSource())))
|
||||
.then(Commands.literal("block")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectBlock(context.getSource())))
|
||||
.then(Commands.literal("hand")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectHand(context.getSource())))
|
||||
.then(Commands.literal("markers")
|
||||
.then(Commands.argument("marker", StringArgumentType.greedyString())
|
||||
.suggests(MARKER_TYPES)
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
inspectMarkers(
|
||||
context.getSource(),
|
||||
StringArgumentType.getString(context, "marker")))));
|
||||
}
|
||||
|
||||
static void clear() {
|
||||
for (MarkerRun run : ACTIVE_MARKER_RUNS.values()) {
|
||||
run.cancelled().set(true);
|
||||
}
|
||||
ACTIVE_MARKER_RUNS.clear();
|
||||
}
|
||||
|
||||
private static int inspectHere(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return playerRequired(source, ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_2);
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_6));
|
||||
return 0;
|
||||
}
|
||||
BlockPos pos = player.blockPosition();
|
||||
int result = inspectBiome(source);
|
||||
result &= inspectRegion(source);
|
||||
int relativeY = pos.getY() - engine.getMinHeight();
|
||||
try {
|
||||
IrisBiome cave = engine.getCaveOrMantleBiome(pos.getX(), relativeY, pos.getZ());
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_CAVE_BIOME,
|
||||
MessageArgument.untrusted("value", cave == null
|
||||
? IrisLanguage.plain(RuntimeUiMessages.STATUS_NONE)
|
||||
: cave.getLoadKey())));
|
||||
} catch (Throwable error) {
|
||||
logLookupFailure(source, "cave biome", error,
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_CAVE_BIOME_LOOKUP_FAILED);
|
||||
result = 0;
|
||||
}
|
||||
int surfaceY = level.getHeight(Heightmap.Types.WORLD_SURFACE, pos.getX(), pos.getZ()) - 1;
|
||||
BlockState surface = level.getBlockState(new BlockPos(pos.getX(), surfaceY, pos.getZ()));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_SURFACE_BLOCK_Y,
|
||||
MessageArgument.untrusted("value", BuiltInRegistries.BLOCK.getKey(surface.getBlock())),
|
||||
MessageArgument.trusted("value2", surfaceY)));
|
||||
sendPosition(source, pos);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int inspectBiome(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return playerRequired(source, ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_2);
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
BlockPos pos = player.blockPosition();
|
||||
NativeBiome nativeBiome = nativeBiome(level, pos);
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_NON_IRIS_BIOME,
|
||||
MessageArgument.untrusted("biome", nativeBiome.key()),
|
||||
MessageArgument.trusted("id", nativeBiome.id())));
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
IrisBiome biome = engine.getBiome(
|
||||
pos.getX(), pos.getY() - engine.getMinHeight(), pos.getZ());
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_IRIS_BIOME,
|
||||
MessageArgument.untrusted("biome", biome.getLoadKey()),
|
||||
MessageArgument.untrusted("name", biome.getName())));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_DERIVATIVE_BIOME,
|
||||
MessageArgument.untrusted("biome", biome.getDerivativeKey())));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_NATIVE_BIOME,
|
||||
MessageArgument.untrusted("biome", nativeBiome.key()),
|
||||
MessageArgument.trusted("id", nativeBiome.id())));
|
||||
return 1;
|
||||
} catch (Throwable error) {
|
||||
logLookupFailure(source, "biome", error,
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_BIOME_LOOKUP_FAILED_2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int inspectRegion(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return playerRequired(source, ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_2);
|
||||
}
|
||||
Engine engine = IrisModdedCommands.engineFor(source.getLevel());
|
||||
if (engine == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_6));
|
||||
return 0;
|
||||
}
|
||||
BlockPos pos = player.blockPosition();
|
||||
int centerX = (pos.getX() & ~15) + 8;
|
||||
int centerZ = (pos.getZ() & ~15) + 8;
|
||||
try {
|
||||
IrisRegion region = engine.getRegion(centerX, centerZ);
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_IRIS_REGION,
|
||||
MessageArgument.untrusted("region", region.getLoadKey()),
|
||||
MessageArgument.untrusted("name", region.getName())));
|
||||
return 1;
|
||||
} catch (Throwable error) {
|
||||
logLookupFailure(source, "region", error,
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_REGION_LOOKUP_FAILED_2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int inspectHand(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return playerRequired(source, ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_IT_INSPECTS);
|
||||
}
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
if (stack.isEmpty()) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_YOUR_MAIN_HAND_IS_EMPTY));
|
||||
return 0;
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_MATERIAL,
|
||||
MessageArgument.untrusted("material", BuiltInRegistries.ITEM.getKey(stack.getItem()))));
|
||||
if (stack.getItem() instanceof BlockItem blockItem) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_FULL_STATE,
|
||||
MessageArgument.untrusted(
|
||||
"state", ModdedBlockState.serialize(blockItem.getBlock().defaultBlockState()))));
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_ITEM_COUNT,
|
||||
MessageArgument.trusted("count", stack.getCount())));
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int inspectBlock(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return playerRequired(source, ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_IT_INSPECTS_2);
|
||||
}
|
||||
HitResult hit = player.pick(128.0D, 1.0F, false);
|
||||
if (!(hit instanceof BlockHitResult blockHit) || hit.getType() != HitResult.Type.BLOCK) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_LOOK_AT_BLOCK_NOT_SKY));
|
||||
return 0;
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
BlockPos pos = blockHit.getBlockPos();
|
||||
BlockState state = level.getBlockState(pos);
|
||||
PlatformBlockState platform = ModdedBlockState.of(state, null);
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_MATERIAL,
|
||||
MessageArgument.untrusted("material", BuiltInRegistries.BLOCK.getKey(state.getBlock()))));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_FULL_STATE,
|
||||
MessageArgument.untrusted("state", ModdedBlockState.serialize(state))));
|
||||
sendPosition(source, pos);
|
||||
sendProperties(source, platform);
|
||||
sendObject(source, level, pos);
|
||||
sendBlockEntity(source, level, pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static void sendPosition(CommandSourceStack source, BlockPos pos) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_POSITION,
|
||||
MessageArgument.trusted("x", pos.getX()),
|
||||
MessageArgument.trusted("y", pos.getY()),
|
||||
MessageArgument.trusted("z", pos.getZ()),
|
||||
MessageArgument.trusted("chunkX", pos.getX() >> 4),
|
||||
MessageArgument.trusted("chunkZ", pos.getZ() >> 4)));
|
||||
}
|
||||
|
||||
private static void sendProperties(CommandSourceStack source, PlatformBlockState platform) {
|
||||
List<String> flags = propertyNames(platform);
|
||||
if (flags.isEmpty()) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(IrisMessages.MODDED_PROPERTIES_NONE));
|
||||
return;
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
IrisMessages.MODDED_PROPERTIES,
|
||||
MessageArgument.untrusted("properties", String.join(", ", flags))));
|
||||
}
|
||||
|
||||
static List<String> propertyNames(PlatformBlockState platform) {
|
||||
List<String> flags = new ArrayList<>();
|
||||
addFlag(flags, platform.isSolid(), RuntimeUiMessages.WHAT_FLAG_SOLID);
|
||||
addFlag(flags, platform.isFluid(), RuntimeUiMessages.WHAT_FLAG_FLUID);
|
||||
addFlag(flags, platform.isWater(), RuntimeUiMessages.WHAT_FLAG_WATER);
|
||||
addFlag(flags, platform.isWaterLogged(), RuntimeUiMessages.WHAT_FLAG_WATERLOGGED);
|
||||
addFlag(flags, platform.isStorage(), RuntimeUiMessages.WHAT_FLAG_STORAGE);
|
||||
addFlag(flags, platform.isLit(), RuntimeUiMessages.WHAT_FLAG_LIT);
|
||||
addFlag(flags, platform.isFoliage(), RuntimeUiMessages.WHAT_FLAG_FOLIAGE);
|
||||
addFlag(flags, platform.isFoliagePlantable(), RuntimeUiMessages.WHAT_FLAG_PLANTABLE_FOLIAGE);
|
||||
addFlag(flags, platform.isDecorant(), RuntimeUiMessages.WHAT_FLAG_DECORANT);
|
||||
addFlag(flags, platform.isOre(), RuntimeUiMessages.WHAT_FLAG_ORE);
|
||||
addFlag(flags, platform.hasTileEntity(), RuntimeUiMessages.WHAT_FLAG_BLOCK_ENTITY);
|
||||
return List.copyOf(flags);
|
||||
}
|
||||
|
||||
private static void addFlag(List<String> flags, boolean enabled,
|
||||
TextKey message) {
|
||||
if (enabled) {
|
||||
flags.add(IrisLanguage.plain(message));
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendObject(CommandSourceStack source, ServerLevel level, BlockPos pos) {
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String object = engine.getObjectPlacementKey(
|
||||
pos.getX(), pos.getY() - engine.getMinHeight(), pos.getZ());
|
||||
if (object != null) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_OBJECT,
|
||||
MessageArgument.untrusted("object", object)));
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris object lookup failed for /iris what block at {}, {}, {}",
|
||||
pos.getX(), pos.getY(), pos.getZ(), error);
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendBlockEntity(CommandSourceStack source,
|
||||
ServerLevel level, BlockPos pos) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (blockEntity == null) {
|
||||
return;
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_BLOCK_ENTITY,
|
||||
MessageArgument.untrusted(
|
||||
"type", BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(blockEntity.getType()))));
|
||||
if (blockEntity instanceof RandomizableContainer container) {
|
||||
ResourceKey<LootTable> lootTable = container.getLootTable();
|
||||
if (lootTable != null) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_LOOT_TABLE,
|
||||
MessageArgument.untrusted("loot", lootTable.identifier())));
|
||||
}
|
||||
}
|
||||
if (blockEntity instanceof SpawnerBlockEntity) {
|
||||
CompoundTag tag = blockEntity.saveWithoutMetadata(level.registryAccess());
|
||||
CompoundTag spawnData = tag.getCompound("SpawnData").orElse(null);
|
||||
CompoundTag entity = spawnData == null ? null : spawnData.getCompound("entity").orElse(null);
|
||||
String entityId = entity == null ? "" : entity.getStringOr("id", "");
|
||||
if (!entityId.isBlank()) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
RuntimeUiMessages.WHAT_SPAWNER_ENTITY,
|
||||
MessageArgument.untrusted("entity", entityId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int inspectMarkers(CommandSourceStack source, String markerRaw) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return playerRequired(source, ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_COMMAND_CAN_ONLY_BE_USED_BY_PLAYERS_MARKERS_RENDER);
|
||||
}
|
||||
ServerLevel level = source.getLevel();
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_7));
|
||||
return 0;
|
||||
}
|
||||
ModdedScheduler scheduler = ModdedEngineBootstrap.schedulerOrNull();
|
||||
if (scheduler == null) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_MARKER_SCAN_FAILED,
|
||||
MessageArgument.untrusted("value", "scheduler unavailable")));
|
||||
return 0;
|
||||
}
|
||||
String marker = markerRaw.trim();
|
||||
BlockPos origin = player.blockPosition();
|
||||
MarkerRun run = new MarkerRun(
|
||||
player.getUUID(), player, level, engine, marker,
|
||||
origin.getX() >> 4, origin.getZ() >> 4, new AtomicBoolean());
|
||||
MarkerRun previous = ACTIVE_MARKER_RUNS.put(player.getUUID(), run);
|
||||
if (previous != null) {
|
||||
previous.cancelled().set(true);
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_SCANNING_MARKERS_AROUND_YOU,
|
||||
MessageArgument.untrusted("marker", marker)));
|
||||
scheduler.async(() -> scanMarkers(source, scheduler, run));
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static void scanMarkers(CommandSourceStack source,
|
||||
ModdedScheduler scheduler, MarkerRun run) {
|
||||
List<BlockPos> hits = new ArrayList<>();
|
||||
MatterMarker marker = new MatterMarker(run.marker());
|
||||
try (GenerationSessionLease lease = run.engine().acquireGenerationLease("modded_what_markers");
|
||||
IrisContext.Scope ignored = IrisContext.open(run.engine(), lease.sessionId(), null)) {
|
||||
for (int chunkX = run.chunkX() - 4; chunkX <= run.chunkX() + 4; chunkX++) {
|
||||
for (int chunkZ = run.chunkZ() - 4; chunkZ <= run.chunkZ() + 4; chunkZ++) {
|
||||
if (run.cancelled().get()) {
|
||||
return;
|
||||
}
|
||||
for (IrisPosition position : run.engine().getMantle().findMarkers(chunkX, chunkZ, marker)) {
|
||||
hits.add(new BlockPos(position.getX(), position.getY(), position.getZ()));
|
||||
if (hits.size() >= MAX_MARKERS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hits.size() >= MAX_MARKERS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hits.size() >= MAX_MARKERS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
scheduler.global(() -> renderMarkerBatch(source, scheduler, run, hits, 0));
|
||||
} catch (GenerationSessionException error) {
|
||||
markerFailure(source, scheduler, run, error);
|
||||
} catch (Throwable error) {
|
||||
markerFailure(source, scheduler, run, error);
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderMarkerBatch(CommandSourceStack source,
|
||||
ModdedScheduler scheduler, MarkerRun run,
|
||||
List<BlockPos> hits, int from) {
|
||||
if (!active(run)) {
|
||||
return;
|
||||
}
|
||||
int to = Math.min(hits.size(), from + MARKER_BATCH_SIZE);
|
||||
for (int index = from; index < to; index++) {
|
||||
BlockPos hit = hits.get(index);
|
||||
run.level().sendParticles(run.player(), MARKER_DUST, true, true,
|
||||
hit.getX() + 0.5D, hit.getY() + 1.0D, hit.getZ() + 0.5D,
|
||||
3, 0.2D, 0.2D, 0.2D, 0.0D);
|
||||
}
|
||||
if (to < hits.size()) {
|
||||
scheduler.laterGlobal(() -> renderMarkerBatch(source, scheduler, run, hits, to), 1);
|
||||
return;
|
||||
}
|
||||
ACTIVE_MARKER_RUNS.remove(run.playerId(), run);
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_FOUND_NEARBY_MARKER_S,
|
||||
MessageArgument.trusted("value", hits.size()),
|
||||
MessageArgument.untrusted("marker", run.marker())));
|
||||
}
|
||||
|
||||
private static boolean active(MarkerRun run) {
|
||||
return !run.cancelled().get()
|
||||
&& ACTIVE_MARKER_RUNS.get(run.playerId()) == run
|
||||
&& !run.player().hasDisconnected()
|
||||
&& !run.player().isRemoved()
|
||||
&& run.player().level() == run.level()
|
||||
&& !run.engine().isClosing()
|
||||
&& !run.engine().isClosed();
|
||||
}
|
||||
|
||||
private static void markerFailure(CommandSourceStack source,
|
||||
ModdedScheduler scheduler, MarkerRun run, Throwable error) {
|
||||
LOGGER.error("Iris marker scan failed for {}", run.marker(), error);
|
||||
scheduler.global(() -> {
|
||||
if (ACTIVE_MARKER_RUNS.remove(run.playerId(), run)) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
ModdedCommandMessages.IRIS_MODDED_COMMANDS_MARKER_SCAN_FAILED,
|
||||
MessageArgument.untrusted("value", error.getClass().getSimpleName())));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static NativeBiome nativeBiome(ServerLevel level, BlockPos pos) {
|
||||
Holder<Biome> holder = level.getBiome(pos);
|
||||
String key = holder.unwrapKey()
|
||||
.map((ResourceKey<Biome> resourceKey) -> resourceKey.identifier().toString())
|
||||
.orElse(IrisLanguage.plain(RuntimeUiMessages.STATUS_UNREGISTERED));
|
||||
Registry<Biome> registry = level.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
return new NativeBiome(key, registry.getId(holder.value()));
|
||||
}
|
||||
|
||||
private static int playerRequired(CommandSourceStack source,
|
||||
TextKey message) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(message));
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void logLookupFailure(CommandSourceStack source,
|
||||
String operation, Throwable error,
|
||||
TextKey message) {
|
||||
LOGGER.error("Iris /what {} lookup failed in {}", operation,
|
||||
source.getLevel().dimension().identifier(), error);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
message,
|
||||
MessageArgument.untrusted("value", error.getClass().getSimpleName())));
|
||||
}
|
||||
|
||||
private record NativeBiome(String key, int id) {
|
||||
}
|
||||
|
||||
private record MarkerRun(
|
||||
UUID playerId,
|
||||
ServerPlayer player,
|
||||
ServerLevel level,
|
||||
Engine engine,
|
||||
String marker,
|
||||
int chunkX,
|
||||
int chunkZ,
|
||||
AtomicBoolean cancelled
|
||||
) {
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -175,7 +175,7 @@ public final class ModdedWorldCommands {
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_PACK_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("pack2", pack)));
|
||||
Thread thread = new Thread(() -> {
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, "master",
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, "master", false,
|
||||
(String line) -> server.execute(() -> IrisModdedCommands.ok(source, line)));
|
||||
server.execute(() -> {
|
||||
if (!installed || !packFolder.isDirectory()) {
|
||||
@@ -278,7 +278,7 @@ public final class ModdedWorldCommands {
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_PACK_IS_NOT_INSTALLED_DOWNLOADING_IRISDIMENSIONS_2, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("pack2", pack)));
|
||||
Thread thread = new Thread(() -> {
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, "master",
|
||||
boolean installed = ModdedPackInstaller.install(ModdedEngineBootstrap.loader().configDir(), pack, "master", false,
|
||||
(String line) -> server.execute(() -> IrisModdedCommands.ok(source, line)));
|
||||
server.execute(() -> {
|
||||
if (!installed || !packFolder.isDirectory()) {
|
||||
|
||||
+7
-3
@@ -56,8 +56,12 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ExecutorService current = service;
|
||||
if (current != null && !current.isShutdown()) {
|
||||
return;
|
||||
if (current != null) {
|
||||
if (!current.isTerminated()) {
|
||||
throw new IllegalStateException(
|
||||
"Iris engine maintenance cannot restart while prior workers are still active");
|
||||
}
|
||||
service = null;
|
||||
}
|
||||
|
||||
IrisSettings.IrisSettingsEngineSVC settings = IrisSettings.get().getPerformance().getEngineSVC();
|
||||
@@ -75,9 +79,9 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
||||
@Override
|
||||
public void onDisable() {
|
||||
ExecutorService active = service;
|
||||
service = null;
|
||||
boolean drained = shutdownAndDrain(active);
|
||||
if (drained) {
|
||||
service = null;
|
||||
inFlight.clear();
|
||||
}
|
||||
lastSavedAt.clear();
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Vorgenerierungs-HUD umschalten"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Vorgenerierungs-HUD umschalten",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Toggle Pregen HUD"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Toggle Pregen HUD",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Alternar HUD de pregeneración"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Alternar HUD de pregeneración",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Vaihda esigeneroinnin HUD"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Vaihda esigeneroinnin HUD",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Activer ou désactiver le HUD de prégénération"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Activer ou désactiver le HUD de prégénération",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "הפעלה או כיבוי של תצוגת הקדם-יצירה"
|
||||
"key.irisworldgen.toggle_pregen_hud": "הפעלה או כיבוי של תצוגת הקדם-יצירה",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Attiva o disattiva l'HUD di pregenerazione"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Attiva o disattiva l'HUD di pregenerazione",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "事前生成 HUD の切り替え"
|
||||
"key.irisworldgen.toggle_pregen_hud": "事前生成 HUD の切り替え",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "사전 생성 HUD 전환"
|
||||
"key.irisworldgen.toggle_pregen_hud": "사전 생성 HUD 전환",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Perjungti išankstinio generavimo HUD"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Perjungti išankstinio generavimo HUD",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "HUD voor vooraf genereren in- of uitschakelen"
|
||||
"key.irisworldgen.toggle_pregen_hud": "HUD voor vooraf genereren in- of uitschakelen",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Przełącz interfejs wstępnego generowania"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Przełącz interfejs wstępnego generowania",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Alternar HUD de pré-geração"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Alternar HUD de pré-geração",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Переключить HUD предварительной генерации"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Переключить HUD предварительной генерации",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Ön oluşturma HUD'unu aç veya kapat"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Ön oluşturma HUD'unu aç veya kapat",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "Bật hoặc tắt HUD tạo trước"
|
||||
"key.irisworldgen.toggle_pregen_hud": "Bật hoặc tắt HUD tạo trước",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "切换预生成 HUD"
|
||||
"key.irisworldgen.toggle_pregen_hud": "切换预生成 HUD",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"key.categories.irisworldgen.iris": "Iris",
|
||||
"key.irisworldgen.toggle_pregen_hud": "切換預先生成 HUD"
|
||||
"key.irisworldgen.toggle_pregen_hud": "切換預先生成 HUD",
|
||||
"key.irisworldgen.open_vision_map": "Open Iris Vision Map",
|
||||
"key.irisworldgen.toggle_what_overlay": "Toggle Iris What Overlay"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "art.arcane.iris.client.mixin",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"client": [
|
||||
"IrisWorldOpenFlowsMixin",
|
||||
"IrisWorldTypeEntryMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package art.arcane.iris.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class IrisClientCursorTest {
|
||||
@Test
|
||||
public void refreshesAnUnchangedPositionAfterTheRefreshInterval() {
|
||||
AtomicLong clock = new AtomicLong(500L);
|
||||
AtomicInteger frames = new AtomicInteger();
|
||||
IrisClientCursor cursor = new IrisClientCursor(frame -> frames.incrementAndGet(), clock::get);
|
||||
|
||||
cursor.requestFor(10, 20);
|
||||
clock.addAndGet(1_999L);
|
||||
cursor.requestFor(10, 20);
|
||||
clock.incrementAndGet();
|
||||
cursor.requestFor(10, 20);
|
||||
|
||||
assertEquals(2, frames.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throttlesRapidPositionChanges() {
|
||||
AtomicLong clock = new AtomicLong(500L);
|
||||
AtomicInteger frames = new AtomicInteger();
|
||||
IrisClientCursor cursor = new IrisClientCursor(frame -> frames.incrementAndGet(), clock::get);
|
||||
|
||||
cursor.requestFor(10, 20);
|
||||
clock.addAndGet(499L);
|
||||
cursor.requestFor(11, 20);
|
||||
clock.incrementAndGet();
|
||||
cursor.requestFor(11, 20);
|
||||
|
||||
assertEquals(2, frames.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearAllowsImmediateRequestAtTheSamePosition() {
|
||||
AtomicLong clock = new AtomicLong(500L);
|
||||
AtomicInteger frames = new AtomicInteger();
|
||||
IrisClientCursor cursor = new IrisClientCursor(frame -> frames.incrementAndGet(), clock::get);
|
||||
|
||||
cursor.requestFor(10, 20);
|
||||
cursor.clear();
|
||||
cursor.requestFor(10, 20);
|
||||
|
||||
assertEquals(2, frames.get());
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
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 IrisClientDimensionTest {
|
||||
@Test
|
||||
public void packSeedAndHeightChangesInvalidateDimensionCaches() {
|
||||
IrisClientDimension dimension = new IrisClientDimension();
|
||||
IrisMessage.DimensionStatus initial = new IrisMessage.DimensionStatus(
|
||||
"minecraft:overworld", "overworld", 1L, -64, 320, true);
|
||||
|
||||
assertTrue(dimension.onDimensionStatus(initial));
|
||||
assertFalse(dimension.onDimensionStatus(initial));
|
||||
assertTrue(dimension.onDimensionStatus(new IrisMessage.DimensionStatus(
|
||||
"minecraft:overworld", "other", 1L, -64, 320, true)));
|
||||
assertTrue(dimension.onDimensionStatus(new IrisMessage.DimensionStatus(
|
||||
"minecraft:overworld", "other", 2L, -64, 320, true)));
|
||||
assertTrue(dimension.onDimensionStatus(new IrisMessage.DimensionStatus(
|
||||
"minecraft:overworld", "other", 2L, 0, 256, true)));
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package art.arcane.iris.client;
|
||||
|
||||
import art.arcane.iris.spi.protocol.IrisMessage;
|
||||
import art.arcane.iris.spi.protocol.IrisProtocol;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisClientSessionTest {
|
||||
@Test
|
||||
public void retriesHelloAndEventuallyMarksUnsupported() {
|
||||
AtomicLong clock = new AtomicLong();
|
||||
AtomicInteger frames = new AtomicInteger();
|
||||
IrisClientSession session = new IrisClientSession(clock::get);
|
||||
session.bind(frame -> frames.incrementAndGet());
|
||||
|
||||
session.sendHello();
|
||||
assertEquals(1, frames.get());
|
||||
assertEquals(IrisClientSession.State.AWAITING_HELLO, session.state());
|
||||
|
||||
for (int attempt = 0; attempt < 5; attempt++) {
|
||||
clock.addAndGet(2_000L);
|
||||
session.tick();
|
||||
}
|
||||
|
||||
assertEquals(5, frames.get());
|
||||
assertEquals(IrisClientSession.State.UNSUPPORTED, session.state());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchingHelloCompletesRetryingSession() {
|
||||
AtomicLong clock = new AtomicLong();
|
||||
IrisClientSession session = new IrisClientSession(clock::get);
|
||||
session.bind(frame -> {
|
||||
});
|
||||
session.sendHello();
|
||||
|
||||
session.onServerHello(new IrisMessage.ServerHello(
|
||||
IrisProtocol.PROTOCOL_VERSION, IrisProtocol.CAPABILITY_VISION, "Iris", true));
|
||||
|
||||
assertTrue(session.isReady());
|
||||
assertEquals("Iris", session.serverBrand());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompatibleHelloIsRejected() {
|
||||
IrisClientSession session = new IrisClientSession();
|
||||
session.onServerHello(new IrisMessage.ServerHello(
|
||||
IrisProtocol.PROTOCOL_VERSION + 1, 0L, "Iris", true));
|
||||
|
||||
assertEquals(IrisClientSession.State.INCOMPATIBLE, session.state());
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -29,7 +29,7 @@ public class IrisModLanguageAssetsTest {
|
||||
@Test
|
||||
public void minecraftLanguageAssetsMatchSharedLocaleManifest() throws Exception {
|
||||
JsonObject english = read("en_us");
|
||||
assertEquals(2, english.size());
|
||||
assertEquals(4, english.size());
|
||||
|
||||
for (String locale : VolmitLocales.nonEnglish()) {
|
||||
String minecraftLocale = VolmitLocales.minecraftCode(locale);
|
||||
@@ -73,9 +73,16 @@ public class IrisModLanguageAssetsTest {
|
||||
|
||||
private Set<String> resourceFiles() throws Exception {
|
||||
URL resource = IrisModLanguageAssetsTest.class.getClassLoader().getResource(ROOT);
|
||||
assertNotNull("Missing mod language resource directory", resource);
|
||||
assertEquals("file", resource.getProtocol());
|
||||
try (Stream<Path> paths = Files.list(Path.of(resource.toURI()))) {
|
||||
Path directory;
|
||||
if (resource != null && "file".equals(resource.getProtocol())) {
|
||||
directory = Path.of(resource.toURI());
|
||||
} else {
|
||||
String sources = System.getProperty("iris.moddedCommonSources");
|
||||
assertNotNull("Missing mod language resource directory and source root", sources);
|
||||
directory = Path.of(sources).getParent()
|
||||
.resolve("resources").resolve(ROOT);
|
||||
}
|
||||
try (Stream<Path> paths = Files.list(directory)) {
|
||||
return paths
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.getFileName().toString())
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
public class ModdedDimensionRegistryStoreTest {
|
||||
@Test
|
||||
public void registryRoundTripsPersistentDimensions() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-dimension-registry");
|
||||
Path file = root.resolve("iris-dimensions.json");
|
||||
try {
|
||||
List<ModdedDimensionRegistryStore.PersistentDimension> expected = List.of(
|
||||
new ModdedDimensionRegistryStore.PersistentDimension(
|
||||
"iris:first", "overworld", "overworld", 42L),
|
||||
new ModdedDimensionRegistryStore.PersistentDimension(
|
||||
"iris:second", "other", "surface", -9L));
|
||||
|
||||
ModdedDimensionRegistryStore.write(file, expected);
|
||||
|
||||
assertEquals(expected, ModdedDimensionRegistryStore.load(file));
|
||||
} finally {
|
||||
Files.deleteIfExists(file);
|
||||
Files.deleteIfExists(root);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedEntryDoesNotDiscardHealthyEntries() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-dimension-registry-partial");
|
||||
Path file = root.resolve("iris-dimensions.json");
|
||||
try {
|
||||
Files.writeString(file, """
|
||||
{
|
||||
"dimensions": [
|
||||
{"id":"iris:good","pack":"overworld","dimension":"overworld","seed":7},
|
||||
{"id":"iris:broken","pack":"overworld"}
|
||||
]
|
||||
}
|
||||
""", StandardCharsets.UTF_8);
|
||||
|
||||
assertEquals(List.of(new ModdedDimensionRegistryStore.PersistentDimension(
|
||||
"iris:good", "overworld", "overworld", 7L)),
|
||||
ModdedDimensionRegistryStore.load(file));
|
||||
} finally {
|
||||
Files.deleteIfExists(file);
|
||||
Files.deleteIfExists(root);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void truncatedRegistryNeverBecomesAnEmptySuccessfulLoad() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-dimension-registry-truncated");
|
||||
Path file = root.resolve("iris-dimensions.json");
|
||||
try {
|
||||
Files.writeString(file, "{\"dimensions\":[", StandardCharsets.UTF_8);
|
||||
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> ModdedDimensionRegistryStore.load(file));
|
||||
} finally {
|
||||
Files.deleteIfExists(file);
|
||||
Files.deleteIfExists(root);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingDimensionsArrayNeverBecomesAnEmptySuccessfulLoad() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-dimension-registry-missing-root");
|
||||
Path file = root.resolve("iris-dimensions.json");
|
||||
try {
|
||||
Files.writeString(file, "{}", StandardCharsets.UTF_8);
|
||||
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> ModdedDimensionRegistryStore.load(file));
|
||||
} finally {
|
||||
Files.deleteIfExists(file);
|
||||
Files.deleteIfExists(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-14
@@ -44,6 +44,7 @@ import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.FA
|
||||
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.TRUE;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -54,9 +55,14 @@ public class ModdedDimensionTypeParityTest {
|
||||
IrisDimension nether = dimension("nether", IrisEnvironment.NETHER, 0, 256, 256, new IrisDimensionTypeOptions());
|
||||
IrisDimension end = dimension("the_end", IrisEnvironment.THE_END, 0, 256, 256, new IrisDimensionTypeOptions());
|
||||
|
||||
assertEquals("irisworldgen:overworld", ModdedForcedDatapack.dimensionTypeRef(overworld));
|
||||
assertEquals("irisworldgen:nether", ModdedForcedDatapack.dimensionTypeRef(nether));
|
||||
assertEquals("irisworldgen:the_end", ModdedForcedDatapack.dimensionTypeRef(end));
|
||||
assertEquals("irisworldgen:packs/6f766572776f726c64/dimensions/6f766572776f726c64/dimension_type",
|
||||
ModdedWorldgenIds.dimensionTypeRef("overworld", overworld.getLoadKey()));
|
||||
assertEquals("irisworldgen:packs/6e6574686572/dimensions/6e6574686572/dimension_type",
|
||||
ModdedWorldgenIds.dimensionTypeRef("nether", nether.getLoadKey()));
|
||||
assertEquals("irisworldgen:packs/7468655f656e64/dimensions/7468655f656e64/dimension_type",
|
||||
ModdedWorldgenIds.dimensionTypeRef("the_end", end.getLoadKey()));
|
||||
assertNotEquals(ModdedWorldgenIds.dimensionTypeRef("first", "overworld"),
|
||||
ModdedWorldgenIds.dimensionTypeRef("second", "overworld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,18 +83,18 @@ public class ModdedDimensionTypeParityTest {
|
||||
roots.add(packDirectory.toFile());
|
||||
try {
|
||||
for (IrisDimension dimension : dimensions) {
|
||||
ModdedForcedDatapack.writeDimensionType(roots, fixer, dimension);
|
||||
Path output = packDirectory.resolve("data/irisworldgen/dimension_type/"
|
||||
+ dimension.getDimensionTypeKey() + ".json");
|
||||
ModdedForcedDatapack.writeDimensionType(
|
||||
roots, fixer, dimension, "contracts", dimension.getLoadKey());
|
||||
Path output = typeFile(packDirectory, "contracts", dimension);
|
||||
assertTrue(Files.isRegularFile(output));
|
||||
assertEquals(dimension.getDimensionType().toJson(fixer),
|
||||
Files.readString(output, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
JSONObject overworldJson = readType(packDirectory, overworld);
|
||||
JSONObject netherJson = readType(packDirectory, nether);
|
||||
JSONObject endJson = readType(packDirectory, end);
|
||||
JSONObject customJson = readType(packDirectory, custom);
|
||||
JSONObject overworldJson = readType(packDirectory, "contracts", overworld);
|
||||
JSONObject netherJson = readType(packDirectory, "contracts", nether);
|
||||
JSONObject endJson = readType(packDirectory, "contracts", end);
|
||||
JSONObject customJson = readType(packDirectory, "contracts", custom);
|
||||
|
||||
assertTrue(overworldJson.getBoolean("has_skylight"));
|
||||
assertFalse(overworldJson.getBoolean("has_ceiling"));
|
||||
@@ -166,10 +172,16 @@ public class ModdedDimensionTypeParityTest {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
private static JSONObject readType(Path packDirectory, IrisDimension dimension) throws IOException {
|
||||
Path output = packDirectory.resolve("data/irisworldgen/dimension_type/"
|
||||
+ dimension.getDimensionTypeKey() + ".json");
|
||||
return new JSONObject(Files.readString(output, StandardCharsets.UTF_8));
|
||||
private static JSONObject readType(Path packDirectory, String pack,
|
||||
IrisDimension dimension) throws IOException {
|
||||
return new JSONObject(Files.readString(
|
||||
typeFile(packDirectory, pack, dimension), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private static Path typeFile(Path packDirectory, String pack, IrisDimension dimension) {
|
||||
String typeRef = ModdedWorldgenIds.dimensionTypeRef(pack, dimension.getLoadKey());
|
||||
return packDirectory.resolve("data/irisworldgen/dimension_type/")
|
||||
.resolve(typeRef.substring(typeRef.indexOf(':') + 1) + ".json");
|
||||
}
|
||||
|
||||
private static void deleteTree(Path root) throws IOException {
|
||||
|
||||
+15
@@ -39,6 +39,21 @@ import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedForcedDatapackTest {
|
||||
@Test
|
||||
public void packScopedIdsCannotCollideAndHaveReadableLabels() {
|
||||
String first = ModdedWorldgenIds.presetRef("overworld", "overworld");
|
||||
String second = ModdedWorldgenIds.presetRef("other", "overworld");
|
||||
|
||||
assertFalse(first.equals(second));
|
||||
assertEquals("IRIS:Overworld",
|
||||
ModdedWorldgenIds.displayName(first.substring(first.indexOf(':') + 1)));
|
||||
assertEquals("IRIS:Other / Overworld",
|
||||
ModdedWorldgenIds.displayName(second.substring(second.indexOf(':') + 1)));
|
||||
assertEquals("iris:overworld", ModdedWorldgenIds.generatorIdentity("overworld"));
|
||||
assertEquals("iris:other/overworld",
|
||||
ModdedWorldgenIds.generatorIdentity("other:overworld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scopesSharedCustomBiomeIdsByNamespace() {
|
||||
Map<String, KSet<String>> seenBiomes = new LinkedHashMap<>();
|
||||
|
||||
+3
-4
@@ -60,16 +60,15 @@ public class ModdedLifecycleFailureContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistentReinjectionRethrowsTheOriginalCause() throws IOException {
|
||||
public void persistentReinjectionQuarantinesBrokenEntriesAndContinues() throws IOException {
|
||||
String source = source("ModdedStartup.java");
|
||||
String reinjection = method(source, "private static void reinjectPersistentDimensions(");
|
||||
String failure = catchBlock(reinjection);
|
||||
|
||||
assertTrue(failure.contains("LOGGER.error("));
|
||||
assertFalse(failure.contains("e.toString()"));
|
||||
assertFalse(failure.contains("continue;"));
|
||||
assertTrue(failure.contains("throw new IllegalStateException("));
|
||||
assertTrue(failure.contains(", e);"));
|
||||
assertFalse(failure.contains("throw new IllegalStateException("));
|
||||
assertTrue(reinjection.contains("injected++;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisModdedCommandParityTest {
|
||||
@Test
|
||||
public void registersPluginParityWhatCommandsAndAliases() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
IrisModdedCommands.register(dispatcher);
|
||||
|
||||
CommandNode<CommandSourceStack> iris = child(dispatcher.getRoot(), "iris");
|
||||
CommandNode<CommandSourceStack> what = child(iris, "what");
|
||||
child(what, "here");
|
||||
child(what, "biome");
|
||||
child(what, "region");
|
||||
child(what, "block");
|
||||
child(what, "hand");
|
||||
child(what, "markers");
|
||||
child(iris, "dust");
|
||||
child(iris, "d");
|
||||
child(iris, "create");
|
||||
child(iris, "c");
|
||||
child(iris, "teleport");
|
||||
child(iris, "tp");
|
||||
child(iris, "height");
|
||||
child(iris, "worlds");
|
||||
child(iris, "accesslist");
|
||||
|
||||
CommandNode<CommandSourceStack> edit = child(iris, "edit");
|
||||
child(edit, "b");
|
||||
child(edit, "r");
|
||||
child(edit, "d");
|
||||
CommandNode<CommandSourceStack> studio = child(iris, "studio");
|
||||
child(studio, "package");
|
||||
child(studio, "pkg");
|
||||
|
||||
CommandNode<CommandSourceStack> download = child(iris, "download");
|
||||
CommandNode<CommandSourceStack> pack = child(download, "pack");
|
||||
child(pack, "force");
|
||||
child(pack, "overwrite");
|
||||
CommandNode<CommandSourceStack> branch = child(pack, "branch");
|
||||
child(branch, "force");
|
||||
child(branch, "overwrite");
|
||||
|
||||
assertSame(iris, child(dispatcher.getRoot(), "ir").getRedirect());
|
||||
assertSame(iris, child(dispatcher.getRoot(), "irs").getRedirect());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void helpDocumentsParityCommandsAndPlatformStubs() {
|
||||
assertTrue(ModdedCommandHelp.documents("what", "here"));
|
||||
assertTrue(ModdedCommandHelp.documents("what", "biome"));
|
||||
assertTrue(ModdedCommandHelp.documents("what", "region"));
|
||||
assertTrue(ModdedCommandHelp.documents("what", "block"));
|
||||
assertTrue(ModdedCommandHelp.documents("what", "hand"));
|
||||
assertTrue(ModdedCommandHelp.documents("what", "markers"));
|
||||
assertTrue(ModdedCommandHelp.documents("", "dust"));
|
||||
assertTrue(ModdedCommandHelp.documents("", "teleport"));
|
||||
assertTrue(ModdedCommandHelp.documents("", "c"));
|
||||
assertTrue(ModdedCommandHelp.documents("edit", "b"));
|
||||
assertTrue(ModdedCommandHelp.documents("studio", "pkg"));
|
||||
assertTrue(ModdedCommandHelp.documents("object", "we"));
|
||||
assertTrue(ModdedCommandHelp.documents("world", "mainworld"));
|
||||
}
|
||||
|
||||
private static CommandNode<CommandSourceStack> child(
|
||||
CommandNode<CommandSourceStack> parent, String name) {
|
||||
CommandNode<CommandSourceStack> child = parent.getChild(name);
|
||||
assertNotNull(name, child);
|
||||
return child;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class IrisModdedStructureCommandTest {
|
||||
assertTrue(source.contains("combineStructureKeys(irisKeys, nativeKeys)"));
|
||||
assertTrue(source.contains("irisGenerator.isNativeStructureReachable(holder)"));
|
||||
assertTrue(source.contains("LocateStatus.SEARCH_LIMIT_REACHED"));
|
||||
assertTrue(source.contains("the density search safety limit was reached"));
|
||||
assertTrue(source.contains("IRIS_MODDED_COMMANDS_UNABLE_LOCATE_IRIS_PLACED_STRUCTURE_DENSITY_SEARCH_SAFETY_LIMIT_WAS"));
|
||||
assertTrue(source.contains("int targetX = result.originX()"));
|
||||
assertTrue(source.contains("int targetY = result.baseY() + 2"));
|
||||
assertTrue(source.contains("int targetZ = result.originZ()"));
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedDustRevealerTest {
|
||||
@Test
|
||||
public void placementClassificationCoversObjectDecorationAndTerrain() {
|
||||
assertTrue(ModdedDustRevealer.placementLine(3, 10, 13, "tree")
|
||||
.contains("object/stilt 'tree'"));
|
||||
assertTrue(ModdedDustRevealer.placementLine(3, 10, 13, null)
|
||||
.contains("decoration/object/stilt"));
|
||||
assertTrue(ModdedDustRevealer.placementLine(0, 10, 10, "ore")
|
||||
.contains("buried object 'ore'"));
|
||||
assertTrue(ModdedDustRevealer.placementLine(-4, 10, 6, null)
|
||||
.contains("depth 4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void revealTraversalUsesDiagonalAdjacencyButNotDisconnectedBlocks() {
|
||||
Set<BlockPos> object = Set.of(
|
||||
new BlockPos(0, 0, 0),
|
||||
new BlockPos(1, 1, 1),
|
||||
new BlockPos(3, 3, 3));
|
||||
List<BlockPos> hits = ModdedDustRevealer.collect(
|
||||
new BlockPos(0, 0, 0),
|
||||
"object",
|
||||
-64,
|
||||
-64,
|
||||
320,
|
||||
new AtomicBoolean(),
|
||||
(int x, int relativeY, int z) ->
|
||||
object.contains(new BlockPos(x, relativeY - 64, z))
|
||||
? "object"
|
||||
: null);
|
||||
|
||||
assertEquals(List.of(new BlockPos(0, 0, 0), new BlockPos(1, 1, 1)), hits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelledRevealDoesNoTraversal() {
|
||||
List<BlockPos> hits = ModdedDustRevealer.collect(
|
||||
new BlockPos(0, 0, 0),
|
||||
"object",
|
||||
-64,
|
||||
-64,
|
||||
320,
|
||||
new AtomicBoolean(true),
|
||||
(int x, int relativeY, int z) -> "object");
|
||||
|
||||
assertTrue(hits.isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,10 @@ neoForge {
|
||||
accessTransformers.from('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
|
||||
runs {
|
||||
client {
|
||||
client()
|
||||
jvmArgument('-Xmx8G')
|
||||
}
|
||||
server {
|
||||
server()
|
||||
String parity = providers.gradleProperty('irisParity').getOrNull()
|
||||
|
||||
@@ -52,6 +52,9 @@ public final class IrisNeoForgeClient {
|
||||
});
|
||||
NeoForge.EVENT_BUS.addListener((ClientPlayerNetworkEvent.LoggingIn event) -> IrisClient.onWorldJoin());
|
||||
NeoForge.EVENT_BUS.addListener((ClientPlayerNetworkEvent.LoggingOut event) -> IrisClient.onDisconnect());
|
||||
NeoForge.EVENT_BUS.addListener((ClientTickEvent.Post event) -> IrisClientKeybinds.pollToggle());
|
||||
NeoForge.EVENT_BUS.addListener((ClientTickEvent.Post event) -> {
|
||||
IrisClient.tick();
|
||||
IrisClientKeybinds.pollToggle();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
public net.minecraft.server.MinecraftServer levels
|
||||
public net.minecraft.server.MinecraftServer executor
|
||||
public net.minecraft.server.MinecraftServer storageSource
|
||||
public net.minecraft.core.MappedRegistry frozen
|
||||
|
||||
@@ -5,6 +5,9 @@ license = "GPL-3.0"
|
||||
[[mixins]]
|
||||
config = "irisworldgen.entity.mixins.json"
|
||||
|
||||
[[mixins]]
|
||||
config = "irisworldgen.client.mixins.json"
|
||||
|
||||
[[mods]]
|
||||
modId = "irisworldgen"
|
||||
version = "${version}"
|
||||
|
||||
@@ -354,6 +354,70 @@ public final class ModdedHelpMessages {
|
||||
"iris.modded.help.entry.command.network",
|
||||
"List network interfaces and their addresses"
|
||||
);
|
||||
public static final TextKey COMMAND_WHAT_HERE_INSPECT_CURRENT_IRIS_CONTEXT = TextKey.of(
|
||||
"iris.modded.help.entry.command.what.here",
|
||||
"Inspect the Iris biome, region, cave biome, surface and chunk at your position"
|
||||
);
|
||||
public static final TextKey COMMAND_WHAT_BIOME_INSPECT_CURRENT_BIOME = TextKey.of(
|
||||
"iris.modded.help.entry.command.what.biome",
|
||||
"Inspect the Iris biome, configured derivative and registered native biome"
|
||||
);
|
||||
public static final TextKey COMMAND_WHAT_REGION_INSPECT_CURRENT_REGION = TextKey.of(
|
||||
"iris.modded.help.entry.command.what.region",
|
||||
"Inspect the Iris region at your current chunk"
|
||||
);
|
||||
public static final TextKey COMMAND_WHAT_BLOCK_INSPECT_TARGET_BLOCK = TextKey.of(
|
||||
"iris.modded.help.entry.command.what.block",
|
||||
"Inspect the targeted block state, properties, object and block entity"
|
||||
);
|
||||
public static final TextKey COMMAND_WHAT_HAND_INSPECT_HELD_ITEM = TextKey.of(
|
||||
"iris.modded.help.entry.command.what.hand",
|
||||
"Inspect the held item and its default block state"
|
||||
);
|
||||
public static final TextKey COMMAND_WHAT_MARKERS_REVEAL_NEARBY_MARKERS = TextKey.of(
|
||||
"iris.modded.help.entry.command.what.markers",
|
||||
"Reveal nearby Iris Mantle markers with particles"
|
||||
);
|
||||
public static final TextKey COMMAND_HEIGHT_PRINT_WORLD_HEIGHT = TextKey.of(
|
||||
"iris.modded.help.entry.command.height",
|
||||
"Print the current dimension height range"
|
||||
);
|
||||
public static final TextKey COMMAND_WORLDS_LIST_WORLD_ACCESS = TextKey.of(
|
||||
"iris.modded.help.entry.command.worlds",
|
||||
"List loaded dimensions and identify the Iris-generated dimensions"
|
||||
);
|
||||
public static final TextKey COMMAND_MAINWORLD_CONFIGURE_PRIMARY_WORLD_PRESET = TextKey.of(
|
||||
"iris.modded.help.entry.command.mainworld",
|
||||
"Configure or clear the Iris primary-world preset used on restart"
|
||||
);
|
||||
public static final TextKey COMMAND_OBJECT_WE_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.object.we",
|
||||
"Explain why WorldEdit selection import requires the Bukkit plugin"
|
||||
);
|
||||
public static final TextKey COMMAND_OBJECT_STUDIO_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.object.studio",
|
||||
"Explain why the object studio world requires the Bukkit toolchain"
|
||||
);
|
||||
public static final TextKey COMMAND_OBJECT_CONVERT_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.object.convert",
|
||||
"Explain why schematic conversion requires the Bukkit plugin"
|
||||
);
|
||||
public static final TextKey COMMAND_STUDIO_LOOT_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.studio.loot",
|
||||
"Explain why the Bukkit loot simulation GUI is unavailable"
|
||||
);
|
||||
public static final TextKey COMMAND_STUDIO_PROFILE_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.studio.profile",
|
||||
"Explain why Bukkit pack profiling is unavailable"
|
||||
);
|
||||
public static final TextKey COMMAND_STUDIO_SPAWN_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.studio.spawn",
|
||||
"Explain why Bukkit Iris entity spawning is unavailable"
|
||||
);
|
||||
public static final TextKey COMMAND_STUDIO_OBJECTS_BUKKIT_ONLY = TextKey.of(
|
||||
"iris.modded.help.entry.command.studio.objects",
|
||||
"Explain why the Bukkit chunk object report is unavailable"
|
||||
);
|
||||
|
||||
private static final List<MessageKey> KEYS = List.of(
|
||||
COMMAND_VERSION_PRINT_VERSION_INFORMATION,
|
||||
@@ -442,7 +506,23 @@ public final class ModdedHelpMessages {
|
||||
COMMAND_CAPTURE_EXPLAIN_BUKKIT_STRUCTURE_CAPTURE_WORKFLOW,
|
||||
COMMAND_VERIFY_REPORT_NATIVE_AND_IRIS_STRUCTURE_REACHABILITY_IN_THE_CURRENT_DIMENSION,
|
||||
COMMAND_SENTRY_SEND_A_TEST_EXCEPTION_TO_THE_IRIS_ERROR_REPORTER,
|
||||
COMMAND_NETWORK_LIST_NETWORK_INTERFACES_AND_THEIR_ADDRESSES
|
||||
COMMAND_NETWORK_LIST_NETWORK_INTERFACES_AND_THEIR_ADDRESSES,
|
||||
COMMAND_WHAT_HERE_INSPECT_CURRENT_IRIS_CONTEXT,
|
||||
COMMAND_WHAT_BIOME_INSPECT_CURRENT_BIOME,
|
||||
COMMAND_WHAT_REGION_INSPECT_CURRENT_REGION,
|
||||
COMMAND_WHAT_BLOCK_INSPECT_TARGET_BLOCK,
|
||||
COMMAND_WHAT_HAND_INSPECT_HELD_ITEM,
|
||||
COMMAND_WHAT_MARKERS_REVEAL_NEARBY_MARKERS,
|
||||
COMMAND_HEIGHT_PRINT_WORLD_HEIGHT,
|
||||
COMMAND_WORLDS_LIST_WORLD_ACCESS,
|
||||
COMMAND_MAINWORLD_CONFIGURE_PRIMARY_WORLD_PRESET,
|
||||
COMMAND_OBJECT_WE_BUKKIT_ONLY,
|
||||
COMMAND_OBJECT_STUDIO_BUKKIT_ONLY,
|
||||
COMMAND_OBJECT_CONVERT_BUKKIT_ONLY,
|
||||
COMMAND_STUDIO_LOOT_BUKKIT_ONLY,
|
||||
COMMAND_STUDIO_PROFILE_BUKKIT_ONLY,
|
||||
COMMAND_STUDIO_SPAWN_BUKKIT_ONLY,
|
||||
COMMAND_STUDIO_OBJECTS_BUKKIT_ONLY
|
||||
);
|
||||
|
||||
private ModdedHelpMessages() {
|
||||
|
||||
@@ -92,6 +92,33 @@ public final class RuntimeUiMessages {
|
||||
public static final TextKey DUST_OBJECTS_IN_CHUNK = TextKey.of("iris.runtime.dust.objects_in_chunk", "Objects in chunk: {objects}");
|
||||
public static final TextKey DUST_COPY_BUTTON = TextKey.of("iris.runtime.dust.copy_button", "[Click to copy these stats]");
|
||||
public static final TextKey DUST_COPY_HOVER = TextKey.of("iris.runtime.dust.copy_hover", "Copy block stats to clipboard");
|
||||
public static final TextKey DUST_REVEAL_FAILED = TextKey.of("iris.runtime.dust.reveal_failed", "Object reveal failed; see the console for details.");
|
||||
public static final TextKey WHAT_MATERIAL = TextKey.of("iris.runtime.what.material", "Material: {material}");
|
||||
public static final TextKey WHAT_FULL_STATE = TextKey.of("iris.runtime.what.full_state", "Full: {state}");
|
||||
public static final TextKey WHAT_ITEM_COUNT = TextKey.of("iris.runtime.what.item_count", "Count: {count}");
|
||||
public static final TextKey WHAT_IRIS_BIOME = TextKey.of("iris.runtime.what.iris_biome", "Iris biome: {biome} ({name})");
|
||||
public static final TextKey WHAT_DERIVATIVE_BIOME = TextKey.of("iris.runtime.what.derivative_biome", "Derivative biome: {biome}");
|
||||
public static final TextKey WHAT_NATIVE_BIOME = TextKey.of("iris.runtime.what.native_biome", "Registered biome: {biome} (ID: {id})");
|
||||
public static final TextKey WHAT_NON_IRIS_BIOME = TextKey.of("iris.runtime.what.non_iris_biome", "Non-Iris biome: {biome} (ID: {id})");
|
||||
public static final TextKey WHAT_IRIS_REGION = TextKey.of("iris.runtime.what.iris_region", "Iris region: {region} ({name})");
|
||||
public static final TextKey WHAT_POSITION = TextKey.of("iris.runtime.what.position", "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})");
|
||||
public static final TextKey WHAT_OBJECT = TextKey.of("iris.runtime.what.object", "Iris object: {object}");
|
||||
public static final TextKey WHAT_BLOCK_ENTITY = TextKey.of("iris.runtime.what.block_entity", "Block entity: {type}");
|
||||
public static final TextKey WHAT_LOOT_TABLE = TextKey.of("iris.runtime.what.loot_table", "Loot table: {loot}");
|
||||
public static final TextKey WHAT_SPAWNER_ENTITY = TextKey.of("iris.runtime.what.spawner_entity", "Spawner entity: {entity}");
|
||||
public static final TextKey WHAT_FLAG_SOLID = TextKey.of("iris.runtime.what.flag.solid", "solid");
|
||||
public static final TextKey WHAT_FLAG_FLUID = TextKey.of("iris.runtime.what.flag.fluid", "fluid");
|
||||
public static final TextKey WHAT_FLAG_WATER = TextKey.of("iris.runtime.what.flag.water", "water");
|
||||
public static final TextKey WHAT_FLAG_WATERLOGGED = TextKey.of("iris.runtime.what.flag.waterlogged", "waterlogged");
|
||||
public static final TextKey WHAT_FLAG_STORAGE = TextKey.of("iris.runtime.what.flag.storage", "storage (loot capable)");
|
||||
public static final TextKey WHAT_FLAG_LIT = TextKey.of("iris.runtime.what.flag.lit", "lit");
|
||||
public static final TextKey WHAT_FLAG_FOLIAGE = TextKey.of("iris.runtime.what.flag.foliage", "foliage");
|
||||
public static final TextKey WHAT_FLAG_PLANTABLE_FOLIAGE = TextKey.of("iris.runtime.what.flag.plantable_foliage", "plantable foliage");
|
||||
public static final TextKey WHAT_FLAG_DECORANT = TextKey.of("iris.runtime.what.flag.decorant", "decorant");
|
||||
public static final TextKey WHAT_FLAG_ORE = TextKey.of("iris.runtime.what.flag.ore", "ore");
|
||||
public static final TextKey WHAT_FLAG_BLOCK_ENTITY = TextKey.of("iris.runtime.what.flag.block_entity", "block entity");
|
||||
public static final TextKey WORLD_HEIGHT_RANGE = TextKey.of("iris.runtime.world.height_range", "World height: {minY} to {maxY}");
|
||||
public static final TextKey WORLD_HEIGHT_TOTAL = TextKey.of("iris.runtime.world.height_total", "Total height: {height}");
|
||||
public static final TextKey PREGEN_STARTING = TextKey.of("iris.runtime.pregen.starting", "Iris Pregen starting...");
|
||||
public static final TextKey PREGEN_HEADER = TextKey.of("iris.runtime.pregen.header", "Iris Pregen");
|
||||
public static final TextKey PREGEN_BOSSBAR_PAUSED = TextKey.of("iris.runtime.pregen.bossbar.paused", "Iris Pregen {generated}/{total} {percent}% PAUSED");
|
||||
@@ -196,6 +223,33 @@ public final class RuntimeUiMessages {
|
||||
DUST_OBJECTS_IN_CHUNK,
|
||||
DUST_COPY_BUTTON,
|
||||
DUST_COPY_HOVER,
|
||||
DUST_REVEAL_FAILED,
|
||||
WHAT_MATERIAL,
|
||||
WHAT_FULL_STATE,
|
||||
WHAT_ITEM_COUNT,
|
||||
WHAT_IRIS_BIOME,
|
||||
WHAT_DERIVATIVE_BIOME,
|
||||
WHAT_NATIVE_BIOME,
|
||||
WHAT_NON_IRIS_BIOME,
|
||||
WHAT_IRIS_REGION,
|
||||
WHAT_POSITION,
|
||||
WHAT_OBJECT,
|
||||
WHAT_BLOCK_ENTITY,
|
||||
WHAT_LOOT_TABLE,
|
||||
WHAT_SPAWNER_ENTITY,
|
||||
WHAT_FLAG_SOLID,
|
||||
WHAT_FLAG_FLUID,
|
||||
WHAT_FLAG_WATER,
|
||||
WHAT_FLAG_WATERLOGGED,
|
||||
WHAT_FLAG_STORAGE,
|
||||
WHAT_FLAG_LIT,
|
||||
WHAT_FLAG_FOLIAGE,
|
||||
WHAT_FLAG_PLANTABLE_FOLIAGE,
|
||||
WHAT_FLAG_DECORANT,
|
||||
WHAT_FLAG_ORE,
|
||||
WHAT_FLAG_BLOCK_ENTITY,
|
||||
WORLD_HEIGHT_RANGE,
|
||||
WORLD_HEIGHT_TOTAL,
|
||||
PREGEN_STARTING,
|
||||
PREGEN_HEADER,
|
||||
PREGEN_BOSSBAR_PAUSED,
|
||||
|
||||
@@ -31,7 +31,7 @@ public final class IrisCursorResolver {
|
||||
IrisBiome surfaceBiome = engine.getSurfaceBiome(blockX, blockZ);
|
||||
IrisRegion region = engine.getRegion(blockX, blockZ);
|
||||
IrisBiome caveBiome = engine.getCaveBiome(blockX, blockZ);
|
||||
int height = engine.getHeight(blockX, blockZ);
|
||||
int height = engine.getMinHeight() + engine.getHeight(blockX, blockZ);
|
||||
String biomeKey = keyOf(surfaceBiome == null ? null : surfaceBiome.getLoadKey());
|
||||
String regionKey = keyOf(region == null ? null : region.getLoadKey());
|
||||
String caveBiomeKey = keyOf(caveBiome == null ? null : caveBiome.getLoadKey());
|
||||
|
||||
@@ -284,11 +284,11 @@ public final class IrisProtocolServer {
|
||||
}
|
||||
|
||||
private void dispatch(IrisSession session, IrisMessage message) {
|
||||
if (session.state() == IrisSession.State.AWAITING_HELLO) {
|
||||
if (message instanceof IrisMessage.ClientHello clientHello) {
|
||||
onClientHello(session, clientHello);
|
||||
return;
|
||||
}
|
||||
if (session.state() == IrisSession.State.AWAITING_HELLO) {
|
||||
droppedBeforeHello.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -524,7 +524,11 @@ public class IrisDimension extends IrisRegistrant {
|
||||
|
||||
public void installBiomes(IDataFixer fixer, DataProvider data, KList<File> datapackRoots, KSet<String> biomes) throws IOException {
|
||||
String namespace = getLoadKey().toLowerCase(Locale.ROOT);
|
||||
installBiomes(fixer, data, datapackRoots, namespace, "", biomes);
|
||||
}
|
||||
|
||||
public void installBiomes(IDataFixer fixer, DataProvider data, KList<File> datapackRoots,
|
||||
String namespace, String pathPrefix, KSet<String> biomes) throws IOException {
|
||||
for (IrisBiome irisBiome : getAllBiomes(data)) {
|
||||
if (!irisBiome.isCustom()) {
|
||||
continue;
|
||||
@@ -542,12 +546,15 @@ public class IrisDimension extends IrisRegistrant {
|
||||
}
|
||||
|
||||
for (File datapackRoot : datapackRoots) {
|
||||
File output = new File(datapackRoot, "data/" + namespace + "/worldgen/biome/" + customBiomeId + ".json");
|
||||
String biomePath = pathPrefix.isBlank()
|
||||
? customBiomeId
|
||||
: pathPrefix + "/" + customBiomeId;
|
||||
File output = new File(datapackRoot, "data/" + namespace + "/worldgen/biome/" + biomePath + ".json");
|
||||
|
||||
IrisLogging.debug(" Installing Data Pack Biome: " + output.getPath());
|
||||
output.getParentFile().mkdirs();
|
||||
IO.writeAll(output, json);
|
||||
installBiomeTags(datapackRoot, namespace + ":" + customBiomeId, customBiome.getTags());
|
||||
installBiomeTags(datapackRoot, namespace + ":" + biomePath, customBiome.getTags());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "Geschwindigkeit: zwischengespeichert {chunksPerSecond} Chunks/s, {regionsPerMinute} Regionen/m, {chunksPerMinute} Chunks/m",
|
||||
"iris.desktop.pregen.time": "{remaining} verbleibend ({elapsed} abgelaufen)",
|
||||
"iris.desktop.pregen.method": "Erzeugungsmethode: {method}",
|
||||
"iris.desktop.pregen.memory": "Speicher: {used} ({usage}) Druck: {pressure}/s"
|
||||
"iris.desktop.pregen.memory": "Speicher: {used} ({usage}) Druck: {pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspect the Iris biome, region, cave biome, surface and chunk at your position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "Velocidad: en caché {chunksPerSecond} chunks/s, {regionsPerMinute} regiones/m, {chunksPerMinute} chunks/m",
|
||||
"iris.desktop.pregen.time": "{remaining} restantes ({elapsed} transcurridos)",
|
||||
"iris.desktop.pregen.method": "Método de generación: {method}",
|
||||
"iris.desktop.pregen.memory": "Memoria: {used} ({usage}) Presión: {pressure}/s"
|
||||
"iris.desktop.pregen.memory": "Memoria: {used} ({usage}) Presión: {pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspect the Iris biome, region, cave biome, surface and chunk at your position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "Nopeus: välimuisti {chunksPerSecond} chunkia/s, {regionsPerMinute} alueet/m {chunksPerMinute} chunkia/m",
|
||||
"iris.desktop.pregen.time": "{remaining} jäljellä ({elapsed} Kulunut)",
|
||||
"iris.desktop.pregen.method": "Generointimenetelmä: {method}",
|
||||
"iris.desktop.pregen.memory": "Muisti: {used} ({usage}) Paine: {pressure}/s"
|
||||
"iris.desktop.pregen.memory": "Muisti: {used} ({usage}) Paine: {pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspect the Iris biome, region, cave biome, surface and chunk at your position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "Vitesse : cache {chunksPerSecond} chunks/s, {regionsPerMinute} régions/m, {chunksPerMinute} chunks/m",
|
||||
"iris.desktop.pregen.time": "{remaining} restantes ({elapsed} écoulées)",
|
||||
"iris.desktop.pregen.method": "Méthode de génération : {method}",
|
||||
"iris.desktop.pregen.memory": "Mémoire : {used} ({usage}) Pression : {pressure}/s"
|
||||
"iris.desktop.pregen.memory": "Mémoire : {used} ({usage}) Pression : {pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspecter le biome Iris, la région, le biome souterrain, la surface et le chunk à votre position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "מהירות: במטמון {chunksPerSecond} צ'אנקים/s, {regionsPerMinute} אזורים/m, {chunksPerMinute} צ'אנקים/m",
|
||||
"iris.desktop.pregen.time": "{remaining} הנותרים ({elapsed} מת)",
|
||||
"iris.desktop.pregen.method": "שיטת דור: {method}",
|
||||
"iris.desktop.pregen.memory": "זיכרון:{used} ({usage}לחץ:{pressure}/s"
|
||||
"iris.desktop.pregen.memory": "זיכרון:{used} ({usage}לחץ:{pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspect the Iris biome, region, cave biome, surface and chunk at your position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "Velocità: cache {chunksPerSecond} chunk/s, {regionsPerMinute} regioni/m, {chunksPerMinute} chunk/m",
|
||||
"iris.desktop.pregen.time": "{remaining} rimanenti ({elapsed} trascorso)",
|
||||
"iris.desktop.pregen.method": "Metodo di generazione: {method}",
|
||||
"iris.desktop.pregen.memory": "Memoria: {used} ({usage}) Pressione: {pressure}/s"
|
||||
"iris.desktop.pregen.memory": "Memoria: {used} ({usage}) Pressione: {pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspect the Iris biome, region, cave biome, surface and chunk at your position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,6 +1427,49 @@
|
||||
"iris.desktop.pregen.speed_cached": "速度: キャッシュ {chunksPerSecond} チャンク/s、{regionsPerMinute} リージョン/m、{chunksPerMinute} チャンク/m",
|
||||
"iris.desktop.pregen.time": "残り {remaining}(経過 {elapsed})",
|
||||
"iris.desktop.pregen.method": "生成方法: {method}",
|
||||
"iris.desktop.pregen.memory": "メモリ: {used}({usage})負荷: {pressure}/s"
|
||||
"iris.desktop.pregen.memory": "メモリ: {used}({usage})負荷: {pressure}/s",
|
||||
"iris.modded.help.entry.command.what.here": "Inspect the Iris biome, region, cave biome, surface and chunk at your position",
|
||||
"iris.modded.help.entry.command.what.biome": "Inspect the Iris biome, configured derivative and registered native biome",
|
||||
"iris.modded.help.entry.command.what.region": "Inspect the Iris region at your current chunk",
|
||||
"iris.modded.help.entry.command.what.block": "Inspect the targeted block state, properties, object and block entity",
|
||||
"iris.modded.help.entry.command.what.hand": "Inspect the held item and its default block state",
|
||||
"iris.modded.help.entry.command.what.markers": "Reveal nearby Iris Mantle markers with particles",
|
||||
"iris.modded.help.entry.command.height": "Print the current dimension height range",
|
||||
"iris.modded.help.entry.command.worlds": "List loaded dimensions and identify the Iris-generated dimensions",
|
||||
"iris.modded.help.entry.command.mainworld": "Configure or clear the Iris primary-world preset used on restart",
|
||||
"iris.modded.help.entry.command.object.we": "Explain why WorldEdit selection import requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.object.studio": "Explain why the object studio world requires the Bukkit toolchain",
|
||||
"iris.modded.help.entry.command.object.convert": "Explain why schematic conversion requires the Bukkit plugin",
|
||||
"iris.modded.help.entry.command.studio.loot": "Explain why the Bukkit loot simulation GUI is unavailable",
|
||||
"iris.modded.help.entry.command.studio.profile": "Explain why Bukkit pack profiling is unavailable",
|
||||
"iris.modded.help.entry.command.studio.spawn": "Explain why Bukkit Iris entity spawning is unavailable",
|
||||
"iris.modded.help.entry.command.studio.objects": "Explain why the Bukkit chunk object report is unavailable",
|
||||
"iris.runtime.dust.reveal_failed": "Object reveal failed; see the console for details.",
|
||||
"iris.runtime.what.material": "Material: {material}",
|
||||
"iris.runtime.what.full_state": "Full: {state}",
|
||||
"iris.runtime.what.item_count": "Count: {count}",
|
||||
"iris.runtime.what.iris_biome": "Iris biome: {biome} ({name})",
|
||||
"iris.runtime.what.derivative_biome": "Derivative biome: {biome}",
|
||||
"iris.runtime.what.native_biome": "Registered biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.non_iris_biome": "Non-Iris biome: {biome} (ID: {id})",
|
||||
"iris.runtime.what.iris_region": "Iris region: {region} ({name})",
|
||||
"iris.runtime.what.position": "Position: {x}, {y}, {z} (chunk {chunkX}, {chunkZ})",
|
||||
"iris.runtime.what.object": "Iris object: {object}",
|
||||
"iris.runtime.what.block_entity": "Block entity: {type}",
|
||||
"iris.runtime.what.loot_table": "Loot table: {loot}",
|
||||
"iris.runtime.what.spawner_entity": "Spawner entity: {entity}",
|
||||
"iris.runtime.what.flag.solid": "solid",
|
||||
"iris.runtime.what.flag.fluid": "fluid",
|
||||
"iris.runtime.what.flag.water": "water",
|
||||
"iris.runtime.what.flag.waterlogged": "waterlogged",
|
||||
"iris.runtime.what.flag.storage": "storage (loot capable)",
|
||||
"iris.runtime.what.flag.lit": "lit",
|
||||
"iris.runtime.what.flag.foliage": "foliage",
|
||||
"iris.runtime.what.flag.plantable_foliage": "plantable foliage",
|
||||
"iris.runtime.what.flag.decorant": "decorant",
|
||||
"iris.runtime.what.flag.ore": "ore",
|
||||
"iris.runtime.what.flag.block_entity": "block entity",
|
||||
"iris.runtime.world.height_range": "World height: {minY} to {maxY}",
|
||||
"iris.runtime.world.height_total": "Total height: {height}"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user