mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-12 03:24:14 +00:00
Compat report, validation and commands
- Force-load every registrant and placement during pack validation and persist the findings with the Minecraft version in the validation cache - Turn an excluded dimension into a blocking validation error and suppress content-key warnings the gate already reported - Print the capped per-key listing after the validation lines on Bukkit and modded, ordered excluded, dropped, substituted - Log one summary line per world engine from the published validation result - Add /iris pack compat on Bukkit and modded with help and locale keys for every shipped language
This commit is contained in:
+16
-2
@@ -60,6 +60,7 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public final class IrisWorldGeneratorResolver {
|
||||
private static final int VALIDATION_STABILITY_ATTEMPTS = 2;
|
||||
private static final int COMPAT_BOOT_KEY_CAP = 3;
|
||||
private static final Object SNAPSHOT_VALIDATION_LOCK = new Object();
|
||||
private static final String IRIS_DIMENSION_NAMESPACE = "iris";
|
||||
private static final String PLOT_SQUARED_DISCOVERY_WORLD = "CheckingPlotSquaredGenerator";
|
||||
@@ -123,6 +124,9 @@ public final class IrisWorldGeneratorResolver {
|
||||
if (packDirectory != null && packFingerprint != null && !packFingerprint.isBlank()) {
|
||||
PackValidationRegistry.publish(packDirectory.toPath(), result, packFingerprint);
|
||||
}
|
||||
String minecraftVersion = IrisPlatforms.isBound() ? IrisPlatforms.get().minecraftVersion() : null;
|
||||
String compatSummary = PackValidator.compatSummary(result, minecraftVersion);
|
||||
String compatSuffix = compatSummary.isEmpty() ? "" : " " + compatSummary;
|
||||
if (!result.isLoadable()) {
|
||||
Iris.error("Pack '" + result.getPackName()
|
||||
+ "' FAILED validation - world and Studio creation with this pack will be refused. Reasons:");
|
||||
@@ -131,12 +135,22 @@ public final class IrisWorldGeneratorResolver {
|
||||
}
|
||||
} else if (!result.getWarnings().isEmpty()) {
|
||||
Iris.info("Pack '" + result.getPackName() + "' validated ("
|
||||
+ result.getWarnings().size() + " warning(s)).");
|
||||
+ result.getWarnings().size() + " warning(s))." + compatSuffix);
|
||||
for (String warning : result.getWarnings()) {
|
||||
Iris.warn(" [" + result.getPackName() + "] " + warning);
|
||||
}
|
||||
} else if (cached.isEmpty()) {
|
||||
Iris.success("Pack '" + result.getPackName() + "' validated.");
|
||||
if (compatSummary.isEmpty()) {
|
||||
Iris.success("Pack '" + result.getPackName() + "' validated.");
|
||||
} else {
|
||||
Iris.info("Pack '" + result.getPackName() + "' validated." + compatSuffix);
|
||||
}
|
||||
} else if (!compatSummary.isEmpty()) {
|
||||
Iris.info("Pack '" + result.getPackName() + "' validated." + compatSuffix);
|
||||
}
|
||||
// Cache hits carry the persisted findings, so the listing prints on every boot, not only after a miss.
|
||||
for (String line : PackValidator.compatBootLines(result, minecraftVersion, COMPAT_BOOT_KEY_CAP)) {
|
||||
Iris.warn(line);
|
||||
}
|
||||
}
|
||||
IrisStartupValidation.markPacksReady();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.core.commands;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.compat.PackCompatReport;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.core.pack.PackResourceCleanup;
|
||||
import art.arcane.iris.core.pack.PackValidationCache;
|
||||
@@ -34,10 +35,13 @@ import art.arcane.volmlib.util.director.annotations.Director;
|
||||
import art.arcane.volmlib.util.director.annotations.Param;
|
||||
import art.arcane.volmlib.util.localization.TextKey;
|
||||
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import art.arcane.iris.core.localization.IrisLanguage;
|
||||
import art.arcane.iris.core.localization.BukkitCommandMessages;
|
||||
@@ -250,6 +254,76 @@ public class CommandPack implements DirectorExecutor {
|
||||
reportResult(s, result);
|
||||
}
|
||||
|
||||
@Director(description = "Show pack content that cannot generate on this Minecraft version", descriptionKey = "iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version", aliases = {"cp"})
|
||||
public void compat(
|
||||
@Param(description = "The pack folder name to report on, or * for every pack", descriptionKey = "iris.director.commandpack.param.pack_folder_name_compat", defaultValue = "*")
|
||||
String pack
|
||||
) {
|
||||
VolmitSender s = sender();
|
||||
if (wantsAllPacks(pack)) {
|
||||
Map<String, PackValidationResult> snapshot = PackValidationRegistry.snapshot();
|
||||
if (snapshot.isEmpty()) {
|
||||
s.sendMessage(IrisLanguage.text(BukkitRuntimeMessages.COMMAND_PACK_NO_VALIDATION_RESULTS_RECORDED_RUN_IRIS_PACK_VALIDATE_FIRST));
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<String, PackValidationResult> entry : snapshot.entrySet()) {
|
||||
for (String line : compatOutput(entry.getKey(), entry.getValue())) {
|
||||
s.sendMessage(line);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (String line : compatOutput(pack, PackValidationRegistry.get(pack))) {
|
||||
s.sendMessage(line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The compat listing for one pack, straight from the persisted validation so no pack is reloaded. Every key is
|
||||
* printed with every subject; the boot listing is the capped form of the same data.
|
||||
*/
|
||||
static List<String> compatOutput(String pack, PackValidationResult result) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
if (result == null) {
|
||||
lines.add(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_PACK_NO_VALIDATION_RESULT_RUN_IRIS_PACK_VALIDATE,
|
||||
MessageArgument.untrusted("pack", String.valueOf(pack)),
|
||||
MessageArgument.untrusted("pack2", String.valueOf(pack))));
|
||||
return lines;
|
||||
}
|
||||
String version = compatVersion(result);
|
||||
if (result.getCompatFindings().isEmpty()) {
|
||||
lines.add(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_PACK_COMPAT_NONE,
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("version", version)));
|
||||
return lines;
|
||||
}
|
||||
lines.add(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_PACK_COMPAT_HEADER,
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("version", version)));
|
||||
for (String line : PackCompatReport.of(result.getCompatFindings()).keyLines(0)) {
|
||||
lines.add(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_PACK_MESSAGE_2,
|
||||
MessageArgument.untrusted("value", line)));
|
||||
}
|
||||
lines.add(IrisLanguage.text(BukkitRuntimeMessages.COMMAND_PACK_COMPAT_REMEDY));
|
||||
return lines;
|
||||
}
|
||||
|
||||
/** The live Minecraft version, falling back to the one the validation ran against. */
|
||||
static String compatVersion(PackValidationResult result) {
|
||||
if (IrisPlatforms.isBound()) {
|
||||
String live = IrisPlatforms.get().minecraftVersion();
|
||||
if (live != null && !live.isBlank()) {
|
||||
return live;
|
||||
}
|
||||
}
|
||||
String persisted = result.getMinecraftVersion();
|
||||
return persisted == null || persisted.isBlank() ? "unknown" : persisted;
|
||||
}
|
||||
|
||||
private PackValidationResult runValidate(VolmitSender s, File packFolder) {
|
||||
try {
|
||||
PackValidationResult result = PackValidator.validate(packFolder);
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package art.arcane.iris.core.commands;
|
||||
|
||||
import art.arcane.iris.core.compat.CompatAction;
|
||||
import art.arcane.iris.core.compat.CompatFinding;
|
||||
import art.arcane.iris.core.compat.CompatRegistry;
|
||||
import art.arcane.iris.core.pack.PackValidationResult;
|
||||
import art.arcane.volmlib.util.director.compat.DirectorAnnotationCompatibility;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorNodeDescriptor;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorParameterDescriptor;
|
||||
import art.arcane.iris.spi.IrisPlatform;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CommandPackCompatTest {
|
||||
private IrisPlatform previousPlatform;
|
||||
|
||||
/** The persisted Minecraft version is only used when no platform is bound, so pin that here. */
|
||||
@Before
|
||||
public void unbindPlatform() {
|
||||
previousPlatform = IrisPlatforms.isBound() ? IrisPlatforms.get() : null;
|
||||
IrisPlatforms.unbind();
|
||||
}
|
||||
|
||||
@After
|
||||
public void rebindPlatform() {
|
||||
IrisPlatforms.unbind();
|
||||
if (previousPlatform != null) {
|
||||
IrisPlatforms.bind(previousPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
private static CompatFinding block(CompatAction action, String subjectKey) {
|
||||
return new CompatFinding(
|
||||
CompatRegistry.BLOCK, "minecraft:sulfur", action, "Biome", subjectKey, "layers[0].palette[1]");
|
||||
}
|
||||
|
||||
private static PackValidationResult result(List<CompatFinding> findings) {
|
||||
return new PackValidationResult("overworld", List.of(), List.of(), 1L, findings, "26.1.2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownPackIsReportedWithoutAnyCompatLines() {
|
||||
List<String> lines = CommandPack.compatOutput("nope", null);
|
||||
|
||||
assertEquals(1, lines.size());
|
||||
assertTrue(lines.getFirst(), lines.getFirst().contains("No validation result for 'nope'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packWithoutFindingsSaysSoAndNamesTheVersion() {
|
||||
List<String> lines = CommandPack.compatOutput("overworld", result(List.of()));
|
||||
|
||||
assertEquals(1, lines.size());
|
||||
assertTrue(lines.getFirst(), lines.getFirst().contains("Pack 'overworld' uses no content"));
|
||||
assertTrue(lines.getFirst(), lines.getFirst().contains("26.1.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findingsArePrintedUncappedWithTheFallbackRemedy() {
|
||||
List<String> lines = CommandPack.compatOutput("overworld", result(List.of(
|
||||
block(CompatAction.EXCLUDED, "cave/a"),
|
||||
block(CompatAction.EXCLUDED, "cave/b"),
|
||||
block(CompatAction.EXCLUDED, "cave/c"),
|
||||
block(CompatAction.EXCLUDED, "cave/d"))));
|
||||
|
||||
assertEquals(3, lines.size());
|
||||
assertTrue(lines.get(0), lines.get(0).contains("Pack 'overworld': content unavailable on Minecraft 26.1.2"));
|
||||
assertTrue(lines.get(1), lines.get(1).contains("minecraft:sulfur (block)"));
|
||||
assertFalse("the command prints every subject", lines.get(1).contains("more"));
|
||||
assertTrue(lines.get(1), lines.get(1).contains("cave/d"));
|
||||
assertTrue(lines.get(2), lines.get(2).contains("blockFallbacks"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compatIsInvocableWithoutAPackArgument() throws Exception {
|
||||
DirectorNodeDescriptor node = DirectorAnnotationCompatibility
|
||||
.fromMethod(CommandPack.class.getDeclaredMethod("compat", String.class))
|
||||
.orElseThrow();
|
||||
DirectorParameterDescriptor pack = node.getParameters().getFirst();
|
||||
|
||||
assertEquals("pack", pack.getName());
|
||||
assertFalse("compat must not require a pack", pack.isRequired());
|
||||
assertFalse("Director needs a non-blank default to treat the parameter as optional",
|
||||
pack.getDefaultValue().isBlank());
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import art.arcane.iris.core.pack.PackValidationRegistry;
|
||||
import art.arcane.iris.core.pack.PackValidationResult;
|
||||
import art.arcane.iris.core.pack.PackValidator;
|
||||
import art.arcane.iris.modded.command.ModdedPackCommands;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -41,6 +42,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class ModdedStartup {
|
||||
private static final int COMPAT_BOOT_KEY_CAP = 3;
|
||||
private static final AtomicBoolean PREPARED = new AtomicBoolean(false);
|
||||
private static final AtomicBoolean STARTED = new AtomicBoolean(false);
|
||||
|
||||
@@ -138,17 +140,23 @@ public final class ModdedStartup {
|
||||
try {
|
||||
PackValidationResult result = PackValidator.validate(packDir);
|
||||
PackValidationRegistry.publish(result);
|
||||
String minecraftVersion = IrisPlatforms.isBound() ? IrisPlatforms.get().minecraftVersion() : null;
|
||||
String compatSummary = PackValidator.compatSummary(result, minecraftVersion);
|
||||
String compatSuffix = compatSummary.isEmpty() ? "" : " " + compatSummary;
|
||||
if (!result.isLoadable()) {
|
||||
ModdedIrisLog.error("Iris pack '{}' FAILED validation with {} blocking error(s); world/studio creation will be refused. First error: {}",
|
||||
result.getPackName(), result.getBlockingErrors().size(),
|
||||
result.getBlockingErrors().getFirst());
|
||||
} else if (!result.getWarnings().isEmpty()) {
|
||||
ModdedIrisLog.info("Iris pack '{}' validated ({} warning(s)).", result.getPackName(), result.getWarnings().size());
|
||||
ModdedIrisLog.info("Iris pack '{}' validated ({} warning(s)).{}", result.getPackName(), result.getWarnings().size(), compatSuffix);
|
||||
for (String warning : result.getWarnings()) {
|
||||
ModdedIrisLog.warn(" [{}] {}", result.getPackName(), warning);
|
||||
}
|
||||
} else {
|
||||
ModdedIrisLog.info("Iris pack '{}' validated.", result.getPackName());
|
||||
ModdedIrisLog.info("Iris pack '{}' validated.{}", result.getPackName(), compatSuffix);
|
||||
}
|
||||
for (String line : PackValidator.compatBootLines(result, minecraftVersion, COMPAT_BOOT_KEY_CAP)) {
|
||||
ModdedIrisLog.warn("{}", line);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ModdedIrisLog.error("Iris pack validation failed for '{}'", packDir.getName(), e);
|
||||
|
||||
+2
-1
@@ -164,7 +164,8 @@ final class ModdedCommandHelp {
|
||||
Entry.command("validate", "[pack]", ModdedHelpMessages.COMMAND_VALIDATE_VALIDATE_A_PACK_OR_EVERY_PACK, "v"),
|
||||
Entry.command("cleanup", "<pack> [apply]", ModdedHelpMessages.COMMAND_CLEANUP_PREVIEW_OR_QUARANTINE_UNUSED_RESOURCE_CANDIDATES, "c"),
|
||||
Entry.command("restore", "<pack> [apply]", ModdedHelpMessages.COMMAND_RESTORE_PREVIEW_OR_RESTORE_THE_LATEST_QUARANTINE, "r"),
|
||||
Entry.command("status", "[pack]", ModdedHelpMessages.COMMAND_STATUS_SHOW_CACHED_VALIDATION_STATUS, "s")
|
||||
Entry.command("status", "[pack]", ModdedHelpMessages.COMMAND_STATUS_SHOW_CACHED_VALIDATION_STATUS, "s"),
|
||||
Entry.command("compat", "[pack]", ModdedHelpMessages.COMMAND_COMPAT_SHOW_CONTENT_THAT_CANNOT_GENERATE_ON_THIS_MINECRAFT_VERSION, "cp")
|
||||
));
|
||||
SECTIONS.put("pk", SECTIONS.get("pack"));
|
||||
SECTIONS.put("world", List.of(
|
||||
|
||||
+81
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.modded.ModdedIrisLog;
|
||||
import art.arcane.iris.core.compat.PackCompatReport;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.core.pack.PackResourceCleanup;
|
||||
@@ -93,6 +94,15 @@ public final class ModdedPackCommands {
|
||||
.then(Commands.argument("pack", StringArgumentType.word()).suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> status(context.getSource(), StringArgumentType.getString(context, "pack")))));
|
||||
|
||||
root.then(Commands.literal("compat")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> compat(context.getSource(), null))
|
||||
.then(Commands.argument("pack", StringArgumentType.word()).suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> compat(context.getSource(), StringArgumentType.getString(context, "pack")))));
|
||||
root.then(Commands.literal("cp")
|
||||
.executes((CommandContext<CommandSourceStack> context) -> compat(context.getSource(), null))
|
||||
.then(Commands.argument("pack", StringArgumentType.word()).suggests(IrisModdedCommands.PACK_NAMES)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> compat(context.getSource(), StringArgumentType.getString(context, "pack")))));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -215,6 +225,77 @@ public final class ModdedPackCommands {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int compat(CommandSourceStack source, String pack) {
|
||||
if (pack == null || pack.isBlank()) {
|
||||
Map<String, PackValidationResult> snapshot = PackValidationRegistry.snapshot();
|
||||
if (snapshot.isEmpty()) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_PACK_COMMANDS_NO_VALIDATION_RESULTS_RECORDED_RUN_IRIS_PACK_VALIDATE_FIRST));
|
||||
return 0;
|
||||
}
|
||||
for (Map.Entry<String, PackValidationResult> entry : snapshot.entrySet()) {
|
||||
for (String line : compatOutput(entry.getKey(), entry.getValue())) {
|
||||
IrisModdedCommands.ok(source, line);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
PackValidationResult result = PackValidationRegistry.get(pack);
|
||||
for (String line : compatOutput(pack, result)) {
|
||||
if (result == null) {
|
||||
IrisModdedCommands.fail(source, line);
|
||||
} else {
|
||||
IrisModdedCommands.ok(source, line);
|
||||
}
|
||||
}
|
||||
return result == null ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The compat listing for one pack, straight from the persisted validation so no pack is reloaded. Every key is
|
||||
* printed with every subject; the boot listing is the capped form of the same data.
|
||||
*/
|
||||
static List<String> compatOutput(String pack, PackValidationResult result) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
if (result == null) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_PACK_COMMANDS_NO_VALIDATION_RESULT_RUN_IRIS_PACK_VALIDATE,
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("pack2", pack)));
|
||||
return lines;
|
||||
}
|
||||
String version = compatVersion(result);
|
||||
if (result.getCompatFindings().isEmpty()) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_PACK_COMMANDS_COMPAT_NONE,
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("version", version)));
|
||||
return lines;
|
||||
}
|
||||
lines.add(IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_PACK_COMMANDS_COMPAT_HEADER,
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("version", version)));
|
||||
for (String line : PackCompatReport.of(result.getCompatFindings()).keyLines(0)) {
|
||||
lines.add(IrisLanguage.plain(
|
||||
ModdedCommandMessages.MODDED_PACK_COMMANDS_MESSAGE_2,
|
||||
MessageArgument.untrusted("value", line)));
|
||||
}
|
||||
lines.add(IrisLanguage.plain(ModdedCommandMessages.MODDED_PACK_COMMANDS_COMPAT_REMEDY));
|
||||
return lines;
|
||||
}
|
||||
|
||||
/** The live Minecraft version, falling back to the one the validation ran against. */
|
||||
static String compatVersion(PackValidationResult result) {
|
||||
if (IrisPlatforms.isBound()) {
|
||||
String live = IrisPlatforms.get().minecraftVersion();
|
||||
if (live != null && !live.isBlank()) {
|
||||
return live;
|
||||
}
|
||||
}
|
||||
String persisted = result.getMinecraftVersion();
|
||||
return persisted == null || persisted.isBlank() ? "unknown" : persisted;
|
||||
}
|
||||
|
||||
private static void report(CommandSourceStack source, PackValidationResult result) {
|
||||
if (result.isLoadable()) {
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_PACK_COMMANDS_PACK_IS_LOADABLE_WARNINGS, MessageArgument.untrusted("value", result.getPackName()), MessageArgument.untrusted("value2", result.getWarnings().size())));
|
||||
|
||||
@@ -158,6 +158,19 @@ public final class BukkitRuntimeMessages {
|
||||
"other", C.GRAY + " ... and {count} more warnings."
|
||||
)
|
||||
);
|
||||
public static final TextKey COMMAND_PACK_COMPAT_HEADER = TextKey.of(
|
||||
"iris.bukkit.runtime.commandpack.compat_header",
|
||||
C.YELLOW + "Pack '" + "{pack}" + "': content unavailable on Minecraft " + "{version}"
|
||||
);
|
||||
public static final TextKey COMMAND_PACK_COMPAT_NONE = TextKey.of(
|
||||
"iris.bukkit.runtime.commandpack.compat_none",
|
||||
C.GREEN + "Pack '" + "{pack}" + "' uses no content that is unavailable on Minecraft " + "{version}" + "."
|
||||
);
|
||||
public static final TextKey COMMAND_PACK_COMPAT_REMEDY = TextKey.of(
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy",
|
||||
C.GRAY + "Update the server to a newer Minecraft to restore this content, or declare fallbacks"
|
||||
+ " (dimension blockFallbacks, block backup)."
|
||||
);
|
||||
public static final LinesKey COMMAND_DEVELOPER_UPDATE_WORLD_WARNING = LinesKey.of(
|
||||
"iris.bukkit.runtime.commanddeveloper.update_world_warning",
|
||||
C.RED + "You should always make a backup before using this",
|
||||
@@ -644,6 +657,9 @@ public final class BukkitRuntimeMessages {
|
||||
COMMAND_PACK_MESSAGE,
|
||||
COMMAND_PACK_MESSAGE_2,
|
||||
COMMAND_PACK_MORE_WARNING_S,
|
||||
COMMAND_PACK_COMPAT_HEADER,
|
||||
COMMAND_PACK_COMPAT_NONE,
|
||||
COMMAND_PACK_COMPAT_REMEDY,
|
||||
COMMAND_DEVELOPER_UPDATE_WORLD_WARNING,
|
||||
BULK_STRUCTURE_IMPORTER_IMPORTING_VANILLA_DATAPACK_STRUCTURES_MODE_INCLUDENONJIGSAW,
|
||||
BULK_STRUCTURE_IMPORTER_FAIL_INVALID_KEY,
|
||||
|
||||
@@ -570,6 +570,14 @@ public final class DirectorCommandMessages {
|
||||
"iris.director.commandpack.param.pack_folder_name",
|
||||
"The pack folder name"
|
||||
);
|
||||
public static final TextKey COMMAND_PACK_DIRECTOR_SHOW_CONTENT_CANNOT_GENERATE_THIS_MINECRAFT_VERSION = TextKey.of(
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version",
|
||||
"Show pack content that cannot generate on this Minecraft version"
|
||||
);
|
||||
public static final TextKey COMMAND_PACK_PARAM_PACK_FOLDER_NAME_COMPAT = TextKey.of(
|
||||
"iris.director.commandpack.param.pack_folder_name_compat",
|
||||
"The pack folder name to report on"
|
||||
);
|
||||
public static final TextKey COMMAND_PREGEN_DIRECTOR_PREGENERATE_YOUR_IRIS_WORLDS = TextKey.of(
|
||||
"iris.director.commandpregen.director.pregenerate_your_iris_worlds",
|
||||
"Pregenerate your Iris worlds!"
|
||||
@@ -1005,6 +1013,8 @@ public final class DirectorCommandMessages {
|
||||
COMMAND_PACK_PARAM_PREVIEW_APPLY_2,
|
||||
COMMAND_PACK_DIRECTOR_SHOW_CACHED_VALIDATION_STATUS_PACK,
|
||||
COMMAND_PACK_PARAM_PACK_FOLDER_NAME,
|
||||
COMMAND_PACK_DIRECTOR_SHOW_CONTENT_CANNOT_GENERATE_THIS_MINECRAFT_VERSION,
|
||||
COMMAND_PACK_PARAM_PACK_FOLDER_NAME_COMPAT,
|
||||
COMMAND_PREGEN_DIRECTOR_PREGENERATE_YOUR_IRIS_WORLDS,
|
||||
COMMAND_PREGEN_DIRECTOR_PREGENERATE_WORLD,
|
||||
COMMAND_PREGEN_PARAM_RADIUS_PREGEN_BLOCKS,
|
||||
|
||||
@@ -771,6 +771,19 @@ public final class ModdedCommandMessages {
|
||||
"iris.modded.moddedpackcommands.message_2",
|
||||
" ! " + "{value}"
|
||||
);
|
||||
public static final TextKey MODDED_PACK_COMMANDS_COMPAT_HEADER = TextKey.of(
|
||||
"iris.modded.moddedpackcommands.compat_header",
|
||||
"Pack '" + "{pack}" + "': content unavailable on Minecraft " + "{version}"
|
||||
);
|
||||
public static final TextKey MODDED_PACK_COMMANDS_COMPAT_NONE = TextKey.of(
|
||||
"iris.modded.moddedpackcommands.compat_none",
|
||||
"Pack '" + "{pack}" + "' uses no content that is unavailable on Minecraft " + "{version}" + "."
|
||||
);
|
||||
public static final TextKey MODDED_PACK_COMMANDS_COMPAT_REMEDY = TextKey.of(
|
||||
"iris.modded.moddedpackcommands.compat_remedy",
|
||||
"Update the server to a newer Minecraft to restore this content, or declare fallbacks"
|
||||
+ " (dimension blockFallbacks, block backup)."
|
||||
);
|
||||
public static final TextKey MODDED_PACK_COMMANDS_MORE_WARNING_S = TextKey.of(
|
||||
"iris.modded.moddedpackcommands.more_warning_s",
|
||||
" ... and " + "{value}" + " more warning(s)."
|
||||
@@ -1432,6 +1445,9 @@ public final class ModdedCommandMessages {
|
||||
MODDED_PACK_COMMANDS_PACK_IS_BROKEN,
|
||||
MODDED_PACK_COMMANDS_MESSAGE,
|
||||
MODDED_PACK_COMMANDS_MESSAGE_2,
|
||||
MODDED_PACK_COMMANDS_COMPAT_HEADER,
|
||||
MODDED_PACK_COMMANDS_COMPAT_NONE,
|
||||
MODDED_PACK_COMMANDS_COMPAT_REMEDY,
|
||||
MODDED_PACK_COMMANDS_MORE_WARNING_S,
|
||||
MODDED_PACK_COMMANDS_NO_CLEANUP_CANDIDATES_FOUND_PACK,
|
||||
MODDED_PACK_COMMANDS_CLEANUP_PREVIEW_PACK_CANDIDATE_S_NO_FILES_WERE_CHANGED,
|
||||
|
||||
@@ -278,6 +278,10 @@ public final class ModdedHelpMessages {
|
||||
"iris.modded.help.entry.command.status_validation",
|
||||
"Show cached validation status"
|
||||
);
|
||||
public static final TextKey COMMAND_COMPAT_SHOW_CONTENT_THAT_CANNOT_GENERATE_ON_THIS_MINECRAFT_VERSION = TextKey.of(
|
||||
"iris.modded.help.entry.command.compat_content",
|
||||
"Show content that cannot generate on this Minecraft version"
|
||||
);
|
||||
public static final TextKey COMMAND_ENABLE_CREATE_AND_INJECT_A_PERSISTENT_IRIS_DIMENSION_AT_RUNTIME_DOWNLOADS_THE_PACK = TextKey.of(
|
||||
"iris.modded.help.entry.command.enable",
|
||||
"Create and inject a persistent Iris dimension at runtime; refuses if the pack is missing, quote pack:dimensionKey to pick a specific pack dimension"
|
||||
@@ -484,6 +488,7 @@ public final class ModdedHelpMessages {
|
||||
COMMAND_CLEANUP_PREVIEW_OR_QUARANTINE_UNUSED_RESOURCE_CANDIDATES,
|
||||
COMMAND_RESTORE_PREVIEW_OR_RESTORE_THE_LATEST_QUARANTINE,
|
||||
COMMAND_STATUS_SHOW_CACHED_VALIDATION_STATUS,
|
||||
COMMAND_COMPAT_SHOW_CONTENT_THAT_CANNOT_GENERATE_ON_THIS_MINECRAFT_VERSION,
|
||||
COMMAND_ENABLE_CREATE_AND_INJECT_A_PERSISTENT_IRIS_DIMENSION_AT_RUNTIME_DOWNLOADS_THE_PACK,
|
||||
COMMAND_REPLACE_OVERWORLD_INJECT_AN_IRIS_PRIMARY_WORLD_AND_ROUTE_PLAYERS_THERE_INSTEAD_OF_THE,
|
||||
COMMAND_DISABLE_EVACUATE_AND_UNLOAD_AN_IRIS_DIMENSION_WORLD_DATA_ON_DISK_IS_KEPT,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package art.arcane.iris.core.pack;
|
||||
|
||||
import art.arcane.iris.core.ServerConfigurator;
|
||||
import art.arcane.iris.core.compat.CompatAction;
|
||||
import art.arcane.iris.core.compat.CompatFinding;
|
||||
import art.arcane.iris.core.compat.CompatRegistry;
|
||||
import art.arcane.iris.spi.IrisPlatform;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.spi.PlatformRegistries;
|
||||
@@ -28,7 +31,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public final class PackValidationCache {
|
||||
private static final int SCHEMA_VERSION = 2;
|
||||
private static final int SCHEMA_VERSION = 3;
|
||||
private static final long MAX_CACHE_BYTES = 16L * 1024L * 1024L;
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
@@ -105,11 +108,17 @@ public final class PackValidationCache {
|
||||
|| !actual.add(cached.packName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
List<CompatFinding> findings = readFindings(cached.compatFindings);
|
||||
if (findings == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
results.add(new PackValidationResult(
|
||||
cached.packName,
|
||||
cached.blockingErrors,
|
||||
cached.warnings,
|
||||
cached.validatedAtMillis));
|
||||
cached.validatedAtMillis,
|
||||
findings,
|
||||
cached.minecraftVersion));
|
||||
}
|
||||
if (!expected.equals(actual)) {
|
||||
return Optional.empty();
|
||||
@@ -144,6 +153,8 @@ public final class PackValidationCache {
|
||||
cached.blockingErrors = List.copyOf(result.getBlockingErrors());
|
||||
cached.warnings = List.copyOf(result.getWarnings());
|
||||
cached.validatedAtMillis = result.getValidatedAtMillis();
|
||||
cached.minecraftVersion = result.getMinecraftVersion();
|
||||
cached.compatFindings = writeFindings(result.getCompatFindings());
|
||||
state.results.add(cached);
|
||||
}
|
||||
|
||||
@@ -167,6 +178,48 @@ public final class PackValidationCache {
|
||||
}
|
||||
}
|
||||
|
||||
/** Null when a persisted finding is malformed; the caller discards the whole cache file. */
|
||||
private static List<CompatFinding> readFindings(List<CachedFinding> cached) {
|
||||
if (cached == null) {
|
||||
return List.of();
|
||||
}
|
||||
List<CompatFinding> findings = new ArrayList<>(cached.size());
|
||||
for (CachedFinding finding : cached) {
|
||||
if (finding == null || finding.key == null || finding.registry == null || finding.action == null) {
|
||||
return null;
|
||||
}
|
||||
CompatRegistry registry;
|
||||
CompatAction action;
|
||||
try {
|
||||
registry = CompatRegistry.valueOf(finding.registry);
|
||||
action = CompatAction.valueOf(finding.action);
|
||||
} catch (IllegalArgumentException unknownEnum) {
|
||||
return null;
|
||||
}
|
||||
findings.add(new CompatFinding(
|
||||
registry, finding.key, action, finding.subjectType, finding.subjectKey, finding.detail));
|
||||
}
|
||||
return List.copyOf(findings);
|
||||
}
|
||||
|
||||
private static List<CachedFinding> writeFindings(List<CompatFinding> findings) {
|
||||
if (findings == null || findings.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
List<CachedFinding> cached = new ArrayList<>(findings.size());
|
||||
for (CompatFinding finding : findings) {
|
||||
CachedFinding entry = new CachedFinding();
|
||||
entry.registry = finding.registry().name();
|
||||
entry.key = finding.key();
|
||||
entry.action = finding.action().name();
|
||||
entry.subjectType = finding.subjectType();
|
||||
entry.subjectKey = finding.subjectKey();
|
||||
entry.detail = finding.detail();
|
||||
cached.add(entry);
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
private static void updateSorted(MessageDigest digest, List<String> values) {
|
||||
List<String> sorted = new ArrayList<>(Objects.requireNonNull(values, "Pack validation registry keys"));
|
||||
sorted.sort(String::compareTo);
|
||||
@@ -197,5 +250,16 @@ public final class PackValidationCache {
|
||||
private List<String> blockingErrors;
|
||||
private List<String> warnings;
|
||||
private long validatedAtMillis;
|
||||
private String minecraftVersion;
|
||||
private List<CachedFinding> compatFindings;
|
||||
}
|
||||
|
||||
private static final class CachedFinding {
|
||||
private String registry;
|
||||
private String key;
|
||||
private String action;
|
||||
private String subjectType;
|
||||
private String subjectKey;
|
||||
private String detail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
package art.arcane.iris.core.pack;
|
||||
|
||||
import art.arcane.iris.core.compat.CompatFinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -27,15 +29,29 @@ public final class PackValidationResult {
|
||||
private final List<String> blockingErrors;
|
||||
private final List<String> warnings;
|
||||
private final long validatedAtMillis;
|
||||
private final List<CompatFinding> compatFindings;
|
||||
private final String minecraftVersion;
|
||||
|
||||
/** Result without version-content gating data; used where the pack was never loaded through the gate. */
|
||||
public PackValidationResult(String packName,
|
||||
List<String> blockingErrors,
|
||||
List<String> warnings,
|
||||
long validatedAtMillis) {
|
||||
this(packName, blockingErrors, warnings, validatedAtMillis, List.of(), null);
|
||||
}
|
||||
|
||||
public PackValidationResult(String packName,
|
||||
List<String> blockingErrors,
|
||||
List<String> warnings,
|
||||
long validatedAtMillis,
|
||||
List<CompatFinding> compatFindings,
|
||||
String minecraftVersion) {
|
||||
this.packName = packName;
|
||||
this.blockingErrors = blockingErrors == null ? new ArrayList<>() : new ArrayList<>(blockingErrors);
|
||||
this.warnings = warnings == null ? new ArrayList<>() : new ArrayList<>(warnings);
|
||||
this.validatedAtMillis = validatedAtMillis;
|
||||
this.compatFindings = compatFindings == null ? List.of() : List.copyOf(compatFindings);
|
||||
this.minecraftVersion = minecraftVersion;
|
||||
}
|
||||
|
||||
public String getPackName() {
|
||||
@@ -57,4 +73,14 @@ public final class PackValidationResult {
|
||||
public long getValidatedAtMillis() {
|
||||
return validatedAtMillis;
|
||||
}
|
||||
|
||||
/** Every version-content gating decision recorded while this pack was validated. */
|
||||
public List<CompatFinding> getCompatFindings() {
|
||||
return compatFindings;
|
||||
}
|
||||
|
||||
/** The raw {@code IrisPlatform.minecraftVersion()} the gate ran against, or null when it did not run. */
|
||||
public String getMinecraftVersion() {
|
||||
return minecraftVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,30 @@
|
||||
|
||||
package art.arcane.iris.core.pack;
|
||||
|
||||
import art.arcane.iris.core.compat.CompatFinding;
|
||||
import art.arcane.iris.core.compat.PackCompatReport;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.loader.IrisRegistrant;
|
||||
import art.arcane.iris.core.loader.ResourceLoader;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisImage;
|
||||
import art.arcane.iris.engine.object.IrisObject;
|
||||
import art.arcane.iris.engine.object.IrisObjectPlacement;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.engine.object.matter.IrisMatterObject;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class PackValidator {
|
||||
@@ -40,6 +61,14 @@ public final class PackValidator {
|
||||
static final List<String> REMOVED_WORLDGEN_FIELDS = List.of("fluidBodies");
|
||||
static final List<String> UNSUPPORTED_STRUCTURE_TRANSFORM_FIELDS = List.of("rotation", "translate", "scale");
|
||||
static final Pattern RESOURCE_KEY_PATTERN = Pattern.compile("[a-z0-9_.-]+:[a-z0-9/._-]+");
|
||||
private static final int BLOCKING_REASON_LIMIT = 3;
|
||||
/**
|
||||
* Binary assets, not key-bearing registrants: an object is gated through the placements that can place it
|
||||
* (palette header only) and images carry no registry keys, so loading every one of them here would parse the
|
||||
* whole object library for nothing.
|
||||
*/
|
||||
private static final Set<Class<?>> UNGATED_LOADERS =
|
||||
Set.of(IrisObject.class, IrisMatterObject.class, IrisImage.class);
|
||||
|
||||
private PackValidator() {
|
||||
}
|
||||
@@ -124,7 +153,184 @@ public final class PackValidator {
|
||||
addDistinct(ContentKeyValidator.strictContent() ? blockingErrors : warnings, contentKeys.strict());
|
||||
addDistinct(warnings, contentKeys.advisory());
|
||||
|
||||
return new PackValidationResult(packName, blockingErrors, warnings, validatedAt);
|
||||
String minecraftVersion = validateLiveRegistries && IrisPlatforms.isBound()
|
||||
? IrisPlatforms.get().minecraftVersion()
|
||||
: null;
|
||||
List<CompatFinding> compatFindings = validateLiveRegistries
|
||||
? gateContent(packFolder, dimensionFiles, minecraftVersion, blockingErrors, warnings)
|
||||
: List.of();
|
||||
|
||||
return new PackValidationResult(
|
||||
packName, blockingErrors, warnings, validatedAt, compatFindings, minecraftVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a complete load of the pack through {@link IrisData} so every registrant and every reachable
|
||||
* {@link IrisObjectPlacement} is evaluated by the version-content gate, then folds the resulting findings into
|
||||
* this validation. Runs on a detached loader that is closed again, and only on a cache miss (the caller's cache
|
||||
* fingerprint already covers the Minecraft version and the registry key sets).
|
||||
*/
|
||||
private static List<CompatFinding> gateContent(
|
||||
File packFolder,
|
||||
File[] dimensionFiles,
|
||||
String minecraftVersion,
|
||||
List<String> blockingErrors,
|
||||
List<String> warnings
|
||||
) {
|
||||
if (!IrisPlatforms.isBound()) {
|
||||
return List.of();
|
||||
}
|
||||
IrisData data = null;
|
||||
try {
|
||||
data = IrisData.openRuntime(packFolder);
|
||||
if (!data.getContentGate().ready()) {
|
||||
return List.of();
|
||||
}
|
||||
boolean dimensionExcluded = loadEverything(data, dimensionFiles);
|
||||
List<CompatFinding> findings = data.getCompatReport().findings();
|
||||
applyCompatFindings(minecraftVersion, dimensionExcluded, findings, blockingErrors, warnings);
|
||||
return findings;
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError("Version-content gating failed for pack '" + packFolder.getName() + "'", e);
|
||||
return List.of();
|
||||
} finally {
|
||||
if (data != null) {
|
||||
try {
|
||||
data.close();
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads every registrant of every loader type (dimensions first, so dimension-level fallbacks are in place before
|
||||
* anything else resolves) and evaluates every placement reachable from the dimensions, regions and biomes.
|
||||
*
|
||||
* @return true when any dimension in the pack cannot generate on this server
|
||||
*/
|
||||
private static boolean loadEverything(IrisData data, File[] dimensionFiles) {
|
||||
boolean dimensionExcluded = false;
|
||||
for (File dimensionFile : dimensionFiles) {
|
||||
IrisDimension dimension = data.getDimensionLoader().load(
|
||||
PackValidationIo.stripExtension(dimensionFile.getName()), false);
|
||||
if (dimension != null && dimension.isCompatExcluded()) {
|
||||
dimensionExcluded = true;
|
||||
}
|
||||
}
|
||||
|
||||
Set<IrisObjectPlacement> placements = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
for (Map.Entry<Class<? extends IrisRegistrant>, ResourceLoader<? extends IrisRegistrant>> entry
|
||||
: data.getLoaders().entrySet()) {
|
||||
if (UNGATED_LOADERS.contains(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
for (String key : entry.getValue().getPossibleKeys()) {
|
||||
collectPlacements(entry.getValue().load(key, false), placements);
|
||||
}
|
||||
}
|
||||
for (IrisObjectPlacement placement : placements) {
|
||||
placement.evaluateCompat(data);
|
||||
}
|
||||
return dimensionExcluded;
|
||||
}
|
||||
|
||||
private static void collectPlacements(IrisRegistrant registrant, Set<IrisObjectPlacement> out) {
|
||||
if (registrant instanceof IrisBiome biome) {
|
||||
addPlacements(biome.getObjects(), out);
|
||||
return;
|
||||
}
|
||||
if (registrant instanceof IrisRegion region) {
|
||||
addPlacements(region.getObjects(), out);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addPlacements(Collection<IrisObjectPlacement> placements, Set<IrisObjectPlacement> out) {
|
||||
if (placements == null) {
|
||||
return;
|
||||
}
|
||||
for (IrisObjectPlacement placement : placements) {
|
||||
if (placement != null) {
|
||||
out.add(placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns gate findings into validation output: an excluded dimension is blocking, and any
|
||||
* {@link ContentKeyValidator} warning about a key the gate already reported is dropped so the operator does not
|
||||
* read the same missing key twice.
|
||||
*/
|
||||
static void applyCompatFindings(
|
||||
String minecraftVersion,
|
||||
boolean dimensionExcluded,
|
||||
List<CompatFinding> findings,
|
||||
List<String> blockingErrors,
|
||||
List<String> warnings
|
||||
) {
|
||||
if (dimensionExcluded) {
|
||||
addDistinct(blockingErrors, List.of(excludedDimensionError(minecraftVersion, findings)));
|
||||
}
|
||||
if (findings == null || findings.isEmpty() || warnings == null) {
|
||||
return;
|
||||
}
|
||||
Set<String> reported = new LinkedHashSet<>();
|
||||
for (CompatFinding finding : findings) {
|
||||
reported.add("'" + finding.key() + "'");
|
||||
}
|
||||
warnings.removeIf(warning -> {
|
||||
for (String quoted : reported) {
|
||||
if (warning.contains(quoted)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/** {@code Pack cannot generate on Minecraft 26.1.2: minecraft:sulfur (block), minecraft:camel (entity)} */
|
||||
static String excludedDimensionError(String minecraftVersion, List<CompatFinding> findings) {
|
||||
StringBuilder sb = new StringBuilder(96);
|
||||
sb.append("Pack cannot generate on Minecraft ")
|
||||
.append(minecraftVersion == null || minecraftVersion.isBlank() ? "unknown" : minecraftVersion)
|
||||
.append(": ");
|
||||
Set<String> reasons = new LinkedHashSet<>();
|
||||
if (findings != null) {
|
||||
for (CompatFinding finding : findings) {
|
||||
if (reasons.size() == BLOCKING_REASON_LIMIT) {
|
||||
break;
|
||||
}
|
||||
reasons.add(finding.key() + " (" + finding.registry().label() + ")");
|
||||
}
|
||||
}
|
||||
sb.append(reasons.isEmpty() ? "the dimension composes content this server does not have"
|
||||
: String.join(", ", reasons));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Boot listing for a validated pack; empty when the gate found nothing. */
|
||||
public static List<String> compatBootLines(PackValidationResult result, String minecraftVersion, int perKeyCap) {
|
||||
if (result == null || result.getCompatFindings().isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
return PackCompatReport.of(result.getCompatFindings())
|
||||
.bootLines(result.getPackName(), versionOf(result, minecraftVersion), perKeyCap);
|
||||
}
|
||||
|
||||
/** One-line compat summary appended to the {@code Pack 'x' validated (...)} line; empty when nothing to say. */
|
||||
public static String compatSummary(PackValidationResult result, String minecraftVersion) {
|
||||
if (result == null || result.getCompatFindings().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return PackCompatReport.of(result.getCompatFindings())
|
||||
.summaryLine(versionOf(result, minecraftVersion));
|
||||
}
|
||||
|
||||
private static String versionOf(PackValidationResult result, String minecraftVersion) {
|
||||
if (minecraftVersion != null && !minecraftVersion.isBlank()) {
|
||||
return minecraftVersion;
|
||||
}
|
||||
return result.getMinecraftVersion();
|
||||
}
|
||||
|
||||
private static void addDistinct(List<String> destination, List<String> additions) {
|
||||
|
||||
@@ -39,6 +39,9 @@ import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisEngineData;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.core.compat.PackCompatReport;
|
||||
import art.arcane.iris.core.pack.PackValidationResult;
|
||||
import art.arcane.iris.core.pack.PackValidationRegistry;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import com.google.common.util.concurrent.AtomicDouble;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
@@ -66,6 +69,7 @@ import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
@@ -234,6 +238,7 @@ public class IrisEngine implements Engine {
|
||||
EngineRuntime initialRuntime = runtimeBuilder.buildRuntime();
|
||||
runtimeBuilder.publishRuntime(initialRuntime, null);
|
||||
IrisLogging.debug("[IrisEngine timing] setupEngine total=" + (M.ms() - _t0) + "ms");
|
||||
logPackCompatSummary();
|
||||
logStudioInitializationPhase("build_runtime", phaseStartedAt, false);
|
||||
phaseStartedAt = System.nanoTime();
|
||||
if (requiredMode.warmGenerationCaches()) {
|
||||
@@ -254,6 +259,38 @@ public class IrisEngine implements Engine {
|
||||
IrisLogging.debug("Engine Initialized " + getCacheID());
|
||||
}
|
||||
|
||||
/**
|
||||
* One line per engine naming what this pack cannot generate on the running Minecraft version. The published
|
||||
* validation result is complete (validation force-loads the whole pack), so it is preferred; an unvalidated pack
|
||||
* falls back to what this engine has gated while building its runtime (dimension, regions, biomes). Never throws:
|
||||
* a report failure must not take an otherwise working world down with it.
|
||||
*/
|
||||
private void logPackCompatSummary() {
|
||||
try {
|
||||
File folder = getData().getDataFolder();
|
||||
// A world engine reads its snapshot copy under <world>/iris/pack, so the dimension key is the pack's name.
|
||||
String pack = getDimension().getLoadKey();
|
||||
String world = target.getWorld().name();
|
||||
String version = IrisPlatforms.isBound() ? IrisPlatforms.get().minecraftVersion() : null;
|
||||
PackValidationResult published = PackValidationRegistry.get(folder.toPath());
|
||||
if (published == null) {
|
||||
published = PackValidationRegistry.get(folder.getName());
|
||||
}
|
||||
PackCompatReport report = published != null && !published.getCompatFindings().isEmpty()
|
||||
? PackCompatReport.of(published.getCompatFindings())
|
||||
: getData().getCompatReport();
|
||||
if (!report.isEmpty()) {
|
||||
IrisLogging.info("World '" + world + "' pack '" + pack + "' " + report.summaryLine(version));
|
||||
}
|
||||
if (getDimension().isCompatExcluded()) {
|
||||
IrisLogging.error("World '" + world + "' pack '" + pack + "' cannot generate on Minecraft "
|
||||
+ (version == null || version.isBlank() ? "unknown" : version));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.debug("Pack compat summary failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void awaitGenerationCacheWarm() {
|
||||
if (generationCacheWarm.isDone() && !generationCacheWarm.isCompletedExceptionally()) {
|
||||
return;
|
||||
@@ -682,7 +719,8 @@ public class IrisEngine implements Engine {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getData().getBiomeLoader().load(getDimension().getFocus());
|
||||
IrisBiome focus = getData().getBiomeLoader().load(getDimension().getFocus());
|
||||
return focus == null || focus.isCompatExcluded() ? null : focus;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -691,7 +729,8 @@ public class IrisEngine implements Engine {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getData().getRegionLoader().load(getDimension().getFocusRegion());
|
||||
IrisRegion focus = getData().getRegionLoader().load(getDimension().getFocusRegion());
|
||||
return focus == null || focus.isCompatExcluded() ? null : focus;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Pack-Inhalte anzeigen, die in dieser Minecraft-Version nicht generiert werden können",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Der Pack-Ordnername für den Bericht",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePack '{pack}': Inhalte in Minecraft {version} nicht verfügbar",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aPack '{pack}' verwendet keine Inhalte, die in Minecraft {version} fehlen.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Aktualisiere den Server auf ein neueres Minecraft, um diese Inhalte wiederherzustellen, oder deklariere Ersatzwerte (Dimension blockFallbacks, Block backup).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Pack '{pack}': Inhalte in Minecraft {version} nicht verfügbar",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Pack '{pack}' verwendet keine Inhalte, die in Minecraft {version} fehlen.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Aktualisiere den Server auf ein neueres Minecraft, um diese Inhalte wiederherzustellen, oder deklariere Ersatzwerte (Dimension blockFallbacks, Block backup).",
|
||||
"iris.modded.help.entry.command.compat_content": "Inhalte anzeigen, die in dieser Minecraft-Version nicht generiert werden können"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Muestra el contenido del pack que no puede generarse en esta versión de Minecraft",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "El nombre de la carpeta del pack sobre el que informar",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePack '{pack}': contenido no disponible en Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aEl pack '{pack}' no usa contenido que falte en Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Actualiza el servidor a un Minecraft más reciente para recuperar este contenido, o declara alternativas (blockFallbacks de la dimensión, backup del bloque).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Pack '{pack}': contenido no disponible en Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "El pack '{pack}' no usa contenido que falte en Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Actualiza el servidor a un Minecraft más reciente para recuperar este contenido, o declara alternativas (blockFallbacks de la dimensión, backup del bloque).",
|
||||
"iris.modded.help.entry.command.compat_content": "Muestra el contenido que no puede generarse en esta versión de Minecraft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Näytä paketin sisältö, jota ei voi luoda tässä Minecraft-versiossa",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Raportoitavan pakettikansion nimi",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePaketti '{pack}': sisältö ei ole käytettävissä Minecraft {version} -versiossa",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aPaketti '{pack}' ei käytä sisältöä, joka puuttuisi Minecraft {version} -versiosta.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Päivitä palvelin uudempaan Minecraft-versioon palauttaaksesi tämän sisällön tai määritä varasisältö (ulottuvuuden blockFallbacks, lohkon backup).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Paketti '{pack}': sisältö ei ole käytettävissä Minecraft {version} -versiossa",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Paketti '{pack}' ei käytä sisältöä, joka puuttuisi Minecraft {version} -versiosta.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Päivitä palvelin uudempaan Minecraft-versioon palauttaaksesi tämän sisällön tai määritä varasisältö (ulottuvuuden blockFallbacks, lohkon backup).",
|
||||
"iris.modded.help.entry.command.compat_content": "Näytä sisältö, jota ei voi luoda tässä Minecraft-versiossa"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Afficher le contenu du pack qui ne peut pas être généré sur cette version de Minecraft",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Le nom du dossier du pack à analyser",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePack '{pack}' : contenu indisponible sur Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aLe pack '{pack}' n'utilise aucun contenu absent de Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Mettez le serveur à jour vers un Minecraft plus récent pour restaurer ce contenu, ou déclarez des replis (blockFallbacks de la dimension, backup du bloc).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Pack '{pack}' : contenu indisponible sur Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Le pack '{pack}' n'utilise aucun contenu absent de Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Mettez le serveur à jour vers un Minecraft plus récent pour restaurer ce contenu, ou déclarez des replis (blockFallbacks de la dimension, backup du bloc).",
|
||||
"iris.modded.help.entry.command.compat_content": "Afficher le contenu qui ne peut pas être généré sur cette version de Minecraft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "הצג תוכן חבילה שלא ניתן ליצור בגרסת Minecraft הזו",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "שם תיקיית החבילה לדיווח",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§eחבילה '{pack}': תוכן לא זמין ב-Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aהחבילה '{pack}' אינה משתמשת בתוכן שחסר ב-Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7עדכן את השרת ל-Minecraft חדש יותר כדי לשחזר את התוכן הזה, או הגדר חלופות (blockFallbacks של הממד, backup של הבלוק).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "חבילה '{pack}': תוכן לא זמין ב-Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "החבילה '{pack}' אינה משתמשת בתוכן שחסר ב-Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "עדכן את השרת ל-Minecraft חדש יותר כדי לשחזר את התוכן הזה, או הגדר חלופות (blockFallbacks של הממד, backup של הבלוק).",
|
||||
"iris.modded.help.entry.command.compat_content": "הצג תוכן שלא ניתן ליצור בגרסת Minecraft הזו"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Mostra i contenuti del pack che non possono essere generati su questa versione di Minecraft",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Il nome della cartella del pack da analizzare",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePack '{pack}': contenuti non disponibili su Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aIl pack '{pack}' non usa contenuti assenti da Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Aggiorna il server a un Minecraft più recente per ripristinare questi contenuti, oppure dichiara delle alternative (blockFallbacks della dimensione, backup del blocco).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Pack '{pack}': contenuti non disponibili su Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Il pack '{pack}' non usa contenuti assenti da Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Aggiorna il server a un Minecraft più recente per ripristinare questi contenuti, oppure dichiara delle alternative (blockFallbacks della dimensione, backup del blocco).",
|
||||
"iris.modded.help.entry.command.compat_content": "Mostra i contenuti che non possono essere generati su questa versione di Minecraft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "この Minecraft バージョンでは生成できないパック内容を表示します",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "対象とするパックフォルダー名",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§eパック '{pack}': Minecraft {version} では利用できない内容があります",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aパック '{pack}' に Minecraft {version} で欠けている内容はありません。",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7この内容を復元するにはサーバーを新しい Minecraft に更新するか、代替を宣言してください (ディメンションの blockFallbacks、ブロックの backup)。",
|
||||
"iris.modded.moddedpackcommands.compat_header": "パック '{pack}': Minecraft {version} では利用できない内容があります",
|
||||
"iris.modded.moddedpackcommands.compat_none": "パック '{pack}' に Minecraft {version} で欠けている内容はありません。",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "この内容を復元するにはサーバーを新しい Minecraft に更新するか、代替を宣言してください (ディメンションの blockFallbacks、ブロックの backup)。",
|
||||
"iris.modded.help.entry.command.compat_content": "この Minecraft バージョンでは生成できない内容を表示します"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "이 Minecraft 버전에서 생성할 수 없는 팩 콘텐츠를 표시합니다",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "보고할 팩 폴더 이름",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§e팩 '{pack}': Minecraft {version} 에서 사용할 수 없는 콘텐츠",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§a팩 '{pack}' 은 Minecraft {version} 에 없는 콘텐츠를 사용하지 않습니다.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7이 콘텐츠를 복원하려면 서버를 최신 Minecraft 로 업데이트하거나 대체를 선언하세요 (차원의 blockFallbacks, 블록의 backup).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "팩 '{pack}': Minecraft {version} 에서 사용할 수 없는 콘텐츠",
|
||||
"iris.modded.moddedpackcommands.compat_none": "팩 '{pack}' 은 Minecraft {version} 에 없는 콘텐츠를 사용하지 않습니다.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "이 콘텐츠를 복원하려면 서버를 최신 Minecraft 로 업데이트하거나 대체를 선언하세요 (차원의 blockFallbacks, 블록의 backup).",
|
||||
"iris.modded.help.entry.command.compat_content": "이 Minecraft 버전에서 생성할 수 없는 콘텐츠를 표시합니다"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Rodyti paketo turinį, kurio negalima sugeneruoti šioje Minecraft versijoje",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Paketo aplanko pavadinimas ataskaitai",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePaketas '{pack}': turinys nepasiekiamas Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aPaketas '{pack}' nenaudoja turinio, kurio trūksta Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Atnaujinkite serverį į naujesnį Minecraft, kad atkurtumėte šį turinį, arba paskelbkite atsargas (dimensijos blockFallbacks, bloko backup).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Paketas '{pack}': turinys nepasiekiamas Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Paketas '{pack}' nenaudoja turinio, kurio trūksta Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Atnaujinkite serverį į naujesnį Minecraft, kad atkurtumėte šį turinį, arba paskelbkite atsargas (dimensijos blockFallbacks, bloko backup).",
|
||||
"iris.modded.help.entry.command.compat_content": "Rodyti turinį, kurio negalima sugeneruoti šioje Minecraft versijoje"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Toon pack-inhoud die niet kan worden gegenereerd op deze Minecraft-versie",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "De naam van de packmap om te rapporteren",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePack '{pack}': inhoud niet beschikbaar op Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aPack '{pack}' gebruikt geen inhoud die ontbreekt in Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Werk de server bij naar een nieuwere Minecraft om deze inhoud te herstellen, of declareer terugvallen (blockFallbacks van de dimensie, backup van het blok).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Pack '{pack}': inhoud niet beschikbaar op Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Pack '{pack}' gebruikt geen inhoud die ontbreekt in Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Werk de server bij naar een nieuwere Minecraft om deze inhoud te herstellen, of declareer terugvallen (blockFallbacks van de dimensie, backup van het blok).",
|
||||
"iris.modded.help.entry.command.compat_content": "Toon inhoud die niet kan worden gegenereerd op deze Minecraft-versie"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Pokaż zawartość paczki, której nie można wygenerować w tej wersji Minecraft",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Nazwa folderu paczki do raportu",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePaczka '{pack}': zawartość niedostępna w Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aPaczka '{pack}' nie używa zawartości brakującej w Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Zaktualizuj serwer do nowszego Minecraft, aby przywrócić tę zawartość, albo zadeklaruj zamienniki (blockFallbacks wymiaru, backup bloku).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Paczka '{pack}': zawartość niedostępna w Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Paczka '{pack}' nie używa zawartości brakującej w Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Zaktualizuj serwer do nowszego Minecraft, aby przywrócić tę zawartość, albo zadeklaruj zamienniki (blockFallbacks wymiaru, backup bloku).",
|
||||
"iris.modded.help.entry.command.compat_content": "Pokaż zawartość, której nie można wygenerować w tej wersji Minecraft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Mostrar o conteúdo do pack que não pode ser gerado nesta versão do Minecraft",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "O nome da pasta do pack a reportar",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePack '{pack}': conteúdo indisponível no Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aO pack '{pack}' não usa conteúdo em falta no Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Atualize o servidor para um Minecraft mais recente para restaurar este conteúdo, ou declare alternativas (blockFallbacks da dimensão, backup do bloco).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Pack '{pack}': conteúdo indisponível no Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "O pack '{pack}' não usa conteúdo em falta no Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Atualize o servidor para um Minecraft mais recente para restaurar este conteúdo, ou declare alternativas (blockFallbacks da dimensão, backup do bloco).",
|
||||
"iris.modded.help.entry.command.compat_content": "Mostrar o conteúdo que não pode ser gerado nesta versão do Minecraft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Показать содержимое пака, которое нельзя сгенерировать в этой версии Minecraft",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Имя папки пака для отчёта",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§eПак '{pack}': содержимое недоступно в Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aПак '{pack}' не использует содержимое, которого нет в Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Обновите сервер до более новой версии Minecraft, чтобы вернуть это содержимое, или объявите замены (blockFallbacks измерения, backup блока).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Пак '{pack}': содержимое недоступно в Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Пак '{pack}' не использует содержимое, которого нет в Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Обновите сервер до более новой версии Minecraft, чтобы вернуть это содержимое, или объявите замены (blockFallbacks измерения, backup блока).",
|
||||
"iris.modded.help.entry.command.compat_content": "Показать содержимое, которое нельзя сгенерировать в этой версии Minecraft"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Bu Minecraft sürümünde üretilemeyen paket içeriğini göster",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Raporlanacak paket klasörü adı",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§ePaket '{pack}': içerik Minecraft {version} sürümünde yok",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aPaket '{pack}' Minecraft {version} sürümünde eksik olan içerik kullanmıyor.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Bu içeriği geri kazanmak için sunucuyu daha yeni bir Minecraft sürümüne güncelleyin veya yedekler tanımlayın (boyutun blockFallbacks, bloğun backup).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Paket '{pack}': içerik Minecraft {version} sürümünde yok",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Paket '{pack}' Minecraft {version} sürümünde eksik olan içerik kullanmıyor.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Bu içeriği geri kazanmak için sunucuyu daha yeni bir Minecraft sürümüne güncelleyin veya yedekler tanımlayın (boyutun blockFallbacks, bloğun backup).",
|
||||
"iris.modded.help.entry.command.compat_content": "Bu Minecraft sürümünde üretilemeyen içeriği göster"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "Hiển thị nội dung gói không thể tạo trên phiên bản Minecraft này",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "Tên thư mục gói cần báo cáo",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§eGói '{pack}': nội dung không có trên Minecraft {version}",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§aGói '{pack}' không dùng nội dung nào thiếu trên Minecraft {version}.",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7Cập nhật máy chủ lên Minecraft mới hơn để khôi phục nội dung này, hoặc khai báo phương án dự phòng (blockFallbacks của chiều, backup của khối).",
|
||||
"iris.modded.moddedpackcommands.compat_header": "Gói '{pack}': nội dung không có trên Minecraft {version}",
|
||||
"iris.modded.moddedpackcommands.compat_none": "Gói '{pack}' không dùng nội dung nào thiếu trên Minecraft {version}.",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "Cập nhật máy chủ lên Minecraft mới hơn để khôi phục nội dung này, hoặc khai báo phương án dự phòng (blockFallbacks của chiều, backup của khối).",
|
||||
"iris.modded.help.entry.command.compat_content": "Hiển thị nội dung không thể tạo trên phiên bản Minecraft này"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "显示在当前 Minecraft 版本中无法生成的资源包内容",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "要报告的资源包文件夹名称",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§e资源包 '{pack}': 内容在 Minecraft {version} 中不可用",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§a资源包 '{pack}' 未使用 Minecraft {version} 中缺失的内容。",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7将服务器升级到更新的 Minecraft 以恢复这些内容,或声明回退 (维度的 blockFallbacks、方块的 backup)。",
|
||||
"iris.modded.moddedpackcommands.compat_header": "资源包 '{pack}': 内容在 Minecraft {version} 中不可用",
|
||||
"iris.modded.moddedpackcommands.compat_none": "资源包 '{pack}' 未使用 Minecraft {version} 中缺失的内容。",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "将服务器升级到更新的 Minecraft 以恢复这些内容,或声明回退 (维度的 blockFallbacks、方块的 backup)。",
|
||||
"iris.modded.help.entry.command.compat_content": "显示在当前 Minecraft 版本中无法生成的内容"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,6 +1550,15 @@
|
||||
"iris.desktop.imagemap.preview_status": "X {x} Z {z} | {value} | {scale} blocks/pixel",
|
||||
"iris.bukkit.commandstudio.opening_image_map_studio": "§aOpening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.image_map_requires_iris_dimension": "Stand in an active Iris or Studio dimension before opening the Image Map Studio.",
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display."
|
||||
"iris.modded.moddedstudiocommands.opening_image_map_studio_on_server_display": "Opening the Image Map Studio for {value} on the server display.",
|
||||
"iris.director.commandpack.director.show_content_cannot_generate_this_minecraft_version": "顯示在目前 Minecraft 版本中無法生成的資源包內容",
|
||||
"iris.director.commandpack.param.pack_folder_name_compat": "要報告的資源包資料夾名稱",
|
||||
"iris.bukkit.runtime.commandpack.compat_header": "§e資源包 '{pack}': 內容在 Minecraft {version} 中無法使用",
|
||||
"iris.bukkit.runtime.commandpack.compat_none": "§a資源包 '{pack}' 未使用 Minecraft {version} 中缺少的內容。",
|
||||
"iris.bukkit.runtime.commandpack.compat_remedy": "§7將伺服器升級到較新的 Minecraft 以還原這些內容,或宣告備援 (維度的 blockFallbacks、方塊的 backup)。",
|
||||
"iris.modded.moddedpackcommands.compat_header": "資源包 '{pack}': 內容在 Minecraft {version} 中無法使用",
|
||||
"iris.modded.moddedpackcommands.compat_none": "資源包 '{pack}' 未使用 Minecraft {version} 中缺少的內容。",
|
||||
"iris.modded.moddedpackcommands.compat_remedy": "將伺服器升級到較新的 Minecraft 以還原這些內容,或宣告備援 (維度的 blockFallbacks、方塊的 backup)。",
|
||||
"iris.modded.help.entry.command.compat_content": "顯示在目前 Minecraft 版本中無法生成的內容"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package art.arcane.iris.core.pack;
|
||||
|
||||
import art.arcane.iris.core.compat.CompatAction;
|
||||
import art.arcane.iris.core.compat.CompatFinding;
|
||||
import art.arcane.iris.core.compat.CompatRegistry;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assume;
|
||||
@@ -16,6 +19,7 @@ import java.util.Optional;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -61,6 +65,55 @@ public class PackValidationCacheTest {
|
||||
cache, "content", "context", List.of("other")).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheRoundTripsCompatFindingsAndMinecraftVersion() throws Exception {
|
||||
Path cache = new File(temporaryFolder.newFolder("compat-round-trip"), "validation.json").toPath();
|
||||
CompatFinding excluded = new CompatFinding(
|
||||
CompatRegistry.BLOCK, "minecraft:sulfur", CompatAction.EXCLUDED,
|
||||
"Biome", "cave/sulfur-grotto", "layers[0].palette[1]");
|
||||
CompatFinding dropped = new CompatFinding(
|
||||
CompatRegistry.ENTITY, "minecraft:camel", CompatAction.DROPPED, "Spawner", "desert", "spawns[0]");
|
||||
PackValidationCache.save(cache, "content", "context", List.of(new PackValidationResult(
|
||||
"overworld", List.of(), List.of("warning"), 7L, List.of(excluded, dropped), "26.1.2")));
|
||||
|
||||
PackValidationResult loaded = PackValidationCache.load(
|
||||
cache, "content", "context", List.of("overworld")).orElseThrow().getFirst();
|
||||
|
||||
assertEquals("26.1.2", loaded.getMinecraftVersion());
|
||||
assertEquals(List.of(excluded, dropped), loaded.getCompatFindings());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultsWithoutGatingRoundTripAsEmptyFindings() throws Exception {
|
||||
Path cache = new File(temporaryFolder.newFolder("compat-empty"), "validation.json").toPath();
|
||||
PackValidationCache.save(cache, "content", "context", List.of(
|
||||
new PackValidationResult("overworld", List.of(), List.of(), 1L)));
|
||||
|
||||
PackValidationResult loaded = PackValidationCache.load(
|
||||
cache, "content", "context", List.of("overworld")).orElseThrow().getFirst();
|
||||
|
||||
assertTrue(loaded.getCompatFindings().isEmpty());
|
||||
assertNull(loaded.getMinecraftVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheWithAnUnreadableFindingIsIgnored() throws Exception {
|
||||
Path cache = new File(temporaryFolder.newFolder("compat-corrupt"), "validation.json").toPath();
|
||||
Files.writeString(cache, """
|
||||
{
|
||||
"schemaVersion": 3,
|
||||
"contentFingerprint": "content",
|
||||
"contextFingerprint": "context",
|
||||
"results": [
|
||||
{"packName":"overworld","blockingErrors":[],"warnings":[],"validatedAtMillis":1,
|
||||
"compatFindings":[{"registry":"NOT_A_REGISTRY","key":"minecraft:sulfur","action":"EXCLUDED"}]}
|
||||
]
|
||||
}
|
||||
""", StandardCharsets.UTF_8);
|
||||
|
||||
assertTrue(PackValidationCache.load(cache, "content", "context", List.of("overworld")).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void corruptCacheIsIgnored() throws Exception {
|
||||
Path cache = new File(temporaryFolder.newFolder("corrupt"), "validation.json").toPath();
|
||||
@@ -77,7 +130,7 @@ public class PackValidationCacheTest {
|
||||
Path cache = new File(temporaryFolder.newFolder("duplicate"), "validation.json").toPath();
|
||||
Files.writeString(cache, """
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"schemaVersion": 3,
|
||||
"contentFingerprint": "content",
|
||||
"contextFingerprint": "context",
|
||||
"results": [
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package art.arcane.iris.core.pack;
|
||||
|
||||
import art.arcane.iris.core.compat.CompatAction;
|
||||
import art.arcane.iris.core.compat.CompatFinding;
|
||||
import art.arcane.iris.core.compat.CompatRegistry;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class PackValidatorCompatTest {
|
||||
private static CompatFinding block(CompatAction action, String subjectKey) {
|
||||
return new CompatFinding(
|
||||
CompatRegistry.BLOCK, "minecraft:sulfur", action, "Biome", subjectKey, "layers[0].palette[1]");
|
||||
}
|
||||
|
||||
private static CompatFinding entity(CompatAction action, String subjectKey) {
|
||||
return new CompatFinding(
|
||||
CompatRegistry.ENTITY, "minecraft:camel", action, "Spawner", subjectKey, "spawns[0]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludedDimensionBecomesABlockingError() {
|
||||
List<String> blockingErrors = new ArrayList<>();
|
||||
List<String> warnings = new ArrayList<>();
|
||||
|
||||
PackValidator.applyCompatFindings(
|
||||
"26.1.2",
|
||||
true,
|
||||
List.of(block(CompatAction.EXCLUDED, "cave/sulfur"), entity(CompatAction.DROPPED, "desert")),
|
||||
blockingErrors,
|
||||
warnings);
|
||||
|
||||
assertEquals(1, blockingErrors.size());
|
||||
assertEquals(
|
||||
"Pack cannot generate on Minecraft 26.1.2: minecraft:sulfur (block), minecraft:camel (entity)",
|
||||
blockingErrors.getFirst());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unexcludedDimensionAddsNoBlockingError() {
|
||||
List<String> blockingErrors = new ArrayList<>();
|
||||
List<String> warnings = new ArrayList<>();
|
||||
|
||||
PackValidator.applyCompatFindings(
|
||||
"26.1.2", false, List.of(block(CompatAction.DROPPED, "cave/sulfur")), blockingErrors, warnings);
|
||||
|
||||
assertTrue(blockingErrors.toString(), blockingErrors.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludedDimensionWithoutFindingsStillNamesTheVersion() {
|
||||
List<String> blockingErrors = new ArrayList<>();
|
||||
|
||||
PackValidator.applyCompatFindings("26.1.2", true, List.of(), blockingErrors, new ArrayList<>());
|
||||
|
||||
assertEquals(
|
||||
"Pack cannot generate on Minecraft 26.1.2: the dimension composes content this server does not have",
|
||||
blockingErrors.getFirst());
|
||||
assertTrue(PackValidator.excludedDimensionError(null, List.of()).contains("Minecraft unknown"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentKeyWarningsForGatedKeysAreSuppressed() {
|
||||
List<String> warnings = new ArrayList<>(List.of(
|
||||
"Unknown block key 'minecraft:sulfur' (missing from the block registry)",
|
||||
"Unknown entity key 'minecraft:camel' (missing from the entity registry)",
|
||||
"Unknown block key 'minecraft:cheese' (missing from the block registry)",
|
||||
"Duplicate generator 'overworld'"));
|
||||
|
||||
PackValidator.applyCompatFindings(
|
||||
"26.1.2",
|
||||
false,
|
||||
List.of(block(CompatAction.EXCLUDED, "cave/sulfur"), entity(CompatAction.DROPPED, "desert")),
|
||||
new ArrayList<>(),
|
||||
warnings);
|
||||
|
||||
assertEquals(List.of(
|
||||
"Unknown block key 'minecraft:cheese' (missing from the block registry)",
|
||||
"Duplicate generator 'overworld'"), warnings);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bootLinesCapSubjectsPerKeyAndSummaryCountsActions() {
|
||||
PackValidationResult result = new PackValidationResult(
|
||||
"overworld",
|
||||
List.of(),
|
||||
List.of(),
|
||||
1L,
|
||||
List.of(
|
||||
block(CompatAction.EXCLUDED, "cave/sulfur-grotto"),
|
||||
block(CompatAction.EXCLUDED, "desert/sulfur-flats"),
|
||||
block(CompatAction.DROPPED, "cave/sulfur-grotto"),
|
||||
block(CompatAction.SUBSTITUTED, "desert/dunes"),
|
||||
entity(CompatAction.EXCLUDED, "camel")),
|
||||
"26.1.2");
|
||||
|
||||
List<String> lines = PackValidator.compatBootLines(result, null, 3);
|
||||
|
||||
assertEquals(4, lines.size());
|
||||
assertEquals("Pack 'overworld': content unavailable on Minecraft 26.1.2", lines.get(0));
|
||||
assertTrue(lines.get(1), lines.get(1).startsWith(" minecraft:sulfur (block): "));
|
||||
assertTrue(lines.get(1), lines.get(1).endsWith("; +1 more"));
|
||||
assertEquals(3, lines.get(1).split("; ").length - 1);
|
||||
assertTrue(lines.get(2), lines.get(2).startsWith(" minecraft:camel (entity): "));
|
||||
assertFalse(lines.get(2), lines.get(2).contains("more"));
|
||||
assertTrue(lines.get(3), lines.get(3).contains("/iris pack compat overworld"));
|
||||
|
||||
assertEquals(
|
||||
"2 content keys unavailable on Minecraft 26.1.2: 3 excluded, 1 dropped, 1 substituted.",
|
||||
PackValidator.compatSummary(result, null));
|
||||
assertEquals(
|
||||
"2 content keys unavailable on Minecraft 26.2: 3 excluded, 1 dropped, 1 substituted.",
|
||||
PackValidator.compatSummary(result, "26.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bootLinesAndSummaryAreEmptyWithoutFindings() {
|
||||
PackValidationResult result = new PackValidationResult("overworld", List.of(), List.of(), 1L);
|
||||
|
||||
assertTrue(PackValidator.compatBootLines(result, "26.1.2", 3).isEmpty());
|
||||
assertEquals("", PackValidator.compatSummary(result, "26.1.2"));
|
||||
assertTrue(PackValidator.compatBootLines(null, "26.1.2", 3).isEmpty());
|
||||
assertEquals("", PackValidator.compatSummary(null, "26.1.2"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user