mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 13:30:08 +00:00
Iris downloader / History update
- Allow people to download in place and update in place the media
This commit is contained in:
1 parent
b18681a3e2
commit
edadd14f4b
40 files changed
+836
-122
No files matched your search
@@ -1465,9 +1465,11 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
|
||||
private void printPacks() {
|
||||
File packFolder = Iris.service(StudioSVC.class).getWorkspaceFolder();
|
||||
for (String line : IrisSplashComposer.composePackLines(packFolder, Iris::reportError)) {
|
||||
Iris.info(line);
|
||||
}
|
||||
IrisSplashComposer.composePackLines(packFolder, Iris::reportError).thenAccept(lines -> {
|
||||
if (isEnabled()) {
|
||||
lines.forEach(Iris::info);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public int getIrisVersion() {
|
||||
|
||||
@@ -21,13 +21,11 @@ package art.arcane.iris.command;
|
||||
import com.google.gson.JsonObject;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.pack.datapack.ServerConfigurator;
|
||||
import art.arcane.iris.world.lifecycle.LifecycleOperationCoordinator;
|
||||
import art.arcane.iris.platform.bukkit.nms.datapack.DataVersion;
|
||||
import art.arcane.iris.world.runtime.ChunkClearer;
|
||||
import art.arcane.iris.generation.validation.GoldenHashScanner;
|
||||
import art.arcane.iris.world.runtime.InPlaceChunkRegenerator;
|
||||
import art.arcane.iris.generation.runtime.IrisEngineSVC;
|
||||
import art.arcane.iris.studio.StudioSVC;
|
||||
import art.arcane.iris.pack.IrisPackBenchmarking;
|
||||
import art.arcane.iris.world.IrisToolbelt;
|
||||
import art.arcane.iris.generation.runtime.IrisEngineMantle;
|
||||
@@ -68,7 +66,6 @@ import art.arcane.iris.localization.IrisLanguage;
|
||||
import art.arcane.iris.localization.BukkitCommandMessages;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import art.arcane.iris.localization.BukkitCommandMessagesExtended;
|
||||
import art.arcane.iris.localization.BukkitRuntimeMessages;
|
||||
@Director(name = "Developer", origin = DirectorOrigin.BOTH, description = "Iris World Manager", descriptionKey = "iris.director.commanddeveloper.director.iris_world_manager", aliases = {"dev"})
|
||||
public class CommandDeveloper implements DirectorExecutor {
|
||||
@Director(description = "Get Loaded TectonicPlates Count", descriptionKey = "iris.director.commanddeveloper.director.get_loaded_tectonicplates_count", origin = DirectorOrigin.BOTH, sync = true)
|
||||
@@ -184,27 +181,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
||||
@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
|
||||
) {
|
||||
if (!confirm) {
|
||||
sender().sendMessage(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_DEVELOPER_UPDATE_WORLD_WARNING,
|
||||
MessageArgument.untrusted("world", world.getName()),
|
||||
MessageArgument.untrusted("pack", pack.getLoadKey())
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
File folder = world.getWorldFolder();
|
||||
folder.mkdirs();
|
||||
|
||||
try (LifecycleOperationCoordinator.Lease lease = LifecycleOperationCoordinator.get().acquire(
|
||||
LifecycleOperationCoordinator.Domain.PACK_MUTATION,
|
||||
LifecycleOperationCoordinator.OperationKind.PACK_PUBLISH,
|
||||
pack.getLoadKey()
|
||||
)) {
|
||||
Iris.service(StudioSVC.class).replaceIntoWorld(sender(), pack, folder, world.getSeed());
|
||||
} catch (LifecycleOperationCoordinator.BusyException e) {
|
||||
sender().sendMessage(C.YELLOW + e.getMessage());
|
||||
}
|
||||
CommandPack.stageWorldUpdate(sender(), world, pack, confirm);
|
||||
}
|
||||
|
||||
@Director(description = "Test", descriptionKey = "iris.director.commanddeveloper.director.test")
|
||||
|
||||
@@ -437,7 +437,9 @@ public class CommandIris implements DirectorExecutor {
|
||||
@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 = "link", description = "A direct HTTP or HTTPS zip link", defaultValue = NO_DOWNLOAD_SOURCE)
|
||||
String link
|
||||
String link,
|
||||
@Param(name = "overwrite", description = "Back up and replace an installed pack", defaultValue = "false")
|
||||
boolean overwrite
|
||||
) {
|
||||
String builtInPack = NO_DOWNLOAD_SOURCE.equals(pack) ? null : pack;
|
||||
String directLink = NO_DOWNLOAD_SOURCE.equals(link) ? null : link;
|
||||
@@ -446,14 +448,14 @@ public class CommandIris implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
if (builtInPack != null) {
|
||||
Iris.service(StudioSVC.class).downloadBuiltIn(sender(), builtInPack);
|
||||
Iris.service(StudioSVC.class).downloadBuiltIn(sender(), builtInPack, overwrite);
|
||||
return;
|
||||
}
|
||||
if (!PackDownloader.isDirectZipUrl(directLink)) {
|
||||
sender().sendMessage(IrisLanguage.text(PackDownloadMessages.INVALID_URL));
|
||||
return;
|
||||
}
|
||||
Iris.service(StudioSVC.class).downloadUrl(sender(), directLink);
|
||||
Iris.service(StudioSVC.class).downloadUrl(sender(), directLink, overwrite);
|
||||
}
|
||||
|
||||
@Director(description = "Get metrics for your world", descriptionKey = "iris.director.commandiris.director.get_metrics_your_world", aliases = "measure", origin = DirectorOrigin.PLAYER)
|
||||
|
||||
@@ -27,6 +27,9 @@ import art.arcane.iris.pack.PackValidationRegistry;
|
||||
import art.arcane.iris.pack.PackValidationResult;
|
||||
import art.arcane.iris.pack.PackValidator;
|
||||
import art.arcane.iris.studio.StudioSVC;
|
||||
import art.arcane.iris.world.IrisToolbelt;
|
||||
import art.arcane.iris.world.lifecycle.LifecycleOperationCoordinator;
|
||||
import art.arcane.iris.localization.C;
|
||||
import art.arcane.iris.generation.terrain.IrisDimension;
|
||||
import art.arcane.iris.command.handlers.DimensionHandler;
|
||||
import art.arcane.iris.platform.bukkit.plugin.VolmitSender;
|
||||
@@ -35,6 +38,7 @@ import art.arcane.volmlib.util.director.annotations.Param;
|
||||
import art.arcane.volmlib.util.localization.TextKey;
|
||||
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -48,6 +52,42 @@ import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import art.arcane.iris.localization.BukkitRuntimeMessages;
|
||||
@Director(name = "pack", aliases = {"pk"}, description = "Pack validation and maintenance", descriptionKey = "iris.director.commandpack.director.pack_validation_maintenance")
|
||||
public class CommandPack implements DirectorExecutor {
|
||||
@Director(name = "update-world", description = "Stage an installed pack for a world and request a clean restart", descriptionKey = "iris.director.commanddeveloper.director.stage_world_generation_update")
|
||||
public void updateWorld(
|
||||
@Param(description = "The world to update", descriptionKey = "iris.director.commanddeveloper.param.world_update", contextual = true, contextualOverride = true)
|
||||
World world,
|
||||
@Param(description = "The installed dimension to use", descriptionKey = "iris.director.commanddeveloper.param.pack_install_into_world", contextual = true, contextualOverride = true, aliases = "dimension")
|
||||
IrisDimension pack,
|
||||
@Param(description = "Confirm that the complete world has been backed up", descriptionKey = "iris.director.commanddeveloper.param.make_sure_make_backup_read_warnings_first", defaultValue = "false", aliases = "c")
|
||||
boolean confirm
|
||||
) {
|
||||
stageWorldUpdate(sender(), world, pack, confirm);
|
||||
}
|
||||
|
||||
static void stageWorldUpdate(VolmitSender sender, World world, IrisDimension pack, boolean confirm) {
|
||||
if (!IrisToolbelt.isIrisWorld(world) || IrisToolbelt.isIrisStudioWorld(world)) {
|
||||
sender.sendMessage(IrisLanguage.text(BukkitRuntimeMessages.COMMAND_PACK_UPDATE_WORLD_REQUIRES_PERSISTENT_WORLD));
|
||||
return;
|
||||
}
|
||||
if (!confirm) {
|
||||
sender.sendMessage(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_DEVELOPER_UPDATE_WORLD_WARNING,
|
||||
MessageArgument.untrusted("world", world.getName()),
|
||||
MessageArgument.untrusted("pack", pack.getLoadKey())
|
||||
));
|
||||
return;
|
||||
}
|
||||
try (LifecycleOperationCoordinator.Lease lease = LifecycleOperationCoordinator.get().acquire(
|
||||
LifecycleOperationCoordinator.Domain.PACK_MUTATION,
|
||||
LifecycleOperationCoordinator.OperationKind.PACK_PUBLISH,
|
||||
world.getName()
|
||||
)) {
|
||||
Iris.service(StudioSVC.class).replaceIntoWorld(sender, pack, world.getWorldFolder(), world.getSeed());
|
||||
} catch (LifecycleOperationCoordinator.BusyException e) {
|
||||
sender.sendMessage(C.YELLOW + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Director treats a blank defaultValue as "required", which made the all-packs branch
|
||||
* unreachable from chat. The "*" sentinel keeps the parameter genuinely optional; a blank
|
||||
|
||||
+6
-3
@@ -15,22 +15,25 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CommandIrisDownloadContractTest {
|
||||
@Test
|
||||
public void commandExposesOnlyPackAndLinkParameters() throws NoSuchMethodException {
|
||||
Method method = CommandIris.class.getDeclaredMethod("download", String.class, String.class);
|
||||
public void commandRequiresExplicitOverwriteForPackReplacement() throws NoSuchMethodException {
|
||||
Method method = CommandIris.class.getDeclaredMethod("download", String.class, String.class, boolean.class);
|
||||
Parameter[] parameters = method.getParameters();
|
||||
Param pack = parameters[0].getAnnotation(Param.class);
|
||||
Param link = parameters[1].getAnnotation(Param.class);
|
||||
Param overwrite = parameters[2].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(3, 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());
|
||||
assertEquals("overwrite", overwrite.name());
|
||||
assertEquals("false", overwrite.defaultValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package art.arcane.iris.command;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.generation.terrain.IrisDimension;
|
||||
import art.arcane.iris.localization.BukkitRuntimeMessages;
|
||||
import art.arcane.iris.localization.IrisLanguage;
|
||||
import art.arcane.iris.platform.bukkit.plugin.VolmitSender;
|
||||
import art.arcane.iris.studio.StudioSVC;
|
||||
import art.arcane.iris.world.IrisToolbelt;
|
||||
import art.arcane.volmlib.util.director.compat.DirectorAnnotationCompatibility;
|
||||
import art.arcane.volmlib.util.director.runtime.DirectorNodeDescriptor;
|
||||
import art.arcane.volmlib.util.localization.MessageArgument;
|
||||
import art.arcane.volmlib.util.localization.TextKey;
|
||||
import org.bukkit.World;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class CommandPackUpdateWorldTest {
|
||||
@Test
|
||||
public void packNamespaceExposesAnExplicitConfirmation() throws Exception {
|
||||
DirectorNodeDescriptor command = DirectorAnnotationCompatibility.fromMethod(
|
||||
CommandPack.class.getDeclaredMethod("updateWorld", World.class, IrisDimension.class, boolean.class)
|
||||
).orElseThrow();
|
||||
|
||||
assertEquals("update-world", command.getName());
|
||||
assertTrue(command.getParameters().get(0).isRequired());
|
||||
assertTrue(command.getParameters().get(1).isRequired());
|
||||
assertFalse(command.getParameters().get(2).isRequired());
|
||||
assertEquals("false", command.getParameters().get(2).getDefaultValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unconfirmedAndNonPersistentWorldUpdatesCannotPublish() {
|
||||
VolmitSender sender = mock(VolmitSender.class);
|
||||
World world = mock(World.class);
|
||||
IrisDimension pack = new IrisDimension();
|
||||
pack.setLoadKey("overworld");
|
||||
when(world.getName()).thenReturn("example");
|
||||
try (MockedStatic<Iris> iris = mockStatic(Iris.class);
|
||||
MockedStatic<IrisToolbelt> toolbelt = mockStatic(IrisToolbelt.class)) {
|
||||
CommandPack.stageWorldUpdate(sender, world, pack, true);
|
||||
toolbelt.when(() -> IrisToolbelt.isIrisWorld(world)).thenReturn(true);
|
||||
toolbelt.when(() -> IrisToolbelt.isIrisStudioWorld(world)).thenReturn(true);
|
||||
CommandPack.stageWorldUpdate(sender, world, pack, true);
|
||||
toolbelt.when(() -> IrisToolbelt.isIrisStudioWorld(world)).thenReturn(false);
|
||||
CommandPack.stageWorldUpdate(sender, world, pack, false);
|
||||
|
||||
iris.verifyNoInteractions();
|
||||
verify(sender, times(2)).sendMessage(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_PACK_UPDATE_WORLD_REQUIRES_PERSISTENT_WORLD));
|
||||
verify(sender).sendMessage(IrisLanguage.text(
|
||||
BukkitRuntimeMessages.COMMAND_DEVELOPER_UPDATE_WORLD_WARNING,
|
||||
MessageArgument.untrusted("world", "example"),
|
||||
MessageArgument.untrusted("pack", "overworld")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateResultsRenderTheWorldPackAndVersion() {
|
||||
for (TextKey key : List.of(BukkitRuntimeMessages.COMMAND_PACK_UPDATE_WORLD_STAGED,
|
||||
BukkitRuntimeMessages.COMMAND_PACK_UPDATE_WORLD_UNCHANGED)) {
|
||||
String message = IrisLanguage.text(key,
|
||||
MessageArgument.untrusted("world", "example"),
|
||||
MessageArgument.untrusted("pack", "overworld"),
|
||||
MessageArgument.untrusted("version", 4011));
|
||||
|
||||
assertTrue(message.contains("example"));
|
||||
assertTrue(message.contains("overworld"));
|
||||
assertTrue(message.contains("4011"));
|
||||
assertFalse(message.contains("{world}"));
|
||||
assertFalse(message.contains("{pack}"));
|
||||
assertFalse(message.contains("{version}"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void confirmedUpdateUsesTheExistingWorldFolderAndSeed() {
|
||||
VolmitSender sender = mock(VolmitSender.class);
|
||||
World world = mock(World.class);
|
||||
IrisDimension pack = new IrisDimension();
|
||||
File folder = new File("example");
|
||||
StudioSVC studio = mock(StudioSVC.class);
|
||||
when(world.getName()).thenReturn("example");
|
||||
when(world.getWorldFolder()).thenReturn(folder);
|
||||
when(world.getSeed()).thenReturn(42L);
|
||||
try (MockedStatic<Iris> iris = mockStatic(Iris.class);
|
||||
MockedStatic<IrisToolbelt> toolbelt = mockStatic(IrisToolbelt.class)) {
|
||||
iris.when(() -> Iris.service(StudioSVC.class)).thenReturn(studio);
|
||||
toolbelt.when(() -> IrisToolbelt.isIrisWorld(world)).thenReturn(true);
|
||||
|
||||
CommandPack.stageWorldUpdate(sender, world, pack, true);
|
||||
|
||||
verify(studio).replaceIntoWorld(sender, pack, folder, 42L);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user