This commit is contained in:
Brian Neumann-Fopiano
2026-08-13 16:54:37 -04:00
parent 1586b4bd1a
commit 32beca236c
49 changed files with 311 additions and 1136 deletions
@@ -175,8 +175,8 @@ public final class IrisWorldGeneratorResolver {
+ " but its dimension failed to load; not redownloading. Fix or delete the pack folder.");
return null;
}
Iris.warn("Unable to find dimension type " + id + ". Install its pack with /iris download "
+ id + " and restart the server.");
Iris.warn("Unable to find dimension type " + id + ". Install its pack with "
+ PackDownloader.downloadCommandFor(id) + " and restart the server.");
}
return dimension;
@@ -197,9 +197,7 @@ public class CommandDeveloper implements DirectorExecutor {
@Param(description = "The pack to install into the world", descriptionKey = "iris.director.commanddeveloper.param.pack_install_into_world", contextual = true, aliases = "dimension")
IrisDimension pack,
@Param(description = "Make sure to make a backup & read the warnings first!", descriptionKey = "iris.director.commanddeveloper.param.make_sure_make_backup_read_warnings_first", defaultValue = "false", aliases = "c")
boolean confirm,
@Param(description = "Should Iris download the pack again for you", descriptionKey = "iris.director.commanddeveloper.param.should_iris_download_pack_again_you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"})
boolean freshDownload
boolean confirm
) {
if (!confirm) {
sender().sendMessage(IrisLanguage.text(
@@ -213,10 +211,6 @@ public class CommandDeveloper implements DirectorExecutor {
File folder = world.getWorldFolder();
folder.mkdirs();
if (freshDownload) {
Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), true);
}
try (LifecycleOperationCoordinator.Lease lease = LifecycleOperationCoordinator.get().acquire(
LifecycleOperationCoordinator.Domain.PACK_MUTATION,
LifecycleOperationCoordinator.OperationKind.PACK_PUBLISH,
@@ -95,6 +95,7 @@ import art.arcane.iris.core.localization.BukkitCommandMessagesExtended;
import art.arcane.iris.core.localization.RuntimeUiMessages;
@Director(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command", descriptionKey = "iris.director.commandiris.director.basic_command")
public class CommandIris implements DirectorExecutor {
private static final String NO_DOWNLOAD_SOURCE = "__none__";
private static final long WORLD_UNLOAD_TIMEOUT_SECONDS = 150L;
private CommandStudio studio;
@@ -169,9 +170,10 @@ public class CommandIris implements DirectorExecutor {
IrisDimension dimension = IrisToolbelt.getDimension(resolvedType);
if (dimension == null) {
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_COULD_NOT_FIND_DOWNLOAD_DIMENSION, MessageArgument.untrusted("resolvedType", resolvedType)));
sender().sendMessage("Could not find dimension '" + resolvedType + "'.");
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_TRY_ONE_OVERWORLD_VANILLA_FLAT_THEEND));
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_DOWNLOAD_MANUALLY_IRIS_DOWNLOAD, MessageArgument.untrusted("resolvedType", resolvedType)));
sender().sendMessage("Install its pack with " + PackDownloader.downloadCommandFor(resolvedType)
+ " and restart the server.");
return;
}
@@ -703,25 +705,28 @@ public class CommandIris implements DirectorExecutor {
@Director(description = "Download a project.", descriptionKey = "iris.director.commandiris.director.download_project", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", descriptionKey = "iris.director.commandiris.param.pack_download", aliases = "project")
@Param(name = "pack", description = "The built-in pack to download", descriptionKey = "iris.director.commandiris.param.pack_download", defaultValue = NO_DOWNLOAD_SOURCE, customHandler = DownloadPackHandler.class)
String pack,
@Param(name = "branch", description = "The branch to download from", descriptionKey = "iris.director.commandiris.param.branch_download_from", defaultValue = PackDownloader.DEFAULT_BRANCH)
String branch,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", descriptionKey = "iris.director.commandiris.param.whether_not_overwrite_pack_with_downloaded_one", aliases = "force", defaultValue = "false")
boolean overwrite
@Param(name = "link", description = "A direct HTTP or HTTPS zip link", defaultValue = NO_DOWNLOAD_SOURCE)
String link
) {
if (PackDownloader.isDirectZipUrl(pack)) {
sender().sendMessage("Downloading Iris pack from " + pack
+ (overwrite ? IrisLanguage.text(RuntimeUiMessages.DOWNLOAD_OVERWRITE_SUFFIX) : "") + ".");
Iris.service(StudioSVC.class).downloadUrl(sender(), pack, overwrite);
} else if (PackDownloader.isManagedPack(pack)) {
sender().sendMessage("Downloading managed Iris pack '" + pack + "' from its configured Git source"
+ (overwrite ? IrisLanguage.text(RuntimeUiMessages.DOWNLOAD_OVERWRITE_SUFFIX) : "") + ".");
Iris.service(StudioSVC.class).downloadManaged(sender(), pack, overwrite);
} else {
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_IRIS_DOWNLOADING_PACK, MessageArgument.untrusted("pack", pack), MessageArgument.untrusted("branch", branch), MessageArgument.trusted("value", overwrite ? IrisLanguage.text(RuntimeUiMessages.DOWNLOAD_OVERWRITE_SUFFIX) : "")));
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, overwrite);
String builtInPack = NO_DOWNLOAD_SOURCE.equals(pack) ? null : pack;
String directLink = NO_DOWNLOAD_SOURCE.equals(link) ? null : link;
if ((builtInPack == null) == (directLink == null)) {
sender().sendMessage("Use exactly one source: /iris download pack=overworld, /iris download pack=underworld, or /iris download link=<zip-url>.");
return;
}
if (builtInPack != null) {
sender().sendMessage("Downloading built-in Iris pack '" + builtInPack + "' from its beta release.");
Iris.service(StudioSVC.class).downloadBuiltIn(sender(), builtInPack);
return;
}
if (!PackDownloader.isDirectZipUrl(directLink)) {
sender().sendMessage("Iris requires link= to contain a valid HTTP or HTTPS .zip URL.");
return;
}
sender().sendMessage("Downloading Iris pack from " + directLink + ".");
Iris.service(StudioSVC.class).downloadUrl(sender(), directLink);
}
@Director(description = "Get metrics for your world", descriptionKey = "iris.director.commandiris.director.get_metrics_your_world", aliases = "measure", origin = DirectorOrigin.PLAYER)
@@ -1063,6 +1068,35 @@ public class CommandIris implements DirectorExecutor {
}
}
public static class DownloadPackHandler implements DirectorParameterHandler<String> {
@Override
public KList<String> getPossibilities() {
return new KList<>(PackDownloader.builtInPacks());
}
@Override
public String toString(String value) {
return value == null ? "" : value;
}
@Override
public String parse(String in, boolean force) throws DirectorParsingException {
if (NO_DOWNLOAD_SOURCE.equals(in)) {
return null;
}
String pack = in == null ? "" : in.trim().toLowerCase(Locale.ROOT);
if (!PackDownloader.isBuiltInPack(pack)) {
throw new DirectorParsingException("Pack must be 'overworld' or 'underworld'");
}
return pack;
}
@Override
public boolean supports(Class<?> type) {
return type == String.class;
}
}
static final class MainWorldPublication implements AutoCloseable {
private final Path target;
private boolean committed;
@@ -0,0 +1,45 @@
package art.arcane.iris.core.commands;
import art.arcane.volmlib.util.director.annotations.Param;
import org.junit.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
public class CommandIrisDownloadContractTest {
@Test
public void commandExposesOnlyPackAndLinkParameters() throws NoSuchMethodException {
Method method = CommandIris.class.getDeclaredMethod("download", String.class, String.class);
Parameter[] parameters = method.getParameters();
Param pack = parameters[0].getAnnotation(Param.class);
Param link = parameters[1].getAnnotation(Param.class);
List<Method> downloadMethods = Arrays.stream(CommandIris.class.getDeclaredMethods())
.filter((Method candidate) -> candidate.getName().equals("download"))
.toList();
assertEquals(1, downloadMethods.size());
assertEquals(2, downloadMethods.getFirst().getParameterCount());
assertEquals("pack", pack.name());
assertEquals(0L, Arrays.stream(pack.aliases()).filter((String alias) -> !alias.isBlank()).count());
assertEquals(CommandIris.DownloadPackHandler.class, pack.customHandler());
assertEquals("link", link.name());
assertEquals(0L, Arrays.stream(link.aliases()).filter((String alias) -> !alias.isBlank()).count());
}
@Test
public void packHandlerAcceptsOnlyTheTwoBuiltInPacks() throws Exception {
CommandIris.DownloadPackHandler handler = new CommandIris.DownloadPackHandler();
assertEquals("overworld", handler.parse("OVERWORLD", false));
assertEquals("underworld", handler.parse("underworld", false));
assertEquals(Arrays.asList("overworld", "underworld"), handler.getPossibilities());
assertNull(handler.parse("__none__", false));
assertThrows(Exception.class, () -> handler.parse("custom", false));
}
}
@@ -1,20 +0,0 @@
package art.arcane.iris.core.commands;
import org.junit.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertTrue;
public class CommandIrisDownloadDefaultTest {
@Test
public void downloadBranchParamDefaultsToTheCoreConstant() throws Exception {
String source = Files.readString(Path.of("src/main/java/art/arcane/iris/core/commands/CommandIris.java"));
int branchParam = source.indexOf("name = \"branch\"");
assertTrue("CommandIris must declare the branch param", branchParam >= 0);
String declaration = source.substring(branchParam, source.indexOf(')', branchParam));
assertTrue("branch param default must be PackDownloader.DEFAULT_BRANCH, not a literal",
declaration.contains("defaultValue = PackDownloader.DEFAULT_BRANCH"));
}
}