mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 05:50:39 +00:00
Dicing things up a little
- Trying to slim this beauty down to a size 6. - Shes a size 7.1
This commit is contained in:
1 parent
d10d70a894
commit
f2887632fe
50 files changed
+668
-491
No files matched your search
@@ -250,9 +250,11 @@ Per-platform tasks: `./gradlew buildBukkit`, `buildFabric`, `buildForge`, `build
|
|||||||
SPI jar (the pure-JVM adapter/platform contract, not the stable plugin API) is built to `spi/build/libs/` by
|
SPI jar (the pure-JVM adapter/platform contract, not the stable plugin API) is built to `spi/build/libs/` by
|
||||||
`./gradlew :spi:jar`.
|
`./gradlew :spi:jar`.
|
||||||
|
|
||||||
`./gradlew buildAll` is a different task: it builds every platform and copies the jars into a
|
`./gradlew buildAll` also runs `buildAllToOut` and copies the jars into a consumer dropin tree
|
||||||
consumer dropin tree for a local test server. It defaults to `build/consumers/` inside the repo;
|
for a local test server. The consumer directory defaults to `../../[Minecraft Server]/consumers/`
|
||||||
override with `-Plocation=/path/to/consumers`.
|
when it exists, otherwise `build/consumers/` inside the repo. `-Plocation=/path/to/consumers`
|
||||||
|
changes only the consumer directory. Both tasks copy all four verified platform jars into
|
||||||
|
`../PluginOuts/`.
|
||||||
|
|
||||||
If you need help compiling as a developer or contributor, ask in the Discord.
|
If you need help compiling as a developer or contributor, ask in the Discord.
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.core.commands;
|
package art.arcane.iris.core.commands;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
import art.arcane.iris.Iris;
|
import art.arcane.iris.Iris;
|
||||||
import art.arcane.iris.core.gui.PregeneratorJob;
|
import art.arcane.iris.core.gui.PregeneratorJob;
|
||||||
import art.arcane.iris.core.pregenerator.PregenTask;
|
import art.arcane.iris.core.pregenerator.PregenTask;
|
||||||
@@ -33,7 +34,6 @@ import org.bukkit.util.Vector;
|
|||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.BukkitCommandMessagesExtended;
|
import art.arcane.iris.core.localization.BukkitCommandMessagesExtended;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
@Director(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!", descriptionKey = "iris.director.commandpregen.director.pregenerate_your_iris_worlds")
|
@Director(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!", descriptionKey = "iris.director.commandpregen.director.pregenerate_your_iris_worlds")
|
||||||
@@ -62,7 +62,7 @@ public class CommandPregen implements DirectorExecutor {
|
|||||||
|
|
||||||
if (PregeneratorJob.getInstance() != null) {
|
if (PregeneratorJob.getInstance() != null) {
|
||||||
// Reject like the modded adapter does; never silently kill a running job.
|
// Reject like the modded adapter does; never silently kill a running job.
|
||||||
sender().sendMessage(IrisLanguage.text(ModdedCommandMessages.IRIS_MODDED_COMMANDS_PREGENERATION_TASK_IS_ALREADY_RUNNING_STOP_IT_FIRST_WITH_IRIS));
|
sender().sendMessage(IrisLanguage.text(IrisMessages.PREGEN_ALREADY_RUNNING));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package art.arcane.iris.client;
|
package art.arcane.iris.client;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.ClientUiMessages;
|
import art.arcane.iris.modded.localization.ClientUiMessages;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.spi.protocol.IrisMessage;
|
import art.arcane.iris.spi.protocol.IrisMessage;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package art.arcane.iris.client;
|
package art.arcane.iris.client;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.ClientUiMessages;
|
import art.arcane.iris.modded.localization.ClientUiMessages;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.iris.spi.protocol.IrisMessage;
|
import art.arcane.iris.spi.protocol.IrisMessage;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package art.arcane.iris.client;
|
package art.arcane.iris.client;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.ClientUiMessages;
|
import art.arcane.iris.modded.localization.ClientUiMessages;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.spi.protocol.IrisMessage;
|
import art.arcane.iris.spi.protocol.IrisMessage;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package art.arcane.iris.client;
|
package art.arcane.iris.client;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.ClientUiMessages;
|
import art.arcane.iris.modded.localization.ClientUiMessages;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.spi.protocol.IrisMessage;
|
import art.arcane.iris.spi.protocol.IrisMessage;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package art.arcane.iris.client.mixin;
|
package art.arcane.iris.client.mixin;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.ClientUiMessages;
|
import art.arcane.iris.modded.localization.ClientUiMessages;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.modded.IrisModdedChunkGenerator;
|
import art.arcane.iris.modded.IrisModdedChunkGenerator;
|
||||||
import art.arcane.iris.modded.ModdedMixinFlags;
|
import art.arcane.iris.modded.ModdedMixinFlags;
|
||||||
|
|||||||
@@ -20,12 +20,24 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|||||||
import org.gradle.api.tasks.compile.JavaCompile
|
import org.gradle.api.tasks.compile.JavaCompile
|
||||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri('https://jitpack.io') }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath('com.github.VolmitSoftware.VolmLib:packaging:master-SNAPSHOT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'net.fabricmc.fabric-loom' version '1.17.14'
|
id 'net.fabricmc.fabric-loom' version '1.17.14'
|
||||||
alias(libs.plugins.shadow)
|
alias(libs.plugins.shadow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'art.arcane.volmit-packaging'
|
||||||
|
|
||||||
apply from: file('../../gradle/modded-generation-build-revision.gradle')
|
apply from: file('../../gradle/modded-generation-build-revision.gradle')
|
||||||
|
|
||||||
Properties rootProperties = new Properties()
|
Properties rootProperties = new Properties()
|
||||||
@@ -320,3 +332,14 @@ tasks.matching { it.name == 'remapJar' }.configureEach {
|
|||||||
tasks.named('assemble').configure {
|
tasks.named('assemble').configure {
|
||||||
dependsOn(tasks.named('shadowJar'))
|
dependsOn(tasks.named('shadowJar'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pluginPackaging {
|
||||||
|
artifacts {
|
||||||
|
create('distribution') {
|
||||||
|
taskName = 'shadowJar'
|
||||||
|
policyName = 'Iris Fabric'
|
||||||
|
prunePrefixes = ['art/arcane/volmlib/']
|
||||||
|
keepPrefixes = ['art/arcane/volmlib/util/matter/slices/']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,12 +20,24 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|||||||
import org.gradle.api.tasks.compile.JavaCompile
|
import org.gradle.api.tasks.compile.JavaCompile
|
||||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri('https://jitpack.io') }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath('com.github.VolmitSoftware.VolmLib:packaging:master-SNAPSHOT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'net.minecraftforge.gradle' version '7.0.31'
|
id 'net.minecraftforge.gradle' version '7.0.31'
|
||||||
alias(libs.plugins.shadow)
|
alias(libs.plugins.shadow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'art.arcane.volmit-packaging'
|
||||||
|
|
||||||
apply from: file('../../gradle/modded-generation-build-revision.gradle')
|
apply from: file('../../gradle/modded-generation-build-revision.gradle')
|
||||||
|
|
||||||
Properties rootProperties = new Properties()
|
Properties rootProperties = new Properties()
|
||||||
@@ -294,3 +306,14 @@ tasks.named('jar').configure {
|
|||||||
tasks.named('assemble').configure {
|
tasks.named('assemble').configure {
|
||||||
dependsOn(tasks.named('shadowJar'))
|
dependsOn(tasks.named('shadowJar'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pluginPackaging {
|
||||||
|
artifacts {
|
||||||
|
create('distribution') {
|
||||||
|
taskName = 'shadowJar'
|
||||||
|
policyName = 'Iris Forge'
|
||||||
|
prunePrefixes = ['art/arcane/volmlib/']
|
||||||
|
keepPrefixes = ['art/arcane/volmlib/util/matter/slices/']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -22,7 +22,7 @@ import art.arcane.iris.modded.ModdedIrisLog;
|
|||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.IrisMessages;
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.PackDownloadMessages;
|
import art.arcane.iris.core.localization.PackDownloadMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.iris.core.lifecycle.LifecycleOperationCoordinator;
|
import art.arcane.iris.core.lifecycle.LifecycleOperationCoordinator;
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ package art.arcane.iris.modded.command;
|
|||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.IrisMessages;
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
import art.arcane.iris.core.localization.ModdedHelpMessages;
|
import art.arcane.iris.modded.localization.ModdedHelpMessages;
|
||||||
import art.arcane.volmlib.util.director.help.DirectorHelpMessages;
|
import art.arcane.volmlib.util.director.help.DirectorHelpMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
import art.arcane.volmlib.util.localization.TextKey;
|
import art.arcane.volmlib.util.localization.TextKey;
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ import java.util.Set;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedDatapackCommands {
|
public final class ModdedDatapackCommands {
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ import java.util.Enumeration;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
final class ModdedDeveloperCommands {
|
final class ModdedDeveloperCommands {
|
||||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import art.arcane.iris.modded.ModdedIrisLog;
|
|||||||
import art.arcane.iris.core.gui.GuiHost;
|
import art.arcane.iris.core.gui.GuiHost;
|
||||||
import art.arcane.iris.core.loader.IrisRegistrant;
|
import art.arcane.iris.core.loader.IrisRegistrant;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.object.IrisBiome;
|
import art.arcane.iris.engine.object.IrisBiome;
|
||||||
import art.arcane.iris.engine.object.IrisRegion;
|
import art.arcane.iris.engine.object.IrisRegion;
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeProgressMessages;
|
import art.arcane.iris.core.localization.RuntimeProgressMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedGoldenHash {
|
public final class ModdedGoldenHash {
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ package art.arcane.iris.modded.command;
|
|||||||
|
|
||||||
import art.arcane.iris.modded.ModdedIrisLog;
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.framework.GenerationSessionException;
|
import art.arcane.iris.engine.framework.GenerationSessionException;
|
||||||
import art.arcane.iris.engine.framework.GenerationSessionLease;
|
import art.arcane.iris.engine.framework.GenerationSessionLease;
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ import java.util.UUID;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedObjectCommands {
|
public final class ModdedObjectCommands {
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ import java.util.Map;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedPackCommands {
|
public final class ModdedPackCommands {
|
||||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|||||||
+3
-2
@@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
package art.arcane.iris.modded.command;
|
package art.arcane.iris.modded.command;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
@@ -59,7 +60,7 @@ final class ModdedPregenCommands {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!started) {
|
if (!started) {
|
||||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_PREGENERATION_TASK_IS_ALREADY_RUNNING_STOP_IT_FIRST_WITH_IRIS));
|
IrisModdedCommands.fail(source, IrisLanguage.plain(IrisMessages.PREGEN_ALREADY_RUNNING));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ModdedPregenBossBar.begin(source.getPlayer());
|
ModdedPregenBossBar.begin(source.getPlayer());
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
public final class ModdedRegen {
|
public final class ModdedRegen {
|
||||||
private static final int APPLY_AHEAD = 8;
|
private static final int APPLY_AHEAD = 8;
|
||||||
private static final long CHUNK_SLOT_TIMEOUT_MILLIS = 120000L;
|
private static final long CHUNK_SLOT_TIMEOUT_MILLIS = 120000L;
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedStructureCommands {
|
public final class ModdedStructureCommands {
|
||||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|||||||
+1
-1
@@ -90,7 +90,7 @@ import java.util.regex.Pattern;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedStudioCommands {
|
public final class ModdedStudioCommands {
|
||||||
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
private static final Predicate<CommandSourceStack> GATE = Commands.hasPermission(Commands.LEVEL_GAMEMASTERS);
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ package art.arcane.iris.modded.command;
|
|||||||
import art.arcane.iris.modded.ModdedIrisLog;
|
import art.arcane.iris.modded.ModdedIrisLog;
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.IrisMessages;
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.framework.GenerationSessionException;
|
import art.arcane.iris.engine.framework.GenerationSessionException;
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import art.arcane.iris.core.localization.IrisLanguage;
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
import art.arcane.iris.core.localization.ModdedCommandMessages;
|
import art.arcane.iris.modded.localization.ModdedCommandMessages;
|
||||||
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
import art.arcane.iris.core.localization.RuntimeUiMessages;
|
||||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||||
public final class ModdedWorldCommands {
|
public final class ModdedWorldCommands {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package art.arcane.iris.core.localization;
|
package art.arcane.iris.modded.localization;
|
||||||
|
|
||||||
import art.arcane.volmlib.util.localization.MessageKey;
|
import art.arcane.volmlib.util.localization.MessageKey;
|
||||||
import art.arcane.volmlib.util.localization.PluralKey;
|
import art.arcane.volmlib.util.localization.PluralKey;
|
||||||
+1
-6
@@ -1,4 +1,4 @@
|
|||||||
package art.arcane.iris.core.localization;
|
package art.arcane.iris.modded.localization;
|
||||||
|
|
||||||
import art.arcane.iris.util.common.format.C;
|
import art.arcane.iris.util.common.format.C;
|
||||||
import art.arcane.volmlib.util.localization.MessageKey;
|
import art.arcane.volmlib.util.localization.MessageKey;
|
||||||
@@ -127,10 +127,6 @@ public final class ModdedCommandMessages {
|
|||||||
"iris.modded.irismoddedcommands.current_dimension_is_not_generated_by_iris_name_one_explicitly",
|
"iris.modded.irismoddedcommands.current_dimension_is_not_generated_by_iris_name_one_explicitly",
|
||||||
"The current dimension (" + "{value}" + ") is not generated by Iris. Name one explicitly: /iris pregen start " + "{radius}" + " <dimension>; see /iris info for loaded Iris dimensions."
|
"The current dimension (" + "{value}" + ") is not generated by Iris. Name one explicitly: /iris pregen start " + "{radius}" + " <dimension>; see /iris info for loaded Iris dimensions."
|
||||||
);
|
);
|
||||||
public static final TextKey IRIS_MODDED_COMMANDS_PREGENERATION_TASK_IS_ALREADY_RUNNING_STOP_IT_FIRST_WITH_IRIS = TextKey.of(
|
|
||||||
"iris.modded.irismoddedcommands.pregeneration_task_is_already_running_stop_it_first_with_iris",
|
|
||||||
"A pregeneration task is already running. Stop it first with /iris pregen stop."
|
|
||||||
);
|
|
||||||
public static final TextKey IRIS_MODDED_COMMANDS_PREGEN_STARTED_BY_BLOCKS_FROM_PROGRESS_LOGS_CONSOLE_SEE_IRIS = TextKey.of(
|
public static final TextKey IRIS_MODDED_COMMANDS_PREGEN_STARTED_BY_BLOCKS_FROM_PROGRESS_LOGS_CONSOLE_SEE_IRIS = TextKey.of(
|
||||||
"iris.modded.irismoddedcommands.pregen_started_by_blocks_from_progress_logs_console_see_iris",
|
"iris.modded.irismoddedcommands.pregen_started_by_blocks_from_progress_logs_console_see_iris",
|
||||||
"Pregen started in " + "{value}" + " of " + "{value2}" + " by " + "{value3}" + " blocks from " + "{centerX}" + "," + "{centerZ}" + "." + "{modeNote}" + " Progress logs to console; see /iris pregen status." + "{guiNote}"
|
"Pregen started in " + "{value}" + " of " + "{value2}" + " by " + "{value3}" + " blocks from " + "{centerX}" + "," + "{centerZ}" + "." + "{modeNote}" + " Progress logs to console; see /iris pregen status." + "{guiNote}"
|
||||||
@@ -1284,7 +1280,6 @@ public final class ModdedCommandMessages {
|
|||||||
IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_5,
|
IRIS_MODDED_COMMANDS_THIS_DIMENSION_IS_NOT_GENERATED_BY_IRIS_5,
|
||||||
IRIS_MODDED_COMMANDS_IS_NOT_GENERATED_BY_IRIS_SEE_IRIS_INFO_LOADED_IRIS,
|
IRIS_MODDED_COMMANDS_IS_NOT_GENERATED_BY_IRIS_SEE_IRIS_INFO_LOADED_IRIS,
|
||||||
IRIS_MODDED_COMMANDS_CURRENT_DIMENSION_IS_NOT_GENERATED_BY_IRIS_NAME_ONE_EXPLICITLY,
|
IRIS_MODDED_COMMANDS_CURRENT_DIMENSION_IS_NOT_GENERATED_BY_IRIS_NAME_ONE_EXPLICITLY,
|
||||||
IRIS_MODDED_COMMANDS_PREGENERATION_TASK_IS_ALREADY_RUNNING_STOP_IT_FIRST_WITH_IRIS,
|
|
||||||
IRIS_MODDED_COMMANDS_PREGEN_STARTED_BY_BLOCKS_FROM_PROGRESS_LOGS_CONSOLE_SEE_IRIS,
|
IRIS_MODDED_COMMANDS_PREGEN_STARTED_BY_BLOCKS_FROM_PROGRESS_LOGS_CONSOLE_SEE_IRIS,
|
||||||
IRIS_MODDED_COMMANDS_STOPPING_PREGENERATION_FINISHING_UP_CURRENT_REGION,
|
IRIS_MODDED_COMMANDS_STOPPING_PREGENERATION_FINISHING_UP_CURRENT_REGION,
|
||||||
IRIS_MODDED_COMMANDS_NO_ACTIVE_PREGENERATION_TASK_STOP,
|
IRIS_MODDED_COMMANDS_NO_ACTIVE_PREGENERATION_TASK_STOP,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package art.arcane.iris.core.localization;
|
package art.arcane.iris.modded.localization;
|
||||||
|
|
||||||
import art.arcane.volmlib.util.localization.MessageKey;
|
import art.arcane.volmlib.util.localization.MessageKey;
|
||||||
import art.arcane.volmlib.util.localization.TextKey;
|
import art.arcane.volmlib.util.localization.TextKey;
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package art.arcane.iris.modded.localization;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.localization.IrisMessageContributor;
|
||||||
|
import art.arcane.volmlib.util.localization.MessageKey;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class ModdedMessageContributor implements IrisMessageContributor {
|
||||||
|
@Override
|
||||||
|
public List<MessageKey> keys() {
|
||||||
|
List<MessageKey> keys = new ArrayList<>();
|
||||||
|
keys.addAll(ModdedCommandMessages.keys());
|
||||||
|
keys.addAll(ModdedHelpMessages.keys());
|
||||||
|
keys.addAll(ClientUiMessages.keys());
|
||||||
|
return List.copyOf(keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
art.arcane.iris.modded.localization.ModdedMessageContributor
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package art.arcane.iris.modded.localization;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.localization.IrisLanguage;
|
||||||
|
import art.arcane.iris.core.localization.IrisMessages;
|
||||||
|
import art.arcane.volmlib.util.localization.MessageKey;
|
||||||
|
import art.arcane.volmlib.util.localization.VolmitLocales;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class ModdedMessageContributorTest {
|
||||||
|
@Test
|
||||||
|
public void loaderDiscoversModdedAndClientMessages() {
|
||||||
|
for (MessageKey key : new ModdedMessageContributor().keys()) {
|
||||||
|
assertNotNull(key.id(), IrisLanguage.catalog().key(key.id()));
|
||||||
|
assertEquals(key.id(), key.englishValue(), IrisLanguage.catalog().require(key.id()).englishValue());
|
||||||
|
}
|
||||||
|
assertEquals("A pregeneration task is already running. Stop it first with /iris pregen stop.",
|
||||||
|
IrisLanguage.plain(IrisMessages.PREGEN_ALREADY_RUNNING));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void completeLoaderCatalogStillMatchesEveryDownloadableLocale() throws Exception {
|
||||||
|
Path sourceRoot = Path.of("../../core/src/main/resources/languages");
|
||||||
|
for (String locale : VolmitLocales.nonEnglish()) {
|
||||||
|
JsonObject document = JsonParser.parseString(Files.readString(sourceRoot.resolve(locale + ".json")))
|
||||||
|
.getAsJsonObject();
|
||||||
|
assertEquals(locale, IrisLanguage.catalog().ids(), document.getAsJsonObject("messages").keySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,12 +20,24 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|||||||
import org.gradle.api.tasks.compile.JavaCompile
|
import org.gradle.api.tasks.compile.JavaCompile
|
||||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri('https://jitpack.io') }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath('com.github.VolmitSoftware.VolmLib:packaging:master-SNAPSHOT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'net.neoforged.moddev' version '2.0.141'
|
id 'net.neoforged.moddev' version '2.0.141'
|
||||||
alias(libs.plugins.shadow)
|
alias(libs.plugins.shadow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'art.arcane.volmit-packaging'
|
||||||
|
|
||||||
apply from: file('../../gradle/modded-generation-build-revision.gradle')
|
apply from: file('../../gradle/modded-generation-build-revision.gradle')
|
||||||
|
|
||||||
Properties rootProperties = new Properties()
|
Properties rootProperties = new Properties()
|
||||||
@@ -270,3 +282,14 @@ tasks.named('jar').configure {
|
|||||||
tasks.named('assemble').configure {
|
tasks.named('assemble').configure {
|
||||||
dependsOn(tasks.named('shadowJar'))
|
dependsOn(tasks.named('shadowJar'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pluginPackaging {
|
||||||
|
artifacts {
|
||||||
|
create('distribution') {
|
||||||
|
taskName = 'shadowJar'
|
||||||
|
policyName = 'Iris NeoForge'
|
||||||
|
prunePrefixes = ['art/arcane/volmlib/']
|
||||||
|
keepPrefixes = ['art/arcane/volmlib/util/matter/slices/']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
-4
@@ -33,11 +33,23 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri('https://jitpack.io') }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath('com.github.VolmitSoftware.VolmLib:packaging:master-SNAPSHOT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'art.arcane.volmit-packaging'
|
||||||
|
|
||||||
group = 'art.arcane'
|
group = 'art.arcane'
|
||||||
version = providers.gradleProperty('irisVersion').getOrElse('4.1.0-26.2')
|
version = providers.gradleProperty('irisVersion').getOrElse('4.1.0-26.2')
|
||||||
|
|
||||||
@@ -167,9 +179,6 @@ tasks.named('jar', Jar).configure {
|
|||||||
delete(layout.buildDirectory.file("libs/Iris-${project.version}.jar"))
|
delete(layout.buildDirectory.file("libs/Iris-${project.version}.jar"))
|
||||||
}
|
}
|
||||||
archiveFileName.set(bukkitArtifactName)
|
archiveFileName.set(bukkitArtifactName)
|
||||||
doLast {
|
|
||||||
JarCompactor.compact(archiveFile.get().asFile)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('iris', Copy) {
|
tasks.register('iris', Copy) {
|
||||||
@@ -611,7 +620,7 @@ tasks.register('buildAllToOut') {
|
|||||||
tasks.register('buildAll') {
|
tasks.register('buildAll') {
|
||||||
group = 'iris'
|
group = 'iris'
|
||||||
outputs.upToDateWhen { false }
|
outputs.upToDateWhen { false }
|
||||||
dependsOn('iris', 'verifyModdedArtifacts')
|
dependsOn('iris', 'verifyModdedArtifacts', 'buildAllToOut')
|
||||||
doLast {
|
doLast {
|
||||||
delete(
|
delete(
|
||||||
file("${bukkitConsumerPath}/Iris-Fabric.jar"),
|
file("${bukkitConsumerPath}/Iris-Fabric.jar"),
|
||||||
@@ -746,3 +755,17 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_25)) {
|
|||||||
System.err.println()
|
System.err.println()
|
||||||
System.exit(69)
|
System.exit(69)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pluginPackaging {
|
||||||
|
artifacts {
|
||||||
|
create('distribution') {
|
||||||
|
taskName = 'jar'
|
||||||
|
policyName = 'Iris Bukkit'
|
||||||
|
stripDirectories = true
|
||||||
|
stripLocalVariables = true
|
||||||
|
releaseCompression = providers.gradleProperty('compactRelease').map { it.toBoolean() }.getOrElse(false)
|
||||||
|
prunePrefixes = ['art/arcane/volmlib/']
|
||||||
|
keepPrefixes = ['art/arcane/volmlib/util/matter/slices/']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.FieldVisitor;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@@ -6,8 +13,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the {@code CONSTANT_Class} entries of a class file. That is exactly the set of types the
|
* Reads the {@code CONSTANT_Class} entries of a class file. That is exactly the set of types the
|
||||||
* class links against - supertypes, field and method owners, casts, catches, constant class
|
* class names directly - supertypes, field and method owners, casts, catches, constant class
|
||||||
* literals. Annotation types live in the annotation attributes as plain UTF-8 descriptors and are
|
* literals. Field and method descriptors are also traversed to include signature-only types. Annotation types live in the annotation attributes as plain UTF-8 descriptors and are
|
||||||
* deliberately not reported: the JVM skips an annotation whose type is absent.
|
* deliberately not reported: the JVM skips an annotation whose type is absent.
|
||||||
*/
|
*/
|
||||||
public final class ClassReferences {
|
public final class ClassReferences {
|
||||||
@@ -42,6 +49,7 @@ public final class ClassReferences {
|
|||||||
int constantCount = readUnsignedShort(classFile, 8);
|
int constantCount = readUnsignedShort(classFile, 8);
|
||||||
String[] utf8 = new String[constantCount];
|
String[] utf8 = new String[constantCount];
|
||||||
List<Integer> classNameIndexes = new ArrayList<>();
|
List<Integer> classNameIndexes = new ArrayList<>();
|
||||||
|
List<Integer> descriptorIndexes = new ArrayList<>();
|
||||||
int offset = 10;
|
int offset = 10;
|
||||||
int index = 1;
|
int index = 1;
|
||||||
while (index < constantCount) {
|
while (index < constantCount) {
|
||||||
@@ -58,10 +66,18 @@ public final class ClassReferences {
|
|||||||
classNameIndexes.add(readUnsignedShort(classFile, offset));
|
classNameIndexes.add(readUnsignedShort(classFile, offset));
|
||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
}
|
||||||
case CONSTANT_STRING, CONSTANT_METHOD_TYPE, CONSTANT_MODULE, CONSTANT_PACKAGE -> offset += 2;
|
case CONSTANT_METHOD_TYPE -> {
|
||||||
|
descriptorIndexes.add(readUnsignedShort(classFile, offset));
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
case CONSTANT_NAME_AND_TYPE -> {
|
||||||
|
descriptorIndexes.add(readUnsignedShort(classFile, offset + 2));
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
case CONSTANT_STRING, CONSTANT_MODULE, CONSTANT_PACKAGE -> offset += 2;
|
||||||
case CONSTANT_METHOD_HANDLE -> offset += 3;
|
case CONSTANT_METHOD_HANDLE -> offset += 3;
|
||||||
case CONSTANT_INTEGER, CONSTANT_FLOAT, CONSTANT_FIELDREF, CONSTANT_METHODREF,
|
case CONSTANT_INTEGER, CONSTANT_FLOAT, CONSTANT_FIELDREF, CONSTANT_METHODREF,
|
||||||
CONSTANT_INTERFACE_METHODREF, CONSTANT_NAME_AND_TYPE, CONSTANT_DYNAMIC,
|
CONSTANT_INTERFACE_METHODREF, CONSTANT_DYNAMIC,
|
||||||
CONSTANT_INVOKE_DYNAMIC -> offset += 4;
|
CONSTANT_INVOKE_DYNAMIC -> offset += 4;
|
||||||
case CONSTANT_LONG, CONSTANT_DOUBLE -> {
|
case CONSTANT_LONG, CONSTANT_DOUBLE -> {
|
||||||
offset += 8;
|
offset += 8;
|
||||||
@@ -83,9 +99,41 @@ public final class ClassReferences {
|
|||||||
references.add(name);
|
references.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int descriptorIndex : descriptorIndexes) {
|
||||||
|
addType(Type.getType(utf8[descriptorIndex]), references);
|
||||||
|
}
|
||||||
|
new ClassReader(classFile).accept(new ClassVisitor(Opcodes.ASM9) {
|
||||||
|
@Override
|
||||||
|
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||||
|
addType(Type.getType(descriptor), references);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
|
||||||
|
String[] exceptions) {
|
||||||
|
addType(Type.getMethodType(descriptor), references);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
return references;
|
return references;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addType(Type type, Set<String> references) {
|
||||||
|
switch (type.getSort()) {
|
||||||
|
case Type.ARRAY -> addType(type.getElementType(), references);
|
||||||
|
case Type.OBJECT -> references.add(type.getInternalName());
|
||||||
|
case Type.METHOD -> {
|
||||||
|
addType(type.getReturnType(), references);
|
||||||
|
for (Type argument : type.getArgumentTypes()) {
|
||||||
|
addType(argument, references);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String normalize(String rawName) {
|
private static String normalize(String rawName) {
|
||||||
if (rawName == null || rawName.isEmpty()) {
|
if (rawName == null || rawName.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
import org.apache.commons.compress.archivers.zip.ExtraFieldUtils;
|
|
||||||
import org.apache.commons.compress.archivers.zip.Zip64Mode;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
|
||||||
import org.gradle.api.GradleException;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.AtomicMoveNotSupportedException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.zip.CRC32;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
public final class JarCompactor {
|
|
||||||
private static final int BUFFER_BYTES = 64 * 1024;
|
|
||||||
|
|
||||||
private JarCompactor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void compact(File artifact) {
|
|
||||||
if (artifact == null || !artifact.isFile()) {
|
|
||||||
throw new GradleException("Cannot compact missing jar artifact: " + artifact);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path source = artifact.toPath();
|
|
||||||
Path temporary = null;
|
|
||||||
try {
|
|
||||||
temporary = Files.createTempFile(source.getParent(), artifact.getName(), ".compact");
|
|
||||||
rewrite(source, temporary);
|
|
||||||
replace(temporary, source);
|
|
||||||
} catch (IOException exception) {
|
|
||||||
if (temporary != null) {
|
|
||||||
try {
|
|
||||||
Files.deleteIfExists(temporary);
|
|
||||||
} catch (IOException cleanupFailure) {
|
|
||||||
exception.addSuppressed(cleanupFailure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new GradleException("Unable to compact jar artifact " + artifact.getAbsolutePath(), exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void rewrite(Path source, Path destination) throws IOException {
|
|
||||||
byte[] buffer = new byte[BUFFER_BYTES];
|
|
||||||
try (ZipFile input = new ZipFile(source.toFile());
|
|
||||||
ZipArchiveOutputStream output = new ZipArchiveOutputStream(destination)) {
|
|
||||||
if (!output.isSeekable()) {
|
|
||||||
throw new IOException("Jar compaction requires seekable output.");
|
|
||||||
}
|
|
||||||
output.setLevel(9);
|
|
||||||
output.setUseZip64(Zip64Mode.Never);
|
|
||||||
output.setCreateUnicodeExtraFields(ZipArchiveOutputStream.UnicodeExtraFieldPolicy.NEVER);
|
|
||||||
Set<String> names = new HashSet<>();
|
|
||||||
Enumeration<? extends ZipEntry> entries = input.entries();
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
ZipEntry entry = entries.nextElement();
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!names.add(entry.getName())) {
|
|
||||||
throw new IOException("Duplicate jar entry: " + entry.getName());
|
|
||||||
}
|
|
||||||
output.putArchiveEntry(copyMetadata(entry));
|
|
||||||
copyEntry(input, output, entry, buffer);
|
|
||||||
output.closeArchiveEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void copyEntry(ZipFile input, ZipArchiveOutputStream output, ZipEntry entry, byte[] buffer)
|
|
||||||
throws IOException {
|
|
||||||
CRC32 crc = new CRC32();
|
|
||||||
long size = 0L;
|
|
||||||
try (InputStream content = input.getInputStream(entry)) {
|
|
||||||
int read;
|
|
||||||
while ((read = content.read(buffer)) != -1) {
|
|
||||||
output.write(buffer, 0, read);
|
|
||||||
crc.update(buffer, 0, read);
|
|
||||||
size += read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (size != entry.getSize() || crc.getValue() != entry.getCrc()) {
|
|
||||||
throw new IOException("Jar entry failed size or CRC verification: " + entry.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ZipArchiveEntry copyMetadata(ZipEntry source) throws IOException {
|
|
||||||
ZipArchiveEntry target = new ZipArchiveEntry(source.getName());
|
|
||||||
target.setMethod(ZipEntry.DEFLATED);
|
|
||||||
if (source.getTime() >= 0L) {
|
|
||||||
target.setTime(source.getTime());
|
|
||||||
}
|
|
||||||
if (source.getComment() != null) {
|
|
||||||
target.setComment(source.getComment());
|
|
||||||
}
|
|
||||||
if (source.getExtra() != null) {
|
|
||||||
target.setExtraFields(ExtraFieldUtils.parse(source.getExtra(), true,
|
|
||||||
ZipArchiveEntry.ExtraFieldParsingMode.BEST_EFFORT));
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void replace(Path temporary, Path source) throws IOException {
|
|
||||||
try {
|
|
||||||
Files.move(
|
|
||||||
temporary,
|
|
||||||
source,
|
|
||||||
StandardCopyOption.ATOMIC_MOVE,
|
|
||||||
StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
} catch (AtomicMoveNotSupportedException exception) {
|
|
||||||
Files.move(temporary, source, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import org.junit.Test;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class ClassReferencesTest {
|
||||||
|
@Test
|
||||||
|
public void includesDeclarationOnlyFieldAndMethodTypes() {
|
||||||
|
ClassWriter writer = createClass();
|
||||||
|
writer.visitField(Opcodes.ACC_PUBLIC, "field", "[[Lexample/FieldType;", null, null).visitEnd();
|
||||||
|
writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, "method",
|
||||||
|
"(Lexample/Argument;[I)[Lexample/Result;", null, null).visitEnd();
|
||||||
|
writer.visitEnd();
|
||||||
|
|
||||||
|
Set<String> references = ClassReferences.read(writer.toByteArray());
|
||||||
|
assertTrue(references.containsAll(Set.of("example/FieldType", "example/Argument", "example/Result")));
|
||||||
|
assertFalse(references.contains("I"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void includesMemberReferenceAndMethodTypeDescriptors() {
|
||||||
|
ClassWriter writer = createClass();
|
||||||
|
writer.newMethod("example/Owner", "method", "(Lexample/Argument;)Lexample/Result;", false);
|
||||||
|
writer.newConst(Type.getMethodType("(Lexample/HandleArgument;)Lexample/HandleResult;"));
|
||||||
|
writer.visitEnd();
|
||||||
|
|
||||||
|
Set<String> references = ClassReferences.read(writer.toByteArray());
|
||||||
|
assertTrue(references.containsAll(Set.of("example/Owner", "example/Argument", "example/Result",
|
||||||
|
"example/HandleArgument", "example/HandleResult")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doesNotTreatStringsOrAnnotationOnlyTypesAsLinkage() {
|
||||||
|
ClassWriter writer = createClass();
|
||||||
|
writer.newConst("Lexample/StringValue;");
|
||||||
|
writer.visitAnnotation("Lexample/Annotation;", true).visitEnd();
|
||||||
|
writer.visitEnd();
|
||||||
|
|
||||||
|
Set<String> references = ClassReferences.read(writer.toByteArray());
|
||||||
|
assertFalse(references.contains("example/StringValue"));
|
||||||
|
assertFalse(references.contains("example/Annotation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassWriter createClass() {
|
||||||
|
ClassWriter writer = new ClassWriter(0);
|
||||||
|
writer.visit(Opcodes.V25, Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
|
||||||
|
"example/Consumer", null, "java/lang/Object", null);
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
|
||||||
import org.gradle.api.GradleException;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.rules.TemporaryFolder;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HexFormat;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
import java.util.jar.JarOutputStream;
|
|
||||||
import java.util.zip.CRC32;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertThrows;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class JarCompactorTest {
|
|
||||||
@Rule
|
|
||||||
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void preservesFilesAndOmitsDirectoryEntries() throws Exception {
|
|
||||||
File artifact = temporaryFolder.newFile("artifact.jar");
|
|
||||||
byte[] content = "Iris artifact content".getBytes(StandardCharsets.UTF_8);
|
|
||||||
try (JarOutputStream output = new JarOutputStream(new FileOutputStream(artifact))) {
|
|
||||||
output.putNextEntry(new JarEntry("example/"));
|
|
||||||
output.closeEntry();
|
|
||||||
output.putNextEntry(new JarEntry("example/value.txt"));
|
|
||||||
output.write(content);
|
|
||||||
output.closeEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
JarCompactor.compact(artifact);
|
|
||||||
|
|
||||||
try (JarFile jar = new JarFile(artifact)) {
|
|
||||||
assertNull(jar.getJarEntry("example/"));
|
|
||||||
assertArrayEquals(content, jar.getInputStream(
|
|
||||||
jar.getJarEntry("example/value.txt")).readAllBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void preservesJarIdentityAndProducesDeterministicSeekableOutput() throws Exception {
|
|
||||||
File artifact = temporaryFolder.newFile("identity.jar");
|
|
||||||
try (JarOutputStream output = new JarOutputStream(new FileOutputStream(artifact));
|
|
||||||
InputStream classResource = getClass().getResourceAsStream("/JarCompactorTest.class")) {
|
|
||||||
output.setLevel(9);
|
|
||||||
writeEntry(output, "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\r\nMulti-Release: true\r\n\r\n"
|
|
||||||
.getBytes(StandardCharsets.UTF_8));
|
|
||||||
writeEntry(output, "JarCompactorTest.class", classResource.readAllBytes());
|
|
||||||
writeEntry(output, "META-INF/iris/generation-kernels/abi-1.revision", "registry fixture".getBytes(StandardCharsets.UTF_8));
|
|
||||||
writeEntry(output, "example/caf\u00e9.txt", "unicode name".getBytes(StandardCharsets.UTF_8));
|
|
||||||
for (int index = 0; index < 100; index++) {
|
|
||||||
writeEntry(output, "example/item-" + index + ".txt", ("value-" + index).getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String, EntryIdentity> original = identity(artifact);
|
|
||||||
long originalBytes = artifact.length();
|
|
||||||
|
|
||||||
JarCompactor.compact(artifact);
|
|
||||||
|
|
||||||
assertEquals(original, identity(artifact));
|
|
||||||
assertTrue(artifact.length() < originalBytes);
|
|
||||||
try (JarFile jar = new JarFile(artifact)) {
|
|
||||||
assertEquals("true", jar.getManifest().getMainAttributes().getValue("Multi-Release"));
|
|
||||||
assertEquals(0xCA, jar.getInputStream(jar.getJarEntry("JarCompactorTest.class")).read());
|
|
||||||
}
|
|
||||||
try (ZipFile zip = ZipFile.builder().setFile(artifact).get()) {
|
|
||||||
Enumeration<ZipArchiveEntry> entries = zip.getEntries();
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
assertFalse(entries.nextElement().getGeneralPurposeBit().usesDataDescriptor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
byte[] first = Files.readAllBytes(artifact.toPath());
|
|
||||||
JarCompactor.compact(artifact);
|
|
||||||
assertArrayEquals(first, Files.readAllBytes(artifact.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void rejectsMalformedArchivesWithoutReplacingTheSource() throws Exception {
|
|
||||||
File artifact = temporaryFolder.newFile("invalid.jar");
|
|
||||||
byte[] original = "not a zip archive".getBytes(StandardCharsets.UTF_8);
|
|
||||||
Files.write(artifact.toPath(), original);
|
|
||||||
|
|
||||||
assertThrows(GradleException.class, () -> JarCompactor.compact(artifact));
|
|
||||||
|
|
||||||
assertArrayEquals(original, Files.readAllBytes(artifact.toPath()));
|
|
||||||
assertEquals(1, temporaryFolder.getRoot().listFiles().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void rejectsCorruptPayloadWithoutReplacingTheSource() throws Exception {
|
|
||||||
File artifact = temporaryFolder.newFile("corrupt.jar");
|
|
||||||
byte[] payload = "checked-payload".getBytes(StandardCharsets.UTF_8);
|
|
||||||
CRC32 crc = new CRC32();
|
|
||||||
crc.update(payload);
|
|
||||||
try (JarOutputStream output = new JarOutputStream(new FileOutputStream(artifact))) {
|
|
||||||
JarEntry entry = new JarEntry("value.txt");
|
|
||||||
entry.setMethod(ZipEntry.STORED);
|
|
||||||
entry.setSize(payload.length);
|
|
||||||
entry.setCrc(crc.getValue());
|
|
||||||
output.putNextEntry(entry);
|
|
||||||
output.write(payload);
|
|
||||||
output.closeEntry();
|
|
||||||
}
|
|
||||||
byte[] corrupt = Files.readAllBytes(artifact.toPath());
|
|
||||||
int payloadOffset = new String(corrupt, StandardCharsets.ISO_8859_1).indexOf("checked-payload");
|
|
||||||
assertTrue(payloadOffset > 0);
|
|
||||||
corrupt[payloadOffset] ^= 1;
|
|
||||||
Files.write(artifact.toPath(), corrupt);
|
|
||||||
|
|
||||||
assertThrows(GradleException.class, () -> JarCompactor.compact(artifact));
|
|
||||||
|
|
||||||
assertArrayEquals(corrupt, Files.readAllBytes(artifact.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void rejectsDuplicateEntriesWithoutReplacingTheSource() throws Exception {
|
|
||||||
File artifact = temporaryFolder.newFile("duplicate.jar");
|
|
||||||
try (ZipArchiveOutputStream output = new ZipArchiveOutputStream(artifact)) {
|
|
||||||
for (int index = 0; index < 2; index++) {
|
|
||||||
output.putArchiveEntry(new ZipArchiveEntry("duplicate.txt"));
|
|
||||||
output.write(index);
|
|
||||||
output.closeArchiveEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
byte[] original = Files.readAllBytes(artifact.toPath());
|
|
||||||
|
|
||||||
assertThrows(GradleException.class, () -> JarCompactor.compact(artifact));
|
|
||||||
|
|
||||||
assertArrayEquals(original, Files.readAllBytes(artifact.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeEntry(JarOutputStream output, String name, byte[] content) throws Exception {
|
|
||||||
JarEntry entry = new JarEntry(name);
|
|
||||||
entry.setTime(315_532_800_000L);
|
|
||||||
entry.setComment("preserved entry comment");
|
|
||||||
entry.setExtra(new byte[]{(byte) 0xFE, (byte) 0xCA, 1, 0, 7});
|
|
||||||
output.putNextEntry(entry);
|
|
||||||
output.write(content);
|
|
||||||
output.closeEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, EntryIdentity> identity(File artifact) throws Exception {
|
|
||||||
Map<String, EntryIdentity> entries = new TreeMap<>();
|
|
||||||
try (JarFile jar = new JarFile(artifact)) {
|
|
||||||
Enumeration<JarEntry> contents = jar.entries();
|
|
||||||
while (contents.hasMoreElements()) {
|
|
||||||
JarEntry entry = contents.nextElement();
|
|
||||||
byte[] bytes;
|
|
||||||
try (InputStream input = jar.getInputStream(entry)) {
|
|
||||||
bytes = input.readAllBytes();
|
|
||||||
}
|
|
||||||
entries.put(entry.getName(), new EntryIdentity(
|
|
||||||
HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(bytes)),
|
|
||||||
entry.getSize(), entry.getCrc(), entry.getTime(), entry.getComment(),
|
|
||||||
entry.getExtra() == null ? "" : HexFormat.of().formatHex(entry.getExtra())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
private record EntryIdentity(String sha256, long size, long crc, long time, String comment, String extra) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-4
@@ -415,10 +415,10 @@ List<String> unusedVolmLibClasses = [
|
|||||||
'art/arcane/volmlib/util/collection/StateList',
|
'art/arcane/volmlib/util/collection/StateList',
|
||||||
'art/arcane/iris/core/pack/IrisPack',
|
'art/arcane/iris/core/pack/IrisPack',
|
||||||
'art/arcane/iris/core/pack/IrisPackRepository',
|
'art/arcane/iris/core/pack/IrisPackRepository',
|
||||||
'art/arcane/iris/core/jobs/DownloadJob',
|
'art/arcane/iris/util/common/scheduling/jobs/DownloadJob',
|
||||||
'art/arcane/iris/core/jobs/JobCollection',
|
'art/arcane/iris/util/common/scheduling/jobs/JobCollection',
|
||||||
'art/arcane/iris/core/jobs/ParallelQueueJob',
|
'art/arcane/iris/util/common/scheduling/jobs/ParallelQueueJob',
|
||||||
'art/arcane/iris/core/jobs/QueueJob',
|
'art/arcane/iris/util/common/scheduling/jobs/QueueJob',
|
||||||
'art/arcane/iris/engine/framework/placer/WorldObjectPlacer',
|
'art/arcane/iris/engine/framework/placer/WorldObjectPlacer',
|
||||||
'art/arcane/iris/engine/object/IPostBlockAccess',
|
'art/arcane/iris/engine/object/IPostBlockAccess',
|
||||||
'art/arcane/iris/engine/object/IrisPotionEffect',
|
'art/arcane/iris/engine/object/IrisPotionEffect',
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public final class CapabilitySnapshot {
|
|||||||
private final Method removeLevelMethod;
|
private final Method removeLevelMethod;
|
||||||
private final String paperLikeResolution;
|
private final String paperLikeResolution;
|
||||||
|
|
||||||
private CapabilitySnapshot(
|
CapabilitySnapshot(
|
||||||
ServerFamily serverFamily,
|
ServerFamily serverFamily,
|
||||||
boolean regionizedRuntime,
|
boolean regionizedRuntime,
|
||||||
Object worldsProvider,
|
Object worldsProvider,
|
||||||
@@ -259,94 +259,6 @@ public final class CapabilitySnapshot {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CapabilitySnapshot forTesting(ServerFamily serverFamily, boolean regionizedRuntime, boolean worldsProviderHealthy, boolean paperLikeRuntimeHealthy) {
|
|
||||||
Object minecraftServer = paperLikeRuntimeHealthy ? new TestingPaperLikeServer("datapack-registry", "server-registry") : null;
|
|
||||||
Method createLevelMethod = null;
|
|
||||||
Field worldLoaderContextField = null;
|
|
||||||
Method serverRegistryAccessMethod = null;
|
|
||||||
try {
|
|
||||||
createLevelMethod = paperLikeRuntimeHealthy
|
|
||||||
? TestingPaperLikeServer.class.getDeclaredMethod("createLevel", Object.class, Object.class, Object.class)
|
|
||||||
: null;
|
|
||||||
worldLoaderContextField = paperLikeRuntimeHealthy
|
|
||||||
? CapabilityResolution.resolveField(TestingPaperLikeServer.class, "worldLoaderContext")
|
|
||||||
: null;
|
|
||||||
serverRegistryAccessMethod = paperLikeRuntimeHealthy
|
|
||||||
? CapabilityResolution.resolveServerRegistryAccessMethod(TestingPaperLikeServer.class)
|
|
||||||
: null;
|
|
||||||
} catch (NoSuchMethodException | NoSuchFieldException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
return new CapabilitySnapshot(
|
|
||||||
serverFamily,
|
|
||||||
regionizedRuntime,
|
|
||||||
worldsProviderHealthy ? new Object() : null,
|
|
||||||
worldsProviderHealthy ? Object.class : null,
|
|
||||||
worldsProviderHealthy ? Object.class : null,
|
|
||||||
worldsProviderHealthy ? "test-provider" : "inactive",
|
|
||||||
null,
|
|
||||||
minecraftServer,
|
|
||||||
createLevelMethod,
|
|
||||||
paperLikeRuntimeHealthy ? PaperLikeFlavor.CURRENT_INFO_AND_DATA : PaperLikeFlavor.UNSUPPORTED,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
worldLoaderContextField,
|
|
||||||
serverRegistryAccessMethod,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
paperLikeRuntimeHealthy ? "available(test)" : "unsupported(test)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CapabilitySnapshot forTestingRuntimeRegistries(ServerFamily serverFamily, boolean regionizedRuntime, Object datapackDimensions, Object serverRegistryAccess) {
|
|
||||||
TestingPaperLikeServer minecraftServer = new TestingPaperLikeServer(datapackDimensions, serverRegistryAccess);
|
|
||||||
Method createLevelMethod;
|
|
||||||
Field worldLoaderContextField;
|
|
||||||
Method registryAccessMethod;
|
|
||||||
try {
|
|
||||||
createLevelMethod = TestingPaperLikeServer.class.getDeclaredMethod("createLevel", Object.class, Object.class, Object.class);
|
|
||||||
worldLoaderContextField = CapabilityResolution.resolveField(TestingPaperLikeServer.class, "worldLoaderContext");
|
|
||||||
registryAccessMethod = CapabilityResolution.resolveServerRegistryAccessMethod(TestingPaperLikeServer.class);
|
|
||||||
} catch (NoSuchMethodException | NoSuchFieldException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
return new CapabilitySnapshot(
|
|
||||||
serverFamily,
|
|
||||||
regionizedRuntime,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
"inactive",
|
|
||||||
null,
|
|
||||||
minecraftServer,
|
|
||||||
createLevelMethod,
|
|
||||||
PaperLikeFlavor.CURRENT_INFO_AND_DATA,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
worldLoaderContextField,
|
|
||||||
registryAccessMethod,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
"available(test-runtime-registries)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerFamily serverFamily() {
|
public ServerFamily serverFamily() {
|
||||||
return serverFamily;
|
return serverFamily;
|
||||||
}
|
}
|
||||||
@@ -578,35 +490,4 @@ public final class CapabilitySnapshot {
|
|||||||
return new Object[]{null, null, null, "inactive(service scan found nothing)"};
|
return new Object[]{null, null, null, "inactive(service scan found nothing)"};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TestingPaperLikeServer {
|
|
||||||
private final TestingWorldLoaderContext worldLoaderContext;
|
|
||||||
private final Object registryAccess;
|
|
||||||
|
|
||||||
private TestingPaperLikeServer(Object datapackDimensions, Object registryAccess) {
|
|
||||||
this.worldLoaderContext = new TestingWorldLoaderContext(datapackDimensions);
|
|
||||||
this.registryAccess = registryAccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private void createLevel(Object levelStem, Object worldLoadingInfoAndData, Object worldDataAndGenSettings) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private Object registryAccess() {
|
|
||||||
return registryAccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class TestingWorldLoaderContext {
|
|
||||||
private final Object datapackDimensions;
|
|
||||||
|
|
||||||
private TestingWorldLoaderContext(Object datapackDimensions) {
|
|
||||||
this.datapackDimensions = datapackDimensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private Object datapackDimensions() {
|
|
||||||
return datapackDimensions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -568,15 +568,20 @@ public final class IrisLanguage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateDownload(String locale, String raw) {
|
static void validateDownload(String locale, String raw) {
|
||||||
LocalizationValidator.validate(CATALOG, List.of(parseOverlay("download:" + locale, locale, raw)))
|
LocaleOverlay overlay = parseDownloadedOverlay("download:" + locale, locale, raw);
|
||||||
.throwIfInvalid();
|
LocalizationValidator.validate(CATALOG, List.of(overlay)).throwIfInvalid();
|
||||||
|
for (MessageKey key : CATALOG.keys()) {
|
||||||
|
if (overlay.value(key.id()) == null) {
|
||||||
|
throw new IllegalArgumentException("Downloaded Iris locale " + locale + " is incomplete: " + key.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LocaleOverlay loadDownloadedOverlay(File root, String locale) {
|
private static LocaleOverlay loadDownloadedOverlay(File root, String locale) {
|
||||||
RemoteLanguageCatalog.CacheResult cached = remote(root).read(locale, IrisLanguage::validateDownload);
|
RemoteLanguageCatalog.CacheResult cached = remote(root).read(locale, IrisLanguage::validateDownload);
|
||||||
if (cached.state() == RemoteLanguageCatalog.CacheState.VALID) {
|
if (cached.state() == RemoteLanguageCatalog.CacheState.VALID) {
|
||||||
return parseOverlay(cached.file().toString(), locale, cached.content());
|
return parseDownloadedOverlay(cached.file().toString(), locale, cached.content());
|
||||||
}
|
}
|
||||||
if (cached.failure() != null) {
|
if (cached.failure() != null) {
|
||||||
IrisLogging.error("Ignoring invalid downloaded Iris locale " + locale + ".");
|
IrisLogging.error("Ignoring invalid downloaded Iris locale " + locale + ".");
|
||||||
@@ -585,6 +590,17 @@ public final class IrisLanguage {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LocaleOverlay parseDownloadedOverlay(String source, String locale, String raw) {
|
||||||
|
LocaleOverlay parsed = parseOverlay(source, locale, raw);
|
||||||
|
LocaleOverlay.Builder builder = LocaleOverlay.builder(source, locale);
|
||||||
|
for (Map.Entry<String, MessageValue> entry : parsed.values().entrySet()) {
|
||||||
|
if (CATALOG.key(entry.getKey()) != null) {
|
||||||
|
builder.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
static LocaleOverlay parseOverlay(String source, String locale, String raw) {
|
static LocaleOverlay parseOverlay(String source, String locale, String raw) {
|
||||||
JsonElement parsed = JsonParser.parseString(raw == null || raw.isBlank() ? "{}" : raw);
|
JsonElement parsed = JsonParser.parseString(raw == null || raw.isBlank() ? "{}" : raw);
|
||||||
if (!parsed.isJsonObject()) {
|
if (!parsed.isJsonObject()) {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package art.arcane.iris.core.localization;
|
||||||
|
|
||||||
|
import art.arcane.volmlib.util.localization.MessageKey;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IrisMessageContributor {
|
||||||
|
List<MessageKey> keys();
|
||||||
|
}
|
||||||
@@ -7,8 +7,14 @@ import art.arcane.volmlib.util.localization.TextKey;
|
|||||||
import art.arcane.volmlib.util.localization.VolmitLocales;
|
import art.arcane.volmlib.util.localization.VolmitLocales;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
public final class IrisMessages {
|
public final class IrisMessages {
|
||||||
|
public static final TextKey PREGEN_ALREADY_RUNNING = TextKey.of(
|
||||||
|
"iris.modded.irismoddedcommands.pregeneration_task_is_already_running_stop_it_first_with_iris",
|
||||||
|
"A pregeneration task is already running. Stop it first with /iris pregen stop."
|
||||||
|
);
|
||||||
|
|
||||||
public static final TextKey COMMAND_PERMISSION_DENIED = TextKey.of(
|
public static final TextKey COMMAND_PERMISSION_DENIED = TextKey.of(
|
||||||
"iris.command.permission_denied",
|
"iris.command.permission_denied",
|
||||||
"You lack the permission '{permission}'"
|
"You lack the permission '{permission}'"
|
||||||
@@ -67,6 +73,7 @@ public final class IrisMessages {
|
|||||||
);
|
);
|
||||||
|
|
||||||
private static final List<MessageKey> RUNTIME_KEYS = List.of(
|
private static final List<MessageKey> RUNTIME_KEYS = List.of(
|
||||||
|
PREGEN_ALREADY_RUNNING,
|
||||||
COMMAND_PERMISSION_DENIED,
|
COMMAND_PERMISSION_DENIED,
|
||||||
COMMAND_UNKNOWN,
|
COMMAND_UNKNOWN,
|
||||||
COMMAND_PLAYER_ONLY,
|
COMMAND_PLAYER_ONLY,
|
||||||
@@ -101,16 +108,16 @@ public final class IrisMessages {
|
|||||||
builder.addAll(RUNTIME_KEYS);
|
builder.addAll(RUNTIME_KEYS);
|
||||||
builder.addAll(BukkitCommandMessages.keys());
|
builder.addAll(BukkitCommandMessages.keys());
|
||||||
builder.addAll(BukkitCommandMessagesExtended.keys());
|
builder.addAll(BukkitCommandMessagesExtended.keys());
|
||||||
builder.addAll(ModdedCommandMessages.keys());
|
|
||||||
builder.addAll(DirectorCommandMessages.keys());
|
builder.addAll(DirectorCommandMessages.keys());
|
||||||
builder.addAll(ModdedHelpMessages.keys());
|
|
||||||
builder.addAll(RuntimeUiMessages.keys());
|
builder.addAll(RuntimeUiMessages.keys());
|
||||||
builder.addAll(BukkitRuntimeMessages.keys());
|
builder.addAll(BukkitRuntimeMessages.keys());
|
||||||
builder.addAll(RuntimeProgressMessages.keys());
|
builder.addAll(RuntimeProgressMessages.keys());
|
||||||
builder.addAll(PackDownloadMessages.keys());
|
builder.addAll(PackDownloadMessages.keys());
|
||||||
builder.addAll(ClientUiMessages.keys());
|
|
||||||
builder.addAll(BukkitUiMessages.keys());
|
builder.addAll(BukkitUiMessages.keys());
|
||||||
builder.addAll(DesktopUiMessages.keys());
|
builder.addAll(DesktopUiMessages.keys());
|
||||||
|
for (IrisMessageContributor contributor : ServiceLoader.load(IrisMessageContributor.class, IrisMessages.class.getClassLoader())) {
|
||||||
|
builder.addAll(contributor.keys());
|
||||||
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ public class BukkitPublicBackendTest {
|
|||||||
worldName, worldKey, World.Environment.NORMAL, generator, biomeProvider,
|
worldName, worldKey, World.Environment.NORMAL, generator, biomeProvider,
|
||||||
WorldType.NORMAL, true, false, 123L, false, false, WorldLifecycleCaller.CREATE);
|
WorldType.NORMAL, true, false, 123L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
BukkitPublicBackend backend = new BukkitPublicBackend(
|
BukkitPublicBackend backend = new BukkitPublicBackend(
|
||||||
CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, false));
|
CapabilitySnapshotFixtures.forTesting(ServerFamily.PAPER, false, false, false));
|
||||||
|
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
assertSame(generator, WorldLifecycleStaging.peekStemGenerator(worldName));
|
assertSame(generator, WorldLifecycleStaging.peekStemGenerator(worldName));
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.lifecycle.CapabilitySnapshot.PaperLikeFlavor;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
final class CapabilitySnapshotFixtures {
|
||||||
|
private CapabilitySnapshotFixtures() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static CapabilitySnapshot forTesting(ServerFamily serverFamily, boolean regionizedRuntime, boolean worldsProviderHealthy, boolean paperLikeRuntimeHealthy) {
|
||||||
|
Object minecraftServer = paperLikeRuntimeHealthy ? new TestingPaperLikeServer("datapack-registry", "server-registry") : null;
|
||||||
|
Method createLevelMethod = null;
|
||||||
|
Field worldLoaderContextField = null;
|
||||||
|
Method serverRegistryAccessMethod = null;
|
||||||
|
try {
|
||||||
|
createLevelMethod = paperLikeRuntimeHealthy
|
||||||
|
? TestingPaperLikeServer.class.getDeclaredMethod("createLevel", Object.class, Object.class, Object.class)
|
||||||
|
: null;
|
||||||
|
worldLoaderContextField = paperLikeRuntimeHealthy
|
||||||
|
? CapabilityResolution.resolveField(TestingPaperLikeServer.class, "worldLoaderContext")
|
||||||
|
: null;
|
||||||
|
serverRegistryAccessMethod = paperLikeRuntimeHealthy
|
||||||
|
? CapabilityResolution.resolveServerRegistryAccessMethod(TestingPaperLikeServer.class)
|
||||||
|
: null;
|
||||||
|
} catch (NoSuchMethodException | NoSuchFieldException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
return new CapabilitySnapshot(
|
||||||
|
serverFamily,
|
||||||
|
regionizedRuntime,
|
||||||
|
worldsProviderHealthy ? new Object() : null,
|
||||||
|
worldsProviderHealthy ? Object.class : null,
|
||||||
|
worldsProviderHealthy ? Object.class : null,
|
||||||
|
worldsProviderHealthy ? "test-provider" : "inactive",
|
||||||
|
null,
|
||||||
|
minecraftServer,
|
||||||
|
createLevelMethod,
|
||||||
|
paperLikeRuntimeHealthy ? PaperLikeFlavor.CURRENT_INFO_AND_DATA : PaperLikeFlavor.UNSUPPORTED,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
worldLoaderContextField,
|
||||||
|
serverRegistryAccessMethod,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
paperLikeRuntimeHealthy ? "available(test)" : "unsupported(test)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CapabilitySnapshot forTestingRuntimeRegistries(ServerFamily serverFamily, boolean regionizedRuntime, Object datapackDimensions, Object serverRegistryAccess) {
|
||||||
|
TestingPaperLikeServer minecraftServer = new TestingPaperLikeServer(datapackDimensions, serverRegistryAccess);
|
||||||
|
Method createLevelMethod;
|
||||||
|
Field worldLoaderContextField;
|
||||||
|
Method registryAccessMethod;
|
||||||
|
try {
|
||||||
|
createLevelMethod = TestingPaperLikeServer.class.getDeclaredMethod("createLevel", Object.class, Object.class, Object.class);
|
||||||
|
worldLoaderContextField = CapabilityResolution.resolveField(TestingPaperLikeServer.class, "worldLoaderContext");
|
||||||
|
registryAccessMethod = CapabilityResolution.resolveServerRegistryAccessMethod(TestingPaperLikeServer.class);
|
||||||
|
} catch (NoSuchMethodException | NoSuchFieldException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
return new CapabilitySnapshot(
|
||||||
|
serverFamily,
|
||||||
|
regionizedRuntime,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"inactive",
|
||||||
|
null,
|
||||||
|
minecraftServer,
|
||||||
|
createLevelMethod,
|
||||||
|
PaperLikeFlavor.CURRENT_INFO_AND_DATA,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
worldLoaderContextField,
|
||||||
|
registryAccessMethod,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"available(test-runtime-registries)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TestingPaperLikeServer {
|
||||||
|
private final TestingWorldLoaderContext worldLoaderContext;
|
||||||
|
private final Object registryAccess;
|
||||||
|
|
||||||
|
private TestingPaperLikeServer(Object datapackDimensions, Object registryAccess) {
|
||||||
|
this.worldLoaderContext = new TestingWorldLoaderContext(datapackDimensions);
|
||||||
|
this.registryAccess = registryAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void createLevel(Object levelStem, Object worldLoadingInfoAndData, Object worldDataAndGenSettings) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private Object registryAccess() {
|
||||||
|
return registryAccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TestingWorldLoaderContext {
|
||||||
|
private final Object datapackDimensions;
|
||||||
|
|
||||||
|
private TestingWorldLoaderContext(Object datapackDimensions) {
|
||||||
|
this.datapackDimensions = datapackDimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private Object datapackDimensions() {
|
||||||
|
return datapackDimensions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -15,7 +15,7 @@ import static org.junit.Assert.fail;
|
|||||||
public class WorldLifecycleDiagnosticsTest {
|
public class WorldLifecycleDiagnosticsTest {
|
||||||
@Test
|
@Test
|
||||||
public void studioCreateSelectionFailurePrintsFullStacktrace() {
|
public void studioCreateSelectionFailurePrintsFullStacktrace() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, false));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.PAPER, false, false, false));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ public class WorldLifecycleRuntimeLevelStemTest {
|
|||||||
public void runtimeStemUsesFullServerRegistryAccessForPlatformGenerators() throws Exception {
|
public void runtimeStemUsesFullServerRegistryAccessForPlatformGenerators() throws Exception {
|
||||||
Object datapackDimensions = new MissingDimensionTypeRegistry();
|
Object datapackDimensions = new MissingDimensionTypeRegistry();
|
||||||
Object serverRegistryAccess = new Object();
|
Object serverRegistryAccess = new Object();
|
||||||
CapabilitySnapshot capabilities = CapabilitySnapshot.forTestingRuntimeRegistries(ServerFamily.PURPUR, false, datapackDimensions, serverRegistryAccess);
|
CapabilitySnapshot capabilities = CapabilitySnapshotFixtures.forTestingRuntimeRegistries(ServerFamily.PURPUR, false, datapackDimensions, serverRegistryAccess);
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest(
|
WorldLifecycleRequest request = new WorldLifecycleRequest(
|
||||||
"studio",
|
"studio",
|
||||||
NamespacedKey.minecraft("studio"),
|
NamespacedKey.minecraft("studio"),
|
||||||
|
|||||||
+11
-11
@@ -21,7 +21,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnPaper() {
|
public void studioSelectsPaperLikeBackendOnPaper() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.PAPER, false, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
@@ -29,7 +29,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnPurpur() {
|
public void studioSelectsPaperLikeBackendOnPurpur() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.PURPUR, false, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
@@ -37,7 +37,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnCanvas() {
|
public void studioSelectsPaperLikeBackendOnCanvas() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.CANVAS, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
@@ -45,7 +45,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnFolia() {
|
public void studioSelectsPaperLikeBackendOnFolia() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.FOLIA, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
@@ -53,7 +53,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void studioSelectsBukkitBackendOnSpigot() {
|
public void studioSelectsBukkitBackendOnSpigot() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.SPIGOT, false, false, false));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.SPIGOT, false, false, false));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
||||||
@@ -61,7 +61,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void persistentCreatePrefersBukkitBackendOnPaperLikeServers() {
|
public void persistentCreatePrefersBukkitBackendOnPaperLikeServers() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.PURPUR, false, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
||||||
@@ -69,7 +69,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void persistentCreateSelectsPaperLikeBackendOnFolia() {
|
public void persistentCreateSelectsPaperLikeBackendOnFolia() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.FOLIA, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
@@ -77,7 +77,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void persistentCreateSelectsPaperLikeBackendOnCanvas() {
|
public void persistentCreateSelectsPaperLikeBackendOnCanvas() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.CANVAS, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
@@ -85,7 +85,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void persistentCreateFailsClosedOnFoliaWithoutRuntime() {
|
public void persistentCreateFailsClosedOnFoliaWithoutRuntime() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, false, false, false));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.FOLIA, false, false, false));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertThrows(IllegalStateException.class, () -> service.selectCreateBackend(request));
|
assertThrows(IllegalStateException.class, () -> service.selectCreateBackend(request));
|
||||||
@@ -93,7 +93,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void unloadUsesRememberedBackendFamily() {
|
public void unloadUsesRememberedBackendFamily() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshotFixtures.forTesting(ServerFamily.PURPUR, false, false, true));
|
||||||
|
|
||||||
service.rememberBackend(NamespacedKey.minecraft("studio"), "paper_like_runtime");
|
service.rememberBackend(NamespacedKey.minecraft("studio"), "paper_like_runtime");
|
||||||
assertEquals("paper_like_runtime", service.selectUnloadBackend("minecraft:studio").backendName());
|
assertEquals("paper_like_runtime", service.selectUnloadBackend("minecraft:studio").backendName());
|
||||||
@@ -104,7 +104,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
CountingBackend selected = new CountingBackend("selected", true);
|
CountingBackend selected = new CountingBackend("selected", true);
|
||||||
CountingBackend inactive = new CountingBackend("inactive", false);
|
CountingBackend inactive = new CountingBackend("inactive", false);
|
||||||
WorldLifecycleService service = new WorldLifecycleService(
|
WorldLifecycleService service = new WorldLifecycleService(
|
||||||
CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, true),
|
CapabilitySnapshotFixtures.forTesting(ServerFamily.PAPER, false, false, true),
|
||||||
selected,
|
selected,
|
||||||
inactive,
|
inactive,
|
||||||
inactive);
|
inactive);
|
||||||
|
|||||||
+1
-1
@@ -279,7 +279,7 @@ public class WorldLifecycleUnloadAsyncTest {
|
|||||||
) {
|
) {
|
||||||
ControlledBackend inactive = new ControlledBackend("inactive");
|
ControlledBackend inactive = new ControlledBackend("inactive");
|
||||||
return new WorldLifecycleService(
|
return new WorldLifecycleService(
|
||||||
CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, false),
|
CapabilitySnapshotFixtures.forTesting(ServerFamily.PURPUR, false, false, false),
|
||||||
inactive,
|
inactive,
|
||||||
remembered,
|
remembered,
|
||||||
fallback
|
fallback
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package art.arcane.iris.core.localization;
|
||||||
|
|
||||||
|
import art.arcane.volmlib.util.localization.LocaleOverlay;
|
||||||
|
import art.arcane.volmlib.util.localization.LocalizationValidator;
|
||||||
|
import art.arcane.volmlib.util.localization.RemoteLanguageCatalog;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
|
import com.sun.net.httpserver.HttpServer;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class IrisDownloadValidationTest {
|
||||||
|
private static final String LOCALE = "de_DE";
|
||||||
|
private static final String MISSING_KEY = "iris.director.commanddeveloper.director.stage_world_generation_update";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void incompleteCacheDownloadsCompleteCatalogAndReusesIt() throws Exception {
|
||||||
|
String complete = completeCatalog();
|
||||||
|
AtomicInteger requests = new AtomicInteger();
|
||||||
|
HttpServer server = server(complete, requests);
|
||||||
|
try (URLClassLoader resources = resources();
|
||||||
|
RemoteLanguageCatalog catalog = catalog(server, resources)) {
|
||||||
|
Path cache = catalog.cacheFile(LOCALE);
|
||||||
|
Files.createDirectories(cache.getParent());
|
||||||
|
Files.writeString(cache, incompleteCatalog(complete));
|
||||||
|
|
||||||
|
RemoteLanguageCatalog.CacheResult initial = catalog.read(LOCALE, IrisLanguage::validateDownload);
|
||||||
|
assertEquals(RemoteLanguageCatalog.CacheState.INVALID, initial.state());
|
||||||
|
assertTrue(initial.failure().getMessage().contains(MISSING_KEY));
|
||||||
|
assertEquals(0, requests.get());
|
||||||
|
|
||||||
|
assertEquals(complete, catalog.readOrDownload(LOCALE, IrisLanguage::validateDownload));
|
||||||
|
assertEquals(complete, Files.readString(cache));
|
||||||
|
assertEquals(RemoteLanguageCatalog.CacheState.VALID,
|
||||||
|
catalog.read(LOCALE, IrisLanguage::validateDownload).state());
|
||||||
|
assertEquals(1, requests.get());
|
||||||
|
|
||||||
|
assertEquals(complete, catalog.readOrDownload(LOCALE, IrisLanguage::validateDownload));
|
||||||
|
assertEquals(1, requests.get());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void incompleteUpstreamDoesNotReplaceAnInvalidCache() throws Exception {
|
||||||
|
String incomplete = incompleteCatalog(completeCatalog());
|
||||||
|
AtomicInteger requests = new AtomicInteger();
|
||||||
|
HttpServer server = server(incomplete, requests);
|
||||||
|
try (URLClassLoader resources = resources();
|
||||||
|
RemoteLanguageCatalog catalog = catalog(server, resources)) {
|
||||||
|
Path cache = catalog.cacheFile(LOCALE);
|
||||||
|
Files.createDirectories(cache.getParent());
|
||||||
|
String cached = "{\"locale\":\"de_DE\",\"messages\":{}}";
|
||||||
|
Files.writeString(cache, cached);
|
||||||
|
|
||||||
|
IllegalArgumentException failure = assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> catalog.readOrDownload(LOCALE, IrisLanguage::validateDownload));
|
||||||
|
assertTrue(failure.getMessage().contains(MISSING_KEY));
|
||||||
|
assertEquals(cached, Files.readString(cache));
|
||||||
|
assertEquals(1, requests.get());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void incompleteUpstreamDoesNotCreateACacheFile() throws Exception {
|
||||||
|
AtomicInteger requests = new AtomicInteger();
|
||||||
|
HttpServer server = server(incompleteCatalog(completeCatalog()), requests);
|
||||||
|
try (URLClassLoader resources = resources();
|
||||||
|
RemoteLanguageCatalog catalog = catalog(server, resources)) {
|
||||||
|
assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> catalog.readOrDownload(LOCALE, IrisLanguage::validateDownload));
|
||||||
|
assertFalse(Files.exists(catalog.cacheFile(LOCALE)));
|
||||||
|
assertEquals(1, requests.get());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void partialOperatorOverridesRemainValid() {
|
||||||
|
LocaleOverlay overlay = IrisLanguage.parseOverlay("override", LOCALE, """
|
||||||
|
{"locale":"de_DE","messages":{"iris.command.unknown":"Unbekannter Iris-Befehl"}}
|
||||||
|
""");
|
||||||
|
|
||||||
|
assertEquals(1, overlay.values().size());
|
||||||
|
assertTrue(LocalizationValidator.validate(IrisLanguage.catalog(), List.of(overlay)).errors().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String completeCatalog() throws IOException {
|
||||||
|
return Files.readString(Path.of("src/main/resources/languages", LOCALE + ".json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String incompleteCatalog(String complete) {
|
||||||
|
JsonObject document = JsonParser.parseString(complete).getAsJsonObject();
|
||||||
|
assertTrue(document.getAsJsonObject("messages").remove(MISSING_KEY) != null);
|
||||||
|
return document.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpServer server(String content, AtomicInteger requests) throws IOException {
|
||||||
|
byte[] response = content.getBytes(StandardCharsets.UTF_8);
|
||||||
|
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||||
|
server.createContext("/master/languages/de_DE.json", exchange -> respond(exchange, response, requests));
|
||||||
|
server.start();
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void respond(HttpExchange exchange, byte[] response, AtomicInteger requests) throws IOException {
|
||||||
|
requests.incrementAndGet();
|
||||||
|
try {
|
||||||
|
exchange.sendResponseHeaders(200, response.length);
|
||||||
|
exchange.getResponseBody().write(response);
|
||||||
|
} finally {
|
||||||
|
exchange.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private URLClassLoader resources() throws IOException {
|
||||||
|
Path resources = temporaryFolder.newFolder().toPath();
|
||||||
|
Files.writeString(resources.resolve("source.properties"), "revision=master\nlocales=de_DE\n");
|
||||||
|
return new URLClassLoader(new URL[]{resources.toUri().toURL()}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RemoteLanguageCatalog catalog(HttpServer server, ClassLoader resources) throws IOException {
|
||||||
|
return RemoteLanguageCatalog.load(new RemoteLanguageCatalog.Options(
|
||||||
|
"Iris",
|
||||||
|
URI.create("http://127.0.0.1:" + server.getAddress().getPort() + "/"),
|
||||||
|
"languages",
|
||||||
|
".json",
|
||||||
|
"source.properties",
|
||||||
|
temporaryFolder.newFolder().toPath(),
|
||||||
|
resources
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -128,7 +128,32 @@ public class IrisLanguageTest {
|
|||||||
|
|
||||||
private LocaleOverlay loadSourceOverlay(String locale) throws Exception {
|
private LocaleOverlay loadSourceOverlay(String locale) throws Exception {
|
||||||
Path source = Path.of("src/main/resources/languages", locale + ".json");
|
Path source = Path.of("src/main/resources/languages", locale + ".json");
|
||||||
return IrisLanguage.parseOverlay(source.toString(), locale, Files.readString(source));
|
return IrisLanguage.parseDownloadedOverlay(source.toString(), locale, Files.readString(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void downloadedCatalogSelectsBukkitKeysWithoutAcceptingUnknownOverrides() {
|
||||||
|
String raw = """
|
||||||
|
{"locale":"de_DE","messages":{
|
||||||
|
"iris.command.unknown":"Unbekannter Iris-Befehl",
|
||||||
|
"iris.modded.help.entry.command.version":"Version anzeigen"
|
||||||
|
}}
|
||||||
|
""";
|
||||||
|
LocaleOverlay downloaded = IrisLanguage.parseDownloadedOverlay("download", "de_DE", raw);
|
||||||
|
assertEquals(Set.of(IrisMessages.COMMAND_UNKNOWN.id()), downloaded.values().keySet());
|
||||||
|
assertTrue(LocalizationValidator.validate(IrisLanguage.catalog(), List.of(downloaded)).errors().isEmpty());
|
||||||
|
LocaleOverlay override = IrisLanguage.parseOverlay("override", "de_DE", raw);
|
||||||
|
assertFalse(LocalizationValidator.validate(IrisLanguage.catalog(), List.of(override)).errors().isEmpty());
|
||||||
|
assertEquals("A pregeneration task is already running. Stop it first with /iris pregen stop.",
|
||||||
|
IrisLanguage.plain(IrisMessages.PREGEN_ALREADY_RUNNING));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void downloadedCatalogStillRejectsInvalidActivePlaceholders() {
|
||||||
|
LocaleOverlay downloaded = IrisLanguage.parseDownloadedOverlay("download", "de_DE", """
|
||||||
|
{"locale":"de_DE","messages":{"iris.command.permission_denied":"Keine Erlaubnis"}}
|
||||||
|
""");
|
||||||
|
assertFalse(LocalizationValidator.validate(IrisLanguage.catalog(), List.of(downloaded)).errors().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -231,7 +256,8 @@ public class IrisLanguageTest {
|
|||||||
}
|
}
|
||||||
assertValueIntegrity(locale, key.id(), key.englishValue(), overlay.value(key.id()));
|
assertValueIntegrity(locale, key.id(), key.englishValue(), overlay.value(key.id()));
|
||||||
}
|
}
|
||||||
assertTrue(locale + " contains too many English placeholder values", translated >= 1050);
|
assertTrue(locale + " contains too many English placeholder values",
|
||||||
|
translated * 10 >= IrisLanguage.catalog().keys().size() * 7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ if (irisUseLocalVolmLib && irisLocalVolmLibDirectory != null) {
|
|||||||
dependencySubstitution {
|
dependencySubstitution {
|
||||||
substitute(module('com.github.VolmitSoftware:VolmLib')).using(project(':shared'))
|
substitute(module('com.github.VolmitSoftware:VolmLib')).using(project(':shared'))
|
||||||
substitute(module('com.github.VolmitSoftware.VolmLib:shared')).using(project(':shared'))
|
substitute(module('com.github.VolmitSoftware.VolmLib:shared')).using(project(':shared'))
|
||||||
|
substitute(module('com.github.VolmitSoftware.VolmLib:packaging')).using(project(':packaging'))
|
||||||
substitute(module('com.github.VolmitSoftware.VolmLib:volmlib-shared')).using(project(':shared'))
|
substitute(module('com.github.VolmitSoftware.VolmLib:volmlib-shared')).using(project(':shared'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user