diff --git a/README.md b/README.md index 7c2dadadb..bf193a837 100644 --- a/README.md +++ b/README.md @@ -64,22 +64,20 @@ content selecting on `#minecraft:is_overworld` and friends. **Plugin (Paper/Purpur/Leaf/Canvas/Folia/Spigot):** drop the plugin jar into `plugins/` and start the server. First boot performs no pack download. Run `/iris download pack=overworld`, `/iris download pack=underworld`, or `/iris download link=https://host/path/pack.zip`, waiting for -each download to finish before starting another. The shipping Overworld declares Towns & Towers -26.1 and Dungeons & Taverns 5.3.0. With the default automatic ingest enabled, the first restart -after download installs those external datapacks and leaves admission restart-required; complete -the ensuing clean restart so Minecraft loads them together with the Iris dimension types and -biomes. If automatic ingest is disabled, run `/iris datapack ingest restart=true` instead and -complete the restart it requests. Plain Spigot supports ordinary managed `/iris create`, but not +each download to finish before starting another. The current built-in packs declare no external +datapack imports. Restart after download so Minecraft loads their dimension types and biomes. +Custom packs that declare `datapackImports` must complete their external-datapack installation and +registry restart first. Plain Spigot supports ordinary managed `/iris create`, but not the early-bootstrap `/iris replace` path for canonical Overworld, Nether, or End slots. **Mod (Fabric/Forge/NeoForge):** drop the mod jar into `mods/` and start the server. The jar is self-contained (core, SPI, and required Fabric API modules are bundled). First boot compiles only packs already on disk and never accesses the network. `/iris download` installs a pack atomically -without stopping the server. Before loading the shipping Overworld, manually place the exact -compatible Towns & Towers 26.1 and Dungeons & Taverns 5.3.0 archives in that save's `datapacks/` -directory; modded `/iris datapack ingest` is an explanatory stub and does not install them. Restart -once only after the Iris pack and both external datapacks are present. Packs register their custom -dimension types, height ranges, biomes, and external structure keys during that boot; worlds created +without stopping the server. The current built-in packs declare no external datapack imports. +Custom packs that declare them require compatible archives in that save's `datapacks/` directory; +modded `/iris datapack ingest` is an explanatory stub and does not install them. Restart only after +the Iris pack and all of its inputs are present. Packs register their custom dimension types, +height ranges, biomes, and external structure keys during that boot; worlds created before it run with fallback registry data. **Singleplayer (modded clients):** installed Iris packs appear as selectable World Types on the @@ -237,7 +235,7 @@ Requirements: JDK 25 (set `JAVA_HOME` to it). The Gradle wrapper handles everyth ./gradlew buildAllToOut ``` -builds every platform artifact into `dist/`: +builds every platform artifact into the workspace-level `../PluginOuts/` directory: ``` Iris v [CraftBukkit] .jar diff --git a/adapters/bukkit/plugin/build.gradle b/adapters/bukkit/plugin/build.gradle index 88404947e..f5033c170 100644 --- a/adapters/bukkit/plugin/build.gradle +++ b/adapters/bukkit/plugin/build.gradle @@ -21,7 +21,6 @@ dependencies { testImplementation('org.mockito:mockito-core:5.23.0') testImplementation(libs.paper.api) testImplementation(libs.bstats) - testImplementation(libs.sentry) testImplementation(project(':core')) testImplementation(volmLibCoordinate) { transitive = false diff --git a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/Iris.java b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/Iris.java index 15ddaacf6..6180a12bf 100644 --- a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/Iris.java +++ b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/Iris.java @@ -423,7 +423,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware { return; } - Bindings.capture(e); boolean debug = false; if (instance != null) { try { @@ -455,6 +454,8 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware { Iris.debug("Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage()); } + + e.printStackTrace(System.err); } public static void reportError(String context, Throwable e) { @@ -473,7 +474,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware { } reportError(error); - error.printStackTrace(System.err); } public static void dump() { @@ -606,7 +606,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware { SimdSupport.install(); services = new KMap<>(); BukkitPlatform.hostHud(new HudActionBar(this), new HudBossBarLane()); - Bindings.setupSentry(); // Explicit, ordered service list: the previous reflective jar scan gave hash-ordered // enable/disable and paid a full-jar class sweep at boot. Infrastructure first, // engine/world services next, commands last. diff --git a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/commands/CommandDeveloper.java b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/commands/CommandDeveloper.java index d821b1acc..3789cdb0f 100644 --- a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/commands/CommandDeveloper.java +++ b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/commands/CommandDeveloper.java @@ -34,7 +34,6 @@ import art.arcane.iris.engine.IrisEngineMantle; import art.arcane.iris.engine.framework.Engine; import art.arcane.iris.engine.object.IrisDimension; import art.arcane.iris.engine.platform.PlatformChunkGenerator; -import art.arcane.iris.util.project.context.IrisContext; import art.arcane.iris.util.project.matter.IrisMatterContext; import art.arcane.iris.util.common.director.DirectorExecutor; import art.arcane.volmlib.util.director.DirectorOrigin; @@ -79,19 +78,6 @@ public class CommandDeveloper implements DirectorExecutor { .engineStatus(sender()); } - @Director(description = "Send a test exception to sentry", descriptionKey = "iris.director.commanddeveloper.director.send_test_exception_sentry") - public void Sentry() { - Engine engine = engine(); - Exception testException = new Exception("This is a test"); - if (engine == null) { - Iris.reportError(testException); - return; - } - try (IrisContext.Scope scope = IrisContext.open(engine, engine.getGenerationSessionId(), null)) { - Iris.reportError(testException); - } - } - @Director(description = "Hash generated block output of a fixed area for determinism/identity testing", descriptionKey = "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing", origin = DirectorOrigin.BOTH) public void genhash( @Param(description = "The world to hash", descriptionKey = "iris.director.commanddeveloper.param.world_hash", contextual = true, contextualOverride = true) diff --git a/adapters/fabric/build.gradle b/adapters/fabric/build.gradle index 1ecc1b3e7..467cea14c 100644 --- a/adapters/fabric/build.gradle +++ b/adapters/fabric/build.gradle @@ -166,8 +166,7 @@ dependencies { libs.lru, libs.caffeine, libs.dom4j, - libs.jaxen, - libs.sentry + libs.jaxen ] shared.each { Object notation -> add('bundle', notation) @@ -275,7 +274,6 @@ tasks.named('shadowJar', ShadowJar).configure { exclude('art/arcane/iris/platform/bukkit/**') duplicatesStrategy = DuplicatesStrategy.EXCLUDE relocate('org.objectweb.asm', 'art.arcane.iris.shadow.asm') - relocate('io.sentry', 'art.arcane.iris.shadow.sentry') // Split-package guard. A co-installed mod that ships any of these at their original coordinates // puts two copies of the same package on one module layer, which the loaders reject at boot // (Terra ships paralithic; caffeine and dom4j are common in mod dependency trees). First-party diff --git a/adapters/forge/build.gradle b/adapters/forge/build.gradle index 3df6827e4..513e806a7 100644 --- a/adapters/forge/build.gradle +++ b/adapters/forge/build.gradle @@ -165,8 +165,7 @@ dependencies { libs.lru, libs.caffeine, libs.dom4j, - libs.jaxen, - libs.sentry + libs.jaxen ] shared.each { Object notation -> add('bundle', notation) @@ -267,7 +266,6 @@ tasks.named('shadowJar', ShadowJar).configure { exclude('art/arcane/iris/platform/bukkit/**') duplicatesStrategy = DuplicatesStrategy.EXCLUDE relocate('org.objectweb.asm', 'art.arcane.iris.shadow.asm') - relocate('io.sentry', 'art.arcane.iris.shadow.sentry') // Split-package guard. A co-installed mod that ships any of these at their original coordinates // puts two copies of the same package on one module layer, which the loaders reject at boot // (Terra ships paralithic; caffeine and dom4j are common in mod dependency trees). First-party diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java index 1f9a15586..d72be750e 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java @@ -331,34 +331,113 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator { if (server == null) { return null; } - // Snapshot, never server.getAllLevels(): this runs off the server thread from data queries. - for (ServerLevel level : ModdedServerLevels.levels(server)) { + ServerLevel resolved = resolveBoundLevel(server, ModdedServerLevels.levels(server)); + if (resolved != null) { + boundLevel = resolved; + } + return resolved; + } + + ServerLevel resolveBoundLevel(MinecraftServer server, List snapshot) { + for (ServerLevel level : snapshot) { if (level.getChunkSource().getGenerator() == this) { - boundLevel = level; return level; } } - return null; + ServerLevel overworld = server.getLevel(Level.OVERWORLD); + return overworld != null && overworld.getChunkSource().getGenerator() == this ? overworld : null; } Engine engine() { - requireBindingAllowed(); - Engine cached = engine; - requireCompletedShutdown(cached); - if (cached != null && !cached.isClosed()) { + Engine cached = readyEngine(); + if (cached != null) { return cached; } ServerLevel level = boundLevel(); if (level == null) { throw new IllegalStateException("Iris generator '" + dimensionKey + "' has no bound ServerLevel yet"); } - return bindEngine(level); + return bindGenerationLevel(level); + } + + private Engine engine(ResourceKey levelKey) { + Engine cached = readyEngine(); + if (cached != null) { + return cached; + } + ServerLevel level = boundLevel; + if (level == null) { + level = requirePublishedLevel(ModdedEngineBootstrap.currentServer(), levelKey); + } else { + requireGeneratorLevel(level, levelKey); + } + return bindGenerationLevel(level); + } + + private Engine engine(ServerLevel generationLevel) { + Engine cached = readyEngine(); + if (cached != null) { + return cached; + } + ServerLevel level = boundLevel == null ? generationLevel : boundLevel; + requireGeneratorLevel(level, generationLevel.dimension()); + return bindGenerationLevel(level); + } + + private Engine readyEngine() { + requireBindingAllowed(); + Engine cached = engine; + requireCompletedShutdown(cached); + if (cached != null && !cached.isClosed()) { + return cached; + } + return null; + } + + private Engine bindGenerationLevel(ServerLevel level) { + bindLevel(level); + Engine bound = readyEngine(); + if (bound == null) { + throw new IllegalStateException("Iris generator '" + dimensionKey + + "' completed generation binding without a ready engine"); + } + return bound; + } + + ServerLevel requirePublishedLevel(MinecraftServer server, ResourceKey levelKey) { + if (server == null) { + throw new IllegalStateException("Iris generator '" + dimensionKey + + "' cannot resolve level '" + levelKey.identifier() + "': server is unavailable"); + } + ServerLevel level = server.getLevel(levelKey); + if (level == null) { + throw new IllegalStateException("Iris generator '" + dimensionKey + + "' has no published ServerLevel for '" + levelKey.identifier() + "'"); + } + requireGeneratorLevel(level, levelKey); + return level; + } + + private void requireGeneratorLevel(ServerLevel level, ResourceKey levelKey) { + if (!levelKey.equals(level.dimension())) { + throw new IllegalStateException("Iris generator '" + dimensionKey + "' resolved level '" + + level.dimension().identifier() + "' while binding '" + levelKey.identifier() + "'"); + } + ChunkGenerator publishedGenerator = level.getChunkSource().getGenerator(); + if (publishedGenerator != this) { + throw new IllegalStateException("Published ServerLevel '" + levelKey.identifier() + + "' does not use Iris generator '" + dimensionKey + "'"); + } } synchronized void bindLevel(ServerLevel level) { if (level.getChunkSource().getGenerator() != this) { throw new IllegalArgumentException("ServerLevel does not use Iris generator '" + dimensionKey + "'"); } + Engine current = engineIfBound(); + if (boundLevel == level && current != null && current.getComplex() != null) { + return; + } requireCompletedShutdown(engine); unloading = false; Engine bound = bindEngine(level); @@ -853,7 +932,6 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator { @Override public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) { Engine current = engine(); - // Self-heal for an engine bound through a data-query path instead of bindLevel; a no-op once prepared. importedFeatures.prepare(current); try (GenerationSessionLease lease = requireGenerationLease(current, "modded_biome_decoration"); IrisContext.Scope ignored = IrisContext.open(current, lease.sessionId(), null)) { @@ -867,7 +945,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator { @Override public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess chunk, StructureTemplateManager templateManager, ResourceKey levelKey) { - Engine current = engine(); + Engine current = engine(levelKey); try (GenerationSessionLease lease = requireGenerationLease(current, "modded_create_structures"); IrisContext.Scope ignored = IrisContext.open(current, lease.sessionId(), null)) { Map previousStarts = new HashMap<>(chunk.getAllStarts()); @@ -891,7 +969,7 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator { @Override public void createReferences(WorldGenLevel level, StructureManager structureManager, ChunkAccess chunk) { - Engine current = engine(); + Engine current = engine(level.getLevel()); try (GenerationSessionLease lease = requireGenerationLease(current, "modded_create_references"); IrisContext.Scope ignored = IrisContext.open(current, lease.sessionId(), null)) { NativeStructureReferenceRepair.createReferences( diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedDimensionManager.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedDimensionManager.java index ac835d03e..b57943039 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedDimensionManager.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedDimensionManager.java @@ -590,6 +590,7 @@ public final class ModdedDimensionManager { boolean loadEventStarted = false; try { + serverAccess.initializeLevelData(server, level); generator.bindLevel(level); Handle handle = new Handle(dimensionId, pack, packDimensionKey, seed, level, generator); ServerLevel previous = serverAccess.putLevelIfAbsent(server, key, level); diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedEngineBootstrap.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedEngineBootstrap.java index c00959c7c..9eaf970d5 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedEngineBootstrap.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedEngineBootstrap.java @@ -113,7 +113,6 @@ public final class ModdedEngineBootstrap { bindWorldGenerators(server); services().enableAll(); ModdedProtocolHandler.start(server); - ModdedSentry.start(loader()); } private static void bindWorldGenerators(MinecraftServer server) { @@ -194,7 +193,6 @@ public final class ModdedEngineBootstrap { MultiBurst.burst.close(); MultiBurst.ioBurst.close(); }); - failure = runStopStage(failure, "sentry", ModdedSentry::flush); failure = runStopStage(failure, "startup state", ModdedStartup::reset); failure = runStopStage(failure, "server state", () -> { currentServer = null; diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedPlatform.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedPlatform.java index fe2c9420b..cdb1b3e1c 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedPlatform.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedPlatform.java @@ -47,7 +47,6 @@ public final class ModdedPlatform implements IrisPlatform { private static final ConcurrentHashMap ERROR_THROTTLES = new ConcurrentHashMap<>(); private static volatile Consumer ERROR_SINK = null; - private static volatile Consumer CAPTURE_SINK = null; private final ModdedLoader loader; private final ModdedRegistries registries; @@ -67,10 +66,6 @@ public final class ModdedPlatform implements IrisPlatform { ERROR_SINK = sink; } - public static void captureSink(Consumer sink) { - CAPTURE_SINK = sink; - } - public MinecraftServer server() { return ModdedEngineBootstrap.currentServer(); } @@ -230,9 +225,8 @@ public final class ModdedPlatform implements IrisPlatform { } /** - * Throttled per exception signature. A single broken pack rule can fail on every generated chunk, and this - * feeds Sentry, so each distinct signature reports its first few occurrences and then only a periodic - * suppressed-count summary. + * Throttled per exception signature. A single broken pack rule can fail on every generated chunk, so each + * distinct signature reports its first few occurrences and then only a periodic suppressed-count summary. */ @Override public void reportError(Throwable error) { @@ -261,14 +255,6 @@ public final class ModdedPlatform implements IrisPlatform { return; } ModdedIrisLog.error(message, error); - Consumer capture = CAPTURE_SINK; - if (capture != null) { - try { - capture.accept(error); - } catch (Throwable captureFailure) { - ModdedIrisLog.error("Iris error-reporting sink failed", captureFailure); - } - } } static void resetErrorThrottles() { diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedSentry.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedSentry.java deleted file mode 100644 index fcb1b6aeb..000000000 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedSentry.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 . - */ - -package art.arcane.iris.modded; - -import art.arcane.iris.BuildConstants; -import art.arcane.iris.core.IrisSettings; -import art.arcane.iris.spi.IrisLogging; -import art.arcane.volmlib.util.json.JSONException; -import com.google.gson.JsonSyntaxException; -import io.sentry.Sentry; - -import java.util.concurrent.atomic.AtomicBoolean; - -public final class ModdedSentry { - private static final String DSN = "http://4cdbb9ac953306529947f4ca1e8e6b26@sentry.volmit.com:8080/2"; - private static final long FLUSH_TIMEOUT_MS = 2000L; - private static final AtomicBoolean STARTED = new AtomicBoolean(false); - - private ModdedSentry() { - } - - public static void start(ModdedLoader loader) { - IrisSettings.IrisSettingsSentry settings = IrisSettings.get().getSentry(); - if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) { - return; - } - if (!STARTED.compareAndSet(false, true)) { - return; - } - IrisLogging.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); - Sentry.init(options -> { - options.setDsn(DSN); - if (settings.debug) { - options.setDebug(true); - } - options.setAttachServerName(false); - options.setEnableUncaughtExceptionHandler(false); - options.setRelease(loader.modVersion()); - options.setEnvironment(BuildConstants.ENVIRONMENT); - options.setBeforeSend((event, hint) -> suppress(event.getThrowable()) ? null : event); - }); - Sentry.configureScope(scope -> { - scope.setTag("server", loader.platformName()); - scope.setTag("server.mc", loader.minecraftVersion()); - scope.setTag("iris.loader", loader.platformName()); - scope.setTag("iris.commit", BuildConstants.COMMIT); - }); - ModdedPlatform.captureSink(Sentry::captureException); - } - - public static void flush() { - if (Sentry.isEnabled()) { - Sentry.flush(FLUSH_TIMEOUT_MS); - Sentry.close(); - } - ModdedPlatform.captureSink(null); - STARTED.set(false); - } - - private static boolean suppress(Throwable error) { - return (error instanceof IllegalStateException state && "zip file closed".equals(state.getMessage())) - || error instanceof JSONException - || error instanceof JsonSyntaxException; - } -} diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerAccess.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerAccess.java index 050a56369..e4fa27511 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerAccess.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerAccess.java @@ -31,6 +31,8 @@ public interface ModdedServerAccess { LevelStorageSource.LevelStorageAccess levelStorage(MinecraftServer server); + void initializeLevelData(MinecraftServer server, ServerLevel level); + ServerLevel putLevel(MinecraftServer server, ResourceKey key, ServerLevel level); ServerLevel putLevelIfAbsent(MinecraftServer server, ResourceKey key, ServerLevel level); diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerLevels.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerLevels.java index 3e0680af0..66e6b7a1a 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerLevels.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedServerLevels.java @@ -23,7 +23,11 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.level.storage.WorldData; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ConcurrentModificationException; import java.util.LinkedHashMap; import java.util.List; @@ -34,6 +38,18 @@ import java.util.function.Consumer; public final class ModdedServerLevels implements ModdedServerAccess { private static final int CAPTURE_ATTEMPTS = 16; + private static final ClassValue HOST_LEVEL_PUBLICATIONS = new ClassValue<>() { + @Override + protected HostLevelPublication computeValue(Class type) { + return HostLevelPublication.detect(type, ServerLevel.class); + } + }; + private static final ClassValue HOST_LEVEL_DATA_ATTACHMENTS = new ClassValue<>() { + @Override + protected HostLevelDataAttachment computeValue(Class type) { + return HostLevelDataAttachment.detect(type, PrimaryLevelData.class, ResourceKey.class); + } + }; private static volatile Snapshot snapshot; private final Consumer levelCacheInvalidator; @@ -43,8 +59,8 @@ public final class ModdedServerLevels implements ModdedServerAccess { } /** - * Immutable view of the loaded levels. {@code server.levels} is a plain map mutated on the server - * thread, so every off-server-thread reader must iterate this snapshot instead of + * Immutable view of the loaded levels. {@code server.levels} is loader-owned and published on the + * server thread, so every off-server-thread reader must iterate this snapshot instead of * {@code server.getAllLevels()} to avoid ConcurrentModificationException. */ public static List levels(MinecraftServer server) { @@ -137,8 +153,32 @@ public final class ModdedServerLevels implements ModdedServerAccess { return server.storageSource; } + @Override + public void initializeLevelData(MinecraftServer server, ServerLevel level) { + Object levelData = level.getLevelData(); + HostLevelDataAttachment attachment = HOST_LEVEL_DATA_ATTACHMENTS.get(levelData.getClass()); + if (!attachment.supported()) { + return; + } + WorldData worldData = server.getWorldData(); + if (!(worldData instanceof PrimaryLevelData rootData)) { + throw new IllegalStateException("Host level data attachment requires PrimaryLevelData, found " + + worldData.getClass().getName()); + } + attachment.attach(levelData, rootData, level.dimension()); + } + @Override public ServerLevel putLevel(MinecraftServer server, ResourceKey key, ServerLevel level) { + HostLevelPublication hostPublication = HOST_LEVEL_PUBLICATIONS.get(server.getClass()); + if (hostPublication.supported()) { + ServerLevel previous = server.levels.get(key); + if (previous != level) { + hostPublication.add(server, level); + capture(server); + } + return previous; + } ServerLevel previous = server.levels.put(key, level); if (previous != level) { capture(server); @@ -149,6 +189,15 @@ public final class ModdedServerLevels implements ModdedServerAccess { @Override public ServerLevel putLevelIfAbsent(MinecraftServer server, ResourceKey key, ServerLevel level) { + HostLevelPublication hostPublication = HOST_LEVEL_PUBLICATIONS.get(server.getClass()); + if (hostPublication.supported()) { + ServerLevel previous = server.levels.get(key); + if (previous == null) { + hostPublication.add(server, level); + capture(server); + } + return previous; + } ServerLevel previous = server.levels.putIfAbsent(key, level); if (previous == null) { capture(server); @@ -159,6 +208,15 @@ public final class ModdedServerLevels implements ModdedServerAccess { @Override public ServerLevel removeLevel(MinecraftServer server, ResourceKey key) { + HostLevelPublication hostPublication = HOST_LEVEL_PUBLICATIONS.get(server.getClass()); + if (hostPublication.supported()) { + ServerLevel removed = server.levels.get(key); + if (removed != null) { + hostPublication.remove(server, removed); + capture(server); + } + return removed; + } ServerLevel removed = server.levels.remove(key); if (removed != null) { capture(server); @@ -175,4 +233,94 @@ public final class ModdedServerLevels implements ModdedServerAccess { private record Snapshot(MinecraftServer server, List levels, Map, ServerLevel> byKey) { } + + static final class HostLevelPublication { + private final Method addLevel; + private final Method removeLevel; + + private HostLevelPublication(Method addLevel, Method removeLevel) { + this.addLevel = addLevel; + this.removeLevel = removeLevel; + } + + static HostLevelPublication detect(Class serverType, Class levelType) { + try { + Method addLevel = serverType.getMethod("addLevel", levelType); + Method removeLevel = serverType.getMethod("removeLevel", levelType); + return new HostLevelPublication(addLevel, removeLevel); + } catch (NoSuchMethodException e) { + return new HostLevelPublication(null, null); + } + } + + boolean supported() { + return addLevel != null && removeLevel != null; + } + + void add(Object server, Object level) { + invoke(addLevel, server, level); + } + + void remove(Object server, Object level) { + invoke(removeLevel, server, level); + } + + private void invoke(Method method, Object server, Object level) { + try { + method.invoke(server, level); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Iris cannot access host level publication method " + + method.getName(), e); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException runtimeException) { + throw runtimeException; + } + if (cause instanceof Error fatalError) { + throw fatalError; + } + throw new IllegalStateException("Host level publication method " + method.getName() + + " failed", cause); + } + } + } + + static final class HostLevelDataAttachment { + private final Method attach; + + private HostLevelDataAttachment(Method attach) { + this.attach = attach; + } + + static HostLevelDataAttachment detect(Class levelDataType, Class rootDataType, + Class dimensionKeyType) { + try { + return new HostLevelDataAttachment(levelDataType.getMethod( + "attach", rootDataType, dimensionKeyType)); + } catch (NoSuchMethodException e) { + return new HostLevelDataAttachment(null); + } + } + + boolean supported() { + return attach != null; + } + + void attach(Object levelData, Object rootData, Object dimensionKey) { + try { + attach.invoke(levelData, rootData, dimensionKey); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Iris cannot access host level data attachment method", e); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException runtimeException) { + throw runtimeException; + } + if (cause instanceof Error fatalError) { + throw fatalError; + } + throw new IllegalStateException("Host level data attachment failed", cause); + } + } + } } diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedCommandHelp.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedCommandHelp.java index 254120a45..719c2b0c8 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedCommandHelp.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedCommandHelp.java @@ -87,7 +87,7 @@ final class ModdedCommandHelp { Entry.group("datapack", ModdedHelpMessages.GROUP_DATAPACK_WORLD_DATAPACK_INSTALL_AND_STATUS_HELPERS, "datapacks", "dp"), Entry.group("structure", ModdedHelpMessages.GROUP_STRUCTURE_IRIS_STRUCTURE_INDEX_INFO_AND_PLACEMENT_TOOLS, "struct", "str"), 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") + Entry.group("developer", ModdedHelpMessages.GROUP_DEVELOPER_DEVELOPER_DIAGNOSTICS_NETWORK_INTERFACES_REGION_FILE_SCAN, "dev") )); SECTIONS.put("what", List.of( Entry.command("here", "", ModdedHelpMessages.COMMAND_WHAT_HERE_INSPECT_CURRENT_IRIS_CONTEXT), @@ -197,7 +197,6 @@ final class ModdedCommandHelp { SECTIONS.put("struct", SECTIONS.get("structure")); SECTIONS.put("str", SECTIONS.get("structure")); SECTIONS.put("developer", List.of( - Entry.command("sentry", "", ModdedHelpMessages.COMMAND_SENTRY_SEND_A_TEST_EXCEPTION_TO_THE_IRIS_ERROR_REPORTER), Entry.command("network", "", ModdedHelpMessages.COMMAND_NETWORK_LIST_NETWORK_INTERFACES_AND_THEIR_ADDRESSES, "ip") )); SECTIONS.put("dev", SECTIONS.get("developer")); diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedDeveloperCommands.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedDeveloperCommands.java index 2c6ccd6e8..1188d9cc3 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedDeveloperCommands.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedDeveloperCommands.java @@ -19,7 +19,6 @@ package art.arcane.iris.modded.command; import art.arcane.iris.modded.ModdedIrisLog; -import art.arcane.iris.spi.IrisPlatforms; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import net.minecraft.commands.CommandSourceStack; @@ -44,20 +43,12 @@ final class ModdedDeveloperCommands { static LiteralArgumentBuilder tree(String name) { return Commands.literal(name).requires(GATE) .executes((CommandContext context) -> ModdedCommandHelp.send(context.getSource(), "developer")) - .then(Commands.literal("sentry") - .executes((CommandContext context) -> sentry(context.getSource()))) .then(Commands.literal("network") .executes((CommandContext context) -> network(context.getSource()))) .then(Commands.literal("ip") .executes((CommandContext context) -> network(context.getSource()))); } - private static int sentry(CommandSourceStack source) { - IrisPlatforms.get().reportError(new Exception("This is an Iris Sentry test exception")); - ModdedCommandFeedback.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_DEVELOPER_COMMANDS_DISPATCHED_TEST_EXCEPTION_IRIS_ERROR_REPORTER_SENTRY_IF_ENABLED)); - return 1; - } - private static int network(CommandSourceStack source) { try { Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedGenerationBootstrapBindingTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedGenerationBootstrapBindingTest.java new file mode 100644 index 000000000..e53978e84 --- /dev/null +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedGenerationBootstrapBindingTest.java @@ -0,0 +1,150 @@ +package art.arcane.iris.modded; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.ChunkGenerator; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class ModdedGenerationBootstrapBindingTest { + private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources"; + + @Test + public void publishedLevelRequiresCurrentGeneratorIdentity() { + IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS); + MinecraftServer server = mock(MinecraftServer.class); + ServerLevel level = mock(ServerLevel.class); + ServerChunkCache chunkSource = mock(ServerChunkCache.class); + when(server.getLevel(Level.OVERWORLD)).thenReturn(level); + when(level.dimension()).thenReturn(Level.OVERWORLD); + when(level.getChunkSource()).thenReturn(chunkSource); + when(chunkSource.getGenerator()).thenReturn(generator); + + assertSame(level, generator.requirePublishedLevel(server, Level.OVERWORLD)); + + ChunkGenerator otherGenerator = mock(ChunkGenerator.class); + when(chunkSource.getGenerator()).thenReturn(otherGenerator); + IllegalStateException mismatch = assertThrows(IllegalStateException.class, + () -> generator.requirePublishedLevel(server, Level.OVERWORLD)); + assertTrue(mismatch.getMessage().contains("does not use Iris generator")); + } + + @Test + public void publishedLevelRejectsMissingServerAndWorld() { + IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS); + IllegalStateException missingServer = assertThrows(IllegalStateException.class, + () -> generator.requirePublishedLevel(null, Level.OVERWORLD)); + assertTrue(missingServer.getMessage().contains("server is unavailable")); + + MinecraftServer server = mock(MinecraftServer.class); + IllegalStateException missingWorld = assertThrows(IllegalStateException.class, + () -> generator.requirePublishedLevel(server, Level.OVERWORLD)); + assertTrue(missingWorld.getMessage().contains("no published ServerLevel")); + } + + @Test + public void staleSnapshotResolvesOnlyCanonicalOverworldOwnedByGenerator() { + IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS); + MinecraftServer server = mock(MinecraftServer.class); + ServerLevel overworld = mock(ServerLevel.class); + ServerChunkCache chunkSource = mock(ServerChunkCache.class); + when(server.getLevel(Level.OVERWORLD)).thenReturn(overworld); + when(overworld.getChunkSource()).thenReturn(chunkSource); + when(chunkSource.getGenerator()).thenReturn(generator); + + assertSame(overworld, generator.resolveBoundLevel(server, List.of())); + + ChunkGenerator otherGenerator = mock(ChunkGenerator.class); + when(chunkSource.getGenerator()).thenReturn(otherGenerator); + assertNull(generator.resolveBoundLevel(server, List.of())); + verify(server, never()).getLevel(Level.NETHER); + } + + @Test + public void dynamicLevelStillResolvesFromSnapshotWithoutCanonicalLookup() { + IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS); + MinecraftServer server = mock(MinecraftServer.class); + ServerLevel dynamicLevel = mock(ServerLevel.class); + ServerChunkCache chunkSource = mock(ServerChunkCache.class); + when(dynamicLevel.getChunkSource()).thenReturn(chunkSource); + when(chunkSource.getGenerator()).thenReturn(generator); + + assertSame(dynamicLevel, generator.resolveBoundLevel(server, List.of(dynamicLevel))); + verify(server, never()).getLevel(Level.OVERWORLD); + } + + @Test + public void firstGenerationStagesProvideAuthoritativeLevelContext() throws IOException { + String source = source("IrisModdedChunkGenerator.java"); + String structures = method(source, "public void createStructures("); + String references = method(source, "public void createReferences("); + assertTrue(structures.contains("Engine current = engine(levelKey);")); + assertTrue(references.contains("Engine current = engine(level.getLevel());")); + + String publishedBinding = method(source, "private Engine engine(ResourceKey levelKey)"); + assertTrue(publishedBinding.contains("requirePublishedLevel(ModdedEngineBootstrap.currentServer(), levelKey)")); + assertTrue(publishedBinding.contains("return bindGenerationLevel(level);")); + assertFalse(publishedBinding.contains("ModdedServerLevels.level(")); + + String fullBinding = method(source, "private Engine bindGenerationLevel(ServerLevel level)"); + assertTrue(fullBinding.contains("bindLevel(level);")); + assertTrue(fullBinding.contains("Engine bound = readyEngine();")); + + String genericBinding = method(source, "Engine engine()"); + assertTrue(genericBinding.contains("return bindGenerationLevel(level);")); + } + + @Test + public void constructorMixinIsNotPartOfGenerationBootstrap() throws IOException { + String sourceRoot = System.getProperty(SOURCE_ROOT_PROPERTY); + assertTrue(sourceRoot != null && !sourceRoot.isBlank()); + Path root = Path.of(sourceRoot); + assertFalse(Files.exists(root.resolve(Path.of("art", "arcane", "iris", "modded", "mixin", + "ServerLevelBindingMixin.java")))); + String mixinConfig = Files.readString(root.getParent().resolve("resources/irisworldgen.entity.mixins.json")); + assertFalse(mixinConfig.contains("ServerLevelBindingMixin")); + } + + private String source(String fileName) throws IOException { + String sourceRoot = System.getProperty(SOURCE_ROOT_PROPERTY); + assertTrue(sourceRoot != null && !sourceRoot.isBlank()); + return Files.readString(Path.of(sourceRoot, "art", "arcane", "iris", "modded", fileName)); + } + + private String method(String source, String signature) { + int start = source.indexOf(signature); + assertTrue(start >= 0); + int body = source.indexOf('{', start); + assertTrue(body >= 0); + int depth = 0; + for (int index = body; index < source.length(); index++) { + char token = source.charAt(index); + if (token == '{') { + depth++; + } else if (token == '}') { + depth--; + if (depth == 0) { + return source.substring(start, index + 1); + } + } + } + throw new IllegalArgumentException("Unclosed source contract method: " + signature); + } +} diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLevelDataAttachmentTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLevelDataAttachmentTest.java new file mode 100644 index 000000000..541337a32 --- /dev/null +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLevelDataAttachmentTest.java @@ -0,0 +1,94 @@ +package art.arcane.iris.modded; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class ModdedLevelDataAttachmentTest { + @Test + public void detectsAndInvokesHostLevelDataAttachment() { + ModdedServerLevels.HostLevelDataAttachment attachment = + ModdedServerLevels.HostLevelDataAttachment.detect( + AttachedLevelData.class, RootData.class, DimensionKey.class); + AttachedLevelData levelData = new AttachedLevelData(); + RootData rootData = new RootData(); + DimensionKey dimensionKey = new DimensionKey(); + + assertTrue(attachment.supported()); + attachment.attach(levelData, rootData, dimensionKey); + assertSame(rootData, levelData.rootData); + assertSame(dimensionKey, levelData.dimensionKey); + } + + @Test + public void ignoresLevelDataWithoutAttachmentCapability() { + ModdedServerLevels.HostLevelDataAttachment attachment = + ModdedServerLevels.HostLevelDataAttachment.detect( + StandardLevelData.class, RootData.class, DimensionKey.class); + + assertFalse(attachment.supported()); + } + + @Test + public void propagatesHostAttachmentFailureWithoutReflectionWrapper() { + ModdedServerLevels.HostLevelDataAttachment attachment = + ModdedServerLevels.HostLevelDataAttachment.detect( + FailingLevelData.class, RootData.class, DimensionKey.class); + IllegalStateException failure = assertThrows(IllegalStateException.class, + () -> attachment.attach(new FailingLevelData(), new RootData(), new DimensionKey())); + + assertNull(failure.getCause()); + } + + @Test + public void initializesLevelDataBeforeBindingAndPublication() throws IOException { + String source = Files.readString(sourcePath("ModdedDimensionManager.java")); + int construction = source.indexOf("ServerLevel level = new ServerLevel("); + int initialization = source.indexOf("serverAccess.initializeLevelData(server, level);", construction); + int binding = source.indexOf("generator.bindLevel(level);", initialization); + int publication = source.indexOf("serverAccess.putLevelIfAbsent(server, key, level);", binding); + + assertTrue(construction >= 0); + assertTrue(initialization > construction); + assertTrue(binding > initialization); + assertTrue(publication > binding); + } + + private static Path sourcePath(String fileName) { + return Path.of(System.getProperty("iris.moddedCommonSources"), + "art/arcane/iris/modded", fileName); + } + + public static final class AttachedLevelData { + private RootData rootData; + private DimensionKey dimensionKey; + + public void attach(RootData rootData, DimensionKey dimensionKey) { + this.rootData = rootData; + this.dimensionKey = dimensionKey; + } + } + + public static final class FailingLevelData { + public void attach(RootData rootData, DimensionKey dimensionKey) { + throw new IllegalStateException("attachment failed"); + } + } + + public static final class StandardLevelData { + } + + public static final class RootData { + } + + public static final class DimensionKey { + } +} diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedServerLevelsTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedServerLevelsTest.java new file mode 100644 index 000000000..0b11aafd0 --- /dev/null +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedServerLevelsTest.java @@ -0,0 +1,73 @@ +package art.arcane.iris.modded; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class ModdedServerLevelsTest { + @Test + public void detectsAndInvokesHostLevelPublicationPair() { + ModdedServerLevels.HostLevelPublication publication = + ModdedServerLevels.HostLevelPublication.detect(PublishingServer.class, PublishedLevel.class); + PublishingServer server = new PublishingServer(); + PublishedLevel level = new PublishedLevel(); + + assertTrue(publication.supported()); + publication.add(server, level); + assertSame(level, server.added); + publication.remove(server, level); + assertSame(level, server.removed); + } + + @Test + public void rejectsPartialHostLevelPublicationCapability() { + ModdedServerLevels.HostLevelPublication publication = + ModdedServerLevels.HostLevelPublication.detect(AddOnlyServer.class, PublishedLevel.class); + + assertFalse(publication.supported()); + } + + @Test + public void propagatesHostPublicationFailureWithoutReflectionWrapper() { + ModdedServerLevels.HostLevelPublication publication = + ModdedServerLevels.HostLevelPublication.detect(FailingServer.class, PublishedLevel.class); + IllegalStateException failure = assertThrows(IllegalStateException.class, + () -> publication.add(new FailingServer(), new PublishedLevel())); + + assertNull(failure.getCause()); + } + + public static final class PublishingServer { + private PublishedLevel added; + private PublishedLevel removed; + + public void addLevel(PublishedLevel level) { + added = level; + } + + public void removeLevel(PublishedLevel level) { + removed = level; + } + } + + public static final class AddOnlyServer { + public void addLevel(PublishedLevel level) { + } + } + + public static final class FailingServer { + public void addLevel(PublishedLevel level) { + throw new IllegalStateException("publication failed"); + } + + public void removeLevel(PublishedLevel level) { + } + } + + public static final class PublishedLevel { + } +} diff --git a/adapters/neoforge/build.gradle b/adapters/neoforge/build.gradle index f785f3412..841a29891 100644 --- a/adapters/neoforge/build.gradle +++ b/adapters/neoforge/build.gradle @@ -135,8 +135,7 @@ dependencies { libs.lru, libs.caffeine, libs.dom4j, - libs.jaxen, - libs.sentry + libs.jaxen ] shared.each { Object notation -> add('bundle', notation) @@ -243,7 +242,6 @@ tasks.named('shadowJar', ShadowJar).configure { exclude('art/arcane/iris/platform/bukkit/**') duplicatesStrategy = DuplicatesStrategy.EXCLUDE relocate('org.objectweb.asm', 'art.arcane.iris.shadow.asm') - relocate('io.sentry', 'art.arcane.iris.shadow.sentry') // Split-package guard. A co-installed mod that ships any of these at their original coordinates // puts two copies of the same package on one module layer, which the loaders reject at boot // (Terra ships paralithic; caffeine and dom4j are common in mod dependency trees). First-party diff --git a/build.gradle b/build.gradle index 3ae113527..aa166e941 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,3 @@ -import de.undercouch.gradle.tasks.download.Download import org.gradle.api.plugins.JavaPlugin import org.gradle.api.tasks.Copy import org.gradle.api.tasks.compile.JavaCompile @@ -39,7 +38,6 @@ buildscript { plugins { id 'java' id 'java-library' - alias(libs.plugins.download) } group = 'art.arcane' @@ -75,6 +73,7 @@ String bukkitArtifactName = irisArtifactName('CraftBukkit', bukkitMinecraftRange String fabricArtifactName = irisArtifactName('Fabric', "${minecraftVersion}+${loaderDisplayVersion(fabricLoaderVersion)}") String forgeArtifactName = irisArtifactName('Forge', "${minecraftVersion}+${loaderDisplayVersion(forgeVersion)}") String neoForgeArtifactName = irisArtifactName('NeoForge', "${minecraftVersion}+${loaderDisplayVersion(neoForgeVersion)}") +File pluginOutDirectory = layout.projectDirectory.dir('../PluginOuts').asFile long maximumBukkitArtifactBytes = 7_000_000L apply plugin: ApiGenerator @@ -281,12 +280,12 @@ tasks.register('buildBukkit', Copy) { group = 'iris' dependsOn('jar') from(layout.buildDirectory.file("libs/${bukkitArtifactName}")) - into(layout.projectDirectory.dir('dist')) + into(pluginOutDirectory) doFirst { - delete(fileTree(layout.projectDirectory.dir('dist')) { + delete(fileTree(pluginOutDirectory) { include('Iris v* [CraftBukkit] *.jar') }) - delete(layout.projectDirectory.file("dist/Iris-${project.version}+mc${minecraftVersion}.jar")) + delete(new File(pluginOutDirectory, "Iris-${project.version}+mc${minecraftVersion}.jar")) } } @@ -384,12 +383,12 @@ tasks.register('buildFabric', Copy) { group = 'iris' dependsOn('fabricJar') from(layout.projectDirectory.file("adapters/fabric/build/libs/${fabricArtifactName}")) - into(layout.projectDirectory.dir('dist')) + into(pluginOutDirectory) doFirst { - delete(fileTree(layout.projectDirectory.dir('dist')) { + delete(fileTree(pluginOutDirectory) { include('Iris v* [Fabric] *.jar') }) - delete(layout.projectDirectory.file("dist/Iris-${project.version}+mc${minecraftVersion}-fabric.jar")) + delete(new File(pluginOutDirectory, "Iris-${project.version}+mc${minecraftVersion}-fabric.jar")) } } @@ -422,12 +421,12 @@ tasks.register('buildForge', Copy) { group = 'iris' dependsOn('forgeJar') from(layout.projectDirectory.file("adapters/forge/build/libs/${forgeArtifactName}")) - into(layout.projectDirectory.dir('dist')) + into(pluginOutDirectory) doFirst { - delete(fileTree(layout.projectDirectory.dir('dist')) { + delete(fileTree(pluginOutDirectory) { include('Iris v* [Forge] *.jar') }) - delete(layout.projectDirectory.file("dist/Iris-${project.version}+mc${minecraftVersion}-forge.jar")) + delete(new File(pluginOutDirectory, "Iris-${project.version}+mc${minecraftVersion}-forge.jar")) } } @@ -460,12 +459,12 @@ tasks.register('buildNeoforge', Copy) { group = 'iris' dependsOn('neoforgeJar') from(layout.projectDirectory.file("adapters/neoforge/build/libs/${neoForgeArtifactName}")) - into(layout.projectDirectory.dir('dist')) + into(pluginOutDirectory) doFirst { - delete(fileTree(layout.projectDirectory.dir('dist')) { + delete(fileTree(pluginOutDirectory) { include('Iris v* [NeoForge] *.jar') }) - delete(layout.projectDirectory.file("dist/Iris-${project.version}+mc${minecraftVersion}-neoforge.jar")) + delete(new File(pluginOutDirectory, "Iris-${project.version}+mc${minecraftVersion}-neoforge.jar")) } } @@ -650,10 +649,9 @@ tasks.register('buildAllToOut') { group = 'iris' dependsOn('buildBukkit', 'buildFabric', 'buildForge', 'buildNeoforge', ':spi:jar') doLast { - File dist = layout.projectDirectory.dir('dist').asFile - File[] jars = dist.listFiles((java.io.FileFilter) { File f -> f.name.endsWith('.jar') }) + File[] jars = pluginOutDirectory.listFiles((java.io.FileFilter) { File f -> f.name.startsWith('Iris v') && f.name.endsWith('.jar') }) println('') - println('=== Iris buildAllToOut -> dist/ ===') + println('=== Iris buildAllToOut -> ' + pluginOutDirectory + ' ===') if (jars != null) { jars.sort { it.name }.each { File f -> println(String.format(' %-60s %8d KB', f.name, (long) (f.length() / 1024))) @@ -725,39 +723,6 @@ tasks.register('irisDev', Copy) { dependsOn(':core:javadocJar') } -def cli = file('sentry-cli.exe') -tasks.register('downloadCli', Download) { - group = 'io.sentry' - src("https://release-registry.services.sentry.io/apps/sentry-cli/latest?response=download&arch=x86_64&platform=${System.getProperty('os.name')}&package=sentry-cli") - dest(cli) - - doLast { - cli.setExecutable(true) - } -} - -tasks.register('release') { - group = 'io.sentry' - dependsOn('downloadCli') - doLast { - String url = 'http://sentry.volmit.com:8080' - def authToken = project.findProperty('sentry.auth.token') ?: System.getenv('SENTRY_AUTH_TOKEN') - String org = 'sentry' - String projectName = 'iris' - runCommand(cli, '--url', url, '--auth-token', authToken, 'releases', 'new', '-o', org, '-p', projectName, version) - runCommand(cli, '--url', url, '--auth-token', authToken, 'releases', 'set-commits', '-o', org, '-p', projectName, version, '--auto', '--ignore-missing') - //exec(cli, "--url", url, "--auth-token", authToken, "releases", "finalize", "-o", org, "-p", projectName, version) - cli.delete() - } -} - -void runCommand(Object... command) { - Process process = new ProcessBuilder(command.collect { it.toString() }).start() - process.inputStream.readLines().each { println(it) } - process.errorStream.readLines().each { println(it) } - process.waitFor() -} - configurations.configureEach { resolutionStrategy.cacheChangingModulesFor(0, 'seconds') resolutionStrategy.cacheDynamicVersionsFor(0, 'seconds') diff --git a/buildSrc/src/main/java/BukkitArtifactVerifier.java b/buildSrc/src/main/java/BukkitArtifactVerifier.java index b86173d8c..17bbcaef1 100644 --- a/buildSrc/src/main/java/BukkitArtifactVerifier.java +++ b/buildSrc/src/main/java/BukkitArtifactVerifier.java @@ -29,7 +29,6 @@ public final class BukkitArtifactVerifier { "art/arcane/iris/util/paper/", "art/arcane/iris/util/kyori/", "art/arcane/iris/util/metrics/", - "art/arcane/iris/util/sentry/", "art/arcane/iris/util/maven/", "art/arcane/iris/util/plexus/", "art/arcane/iris/util/sisu/", diff --git a/core/build.gradle b/core/build.gradle index d83c5df85..ccd2ac5a2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,5 +1,4 @@ import io.github.slimjar.resolver.data.Mirror -import org.gradle.api.Task import org.gradle.api.tasks.Copy import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.JavaCompile @@ -31,7 +30,6 @@ plugins { id 'java' id 'java-library' alias(libs.plugins.shadow) - alias(libs.plugins.sentry) alias(libs.plugins.slimjar) } @@ -39,8 +37,6 @@ def lib = 'art.arcane.iris.util' String volmLibCoordinate = providers.gradleProperty('volmLibCoordinate') .orElse('com.github.VolmitSoftware:VolmLib:e6574cf814b3dd670385a4d632a63fde2038e186') .get() -String sentryAuthToken = findProperty('sentry.auth.token') as String ?: System.getenv('SENTRY_AUTH_TOKEN') -boolean hasSentryAuthToken = sentryAuthToken != null && !sentryAuthToken.isBlank() /** * Dependencies. @@ -97,8 +93,6 @@ dependencies { slim(libs.adventure.serializer.legacy) slim(libs.adventure.serializer.plain) slim(libs.bstats) - slim(libs.sentry) - slim(libs.commons.io) slim(libs.commons.lang3) slim(libs.oshi) @@ -134,16 +128,6 @@ java { } } -sentry { - url = 'http://sentry.volmit.com:8080' - autoInstallation.enabled = false - includeSourceContext = true - - org = 'sentry' - projectName = 'iris' - authToken = sentryAuthToken -} - slimJar { mirrors = [ new Mirror( @@ -158,7 +142,6 @@ slimJar { relocate('io.papermc.lib', "${lib}.paper") relocate('net.kyori', "${lib}.kyori") relocate('org.bstats', "${lib}.metrics") - relocate('io.sentry', "${lib}.sentry") relocate('org.apache.maven', "${lib}.maven") relocate('org.codehaus.plexus', "${lib}.plexus") relocate('org.eclipse.sisu', "${lib}.sisu") @@ -464,22 +447,6 @@ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.Shadow } } -tasks.named('sentryCollectSourcesJava').configure { - dependsOn(generateTemplates) -} - -tasks.named('generateSentryBundleIdJava').configure { - dependsOn(generateTemplates) -} - -tasks.matching { Task task -> - task.name.startsWith('sentry') || task.name.startsWith('generateSentry') -}.configureEach { - onlyIf { - hasSentryAuthToken - } -} - rootProject.tasks.matching { it.name == 'prepareKotlinBuildScriptModel' }.configureEach { diff --git a/core/purity-allowlist.txt b/core/purity-allowlist.txt index 31a622766..e0b8379a5 100644 --- a/core/purity-allowlist.txt +++ b/core/purity-allowlist.txt @@ -187,5 +187,3 @@ art/arcane/iris/util/project/matter/IrisMatterSupport.java art/arcane/iris/util/project/matter/WorldMatter.java art/arcane/iris/util/project/matter/slices/EntityMatter.java art/arcane/iris/util/project/matter/slices/TileMatter.java -art/arcane/iris/util/project/sentry/Attachments.java -art/arcane/iris/util/project/sentry/ServerID.java diff --git a/core/src/main/java/art/arcane/iris/core/IrisSettings.java b/core/src/main/java/art/arcane/iris/core/IrisSettings.java index a3996e6da..da75c4be5 100644 --- a/core/src/main/java/art/arcane/iris/core/IrisSettings.java +++ b/core/src/main/java/art/arcane/iris/core/IrisSettings.java @@ -47,7 +47,6 @@ public class IrisSettings { private IrisSettingsStudio studio = new IrisSettingsStudio(); private IrisSettingsPerformance performance = new IrisSettingsPerformance(); private IrisSettingsPregen pregen = new IrisSettingsPregen(); - private IrisSettingsSentry sentry = new IrisSettingsSentry(); private IrisSettingsTreeFeller treeFeller = new IrisSettingsTreeFeller(); public static int getThreadCount(int c) { @@ -182,7 +181,6 @@ public class IrisSettings { studio = studio == null ? new IrisSettingsStudio() : studio; performance = performance == null ? new IrisSettingsPerformance() : performance; pregen = pregen == null ? new IrisSettingsPregen() : pregen; - sentry = sentry == null ? new IrisSettingsSentry() : sentry; treeFeller = treeFeller == null ? new IrisSettingsTreeFeller() : treeFeller; } @@ -340,13 +338,6 @@ public class IrisSettings { } } - @Data - public static class IrisSettingsSentry { - public boolean includeServerId = true; - public boolean disableAutoReporting = false; - public boolean debug = false; - } - @Data public static class IrisSettingsGUI { public boolean useServerLaunchedGuis = true; diff --git a/core/src/main/java/art/arcane/iris/core/localization/DirectorCommandMessages.java b/core/src/main/java/art/arcane/iris/core/localization/DirectorCommandMessages.java index f2f4986df..6f1dd4393 100644 --- a/core/src/main/java/art/arcane/iris/core/localization/DirectorCommandMessages.java +++ b/core/src/main/java/art/arcane/iris/core/localization/DirectorCommandMessages.java @@ -38,10 +38,6 @@ public final class DirectorCommandMessages { "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count", "Get Loaded TectonicPlates Count" ); - public static final TextKey COMMAND_DEVELOPER_DIRECTOR_SEND_TEST_EXCEPTION_SENTRY = TextKey.of( - "iris.director.commanddeveloper.director.send_test_exception_sentry", - "Send a test exception to sentry" - ); public static final TextKey COMMAND_DEVELOPER_DIRECTOR_HASH_GENERATED_BLOCK_OUTPUT_FIXED_AREA_DETERMINISM_IDENTITY_TESTING = TextKey.of( "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing", "Hash generated block output of a fixed area for determinism/identity testing" @@ -876,7 +872,6 @@ public final class DirectorCommandMessages { COMMAND_DATAPACK_PARAM_DATAPACK_ID_FOLDER_NAME_SHOWN_BY_IRIS_DATAPACK_LIST, COMMAND_DEVELOPER_DIRECTOR_IRIS_WORLD_MANAGER, COMMAND_DEVELOPER_DIRECTOR_GET_LOADED_TECTONICPLATES_COUNT, - COMMAND_DEVELOPER_DIRECTOR_SEND_TEST_EXCEPTION_SENTRY, COMMAND_DEVELOPER_DIRECTOR_HASH_GENERATED_BLOCK_OUTPUT_FIXED_AREA_DETERMINISM_IDENTITY_TESTING, COMMAND_DEVELOPER_PARAM_WORLD_HASH, COMMAND_DEVELOPER_PARAM_RADIUS_CHUNKS_AROUND_CENTER, diff --git a/core/src/main/java/art/arcane/iris/core/localization/ModdedCommandMessages.java b/core/src/main/java/art/arcane/iris/core/localization/ModdedCommandMessages.java index 7d59a718a..caadca06f 100644 --- a/core/src/main/java/art/arcane/iris/core/localization/ModdedCommandMessages.java +++ b/core/src/main/java/art/arcane/iris/core/localization/ModdedCommandMessages.java @@ -503,10 +503,6 @@ public final class ModdedCommandMessages { "iris.modded.moddeddatapackcommands.message_2", " - " + "{name}" ); - public static final TextKey MODDED_DEVELOPER_COMMANDS_DISPATCHED_TEST_EXCEPTION_IRIS_ERROR_REPORTER_SENTRY_IF_ENABLED = TextKey.of( - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled", - "Dispatched a test exception to the Iris error reporter (Sentry if enabled)." - ); public static final TextKey MODDED_DEVELOPER_COMMANDS_MESSAGE = TextKey.of( "iris.modded.moddeddevelopercommands.message", " " + "{value}" @@ -1369,7 +1365,6 @@ public final class ModdedCommandMessages { MODDED_DATAPACK_COMMANDS_MODRINTH_INGEST_IS_BUKKIT_ONLY_INSTALL_THESE_MANUALLY_INTO_WORLD, MODDED_DATAPACK_COMMANDS_INSTALLED_WORLD_DATAPACKS, MODDED_DATAPACK_COMMANDS_MESSAGE_2, - MODDED_DEVELOPER_COMMANDS_DISPATCHED_TEST_EXCEPTION_IRIS_ERROR_REPORTER_SENTRY_IF_ENABLED, MODDED_DEVELOPER_COMMANDS_MESSAGE, MODDED_DEVELOPER_COMMANDS_NETWORK_SCAN_FAILED, MODDED_GOLDEN_HASH_GOLDENHASH_SCAN_IS_ALREADY_RUNNING, diff --git a/core/src/main/java/art/arcane/iris/core/localization/ModdedHelpMessages.java b/core/src/main/java/art/arcane/iris/core/localization/ModdedHelpMessages.java index efd1762cc..070203132 100644 --- a/core/src/main/java/art/arcane/iris/core/localization/ModdedHelpMessages.java +++ b/core/src/main/java/art/arcane/iris/core/localization/ModdedHelpMessages.java @@ -98,9 +98,9 @@ public final class ModdedHelpMessages { "iris.modded.help.entry.command.goldenhash", "Generate deterministic block hashes for parity testing" ); - public static final TextKey GROUP_DEVELOPER_DEVELOPER_DIAGNOSTICS_SENTRY_TEST_NETWORK_INTERFACES_REGION_FILE_SCAN = TextKey.of( + public static final TextKey GROUP_DEVELOPER_DEVELOPER_DIAGNOSTICS_NETWORK_INTERFACES_REGION_FILE_SCAN = TextKey.of( "iris.modded.help.entry.group.developer", - "Developer diagnostics: Sentry test, network interfaces, region-file scan" + "Developer diagnostics: network interfaces and region-file scan" ); public static final TextKey COMMAND_BIOME_FIND_AN_IRIS_BIOME = TextKey.of( "iris.modded.help.entry.command.biome", @@ -346,10 +346,6 @@ public final class ModdedHelpMessages { "iris.modded.help.entry.command.verify", "Report native and Iris structure reachability in the current dimension" ); - public static final TextKey COMMAND_SENTRY_SEND_A_TEST_EXCEPTION_TO_THE_IRIS_ERROR_REPORTER = TextKey.of( - "iris.modded.help.entry.command.sentry", - "Send a test exception to the Iris error reporter" - ); public static final TextKey COMMAND_NETWORK_LIST_NETWORK_INTERFACES_AND_THEIR_ADDRESSES = TextKey.of( "iris.modded.help.entry.command.network", "List network interfaces and their addresses" @@ -443,7 +439,7 @@ public final class ModdedHelpMessages { GROUP_DATAPACK_WORLD_DATAPACK_INSTALL_AND_STATUS_HELPERS, GROUP_STRUCTURE_IRIS_STRUCTURE_INDEX_INFO_AND_PLACEMENT_TOOLS, COMMAND_GOLDENHASH_GENERATE_DETERMINISTIC_BLOCK_HASHES_FOR_PARITY_TESTING, - GROUP_DEVELOPER_DEVELOPER_DIAGNOSTICS_SENTRY_TEST_NETWORK_INTERFACES_REGION_FILE_SCAN, + GROUP_DEVELOPER_DEVELOPER_DIAGNOSTICS_NETWORK_INTERFACES_REGION_FILE_SCAN, COMMAND_BIOME_FIND_AN_IRIS_BIOME, COMMAND_REGION_FIND_AN_IRIS_REGION, COMMAND_OBJECT_FIND_AN_OBJECT_PLACEMENT, @@ -505,7 +501,6 @@ public final class ModdedHelpMessages { COMMAND_IMPORT_EXPLAIN_BUKKIT_STRUCTURE_IMPORT_WORKFLOW, 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_WHAT_HERE_INSPECT_CURRENT_IRIS_CONTEXT, COMMAND_WHAT_BIOME_INSPECT_CURRENT_BIOME, diff --git a/core/src/main/java/art/arcane/iris/engine/IrisEngineMantle.java b/core/src/main/java/art/arcane/iris/engine/IrisEngineMantle.java index 8423f7a4b..fca4c2fae 100644 --- a/core/src/main/java/art/arcane/iris/engine/IrisEngineMantle.java +++ b/core/src/main/java/art/arcane/iris/engine/IrisEngineMantle.java @@ -18,7 +18,6 @@ package art.arcane.iris.engine; -import art.arcane.iris.spi.IrisPlatforms; import art.arcane.iris.core.IrisSettings; import art.arcane.iris.core.loader.IrisData; import art.arcane.iris.core.tools.WorldMaintenance; @@ -34,6 +33,7 @@ import art.arcane.iris.engine.mantle.components.MantleHydrologyComponent; import art.arcane.iris.engine.mantle.components.IrisStructureComponent; import art.arcane.iris.engine.object.IrisDimension; import art.arcane.iris.spi.IrisLogging; +import art.arcane.iris.spi.IrisPlatforms; import art.arcane.iris.spi.PlatformBlockState; import art.arcane.iris.util.project.matter.IrisMatterContext; import art.arcane.iris.util.project.matter.IrisMatterSupport; @@ -53,7 +53,6 @@ import art.arcane.iris.util.common.format.C; import art.arcane.volmlib.util.matter.IrisMatter; import art.arcane.volmlib.util.matter.Matter; import art.arcane.volmlib.util.matter.MatterSlice; -import art.arcane.iris.platform.bukkit.BukkitPlatform; import art.arcane.iris.util.common.parallel.HyperLock; import art.arcane.iris.util.common.parallel.MultiBurst; import lombok.AccessLevel; @@ -76,7 +75,6 @@ import java.util.function.Supplier; @ToString(exclude = "engine") public class IrisEngineMantle implements EngineMantle { public static final String STORAGE_FOLDER_NAME = "mantle-hydrology"; - private static final boolean BUKKIT_PRESENT = IrisMatterSupport.isBukkitPresent(); private final Engine engine; private final Mantle mantle; @Getter(AccessLevel.NONE) @@ -260,10 +258,7 @@ public class IrisEngineMantle implements EngineMantle { if (value instanceof PlatformBlockState) { return PlatformBlockState.class; } - if (BUKKIT_PRESENT) { - return BukkitPlatform.classifyMantleValue(value); - } - return value.getClass(); + return IrisPlatforms.get().classifyMantleValue(value); } @Override diff --git a/core/src/main/java/art/arcane/iris/engine/decorator/DecoratorCore.java b/core/src/main/java/art/arcane/iris/engine/decorator/DecoratorCore.java index b752e8910..6420bd650 100644 --- a/core/src/main/java/art/arcane/iris/engine/decorator/DecoratorCore.java +++ b/core/src/main/java/art/arcane/iris/engine/decorator/DecoratorCore.java @@ -43,21 +43,11 @@ final class DecoratorCore { private static final String WEEPING_VINES_PLANT = "minecraft:weeping_vines_plant"; private static final String TWISTING_VINES = "minecraft:twisting_vines"; private static final String TWISTING_VINES_PLANT = "minecraft:twisting_vines_plant"; - private static final boolean BUKKIT_PRESENT = detectBukkit(); private static volatile PlatformBlockState weepingVines; private static volatile PlatformBlockState weepingVinesPlant; private static volatile PlatformBlockState twistingVines; private static volatile PlatformBlockState twistingVinesPlant; - private static boolean detectBukkit() { - try { - Class.forName("org.bukkit.Bukkit", false, DecoratorCore.class.getClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - static final ThreadLocal SCRATCH_OPTS = ThreadLocal.withInitial(PlaceOpts::new); static final class PlaceOpts { @@ -391,9 +381,9 @@ final class DecoratorCore { if (!B.isVineBlock(b)) { return b; } - if (!BUKKIT_PRESENT) { - DecoratorPlatformHooks.FaceFixer fixer = DecoratorPlatformHooks.faceFixer(); - return fixer == null ? b : fixer.fixFaces(b, hunk, rX, rZ, x, y, z, mantle); + DecoratorPlatformHooks.FaceFixer fixer = DecoratorPlatformHooks.faceFixer(); + if (fixer != null) { + return fixer.fixFaces(b, hunk, rX, rZ, x, y, z, mantle); } BlockData rawB = (BlockData) b.nativeHandle(); BlockData cloned = rawB.clone(); @@ -447,9 +437,9 @@ final class DecoratorCore { if (!B.canPlaceOnto(decorator, surface)) { return false; } - if (!BUKKIT_PRESENT) { - DecoratorPlatformHooks.SurfaceSturdiness sturdiness = DecoratorPlatformHooks.surfaceSturdiness(); - return sturdiness == null ? B.isSolid(surface) : sturdiness.canGoOn(surface); + DecoratorPlatformHooks.SurfaceSturdiness sturdiness = DecoratorPlatformHooks.surfaceSturdiness(); + if (sturdiness != null) { + return sturdiness.canGoOn(surface); } return ((BlockData) surface.nativeHandle()).isFaceSturdy(BlockFace.UP, BlockSupport.FULL); } diff --git a/core/src/main/java/art/arcane/iris/engine/hydrology/HydrologyFeatureQuery.java b/core/src/main/java/art/arcane/iris/engine/hydrology/HydrologyFeatureQuery.java index ca54784fc..cdb5bded3 100644 --- a/core/src/main/java/art/arcane/iris/engine/hydrology/HydrologyFeatureQuery.java +++ b/core/src/main/java/art/arcane/iris/engine/hydrology/HydrologyFeatureQuery.java @@ -19,7 +19,6 @@ public record HydrologyFeatureQuery(Set types, String prof HydrologyFeatureType.MOUTH ); private static final Set UNDERGROUND = Set.of( - HydrologyFeatureType.RIDGE_BORE, HydrologyFeatureType.UNDERGROUND_POOL, HydrologyFeatureType.UNDERGROUND_DROP, HydrologyFeatureType.SINKHOLE @@ -94,7 +93,6 @@ public record HydrologyFeatureQuery(Set types, String prof builtIns.put("coastal_grotto", Set.of(HydrologyFeatureType.COASTAL_GROTTO)); builtIns.put("inland_grotto", Set.of(HydrologyFeatureType.INLAND_GROTTO)); builtIns.put("mouth", Set.of(HydrologyFeatureType.MOUTH)); - builtIns.put("ridge_tunnel", Set.of(HydrologyFeatureType.RIDGE_BORE)); builtIns.put("deep", DEEP); builtIns.put("pool", Set.of(HydrologyFeatureType.STANDING_POOL)); return Collections.unmodifiableMap(builtIns); diff --git a/core/src/main/java/art/arcane/iris/engine/object/BlockDataMergeSupport.java b/core/src/main/java/art/arcane/iris/engine/object/BlockDataMergeSupport.java index 562d0d6fe..2c12aedfe 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/BlockDataMergeSupport.java +++ b/core/src/main/java/art/arcane/iris/engine/object/BlockDataMergeSupport.java @@ -9,7 +9,6 @@ import java.util.Objects; import java.util.function.Function; public final class BlockDataMergeSupport { - private static final boolean BUKKIT_PRESENT = detectBukkit(); private static volatile StateMerger PLATFORM_MERGER = null; private BlockDataMergeSupport() { @@ -29,31 +28,15 @@ public final class BlockDataMergeSupport { PLATFORM_MERGER = merger; } - private static boolean detectBukkit() { - try { - Class.forName("org.bukkit.Bukkit", false, BlockDataMergeSupport.class.getClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - static PlatformBlockState merge(PlatformBlockState base, PlatformBlockState update) { - if (!BUKKIT_PRESENT) { - StateMerger merger = requirePlatformMerger(PLATFORM_MERGER); + StateMerger merger = PLATFORM_MERGER; + if (merger != null) { return merger.merge(base, update); } BlockData merged = merge((BlockData) base.nativeHandle(), (BlockData) update.nativeHandle(), BukkitBlockResolution::get); return merged == null ? null : BukkitBlockState.of(merged); } - static StateMerger requirePlatformMerger(StateMerger merger) { - if (merger == null) { - throw new IllegalStateException("No platform block-state merger is bound"); - } - return merger; - } - static BlockData merge(BlockData base, BlockData update, Function resolver) { try { return base.merge(update); diff --git a/core/src/main/java/art/arcane/iris/engine/object/IrisObjectRotation.java b/core/src/main/java/art/arcane/iris/engine/object/IrisObjectRotation.java index a2094c482..cba70c470 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/IrisObjectRotation.java +++ b/core/src/main/java/art/arcane/iris/engine/object/IrisObjectRotation.java @@ -53,7 +53,6 @@ import java.util.Set; @Desc("Configures rotation for iris") @Data public class IrisObjectRotation { - private static final boolean BUKKIT_PRESENT = detectBukkit(); private static volatile StateRotator PLATFORM_ROTATOR = null; public interface StateRotator { @@ -70,15 +69,6 @@ public class IrisObjectRotation { PLATFORM_ROTATOR = rotator; } - private static boolean detectBukkit() { - try { - Class.forName("org.bukkit.Bukkit", false, IrisObjectRotation.class.getClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - private static final class Faces { private static final List WALL_FACES = List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST); } @@ -298,8 +288,8 @@ public class IrisObjectRotation { return null; } - if (!BUKKIT_PRESENT) { - StateRotator rotator = requirePlatformRotator(PLATFORM_ROTATOR); + StateRotator rotator = PLATFORM_ROTATOR; + if (rotator != null) { return rotator.rotate(this, state, spinx, spiny, spinz); } @@ -313,13 +303,6 @@ public class IrisObjectRotation { return rotated == null ? null : BukkitBlockState.of(rotated); } - static StateRotator requirePlatformRotator(StateRotator rotator) { - if (rotator == null) { - throw new IllegalStateException("No platform block-state rotator is bound"); - } - return rotator; - } - private static boolean canRotateBlockData(BlockData data) { return data instanceof Directional || data instanceof Rotatable diff --git a/core/src/main/java/art/arcane/iris/engine/object/LegacyTileData.java b/core/src/main/java/art/arcane/iris/engine/object/LegacyTileData.java index bf4458639..bb2fe4f6c 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/LegacyTileData.java +++ b/core/src/main/java/art/arcane/iris/engine/object/LegacyTileData.java @@ -45,9 +45,9 @@ import java.util.stream.StreamSupport; /** * Bukkit-only pre-key tile format. Unreachable from the modded loaders: every entry point is * either Bukkit-typed ({@link #fromBukkit(BlockState)}, reached only from - * {@link TileData#getTileState(Block, boolean)} and the Bukkit structure importer) or sits behind - * the {@code BUKKIT_PRESENT} short-circuit in {@link TileData#read(DataInputStream)}, which hands - * off to the bound platform reader before this class is ever referenced. The nested handler types + * {@link TileData#getTileState(Block, boolean)} and the Bukkit structure importer) or follows the + * bound platform-reader path in {@link TileData#read(DataInputStream)}, which returns before this + * class is ever referenced. The nested handler types * therefore keep their raw Bukkit fields. */ @ToString diff --git a/core/src/main/java/art/arcane/iris/engine/object/TileData.java b/core/src/main/java/art/arcane/iris/engine/object/TileData.java index cea2c1051..2b41dcccc 100644 --- a/core/src/main/java/art/arcane/iris/engine/object/TileData.java +++ b/core/src/main/java/art/arcane/iris/engine/object/TileData.java @@ -64,7 +64,6 @@ public class TileData implements Cloneable { * never part of that walk. Bounded by the number of distinct material keys a pack can name. */ private static final Map RESOLVED_MATERIALS = new ConcurrentHashMap<>(); - private static final boolean BUKKIT_PRESENT = detectBukkit(); private static volatile TileReader PLATFORM_READER = null; private static volatile TileFactory PLATFORM_FACTORY = null; @@ -96,15 +95,6 @@ public class TileData implements Cloneable { PLATFORM_FACTORY = factory; } - private static boolean detectBukkit() { - try { - Class.forName("org.bukkit.Bukkit", false, TileData.class.getClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - /** * The block key this tile belongs to, stored as text so the field type never drags * org.bukkit.Material onto a Gson field walk or into generated equals/hashCode/toString. @@ -147,8 +137,9 @@ public class TileData implements Cloneable { } public static TileData of(PlatformBlockState state, KMap properties) { - if (!BUKKIT_PRESENT) { - return requirePlatformFactory(PLATFORM_FACTORY).create(state, properties); + TileFactory factory = PLATFORM_FACTORY; + if (factory != null) { + return factory.create(state, properties); } Object handle = state.nativeHandle(); if (!(handle instanceof BlockData blockData)) { @@ -158,8 +149,9 @@ public class TileData implements Cloneable { } public static TileData read(DataInputStream in) throws IOException { - if (!BUKKIT_PRESENT) { - return requirePlatformReader(PLATFORM_READER).read(in); + TileReader reader = PLATFORM_READER; + if (reader != null) { + return reader.read(in); } if (!in.markSupported()) throw new IOException("Mark not supported"); @@ -215,20 +207,6 @@ public class TileData implements Cloneable { return resolved; } - static TileFactory requirePlatformFactory(TileFactory factory) { - if (factory == null) { - throw new IllegalStateException("No platform tile-data factory is bound"); - } - return factory; - } - - static TileReader requirePlatformReader(TileReader reader) throws IOException { - if (reader == null) { - throw new IOException("No platform tile-data reader is bound"); - } - return reader; - } - public boolean isApplicable(BlockData data) { Material resolved = resolveMaterial(); return resolved != null && data.getMaterial() == resolved; diff --git a/core/src/main/java/art/arcane/iris/platform/bukkit/BukkitPlatform.java b/core/src/main/java/art/arcane/iris/platform/bukkit/BukkitPlatform.java index a6b81b666..b681fe28e 100644 --- a/core/src/main/java/art/arcane/iris/platform/bukkit/BukkitPlatform.java +++ b/core/src/main/java/art/arcane/iris/platform/bukkit/BukkitPlatform.java @@ -175,7 +175,8 @@ public final class BukkitPlatform implements IrisPlatform { return BukkitBiome.of((Biome) biome); } - public static Class classifyMantleValue(Object value) { + @Override + public Class classifyMantleValue(Object value) { if (value instanceof World) { return World.class; } @@ -191,6 +192,11 @@ public final class BukkitPlatform implements IrisPlatform { return value.getClass(); } + @Override + public boolean supportsMatterWorldIo() { + return true; + } + public static void unregisterListener(Object candidate) { if (candidate instanceof Listener listener) { volmitPlugin().unregisterListener(listener); diff --git a/core/src/main/java/art/arcane/iris/util/common/misc/Bindings.java b/core/src/main/java/art/arcane/iris/util/common/misc/Bindings.java index 7cda961be..9096abd56 100644 --- a/core/src/main/java/art/arcane/iris/util/common/misc/Bindings.java +++ b/core/src/main/java/art/arcane/iris/util/common/misc/Bindings.java @@ -1,23 +1,10 @@ package art.arcane.iris.util.common.misc; -import art.arcane.iris.util.project.sentry.Attachments; -import art.arcane.iris.util.project.sentry.IrisLogger; -import art.arcane.iris.util.project.sentry.ServerID; -import com.google.gson.JsonSyntaxException; import art.arcane.iris.BuildConstants; -import art.arcane.iris.spi.IrisLogging; -import art.arcane.iris.platform.bukkit.BukkitPlatform; -import art.arcane.iris.core.IrisSettings; -import art.arcane.iris.core.nms.INMS; -import art.arcane.iris.core.safeguard.IrisSafeguard; import art.arcane.iris.core.tools.IrisToolbelt; import art.arcane.iris.engine.platform.PlatformChunkGenerator; -import art.arcane.iris.util.project.context.IrisContext; -import art.arcane.volmlib.util.json.JSONException; import art.arcane.iris.util.common.plugin.VolmitPlugin; import art.arcane.iris.util.common.scheduling.J; - -import io.sentry.Sentry; import org.bstats.bukkit.Metrics; import org.bstats.charts.DrilldownPie; import org.bstats.charts.SingleLineChart; @@ -29,56 +16,6 @@ import java.util.Objects; import java.util.stream.Collectors; public class Bindings { - - public static void capture(Throwable throwable) { - Sentry.captureException(throwable); - } - - public static void setupSentry() { - var settings = IrisSettings.get().getSentry(); - if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return; - IrisLogging.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); - IrisLogging.info("Your server ID is: " + ServerID.getId()); - - Sentry.init(options -> { - options.setDsn("http://4cdbb9ac953306529947f4ca1e8e6b26@sentry.volmit.com:8080/2"); - if (settings.debug) { - options.setLogger(new IrisLogger()); - options.setDebug(true); - } - - options.setAttachServerName(false); - options.setEnableUncaughtExceptionHandler(false); - options.setRelease(BukkitPlatform.plugin().getDescription().getVersion()); - options.setEnvironment(BuildConstants.ENVIRONMENT); - options.setBeforeSend((event, hint) -> { - if (suppress(event.getThrowable())) return null; - event.setTag("iris.safeguard", IrisSafeguard.mode().getId()); - event.setTag("iris.nms", INMS.get().getClass().getCanonicalName()); - var context = IrisContext.get(); - if (context != null) event.getContexts().set("engine", context.asContext()); - event.getContexts().set("safeguard", IrisSafeguard.asContext()); - return event; - }); - }); - Sentry.configureScope(scope -> { - if (settings.includeServerId) scope.setUser(ServerID.asUser()); - scope.addAttachment(Attachments.PLUGINS); - scope.addAttachment(Attachments.SAFEGUARD); - scope.setTag("server", Bukkit.getVersion()); - scope.setTag("server.type", Bukkit.getName()); - scope.setTag("server.api", Bukkit.getBukkitVersion()); - scope.setTag("iris.commit", BuildConstants.COMMIT); - }); - } - - private static boolean suppress(Throwable e) { - return (e instanceof IllegalStateException ex && "zip file closed".equals(ex.getMessage())) - || e instanceof JSONException - || e instanceof JsonSyntaxException; - } - - // bstats.org plugin id private static final int BSTATS_PLUGIN_ID = 24220; @@ -87,7 +24,7 @@ public class Bindings { return; } J.s(() -> { - var metrics = new Metrics(plugin, BSTATS_PLUGIN_ID); + Metrics metrics = new Metrics(plugin, BSTATS_PLUGIN_ID); metrics.addCustomChart(new SingleLineChart("custom_dimensions", () -> Bukkit.getWorlds() .stream() .filter(IrisToolbelt::isIrisWorld) @@ -100,7 +37,7 @@ public class Bindings { .map(PlatformChunkGenerator::getEngine) .filter(Objects::nonNull) .collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> { - var hash32 = engine.getHash32().getNow(null); + Long hash32 = engine.getHash32().getNow(null); if (hash32 == null) return Map.of(); int version = engine.getDimension().getVersion(); String checksum = Long.toHexString(hash32); diff --git a/core/src/main/java/art/arcane/iris/util/common/scheduling/J.java b/core/src/main/java/art/arcane/iris/util/common/scheduling/J.java index f811bfc5d..dd2cee405 100644 --- a/core/src/main/java/art/arcane/iris/util/common/scheduling/J.java +++ b/core/src/main/java/art/arcane/iris/util/common/scheduling/J.java @@ -121,7 +121,7 @@ public class J { } public static void aBukkit(Runnable a) { - if (!BUKKIT_PRESENT) { + if (!usesBukkitScheduler()) { if (IrisPlatforms.isBound()) { IrisPlatforms.get().scheduler().async(a); } @@ -186,7 +186,7 @@ public class J { } public static boolean isFolia() { - return BUKKIT_PRESENT && FoliaScheduler.isFolia(Bukkit.getServer()); + return usesBukkitScheduler() && FoliaScheduler.isFolia(Bukkit.getServer()); } public static boolean isPrimaryThread() { @@ -345,7 +345,7 @@ public class J { return false; } - if (!BUKKIT_PRESENT) { + if (!usesBukkitScheduler()) { if (!IrisPlatforms.isBound()) { return false; } @@ -416,7 +416,7 @@ public class J { public static void cancelPluginTasks() { cancelTrackedRepeatingTasks(); - if (!BukkitPlatform.hasPlugin()) { + if (!usesBukkitScheduler() || !BukkitPlatform.hasPlugin()) { return; } @@ -442,7 +442,7 @@ public class J { } public static void s(Runnable r) { - if (!BUKKIT_PRESENT) { + if (!usesBukkitScheduler()) { if (IrisPlatforms.isBound()) { IrisPlatforms.get().scheduler().global(r); } @@ -566,7 +566,7 @@ public class J { } public static void s(Runnable r, int delay) { - if (!BUKKIT_PRESENT) { + if (!usesBukkitScheduler()) { if (IrisPlatforms.isBound()) { IrisPlatforms.get().scheduler().laterGlobal(r, delay); } @@ -667,7 +667,7 @@ public class J { } public static void a(Runnable r, int delay) { - if (!BUKKIT_PRESENT) { + if (!usesBukkitScheduler()) { if (IrisPlatforms.isBound()) { if (delay <= 0) { IrisPlatforms.get().scheduler().async(r); @@ -772,11 +772,17 @@ public class J { } private static boolean isPluginEnabled() { - return BUKKIT_PRESENT && BukkitPlatform.hasPlugin() && Bukkit.getPluginManager().isPluginEnabled(BukkitPlatform.plugin()); + return usesBukkitScheduler() && BukkitPlatform.hasPlugin() && Bukkit.getPluginManager().isPluginEnabled(BukkitPlatform.plugin()); } private static boolean canSchedule() { - return BUKKIT_PRESENT ? isPluginEnabled() : IrisPlatforms.isBound(); + return usesBukkitScheduler() ? isPluginEnabled() : IrisPlatforms.isBound(); + } + + static boolean usesBukkitScheduler() { + return BUKKIT_PRESENT + && IrisPlatforms.isBound() + && "bukkit".equalsIgnoreCase(IrisPlatforms.get().platformName()); } private static long ticksToMilliseconds(int ticks) { diff --git a/core/src/main/java/art/arcane/iris/util/project/matter/IrisMatterSupport.java b/core/src/main/java/art/arcane/iris/util/project/matter/IrisMatterSupport.java index 9d6b72e15..ae6bb0538 100644 --- a/core/src/main/java/art/arcane/iris/util/project/matter/IrisMatterSupport.java +++ b/core/src/main/java/art/arcane/iris/util/project/matter/IrisMatterSupport.java @@ -38,25 +38,11 @@ import art.arcane.iris.util.common.math.IrisBlockVector; import java.io.File; public final class IrisMatterSupport { - private static final boolean BUKKIT_PRESENT = detectBukkit(); private static boolean registered; private IrisMatterSupport() { } - public static boolean isBukkitPresent() { - return BUKKIT_PRESENT; - } - - private static boolean detectBukkit() { - try { - Class.forName("org.bukkit.World", false, IrisMatterSupport.class.getClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - public static synchronized void ensureRegistered() { if (registered) { return; diff --git a/core/src/main/java/art/arcane/iris/util/project/matter/slices/EntityMatter.java b/core/src/main/java/art/arcane/iris/util/project/matter/slices/EntityMatter.java index 6a89092cc..0b58625b9 100644 --- a/core/src/main/java/art/arcane/iris/util/project/matter/slices/EntityMatter.java +++ b/core/src/main/java/art/arcane/iris/util/project/matter/slices/EntityMatter.java @@ -21,7 +21,7 @@ package art.arcane.iris.util.project.matter.slices; import art.arcane.iris.platform.bukkit.BukkitPlatform; import art.arcane.iris.core.nms.INMS; import art.arcane.iris.engine.object.IrisPosition; -import art.arcane.iris.util.project.matter.IrisMatterSupport; +import art.arcane.iris.spi.IrisPlatforms; import art.arcane.volmlib.util.collection.KList; import art.arcane.volmlib.util.collection.KMap; import art.arcane.volmlib.util.data.Varint; @@ -53,7 +53,7 @@ public class EntityMatter extends RawMatter { public EntityMatter(int width, int height, int depth) { super(width, height, depth, MatterEntityGroup.class); - if (IrisMatterSupport.isBukkitPresent()) { + if (IrisPlatforms.isBound() && IrisPlatforms.get().supportsMatterWorldIo()) { registerBukkitIO(); } } diff --git a/core/src/main/java/art/arcane/iris/util/project/matter/slices/TileMatter.java b/core/src/main/java/art/arcane/iris/util/project/matter/slices/TileMatter.java index 71dee5144..7b2d0586c 100644 --- a/core/src/main/java/art/arcane/iris/util/project/matter/slices/TileMatter.java +++ b/core/src/main/java/art/arcane/iris/util/project/matter/slices/TileMatter.java @@ -20,7 +20,7 @@ package art.arcane.iris.util.project.matter.slices; import art.arcane.iris.engine.object.TileData; -import art.arcane.iris.util.project.matter.IrisMatterSupport; +import art.arcane.iris.spi.IrisPlatforms; import art.arcane.iris.util.project.matter.TileWrapper; import art.arcane.volmlib.util.data.palette.Palette; import art.arcane.volmlib.util.matter.Sliced; @@ -42,7 +42,7 @@ public class TileMatter extends RawMatter { public TileMatter(int width, int height, int depth) { super(width, height, depth, TileWrapper.class); - if (IrisMatterSupport.isBukkitPresent()) { + if (IrisPlatforms.isBound() && IrisPlatforms.get().supportsMatterWorldIo()) { registerBukkitIO(); } } diff --git a/core/src/main/java/art/arcane/iris/util/project/sentry/Attachments.java b/core/src/main/java/art/arcane/iris/util/project/sentry/Attachments.java deleted file mode 100644 index 026908c5c..000000000 --- a/core/src/main/java/art/arcane/iris/util/project/sentry/Attachments.java +++ /dev/null @@ -1,43 +0,0 @@ -package art.arcane.iris.util.project.sentry; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import art.arcane.iris.core.safeguard.IrisSafeguard; -import art.arcane.volmlib.util.collection.KMap; -import io.sentry.Attachment; -import org.bukkit.Bukkit; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.Callable; - -public class Attachments { - private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); - public static final Attachment PLUGINS = jsonProvider(Attachments::plugins, "plugins.json"); - public static final Attachment SAFEGUARD = jsonProvider(IrisSafeguard::asAttachment, "safeguard.json"); - - public static Attachment json(Object object, String name) { - return new Attachment(GSON.toJson(object).getBytes(StandardCharsets.UTF_8), name, "application/json", "event.attachment", true); - } - - public static Attachment jsonProvider(Callable object, String name) { - return new Attachment(() -> GSON.toJson(object.call()).getBytes(StandardCharsets.UTF_8), name, "application/json", "event.attachment", true); - } - - private static KMap plugins() { - KMap enabled = new KMap<>(); - KMap disabled = new KMap<>(); - - var pm = Bukkit.getPluginManager(); - for (var plugin : pm.getPlugins()) { - if (plugin.isEnabled()) { - enabled.put(plugin.getName(), plugin.getDescription().getVersion()); - } else { - disabled.put(plugin.getName(), plugin.getDescription().getVersion()); - } - } - - return new KMap() - .qput("enabled", enabled) - .qput("disabled", disabled); - } -} diff --git a/core/src/main/java/art/arcane/iris/util/project/sentry/IrisLogger.java b/core/src/main/java/art/arcane/iris/util/project/sentry/IrisLogger.java deleted file mode 100644 index 36b789711..000000000 --- a/core/src/main/java/art/arcane/iris/util/project/sentry/IrisLogger.java +++ /dev/null @@ -1,47 +0,0 @@ -package art.arcane.iris.util.project.sentry; - -import art.arcane.iris.spi.IrisLogging; -import io.sentry.ILogger; -import io.sentry.SentryLevel; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.PrintWriter; -import java.io.StringWriter; - -public class IrisLogger implements ILogger { - @Override - public void log(@NotNull SentryLevel level, @NotNull String message, @Nullable Object... args) { - IrisLogging.msg(String.format("%s: %s", level, String.format(message, args))); - } - - @Override - public void log(@NotNull SentryLevel level, @NotNull String message, @Nullable Throwable throwable) { - if (throwable == null) { - log(level, message); - } else { - IrisLogging.msg(String.format("%s: %s\n%s", level, String.format(message, throwable), captureStackTrace(throwable))); - } - } - - @Override - public void log(@NotNull SentryLevel level, @Nullable Throwable throwable, @NotNull String message, @Nullable Object... args) { - if (throwable == null) { - log(level, message, args); - } else { - IrisLogging.msg(String.format("%s: %s\n%s", level, String.format(message, throwable), captureStackTrace(throwable))); - } - } - - @Override - public boolean isEnabled(@Nullable SentryLevel level) { - return true; - } - - private @NotNull String captureStackTrace(@NotNull Throwable throwable) { - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stringWriter); - throwable.printStackTrace(printWriter); - return stringWriter.toString(); - } -} diff --git a/core/src/main/java/art/arcane/iris/util/project/sentry/ServerID.java b/core/src/main/java/art/arcane/iris/util/project/sentry/ServerID.java deleted file mode 100644 index 69b99e06f..000000000 --- a/core/src/main/java/art/arcane/iris/util/project/sentry/ServerID.java +++ /dev/null @@ -1,65 +0,0 @@ -package art.arcane.iris.util.project.sentry; - -import art.arcane.volmlib.util.io.IO; -import io.sentry.protocol.User; -import lombok.SneakyThrows; -import org.bukkit.Bukkit; -import oshi.SystemInfo; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class ServerID { - private static final class Holder { - private static final String ID = calculate(); - } - - public static String getId() { - return Holder.ID; - } - - public static User asUser() { - User u = new User(); - u.setId(Holder.ID); - return u; - } - - @SneakyThrows - private static String calculate() { - Digest md = new Digest(); - md.update(System.getProperty("java.vm.name")); - md.update(System.getProperty("java.vm.version")); - md.update(new SystemInfo().getHardware().getProcessor().toString()); - md.update(Runtime.getRuntime().maxMemory()); - for (var p : Bukkit.getPluginManager().getPlugins()) { - md.update(p.getName()); - } - - return IO.bytesToHex(md.digest()); - } - - private static final class Digest { - private final MessageDigest md = MessageDigest.getInstance("SHA-256"); - private final byte[] buffer = new byte[8]; - private final ByteBuffer wrapped = ByteBuffer.wrap(buffer); - - private Digest() throws NoSuchAlgorithmException { - } - - public void update(String string) { - if (string == null) return; - md.update(string.getBytes(StandardCharsets.UTF_8)); - } - - public void update(long Long) { - wrapped.putLong(0, Long); - md.update(buffer, 0, 8); - } - - public byte[] digest() { - return md.digest(); - } - } -} diff --git a/core/src/main/resources/languages/de_DE.json b/core/src/main/resources/languages/de_DE.json index c1d184202..60e762b83 100644 --- a/core/src/main/resources/languages/de_DE.json +++ b/core/src/main/resources/languages/de_DE.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Der Modrinth-Import ist nur unter Bukkit verfügbar; installiere diese Datapacks bei Bedarf manuell unter world/datapacks.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Installierte Weltdatenpakete: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Eine Testausnahme wurde an den Iris-Fehlerreporter gesendet (Sentry, falls aktiviert).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Netzwerk-Scan fehlgeschlagen: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Es läuft bereits ein GoldenHash-Scan.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Die Datapack-ID (Ordnername) wird angezeigt von /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris-Weltverwaltung", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Anzahl geladener TectonicPlates abrufen", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Eine Testausnahme an Sentry senden", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Generierte Blockausgabe eines festen Bereichs für Determinismus- und Identitätstests hashen", "iris.director.commanddeveloper.param.world_hash": "Die zu hashende Welt", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Radius in Chunks um die Mitte", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Hilfen für Installation und Status von Welt-Datapacks", "iris.modded.help.entry.group.structure": "Werkzeuge für Iris-Strukturindex, Informationen und Platzierung", "iris.modded.help.entry.command.goldenhash": "Generieren Sie deterministische Block-Hashes für Paritätstests", - "iris.modded.help.entry.group.developer": "Entwicklerdiagnostik: Sentry-Test, Netzwerkschnittstellen, Region-Datei-Scan", + "iris.modded.help.entry.group.developer": "Entwicklerdiagnostik: Netzwerkschnittstellen und Region-Datei-Scan", "iris.modded.help.entry.command.biome": "Ein Iris-Biom finden", "iris.modded.help.entry.command.region": "Eine Iris-Region finden", "iris.modded.help.entry.command.object": "Finden Sie eine Objektplatzierung", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Bukkit-Ablauf für den Strukturimport erklären", "iris.modded.help.entry.command.capture": "Bukkit-Ablauf für die Strukturerfassung erklären", "iris.modded.help.entry.command.verify": "Erreichbarkeit nativer und Iris-Strukturen in der aktuellen Dimension anzeigen", - "iris.modded.help.entry.command.sentry": "Eine Testausnahme an den Iris-Fehlerbericht senden", "iris.modded.help.entry.command.network": "Liste der Netzwerkschnittstellen und ihrer Adressen", "iris.runtime.progress.finding_regions": "Regionen werden gesucht", "iris.runtime.progress.converting": "Umwandlung", diff --git a/core/src/main/resources/languages/es_ES.json b/core/src/main/resources/languages/es_ES.json index acf750762..1594a39d9 100644 --- a/core/src/main/resources/languages/es_ES.json +++ b/core/src/main/resources/languages/es_ES.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "La ingesta de Modrinth solo está disponible en Bukkit; instala estos datapacks manualmente en world/datapacks si es necesario.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Datapacks del mundo instalados: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Se envió una excepción de prueba al sistema de informes de errores de Iris (Sentry si está habilitado).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "El escaneo de red falló: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Ya hay un análisis GoldenHash en curso.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "El id del datapack (nombre de carpeta) que muestra /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Gestor de mundos de Iris", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Obtener el número de TectonicPlates cargadas", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Enviar una excepción de prueba a Sentry", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Calcular el hash de los bloques generados en un área fija para comprobar el determinismo y la identidad", "iris.director.commanddeveloper.param.world_hash": "El mundo cuyo hash se calculará", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Radio en chunks alrededor del centro", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Herramientas de instalación y estado de datapacks del mundo", "iris.modded.help.entry.group.structure": "Herramientas de índice, información y colocación de estructuras de Iris", "iris.modded.help.entry.command.goldenhash": "Generar hashes de bloques deterministas para pruebas de paridad", - "iris.modded.help.entry.group.developer": "Diagnósticos para desarrolladores: prueba de Sentry, interfaces de red y análisis de archivos de región", + "iris.modded.help.entry.group.developer": "Diagnósticos para desarrolladores: interfaces de red y análisis de archivos de región", "iris.modded.help.entry.command.biome": "Buscar un bioma de Iris", "iris.modded.help.entry.command.region": "Buscar una región de Iris", "iris.modded.help.entry.command.object": "Buscar la colocación de un objeto", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Explicar el flujo de importación de estructuras de Bukkit", "iris.modded.help.entry.command.capture": "Explicar el flujo de captura de estructuras de Bukkit", "iris.modded.help.entry.command.verify": "Informar de la accesibilidad de estructuras nativas y de Iris en la dimensión actual", - "iris.modded.help.entry.command.sentry": "Enviar una excepción de prueba al sistema de informes de errores de Iris", "iris.modded.help.entry.command.network": "Listar las interfaces de red y sus direcciones", "iris.runtime.progress.finding_regions": "Buscando regiones", "iris.runtime.progress.converting": "Convirtiendo", diff --git a/core/src/main/resources/languages/fi_FI.json b/core/src/main/resources/languages/fi_FI.json index f793ecf05..b26961ff5 100644 --- a/core/src/main/resources/languages/fi_FI.json +++ b/core/src/main/resources/languages/fi_FI.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth ingest on Bukkit-vain; asenna nämä käsin world/datapacks tarvittaessa.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Asennetut maailman datapaketit: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Lähetti testipoikkeuksen Iris virheilmoittaja (Sentry, jos käytössä).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Verkkoskannaus epäonnistui: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Kultahaskanneri on jo käynnissä.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Datapaketin tunniste (kansionimi) /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Maailmanjohtaja", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Hae Ladattu TectonicPlates Lukumäärä", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Lähetä testipoikkeus vartijalle", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Hashin tuottama lohkon tuotos kiinteällä alueella determinismi-/identiteettitestausta varten", "iris.director.commanddeveloper.param.world_hash": "Maailma hasista", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Radius palasina keskellä", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "maailman datapaketin asennus- ja tilaapurit", "iris.modded.help.entry.group.structure": "Iris rakenneindeksi, tiedot ja työvälineet", "iris.modded.help.entry.command.goldenhash": "Luo deterministinen lohkon hashes pariteettitestaus", - "iris.modded.help.entry.group.developer": "Kehittäjän diagnostiikka: Sentry-testi, verkkoliitännät, aluetiedostojen skannaus", + "iris.modded.help.entry.group.developer": "Kehittäjän diagnostiikka: verkkoliitännät ja aluetiedostojen skannaus", "iris.modded.help.entry.command.biome": "Etsi Iris bome", "iris.modded.help.entry.command.region": "Etsi Iris alue", "iris.modded.help.entry.command.object": "Etsi kohteen sijoitus", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Selitä Bukkit rakenteen mukainen työnkulku", "iris.modded.help.entry.command.capture": "Selitä Bukkit rakenteen kaappaustyövirta", "iris.modded.help.entry.command.verify": "Ilmoita syntyperäinen ja Iris rakenteen saavutettavuus nykyisessä ulottuvuudessa", - "iris.modded.help.entry.command.sentry": "Lähetä testi poikkeus Iris virheraportointi", "iris.modded.help.entry.command.network": "Listaa verkkoliittymät ja niiden osoitteet", "iris.runtime.progress.finding_regions": "Alueet", "iris.runtime.progress.converting": "Muunnetaan", diff --git a/core/src/main/resources/languages/fr_FR.json b/core/src/main/resources/languages/fr_FR.json index 30136d9b9..b017acdb3 100644 --- a/core/src/main/resources/languages/fr_FR.json +++ b/core/src/main/resources/languages/fr_FR.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "L'ingestion Modrinth est réservée à Bukkit ; installez ces datapacks manuellement dans world/datapacks si nécessaire.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Datapacks du monde installés : {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Une exception de test a été envoyée au système de rapports d'erreurs Iris (Sentry s'il est activé).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "La numérisation réseau a échoué : {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Une analyse GoldenHash est déjà en cours.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "L'id du datapack (nom du dossier) affiché par /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Gestionnaire de mondes Iris", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Obtenir le nombre de TectonicPlates chargées", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Envoyer une exception de test à Sentry", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Calculer le hash des blocs générés dans une zone fixe afin de tester le déterminisme et l'identité", "iris.director.commanddeveloper.param.world_hash": "Le monde dont le hash sera calculé", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Rayon en chunks autour du centre", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Outils d'installation et d'état des datapacks du monde", "iris.modded.help.entry.group.structure": "Outils d'index, d'informations et de placement des structures Iris", "iris.modded.help.entry.command.goldenhash": "Générer des hashes de blocs déterministes pour les tests de parité", - "iris.modded.help.entry.group.developer": "Diagnostics développeur : test Sentry, interfaces réseau et analyse des fichiers de région", + "iris.modded.help.entry.group.developer": "Diagnostics développeur : interfaces réseau et analyse des fichiers de région", "iris.modded.help.entry.command.biome": "Rechercher un biome Iris", "iris.modded.help.entry.command.region": "Rechercher une région Iris", "iris.modded.help.entry.command.object": "Rechercher le placement d'un objet", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Expliquer le flux d'importation des structures Bukkit", "iris.modded.help.entry.command.capture": "Expliquer le flux de capture des structures Bukkit", "iris.modded.help.entry.command.verify": "Afficher l'accessibilité des structures natives et Iris dans la dimension actuelle", - "iris.modded.help.entry.command.sentry": "Envoyer une exception de test au rapporteur d'erreurs Iris", "iris.modded.help.entry.command.network": "Lister les interfaces réseau et leurs adresses", "iris.runtime.progress.finding_regions": "Recherche des régions", "iris.runtime.progress.converting": "Conversion", diff --git a/core/src/main/resources/languages/he_IL.json b/core/src/main/resources/languages/he_IL.json index 6a91a0f60..cf3124630 100644 --- a/core/src/main/resources/languages/he_IL.json +++ b/core/src/main/resources/languages/he_IL.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth טעינה Bukkit- רק; להתקין אותם באופן ידני world/datapacks אם צריך.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "התקנת חבילות נתונים עולמיות: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "נשלחה חריגת בדיקה אל מדווח השגיאות של Iris (Sentry אם מופעל).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "סריקות רשת נכשלות: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "סריקת זהב כבר פועלת.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "חבילת הנתונים id (שם כפול) מוצג על ידי /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris מנהל עולמי", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "קבל טעון TectonicPlates הרוזן", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "שלח יוצא מן הבחינה לשולח", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "האש יצרה פלט בלוק של אזור קבוע עבור בדיקות determin / זהות", "iris.director.commanddeveloper.param.world_hash": "העולם שיש", "iris.director.commanddeveloper.param.radius_chunks_around_center": "רדינוס בחלקים סביב המרכז", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "חבילת נתונים עולמית להתקין ועוזרי סטטוס", "iris.modded.help.entry.group.structure": "Iris מדד מבנה, מידע וכלי מיקום", "iris.modded.help.entry.command.goldenhash": "לייצר בלוק determins עבור מבחן תאימות", - "iris.modded.help.entry.group.developer": "אבחון למפתחים: בדיקת Sentry, ממשקי רשת וסריקת קובצי אזור", + "iris.modded.help.entry.group.developer": "אבחון למפתחים: ממשקי רשת וסריקת קובצי אזור", "iris.modded.help.entry.command.biome": "מצא Iris ביו", "iris.modded.help.entry.command.region": "מצא Iris האזור האזורי", "iris.modded.help.entry.command.object": "מצא מיקום אובייקט", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "להסביר Bukkit ייבוא תהליך עבודה", "iris.modded.help.entry.command.capture": "להסביר Bukkit מבנה לכידת עבודה", "iris.modded.help.entry.command.verify": "דו\"ח Native ו- Iris מגיע לשיאות במימד הנוכחי", - "iris.modded.help.entry.command.sentry": "שלח יוצא דופן במבחן Iris עיתונאי טעות", "iris.modded.help.entry.command.network": "ממשקי רשת וכתובות", "iris.runtime.progress.finding_regions": "מציאת אזורים", "iris.runtime.progress.converting": "המרת", diff --git a/core/src/main/resources/languages/it_IT.json b/core/src/main/resources/languages/it_IT.json index 99b902141..aec0c8fec 100644 --- a/core/src/main/resources/languages/it_IT.json +++ b/core/src/main/resources/languages/it_IT.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "L'importazione da Modrinth è disponibile solo su Bukkit; se necessario, installa manualmente questi datapack in world/datapacks.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Datapack installati nel mondo: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "È stata inviata un'eccezione di prova al sistema di segnalazione errori di Iris (Sentry se abilitato).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "La scansione di rete non è riuscita: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "È già in esecuzione una scansione GoldenHash.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Il datapack id (nome della cartella) indicato da /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Gestore dei mondi Iris", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Ottieni il numero di TectonicPlates caricate", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Invia un'eccezione di prova a Sentry", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Calcola l'hash dei blocchi generati in un'area fissa per test di determinismo e identità", "iris.director.commanddeveloper.param.world_hash": "Il mondo di cui calcolare l'hash", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Radio in chunk intorno al centro", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Installazione e stato dei datapack del mondo", "iris.modded.help.entry.group.structure": "Iris struttura indice, info e strumenti di posizionamento", "iris.modded.help.entry.command.goldenhash": "Genera blocchi deterministici per prove di parità", - "iris.modded.help.entry.group.developer": "Diagnostica degli sviluppatori: Test di Sentry, interfacce di rete, scansione dei file regionali", + "iris.modded.help.entry.group.developer": "Diagnostica degli sviluppatori: interfacce di rete e scansione dei file regionali", "iris.modded.help.entry.command.biome": "Trova un bioma Iris", "iris.modded.help.entry.command.region": "Trova una regione Iris", "iris.modded.help.entry.command.object": "Trova un posizionamento degli oggetti", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Spiega il flusso Bukkit per l'importazione delle strutture", "iris.modded.help.entry.command.capture": "Spiega il flusso Bukkit per l'acquisizione delle strutture", "iris.modded.help.entry.command.verify": "Mostra la raggiungibilità delle strutture native e Iris nella dimensione corrente", - "iris.modded.help.entry.command.sentry": "Invia un'eccezione di prova al sistema di segnalazione errori Iris", "iris.modded.help.entry.command.network": "Elenca le interfacce di rete e i loro indirizzi", "iris.runtime.progress.finding_regions": "Ricerca delle regioni", "iris.runtime.progress.converting": "Conversione", diff --git a/core/src/main/resources/languages/ja-JP.json b/core/src/main/resources/languages/ja-JP.json index 4d9d3856d..75ac9c0cb 100644 --- a/core/src/main/resources/languages/ja-JP.json +++ b/core/src/main/resources/languages/ja-JP.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth の取り込みは Bukkit 専用です。必要に応じて world/datapacks に手動でインストールしてください。", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "インストール済みのワールドデータパック: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "テスト例外を Iris のエラーレポーターに送信しました(有効な場合は Sentry)。", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "ネットワークスキャン失敗: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "GoldenHash スキャンはすでに実行中です。", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "/iris datapack list に表示されるデータパック ID(フォルダー名)", "iris.director.commanddeveloper.director.iris_world_manager": "Iris ワールドマネージャー", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "読み込み済み TectonicPlates の数を取得します", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Sentry へテスト例外を送信します", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "固定範囲で生成されたブロック出力をハッシュ化し、決定性と一致性を検証します", "iris.director.commanddeveloper.param.world_hash": "ハッシュ化するワールド", "iris.director.commanddeveloper.param.radius_chunks_around_center": "中心からの半径(チャンク単位)", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "ワールドデータパックのインストールと状態確認を支援します", "iris.modded.help.entry.group.structure": "Iris 構造物のインデックス、情報、配置ツールです", "iris.modded.help.entry.command.goldenhash": "互換性テスト用に決定論的なブロックハッシュを生成します", - "iris.modded.help.entry.group.developer": "開発者の診断: Sentryテスト、ネットワーク インターフェイス、地域 ファイル スキャン", + "iris.modded.help.entry.group.developer": "開発者診断: ネットワークインターフェースとリージョンファイルのスキャン", "iris.modded.help.entry.command.biome": "Iris バイオームを検索します", "iris.modded.help.entry.command.region": "Iris リージョンを検索します", "iris.modded.help.entry.command.object": "オブジェクト配置を検索します", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Bukkit の構造物インポート手順を説明します", "iris.modded.help.entry.command.capture": "Bukkit の構造物キャプチャ手順を説明します", "iris.modded.help.entry.command.verify": "現在のディメンションでネイティブ構造物と Iris 構造物が到達可能か報告します", - "iris.modded.help.entry.command.sentry": "Iris エラーレポーターへテスト例外を送信します", "iris.modded.help.entry.command.network": "ネットワークインターフェースとアドレスを一覧表示します", "iris.runtime.progress.finding_regions": "リージョンを検索中", "iris.runtime.progress.converting": "変換中", diff --git a/core/src/main/resources/languages/ko_KR.json b/core/src/main/resources/languages/ko_KR.json index 693a15fb5..f8601297a 100644 --- a/core/src/main/resources/languages/ko_KR.json +++ b/core/src/main/resources/languages/ko_KR.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth 수집는 Bukkit-만; 수동으로 설치 world/datapacks 필요한 경우.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "설치된 세계 데이터 팩: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "테스트 예외를 Iris 오류 보고기로 전송했습니다(Sentry가 활성화된 경우).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "네트워크 검사 실패: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "황금빛 검사는 이미 달리고 있습니다.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "/iris datapack list에 표시되는 데이터 팩 ID(폴더 이름)", "iris.director.commanddeveloper.director.iris_world_manager": "Iris 월드 관리자", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "로드된 TectonicPlates 수를 가져옵니다", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Sentry로 테스트 예외를 보냅니다", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "고정 영역의 생성 블록 출력을 해시해 결정성과 일치성을 검사합니다", "iris.director.commanddeveloper.param.world_hash": "해시할 월드", "iris.director.commanddeveloper.param.radius_chunks_around_center": "중심 기준 반경(청크 단위)", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "월드 데이터 팩 설치와 상태 확인 도구입니다", "iris.modded.help.entry.group.structure": "Iris 구조물 인덱스, 정보, 배치 도구입니다", "iris.modded.help.entry.command.goldenhash": "동일성 검사용 결정적 블록 해시를 생성합니다", - "iris.modded.help.entry.group.developer": "개발자 진단: Sentry 테스트, 네트워크 인터페이스, 리전 파일 검사", + "iris.modded.help.entry.group.developer": "개발자 진단: 네트워크 인터페이스와 리전 파일 검사", "iris.modded.help.entry.command.biome": "Iris 바이옴을 찾습니다", "iris.modded.help.entry.command.region": "Iris 리전을 찾습니다", "iris.modded.help.entry.command.object": "오브젝트 배치를 찾습니다", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Bukkit 구조물 가져오기 절차를 설명합니다", "iris.modded.help.entry.command.capture": "Bukkit 구조물 캡처 절차를 설명합니다", "iris.modded.help.entry.command.verify": "현재 차원의 네이티브 및 Iris 구조물 도달 가능성을 보고합니다", - "iris.modded.help.entry.command.sentry": "Iris 오류 보고기로 테스트 예외를 보냅니다", "iris.modded.help.entry.command.network": "네트워크 인터페이스와 주소를 나열합니다", "iris.runtime.progress.finding_regions": "지역 찾기", "iris.runtime.progress.converting": "변환 중", diff --git a/core/src/main/resources/languages/lt_LT.json b/core/src/main/resources/languages/lt_LT.json index cb808e5cf..a7940d8bf 100644 --- a/core/src/main/resources/languages/lt_LT.json +++ b/core/src/main/resources/languages/lt_LT.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth vartoti Bukkit-tik; įdiegti šiuos rankiniu būdu į world/datapacks jei reikia.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Įdiegti pasauliniai duomenys: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Bandomoji išimtis išsiųsta į Iris klaidų pranešimų sistemą (Sentry, jei įjungta).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Tinklo skenavimas nepavyko: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Auksinis skenavimas jau veikia.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Datapack id (aplanko pavadinimas) rodo /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Pasaulio vadybininkas", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Įkelti TectonicPlates Skaičius", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Siųsti bandymo išimtį Sentry", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Stacionarios zonos sukauptas bloko išvestis determinizmui / tapatumo bandymams", "iris.director.commanddeveloper.param.world_hash": "Pasaulis, kuriam reikia maišyti", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Spindulys į gabaliukus aplink centrą", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "World datapack įdiegti ir būsenos pagalbininkai", "iris.modded.help.entry.group.structure": "Iris struktūros indeksas, informacija ir diegimo įrankiai", "iris.modded.help.entry.command.goldenhash": "Sugeneruoti deterministinius bloko smūgius pariteto bandymams", - "iris.modded.help.entry.group.developer": "Kūrėjo diagnostika: Sentry testas, tinklo sąsajos, regionų failų nuskaitymas", + "iris.modded.help.entry.group.developer": "Kūrėjo diagnostika: tinklo sąsajos ir regionų failų nuskaitymas", "iris.modded.help.entry.command.biome": "Rasti Iris biomas", "iris.modded.help.entry.command.region": "Rasti Iris regionas", "iris.modded.help.entry.command.object": "Rasti objekto vietą", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Paaiškinti Bukkit struktūra importo darbo eiga", "iris.modded.help.entry.command.capture": "Paaiškinti Bukkit struktūros surinkimo darbų srautas", "iris.modded.help.entry.command.verify": "Pranešti vietos ir Iris struktūros pasiekiamumas dabartiniame matmenyje", - "iris.modded.help.entry.command.sentry": "Siųsti bandymo išimtį Iris klaidų reporteris", "iris.modded.help.entry.command.network": "Išvardyti tinklo sąsajas ir jų adresus", "iris.runtime.progress.finding_regions": "Ieškomi regionai", "iris.runtime.progress.converting": "Konvertuojama", diff --git a/core/src/main/resources/languages/nl_NL.json b/core/src/main/resources/languages/nl_NL.json index 24ccf2568..18034346c 100644 --- a/core/src/main/resources/languages/nl_NL.json +++ b/core/src/main/resources/languages/nl_NL.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth Inname is Bukkit-alleen; installeer deze handmatig in world/datapacks indien nodig.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Geïnstalleerde werelddatapacks: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Een testuitzondering is naar de Iris-foutrapportage verzonden (Sentry indien ingeschakeld).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Netwerkscan mislukt: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Een Goldenhash scan loopt al.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Het datapack id (mapnaam) getoond door /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Wereldmanager", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Laden TectonicPlates Aantal", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Stuur een test uitzondering naar de wachtdienst", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Hash gegenereerde blokuitgang van een vaste zone voor determinisme/identiteitstest", "iris.director.commanddeveloper.param.world_hash": "De wereld te hash", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Straal in stukjes rond het centrum", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "World Datapack installatie en status helpers", "iris.modded.help.entry.group.structure": "Iris structuurindex, info- en plaatsingsinstrumenten", "iris.modded.help.entry.command.goldenhash": "Genereer deterministische blokhashes voor pariteitstests", - "iris.modded.help.entry.group.developer": "Ontwikkelaardiagnostiek: Sentry test, netwerk interfaces, regio-bestand scan", + "iris.modded.help.entry.group.developer": "Ontwikkelaardiagnostiek: netwerkinterfaces en regio-bestandsscan", "iris.modded.help.entry.command.biome": "Zoek een Iris biom", "iris.modded.help.entry.command.region": "Zoek een Iris regio", "iris.modded.help.entry.command.object": "Een objectplaatsing zoeken", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Leg uit Bukkit structuur import workflow", "iris.modded.help.entry.command.capture": "Leg uit Bukkit structuur capture workflow", "iris.modded.help.entry.command.verify": "Native en Iris Bereikbaarheid van de structuur in de huidige dimensie", - "iris.modded.help.entry.command.sentry": "Stuur een testuitzondering naar de Iris foutverslaggever", "iris.modded.help.entry.command.network": "Lijst van netwerkinterfaces en hun adressen", "iris.runtime.progress.finding_regions": "Regio's vinden", "iris.runtime.progress.converting": "Converteren", diff --git a/core/src/main/resources/languages/pl_PL.json b/core/src/main/resources/languages/pl_PL.json index dd19ddfb4..8b30423eb 100644 --- a/core/src/main/resources/languages/pl_PL.json +++ b/core/src/main/resources/languages/pl_PL.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth jeśli Bukkit-tylko; zainstalować je ręcznie world/datapacks w razie potrzeby.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Zainstalowane world datapacks: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Wysłano wyjątek testowy do systemu raportowania błędów Iris (Sentry, jeśli jest włączony).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Skanowanie sieci nie powiodło się: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Skaner już działa.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Identyfikator datapack (nazwa folderu) pokazany przez /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Światowy menedżer", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Napełnij TectonicPlates Licz", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Wyślij wyjątek testowy do wartownika", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Wygenerowane przez Hasha wyjście blokowe stałego obszaru do celów badania determinizmu / tożsamości", "iris.director.commanddeveloper.param.world_hash": "Świat, by się zahaczyć", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Promień w chunkach wokół centrum", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Narzędzia instalacji i stanu datapacków świata", "iris.modded.help.entry.group.structure": "Iris indeks struktury, narzędzia informacyjne i umieszczania", "iris.modded.help.entry.command.goldenhash": "Generowanie hash bloku deterministycznego do badania parytetu", - "iris.modded.help.entry.group.developer": "Diagnostyka deweloperska: test Sentry, interfejsy sieciowe, skan plików regionów", + "iris.modded.help.entry.group.developer": "Diagnostyka deweloperska: interfejsy sieciowe i skan plików regionów", "iris.modded.help.entry.command.biome": "Znajdź Iris biom", "iris.modded.help.entry.command.region": "Znajdź Iris regiony", "iris.modded.help.entry.command.object": "Znajdź lokalizację obiektu", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Wyjaśnij Bukkit struktura importu pracy", "iris.modded.help.entry.command.capture": "Wyjaśnij Bukkit structure catch workflow", "iris.modded.help.entry.command.verify": "Zgłoś rodzime i Iris stabilność struktury w obecnym wymiarze", - "iris.modded.help.entry.command.sentry": "Wyślij wyjątek testowy do Iris zgłaszający błędy", "iris.modded.help.entry.command.network": "Lista interfejsów sieciowych i ich adresów", "iris.runtime.progress.finding_regions": "Znalezienie regionów", "iris.runtime.progress.converting": "Konwersja", diff --git a/core/src/main/resources/languages/pt_PT.json b/core/src/main/resources/languages/pt_PT.json index 3b53d61ae..e6cf58cf5 100644 --- a/core/src/main/resources/languages/pt_PT.json +++ b/core/src/main/resources/languages/pt_PT.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth ingerir é Bukkit- somente; instale estes manualmente em world/datapacks se necessário.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Pacotes de dados mundiais instalados: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Foi enviada uma exceção de teste para o sistema de relatórios de erros do Iris (Sentry, se estiver ativado).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Falha na verificação da rede: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Já está a ser feito um exame ao Goldenhash.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "O ID do pacote de dados (nome da pasta) mostrado por /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Gestor Mundial", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Obter Carregado TectonicPlates Contagem", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Enviar uma exceção de teste para o sentinela", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Saída de bloco gerada por hash de uma área fixa para testes de determinismo/identidade", "iris.director.commanddeveloper.param.world_hash": "O mundo para hash", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Raio em chunks ao redor do centro", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Mundial datapack install e status helpers", "iris.modded.help.entry.group.structure": "Iris índice de estrutura, informações e ferramentas de colocação", "iris.modded.help.entry.command.goldenhash": "Gerar hashes de blocos determinísticos para testes de paridade", - "iris.modded.help.entry.group.developer": "Diagnóstico de programador: teste do Sentry, interfaces de rede e análise de ficheiros de região", + "iris.modded.help.entry.group.developer": "Diagnóstico de programador: interfaces de rede e análise de ficheiros de região", "iris.modded.help.entry.command.biome": "Procurar um Iris bioma", "iris.modded.help.entry.command.region": "Procurar um Iris região", "iris.modded.help.entry.command.object": "Encontrar uma colocação de objeto", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Explicar Bukkit workflow de importação da estrutura", "iris.modded.help.entry.command.capture": "Explicar Bukkit workflow de captura da estrutura", "iris.modded.help.entry.command.verify": "Relatório nativo e Iris capacidade de alcance da estrutura na dimensão atual", - "iris.modded.help.entry.command.sentry": "Enviar uma excepção de teste para o Iris repórter de erro", "iris.modded.help.entry.command.network": "Listar as interfaces de rede e os seus endereços", "iris.runtime.progress.finding_regions": "Regiões de pesquisa", "iris.runtime.progress.converting": "Conversão", diff --git a/core/src/main/resources/languages/ru_RU.json b/core/src/main/resources/languages/ru_RU.json index 8c7e606a9..a56d969a4 100644 --- a/core/src/main/resources/languages/ru_RU.json +++ b/core/src/main/resources/languages/ru_RU.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth глотать - это Bukkit-только; установить эти вручную в world/datapacks при необходимости.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Установка мировых пакетов данных: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Тестовое исключение отправлено в систему отчётов об ошибках Iris (Sentry, если включён).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Сканирование сети не удалось: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Сканирование Goldhash уже запущено.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "ID пакета данных (название папки), показанный /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Мировой менеджер", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Заряжайся TectonicPlates граф", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Отправить тестовое исключение для часового", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Hash генерируется блок выход фиксированной области для детерминизма/идентификации тестирования", "iris.director.commanddeveloper.param.world_hash": "Мир для хеширования", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Радиус в чанках вокруг центра", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Установка Мировой пакет данных и статус помощников", "iris.modded.help.entry.group.structure": "Iris Индекс структуры, информация и инструменты размещения", "iris.modded.help.entry.command.goldenhash": "Генерировать детерминированные хэши блоков для тестирования паритета", - "iris.modded.help.entry.group.developer": "Диагностика разработчиков: тест Sentry, сетевые интерфейсы, региональное сканирование файлов", + "iris.modded.help.entry.group.developer": "Диагностика разработчиков: сетевые интерфейсы и сканирование файлов регионов", "iris.modded.help.entry.command.biome": "Найти Iris биом", "iris.modded.help.entry.command.region": "Найти Iris регион", "iris.modded.help.entry.command.object": "Найти объект размещения", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Объяснять Bukkit Структура импортного рабочего процесса", "iris.modded.help.entry.command.capture": "Объяснять Bukkit Структура захвата рабочего процесса", "iris.modded.help.entry.command.verify": "Сообщение родного и Iris Достижимость структуры в текущем измерении", - "iris.modded.help.entry.command.sentry": "Отправить тестовое исключение из Iris репортер ошибок", "iris.modded.help.entry.command.network": "Список сетевых интерфейсов и их адреса", "iris.runtime.progress.finding_regions": "Поиск регионов", "iris.runtime.progress.converting": "преобразовывать", diff --git a/core/src/main/resources/languages/tr_TR.json b/core/src/main/resources/languages/tr_TR.json index 2cf7e6b35..8d264d1e3 100644 --- a/core/src/main/resources/languages/tr_TR.json +++ b/core/src/main/resources/languages/tr_TR.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth Ingest is ingest BukkitSadece; bunları manuel olarak yükleme world/datapacks Gerekirse.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Bağlantılı dünya veri paketleri: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Iris hata raporlayıcısına bir test istisnası gönderildi (etkinse Sentry).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Ağ tarama başarısız oldu: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Altınhash tarama zaten çalışıyor.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Datapack id (folder adı) tarafından gösterilen /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Dünya Yöneticisi", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Yükleme alın TectonicPlates Kont", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Gönderilen bir test istisnaı gönder", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Hash, determinism/identity test için sabit bir bölgenin blok çıktısını üretti", "iris.director.commanddeveloper.param.world_hash": "Dünyanın sahip olması", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Radius merkez çevresinde", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Dünya veri paketi ve statü yardımcıları", "iris.modded.help.entry.group.structure": "Iris Yapı indeksi, bilgi ve yerleştirme araçları", "iris.modded.help.entry.command.goldenhash": "Genrate deterministic blok parity testi için vardır", - "iris.modded.help.entry.group.developer": "Geliştirici tanıları: Sentry testi, ağ arabirimleri, bölge-file tarama", + "iris.modded.help.entry.group.developer": "Geliştirici tanıları: ağ arabirimleri ve bölge dosyası taraması", "iris.modded.help.entry.command.biome": "Bir an bulun Iris Biyome", "iris.modded.help.entry.command.region": "Bir an bulun Iris Bölge bölgesi", "iris.modded.help.entry.command.object": "Bir nesne yerleşimi bulun", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Açık Açıklama Bukkit Yapı import iş akışı", "iris.modded.help.entry.command.capture": "Açık Açıklama Bukkit Yapı yakalama", "iris.modded.help.entry.command.verify": "Rapor yerli ve Iris Yapı mevcut boyutta erişilebilirlik", - "iris.modded.help.entry.command.sentry": "Bir test istisnaı gönderin Iris hata muhabiri", "iris.modded.help.entry.command.network": "Liste ağ arabirimleri ve adresleri", "iris.runtime.progress.finding_regions": "Bölgeleri bulmak", "iris.runtime.progress.converting": "Dönüştürmek", diff --git a/core/src/main/resources/languages/vi_VI.json b/core/src/main/resources/languages/vi_VI.json index 57ac04c79..dfa29fa2c 100644 --- a/core/src/main/resources/languages/vi_VI.json +++ b/core/src/main/resources/languages/vi_VI.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth Ăn là Bukkit-Chỉ; cài đặt những điều này bằng tay vào world/datapacks nếu cần thiết.", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "Bộ dữ liệu thế giới đã cài đặt: {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "Đã gửi một ngoại lệ thử nghiệm đến trình báo lỗi Iris (Sentry nếu được bật).", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "Việc quét mạng bị lỗi: {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "Chụp cắt lớp vàng đã chạy rồi.", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "Mã nhận diện dữ liệu (tên thư mục) được hiển thị bởi /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris Quản lý thế giới", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "Đã nạp TectonicPlates Số lượng", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "Name", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "Đã tạo ra khối kết xuất của một khu vực cố định để thử nghiệm chủ nghĩa xác định/không xác định", "iris.director.commanddeveloper.param.world_hash": "♪ Thế giới sẽ khô cằn ♪", "iris.director.commanddeveloper.param.radius_chunks_around_center": "Bán kính trong mảng xung quanh trung tâm", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "Name", "iris.modded.help.entry.group.structure": "Iris chỉ mục cấu trúc, thông tin và công cụ định vị", "iris.modded.help.entry.command.goldenhash": "Tạo ra khối quyết định để kiểm tra cân bằng", - "iris.modded.help.entry.group.developer": "Chẩn đoán dành cho nhà phát triển: kiểm tra Sentry, giao diện mạng và quét tệp vùng", + "iris.modded.help.entry.group.developer": "Chẩn đoán dành cho nhà phát triển: giao diện mạng và quét tệp vùng", "iris.modded.help.entry.command.biome": "Tìm một Iris sinh học", "iris.modded.help.entry.command.region": "Tìm một Iris vùng", "iris.modded.help.entry.command.object": "Tìm một vị trí đối tượng", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "Giải thích Bukkit Comment", "iris.modded.help.entry.command.capture": "Giải thích Bukkit Name", "iris.modded.help.entry.command.verify": "Báo cáo bản địa và Iris cấu trúc khả năng chạm tới trong chiều không gian hiện tại", - "iris.modded.help.entry.command.sentry": "Gửi một ngoại lệ thử nghiệm đến Iris Thông báo lỗi", "iris.modded.help.entry.command.network": "Liệt kê các giao diện mạng và địa chỉ của chúng", "iris.runtime.progress.finding_regions": "Tìm vùng", "iris.runtime.progress.converting": "Chuyển đổi", diff --git a/core/src/main/resources/languages/zh_CN.json b/core/src/main/resources/languages/zh_CN.json index 463e61b8d..72588fc7c 100644 --- a/core/src/main/resources/languages/zh_CN.json +++ b/core/src/main/resources/languages/zh_CN.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth 摄入是 Bukkit- 只安装; 手动安装到 world/datapacks 如果需要的话。", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "安装的世界数据包 : {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "已向 Iris 错误报告器发送测试异常(若已启用 Sentry)。", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "网络扫描失败 : {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "金色扫描已经运行中 。", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "数据包 id (文件夹名称) 显示于 /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris 世界经理", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "加载 TectonicPlates 计数", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "向哨兵发送测试例外", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "用于确定/识别测试的固定区域的散列输出", "iris.director.commanddeveloper.param.world_hash": "散开的世界", "iris.director.commanddeveloper.param.radius_chunks_around_center": "半径为中心周围的块", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "世界数据包安装和状态工具", "iris.modded.help.entry.group.structure": "Iris 结构索引、信息和放置工具", "iris.modded.help.entry.command.goldenhash": "为一致性测试生成确定性方块哈希", - "iris.modded.help.entry.group.developer": "开发者诊断:Sentry 测试、网络接口和区域文件扫描", + "iris.modded.help.entry.group.developer": "开发者诊断:网络接口和区域文件扫描", "iris.modded.help.entry.command.biome": "查找 Iris 群系", "iris.modded.help.entry.command.region": "查找 Iris 区域", "iris.modded.help.entry.command.object": "查找对象放置", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "说明 Bukkit 结构导入流程", "iris.modded.help.entry.command.capture": "说明 Bukkit 结构捕获流程", "iris.modded.help.entry.command.verify": "报告当前维度中原生结构和 Iris 结构的可达性", - "iris.modded.help.entry.command.sentry": "向 Iris 错误报告器发送测试异常", "iris.modded.help.entry.command.network": "列出网络接口及其地址", "iris.runtime.progress.finding_regions": "寻找区域", "iris.runtime.progress.converting": "转换", diff --git a/core/src/main/resources/languages/zh_TW.json b/core/src/main/resources/languages/zh_TW.json index 8f86bf22b..e27df451c 100644 --- a/core/src/main/resources/languages/zh_TW.json +++ b/core/src/main/resources/languages/zh_TW.json @@ -429,7 +429,6 @@ "iris.modded.moddeddatapackcommands.modrinth_ingest_is_bukkit_only_install_these_manually_into_world": "Modrinth 攝入是 Bukkit- 只安裝; 手動安裝到 world/datapacks 如果需要的話。", "iris.modded.moddeddatapackcommands.installed_world_datapacks": "安裝的世界資料包 : {value}", "iris.modded.moddeddatapackcommands.message_2": " - {name}", - "iris.modded.moddeddevelopercommands.dispatched_test_exception_iris_error_reporter_sentry_if_enabled": "已向 Iris 錯誤報告器傳送測試例外(若已啟用 Sentry)。", "iris.modded.moddeddevelopercommands.message": " {value}", "iris.modded.moddeddevelopercommands.network_scan_failed": "網路掃描失敗 : {value}", "iris.modded.moddedgoldenhash.goldenhash_scan_is_already_running": "金色掃描已經執行中 。", @@ -620,7 +619,6 @@ "iris.director.commanddatapack.param.datapack_id_folder_name_shown_by_iris_datapack_list": "資料包 id (資料夾名稱) 顯示於 /iris datapack list", "iris.director.commanddeveloper.director.iris_world_manager": "Iris 世界經理", "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count": "載入 TectonicPlates 計數", - "iris.director.commanddeveloper.director.send_test_exception_sentry": "向哨兵傳送測試例外", "iris.director.commanddeveloper.director.hash_generated_block_output_fixed_area_determinism_identity_testing": "用於確定/識別測試的固定區域的雜湊輸出", "iris.director.commanddeveloper.param.world_hash": "散開的世界", "iris.director.commanddeveloper.param.radius_chunks_around_center": "半徑為中心周圍的塊", @@ -850,7 +848,7 @@ "iris.modded.help.entry.group.datapack": "世界資料包安裝和狀態工具", "iris.modded.help.entry.group.structure": "Iris 結構索引、資訊和放置工具", "iris.modded.help.entry.command.goldenhash": "為一致性測試生成確定性方塊雜湊", - "iris.modded.help.entry.group.developer": "開發者診斷:Sentry 測試、網路介面和區域檔案掃描", + "iris.modded.help.entry.group.developer": "開發者診斷:網路介面和區域檔案掃描", "iris.modded.help.entry.command.biome": "尋找 Iris 生態域", "iris.modded.help.entry.command.region": "尋找 Iris 區域", "iris.modded.help.entry.command.object": "尋找物件放置", @@ -912,7 +910,6 @@ "iris.modded.help.entry.command.import": "說明 Bukkit 結構匯入流程", "iris.modded.help.entry.command.capture": "說明 Bukkit 結構擷取流程", "iris.modded.help.entry.command.verify": "回報目前維度中原生結構和 Iris 結構的可達性", - "iris.modded.help.entry.command.sentry": "向 Iris 錯誤回報器傳送測試例外", "iris.modded.help.entry.command.network": "列出網路介面及其位址", "iris.runtime.progress.finding_regions": "尋找區域", "iris.runtime.progress.converting": "轉換", diff --git a/core/src/test/java/art/arcane/iris/core/localization/IrisLanguageTest.java b/core/src/test/java/art/arcane/iris/core/localization/IrisLanguageTest.java index 443fc3593..a7d10fa3d 100644 --- a/core/src/test/java/art/arcane/iris/core/localization/IrisLanguageTest.java +++ b/core/src/test/java/art/arcane/iris/core/localization/IrisLanguageTest.java @@ -55,7 +55,7 @@ public class IrisLanguageTest { + "|\\b[A-Za-z0-9_*{}.-]+\\.(?:json|toml|ya?ml|jar|nbt|iob|properties|log|zip)\\b" ); private static final Pattern PROPER_NAME = Pattern.compile( - "\\b(?:IrisDimensions|Iris|Minecraft|CraftBukkit|Bukkit|Paper|Folia|Fabric|NeoForge|Forge|Modrinth|GitHub|VSCode|Brigadier|Mantle|MiniMessage|Adventure|Sentry|NMS|NBT|JSON|TOML|YAML|GUI|HUD|TPS|MSPT|FPS|CPU|GPU|RAM|JAR|API|UUID|BUD|ETA|HD|LQ|ms)\\b" + "\\b(?:IrisDimensions|Iris|Minecraft|CraftBukkit|Bukkit|Paper|Folia|Fabric|NeoForge|Forge|Modrinth|GitHub|VSCode|Brigadier|Mantle|MiniMessage|Adventure|NMS|NBT|JSON|TOML|YAML|GUI|HUD|TPS|MSPT|FPS|CPU|GPU|RAM|JAR|API|UUID|BUD|ETA|HD|LQ|ms)\\b" ); private static final List IRIS_PRODUCT_NAMES = List.of( "Iris Vision", @@ -66,7 +66,6 @@ public class IrisLanguageTest { "ResourceManager", "GoldenHash", "IGenData", - "Sentry", "TectonicPlates" ); private static final Pattern MARKER_DEBRIS = Pattern.compile("(?:⟬|⟭|\\b(?:XQ|QZ)[A-Z0-9_]*\\b|[\\uE000-\\uF8FF])"); diff --git a/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java b/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java index 7d4f6bee7..f5bbbd86c 100644 --- a/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java +++ b/core/src/test/java/art/arcane/iris/core/pack/PackHydrologyValidatorTest.java @@ -1090,8 +1090,6 @@ public class PackHydrologyValidatorTest { "inland_grotto", "inland-grotto", "mouth", - "ridge_tunnel", - "ridge-tunnel", "deep" )) { File pack = pack(""" diff --git a/core/src/test/java/art/arcane/iris/engine/IrisEnginePlatformHookIsolationTest.java b/core/src/test/java/art/arcane/iris/engine/IrisEnginePlatformHookIsolationTest.java index b6b0f2edf..a92760089 100644 --- a/core/src/test/java/art/arcane/iris/engine/IrisEnginePlatformHookIsolationTest.java +++ b/core/src/test/java/art/arcane/iris/engine/IrisEnginePlatformHookIsolationTest.java @@ -47,7 +47,7 @@ public class IrisEnginePlatformHookIsolationTest { ); @Test - public void sharedGeneratorHotPathsDoNotLinkBukkitImplementations() throws IOException { + public void sharedGeneratorHotPathsDoNotLinkBukkitImplementations() throws IOException, ClassNotFoundException { assertNoClassLinks(IrisEngine.class, BUKKIT_ENGINE_CLASSES); assertNoClassLinks(EngineBackgroundTasks.class, BUKKIT_ENGINE_CLASSES); assertNoClassLinks(EngineDataStore.class, BUKKIT_ENGINE_CLASSES); @@ -56,6 +56,8 @@ public class IrisEnginePlatformHookIsolationTest { assertNoClassLinks(EngineRuntimeBuilder.class, BUKKIT_ENGINE_CLASSES); assertNoClassLinks(EngineShutdownSequence.class, BUKKIT_ENGINE_CLASSES); assertNoClassLinks(EngineTickRegistry.class, BUKKIT_ENGINE_CLASSES); + assertNoClassLinks(IrisEngineMantle.class, BUKKIT_ENGINE_CLASSES); + assertNoClassLinks(Class.forName(IrisEngineMantle.class.getName() + "$1"), BUKKIT_ENGINE_CLASSES); assertNoClassLinks(Engine.class, ENGINE_POLICY_CLASSES); assertNoClassLinks(EngineMode.class, PLATFORM_POLICY_CLASSES); assertNoClassLinks(EngineMantle.class, PLATFORM_POLICY_CLASSES); @@ -63,7 +65,8 @@ public class IrisEnginePlatformHookIsolationTest { } private static void assertNoClassLinks(Class type, List forbiddenClasses) throws IOException { - InputStream stream = type.getResourceAsStream(type.getSimpleName() + ".class"); + String resourceName = type.getName().substring(type.getName().lastIndexOf('.') + 1) + ".class"; + InputStream stream = type.getResourceAsStream(resourceName); assertNotNull(stream); String bytecode; try (InputStream input = stream) { diff --git a/core/src/test/java/art/arcane/iris/engine/decorator/DecoratorCoreTest.java b/core/src/test/java/art/arcane/iris/engine/decorator/DecoratorCoreTest.java index 4170a13c7..14841123d 100644 --- a/core/src/test/java/art/arcane/iris/engine/decorator/DecoratorCoreTest.java +++ b/core/src/test/java/art/arcane/iris/engine/decorator/DecoratorCoreTest.java @@ -429,6 +429,28 @@ public class DecoratorCoreTest { assertEquals("minecraft:twisting_vines", DecoratorCore.stackedVineKey(vine, 3, 2)); } + @Test + public void boundDecoratorHooksWinWhenBukkitClassesArePresent() { + PlatformBlockState vine = mock(PlatformBlockState.class); + PlatformBlockState fixed = mock(PlatformBlockState.class); + PlatformBlockState decorator = mock(PlatformBlockState.class); + PlatformBlockState surface = mock(PlatformBlockState.class); + Hunk output = Hunk.newArrayHunk(1, 1, 1); + DecoratorPlatformHooks.FaceFixer faceFixer = mock(DecoratorPlatformHooks.FaceFixer.class); + DecoratorPlatformHooks.SurfaceSturdiness sturdiness = mock(DecoratorPlatformHooks.SurfaceSturdiness.class); + when(vine.isVineBlock()).thenReturn(true); + when(faceFixer.fixFaces(vine, output, 0, 0, 0, 0, 0, null)).thenReturn(fixed); + when(decorator.canPlaceOnto(surface)).thenReturn(true); + when(sturdiness.canGoOn(surface)).thenReturn(true); + DecoratorPlatformHooks.Bindings previous = DecoratorPlatformHooks.bind(faceFixer, sturdiness); + try { + assertSame(fixed, DecoratorCore.fixFacesForHunk(vine, output, 0, 0, 0, 0, 0, null)); + assertTrue(DecoratorCore.canGoOn(decorator, surface)); + } finally { + DecoratorPlatformHooks.restore(previous); + } + } + private PlatformBlockState airState() { PlatformBlockState air = mock(PlatformBlockState.class); when(air.isAir()).thenReturn(true); diff --git a/core/src/test/java/art/arcane/iris/engine/hydrology/HydrologyModelTest.java b/core/src/test/java/art/arcane/iris/engine/hydrology/HydrologyModelTest.java index 37f864625..893d5d091 100644 --- a/core/src/test/java/art/arcane/iris/engine/hydrology/HydrologyModelTest.java +++ b/core/src/test/java/art/arcane/iris/engine/hydrology/HydrologyModelTest.java @@ -496,7 +496,7 @@ public class HydrologyModelTest { @Test public void featureQuerySuggestionsIncludeConfiguredDeepFluidsWithoutHardcodedProfiles() { List suggestions = HydrologyFeatureQuery.suggestions( - List.of("acid", "deep_lava", "acid", "surface", "ridge-tunnel") + List.of("acid", "deep_lava", "acid", "surface", "coastal-grotto") ); assertEquals(List.of( @@ -508,7 +508,6 @@ public class HydrologyModelTest { "coastal_grotto", "inland_grotto", "mouth", - "ridge_tunnel", "deep", "pool", "acid", @@ -527,7 +526,6 @@ public class HydrologyModelTest { "coastal_grotto", "inland_grotto", "mouth", - "ridge_tunnel", "deep", "pool" ); @@ -538,6 +536,8 @@ public class HydrologyModelTest { assertTrue(keyword, HydrologyFeatureQuery.isReservedKeyword(keyword.replace('_', '-'))); } assertFalse(HydrologyFeatureQuery.isReservedKeyword("acid")); + assertFalse(HydrologyFeatureQuery.isReservedKeyword("ridge_tunnel")); + assertFalse(HydrologyFeatureQuery.isReservedKeyword("ridge-tunnel")); assertFalse(HydrologyFeatureQuery.isReservedKeyword(null)); assertEquals(Set.of(HydrologyFeatureType.SINKHOLE), HydrologyFeatureQuery.parse("sinkhole").types()); } diff --git a/core/src/test/java/art/arcane/iris/engine/object/PlatformStateHookContractTest.java b/core/src/test/java/art/arcane/iris/engine/object/PlatformStateHookContractTest.java index 0a099d011..b0c0ef2dc 100644 --- a/core/src/test/java/art/arcane/iris/engine/object/PlatformStateHookContractTest.java +++ b/core/src/test/java/art/arcane/iris/engine/object/PlatformStateHookContractTest.java @@ -1,42 +1,74 @@ package art.arcane.iris.engine.object; +import art.arcane.iris.spi.PlatformBlockState; +import art.arcane.volmlib.util.collection.KMap; import org.junit.Test; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.IOException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class PlatformStateHookContractTest { @Test - public void missingPlatformRotatorFailsLoudly() { - IllegalStateException error = assertThrows(IllegalStateException.class, - () -> IrisObjectRotation.requirePlatformRotator(null)); - - assertEquals("No platform block-state rotator is bound", error.getMessage()); + public void boundRotatorWinsWhenBukkitClassesArePresent() { + PlatformBlockState source = mock(PlatformBlockState.class); + PlatformBlockState rotated = mock(PlatformBlockState.class); + IrisObjectRotation.StateRotator hook = mock(IrisObjectRotation.StateRotator.class); + IrisObjectRotation rotation = new IrisObjectRotation(); + when(hook.rotate(rotation, source, 1, 2, 3)).thenReturn(rotated); + IrisObjectRotation.StateRotator previous = IrisObjectRotation.bindPlatformRotator(hook); + try { + assertSame(rotated, rotation.rotate(source, 1, 2, 3)); + } finally { + IrisObjectRotation.restorePlatformRotator(previous); + } } @Test - public void missingPlatformMergerFailsLoudly() { - IllegalStateException error = assertThrows(IllegalStateException.class, - () -> BlockDataMergeSupport.requirePlatformMerger(null)); - - assertEquals("No platform block-state merger is bound", error.getMessage()); + public void boundMergerWinsWhenBukkitClassesArePresent() { + PlatformBlockState base = mock(PlatformBlockState.class); + PlatformBlockState update = mock(PlatformBlockState.class); + PlatformBlockState merged = mock(PlatformBlockState.class); + BlockDataMergeSupport.StateMerger hook = mock(BlockDataMergeSupport.StateMerger.class); + when(hook.merge(base, update)).thenReturn(merged); + BlockDataMergeSupport.StateMerger previous = BlockDataMergeSupport.bindPlatformMerger(hook); + try { + assertSame(merged, BlockDataMergeSupport.merge(base, update)); + } finally { + BlockDataMergeSupport.restorePlatformMerger(previous); + } } @Test - public void missingPlatformTileFactoryFailsLoudly() { - IllegalStateException error = assertThrows(IllegalStateException.class, - () -> TileData.requirePlatformFactory(null)); - - assertEquals("No platform tile-data factory is bound", error.getMessage()); + public void boundTileFactoryWinsWhenBukkitClassesArePresent() { + PlatformBlockState state = mock(PlatformBlockState.class); + KMap properties = new KMap<>(); + TileData expected = mock(TileData.class); + TileData.TileFactory hook = mock(TileData.TileFactory.class); + when(hook.create(state, properties)).thenReturn(expected); + TileData.TileFactory previous = TileData.bindPlatformFactory(hook); + try { + assertSame(expected, TileData.of(state, properties)); + } finally { + TileData.restorePlatformFactory(previous); + } } @Test - public void missingPlatformTileReaderFailsLoudly() { - IOException error = assertThrows(IOException.class, - () -> TileData.requirePlatformReader(null)); - - assertEquals("No platform tile-data reader is bound", error.getMessage()); + public void boundTileReaderWinsWhenBukkitClassesArePresent() throws IOException { + TileData expected = mock(TileData.class); + TileData.TileReader hook = mock(TileData.TileReader.class); + DataInputStream input = new DataInputStream(new ByteArrayInputStream(new byte[0])); + when(hook.read(input)).thenReturn(expected); + TileData.TileReader previous = TileData.bindPlatformReader(hook); + try { + assertSame(expected, TileData.read(input)); + } finally { + TileData.restorePlatformReader(previous); + } } } diff --git a/core/src/test/java/art/arcane/iris/platform/bukkit/BukkitSpiConformanceTest.java b/core/src/test/java/art/arcane/iris/platform/bukkit/BukkitSpiConformanceTest.java index 4b31e14de..939f33eed 100644 --- a/core/src/test/java/art/arcane/iris/platform/bukkit/BukkitSpiConformanceTest.java +++ b/core/src/test/java/art/arcane/iris/platform/bukkit/BukkitSpiConformanceTest.java @@ -26,7 +26,9 @@ import art.arcane.iris.spi.PlatformRegistries; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Server; +import org.bukkit.World; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; @@ -102,6 +104,16 @@ public class BukkitSpiConformanceTest { assertSame(BukkitBlockState.of(first), BukkitBlockState.of(second)); } + @Test + public void mantleValuesUseStableBukkitInterfaceSlices() { + BukkitPlatform platform = new BukkitPlatform(); + assertTrue(platform.supportsMatterWorldIo()); + assertSame(World.class, platform.classifyMantleValue(mock(World.class))); + assertSame(BlockData.class, platform.classifyMantleValue(blockData("minecraft:stone"))); + assertSame(Entity.class, platform.classifyMantleValue(mock(Entity.class))); + assertSame(String.class, platform.classifyMantleValue("value")); + } + @Test public void blockStateKeyMatchesCanonicalString() { BlockData data = blockData("iristest:key_block[facing=north,lit=true]"); diff --git a/core/src/test/java/art/arcane/iris/util/common/scheduling/JHybridPlatformTest.java b/core/src/test/java/art/arcane/iris/util/common/scheduling/JHybridPlatformTest.java new file mode 100644 index 000000000..6d97dfe0d --- /dev/null +++ b/core/src/test/java/art/arcane/iris/util/common/scheduling/JHybridPlatformTest.java @@ -0,0 +1,55 @@ +package art.arcane.iris.util.common.scheduling; + +import art.arcane.iris.spi.IrisPlatform; +import art.arcane.iris.spi.IrisPlatforms; +import art.arcane.iris.spi.PlatformScheduler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class JHybridPlatformTest { + @Before + public void clearPlatform() { + IrisPlatforms.unbind(); + } + + @After + public void cleanup() { + J.cancelTrackedRepeatingTasks(); + IrisPlatforms.unbind(); + } + + @Test + public void boundBukkitIdentitySelectsBukkitScheduler() { + IrisPlatform platform = mock(IrisPlatform.class); + when(platform.platformName()).thenReturn("bukkit"); + IrisPlatforms.bind(platform); + + assertTrue(J.usesBukkitScheduler()); + } + + @Test + public void hybridHostRepeaterUsesBoundModdedScheduler() { + IrisPlatform platform = mock(IrisPlatform.class); + PlatformScheduler scheduler = mock(PlatformScheduler.class); + when(platform.platformName()).thenReturn("neoforge"); + when(platform.scheduler()).thenReturn(scheduler); + IrisPlatforms.bind(platform); + + assertFalse(J.usesBukkitScheduler()); + int taskId = J.ar(() -> { + }, 1); + + assertNotEquals(-1, taskId); + verify(scheduler).laterGlobal(any(Runnable.class), eq(1)); + } +} diff --git a/core/src/test/java/art/arcane/iris/util/project/matter/slices/IrisMatterPlatformSelectionTest.java b/core/src/test/java/art/arcane/iris/util/project/matter/slices/IrisMatterPlatformSelectionTest.java new file mode 100644 index 000000000..0b1323d0c --- /dev/null +++ b/core/src/test/java/art/arcane/iris/util/project/matter/slices/IrisMatterPlatformSelectionTest.java @@ -0,0 +1,46 @@ +package art.arcane.iris.util.project.matter.slices; + +import art.arcane.iris.spi.IrisPlatform; +import art.arcane.iris.spi.IrisPlatforms; +import org.bukkit.World; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class IrisMatterPlatformSelectionTest { + @Test + public void hybridClasspathDoesNotEnableBukkitMatterIoForModdedPlatform() { + IrisPlatform platform = mock(IrisPlatform.class); + withPlatform(platform, () -> { + assertNull(new EntityMatter().readFrom(World.class)); + assertNull(new TileMatter().readFrom(World.class)); + }); + } + + @Test + public void bukkitPlatformCapabilityEnablesBukkitMatterIo() { + IrisPlatform platform = mock(IrisPlatform.class); + when(platform.supportsMatterWorldIo()).thenReturn(true); + withPlatform(platform, () -> { + assertNotNull(new EntityMatter().readFrom(World.class)); + assertNotNull(new TileMatter().readFrom(World.class)); + }); + } + + private void withPlatform(IrisPlatform platform, Runnable test) { + IrisPlatform previous = IrisPlatforms.isBound() ? IrisPlatforms.get() : null; + IrisPlatforms.unbind(); + IrisPlatforms.bind(platform); + try { + test.run(); + } finally { + IrisPlatforms.unbind(); + if (previous != null) { + IrisPlatforms.bind(previous); + } + } + } +} diff --git a/gradle.properties b/gradle.properties index a6f725308..ac2f45f37 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,7 +23,7 @@ org.gradle.configureondemand=false nmsTools.repo-url=https://repo.codemc.org/repository/nms/ nmsTools.specialSourceVersion=1.11.4 -irisVersion=4.0.0-26.2 +irisVersion=4.0.1-26.2 minecraftVersion=26.2 # Bukkit plugin api-version: lowest supported Minecraft release line so one artifact loads on 26.1.2 and 26.2 apiVersion=26.1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8ccf6dbff..edeb4b5cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,8 +6,6 @@ # Plugins shadow = "9.5.1" # https://plugins.gradle.org/plugin/com.gradleup.shadow slimjar = "2.1.9" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar -download = "5.7.0" # https://plugins.gradle.org/plugin/de.undercouch.download -sentryPlugin = "6.14.0" # https://github.com/getsentry/sentry-android-gradle-plugin # Core Libraries lombok = "1.18.46" @@ -20,7 +18,6 @@ annotations = "26.1.0" # https://central.sonatype.com/artifact/org.jetbrains/ann paralithic = "0.8.1" # https://github.com/PolyhedralDev/Paralithic/ paperlib = "1.0.8" # https://github.com/PaperMC/PaperLib/ bstats = "3.2.1" # https://github.com/Bastian/bstats-metrics/tree/master -sentry = "8.48.0" # https://github.com/getsentry/sentry-java commons-io = "2.22.0" # https://central.sonatype.com/artifact/commons-io/commons-io commons-lang3 = "3.20.0" # https://central.sonatype.com/artifact/org.apache.commons/commons-lang3 oshi = "6.9.0" # Minecraft 26.2 runtime ceiling @@ -80,7 +77,6 @@ adventure-serializer-plain = { module = "net.kyori:adventure-text-serializer-pla paralithic = { module = "com.dfsek:paralithic", version.ref = "paralithic" } paperlib = { module = "io.papermc:paperlib", version.ref = "paperlib" } bstats = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } -sentry = { module = "io.sentry:sentry", version.ref = "sentry" } commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" } commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commons-lang3" } oshi = { module = "com.github.oshi:oshi-core", version.ref = "oshi" } @@ -127,5 +123,3 @@ fabricApi-permission = { module = "net.fabricmc.fabric-api:fabric-permission-api [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } slimjar = { id = "de.crazydev22.slimjar", version.ref = "slimjar" } -download = { id = "de.undercouch.download", version.ref = "download" } -sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" } diff --git a/probe/build.gradle b/probe/build.gradle index 0cd889d66..732d28431 100644 --- a/probe/build.gradle +++ b/probe/build.gradle @@ -33,7 +33,6 @@ dependencies { runtimeOnly(libs.lz4) runtimeOnly(libs.zip) runtimeOnly(libs.guava) - runtimeOnly(libs.sentry) runtimeOnly(libs.oshi) runtimeOnly(libs.byteBuddy.core) runtimeOnly(libs.byteBuddy.agent) diff --git a/probe/src/main/resources/classload-allowlist.tsv b/probe/src/main/resources/classload-allowlist.tsv index d28c8c8cd..7079199fc 100644 --- a/probe/src/main/resources/classload-allowlist.tsv +++ b/probe/src/main/resources/classload-allowlist.tsv @@ -86,4 +86,3 @@ art.arcane.iris.util.common.plugin.VolmitPlugin BUKKIT_API org.bukkit.event.List art.arcane.iris.util.common.plugin.VolmitSender BUKKIT_API org.bukkit.command.CommandSender art.arcane.iris.util.common.plugin.chunk.ChunkTickets BUKKIT_API org.bukkit.event.Listener art.arcane.iris.util.nbt.common.mca.NBTWorld$Holder BUKKIT_API org.bukkit.Material -art.arcane.iris.util.project.sentry.ServerID$Holder BUKKIT_API org.bukkit.Bukkit diff --git a/spi/src/main/java/art/arcane/iris/spi/IrisPlatform.java b/spi/src/main/java/art/arcane/iris/spi/IrisPlatform.java index cef86964d..a928e9eaf 100644 --- a/spi/src/main/java/art/arcane/iris/spi/IrisPlatform.java +++ b/spi/src/main/java/art/arcane/iris/spi/IrisPlatform.java @@ -66,6 +66,14 @@ public interface IrisPlatform { */ PlatformBiomeWriter biomeWriter(); + default Class classifyMantleValue(Object value) { + return value.getClass(); + } + + default boolean supportsMatterWorldIo() { + return false; + } + /** * Root folder Iris owns for packs, settings and generated data. Created if missing. Never null. */