Imagemap sanitization

This commit is contained in:
Brian Neumann-Fopiano
2026-08-24 13:44:44 -04:00
parent e20bb86f40
commit 37b01b73c4
112 changed files with 11127 additions and 670 deletions
@@ -102,6 +102,9 @@ import art.arcane.volmlib.util.io.IO;
import art.arcane.volmlib.util.io.InstanceState;
import art.arcane.volmlib.util.math.M;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.plugin.ComponentLog;
import art.arcane.volmlib.util.plugin.ComponentMessenger;
import art.arcane.volmlib.util.plugin.ComponentText;
import art.arcane.iris.util.common.misc.Bindings;
import art.arcane.iris.util.common.misc.ServerProperties;
import art.arcane.iris.util.common.misc.SlimJar;
@@ -147,6 +150,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -161,7 +165,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
}
public static Iris instance;
public static Bindings.Adventure audiences;
public static MultiverseCoreLink linkMultiverseCore;
public static IrisCompat compat;
public static ChunkTickets tickets;
@@ -256,7 +259,15 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
getSender().sendMessage(string);
} catch (Throwable e) {
try {
instance.getLogger().info(instance.getTag() + IrisLogging.clean(string));
Iris plugin = instance;
String tag = plugin == null ? "" : plugin.getTag();
ComponentLog.logMarkup(
plugin,
Logger.getLogger("Iris"),
"[Iris] ",
Level.INFO,
tag + string,
null);
} catch (Throwable inner) {
System.err.println("[Iris] Failed to emit log message: " + inner.getMessage());
inner.printStackTrace(System.err);
@@ -550,20 +561,13 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
private static void diagnostic(Level level, String message) {
String line = IrisLogging.clean(message);
Iris plugin = instance;
if (plugin != null) {
try {
plugin.getLogger().log(level, line);
return;
} catch (Throwable unavailable) {
// Paper runs the bootstrap before a plugin logger exists; the streams below are all there is.
}
}
if (level.intValue() >= Level.WARNING.intValue()) {
System.err.println("[Iris] " + line);
return;
}
System.out.println("[Iris] " + line);
ComponentLog.log(
instance,
Logger.getLogger("Iris"),
"[Iris] ",
level,
ComponentText.literal(line),
null);
}
/**
@@ -595,7 +599,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
PaperLibBootstrap.install();
SimdSupport.install();
services = new KMap<>();
setupAudience();
BukkitPlatform.hostHud(new HudActionBar(this), new HudBossBarLane());
Bindings.setupSentry();
// Explicit, ordered service list: the previous reflective jar scan gave hash-ordered
@@ -794,17 +797,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
}
}
private void setupAudience() {
try {
audiences = new Bindings.Adventure(this);
BukkitPlatform.hostAudiences(audiences);
} catch (Throwable e) {
IrisSettings.get().getGeneral().setUseConsoleCustomColors(false);
IrisSettings.get().getGeneral().setUseCustomColorsIngame(false);
Iris.reportError("Failed to set up Adventure; custom colors are disabled.", e);
}
}
public void onEnable() {
IrisPlatforms.bind(new BukkitPlatform());
IrisStartupValidation.begin();
@@ -1215,7 +1207,9 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
}
public void imsg(CommandSender s, String msg) {
s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg);
ComponentMessenger.sendSection(
s,
C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg);
}
@Nullable
@@ -398,7 +398,7 @@ public class CommandObject implements DirectorExecutor {
MessageArgument.trusted("value2", targets.size())
));
org.bukkit.command.CommandSender s = sender();
VolmitSender s = sender();
List<TreePlausibilizeBatch.Target> queued = targets;
J.a(() -> TreePlausibilizeBatch.run(queued, dryRun, reach, nearest, (TreePlausibilizeBatch.Output output) ->
s.sendMessage(output.headline()
@@ -21,6 +21,7 @@ package art.arcane.iris.core.commands;
import art.arcane.iris.Iris;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.gui.ImageMapStudioGUI;
import art.arcane.iris.core.gui.NoiseExplorerGUI;
import art.arcane.iris.core.gui.VisionGUI;
import art.arcane.iris.core.loader.IrisData;
@@ -263,6 +264,28 @@ public class CommandStudio implements DirectorExecutor {
NoiseExplorerGUI.launchGeneratorKey(generatorKey, generator, seed);
}
@Director(description = "Open the image-map studio (External GUI)", descriptionKey = "iris.director.commandstudio.director.open_image_map_studio_external_gui", aliases = {"imap"})
public void imagemap(
@Param(name = "world", description = "The Iris world whose active pack receives image-map exports", descriptionKey = "iris.director.commandstudio.param.world_open_image_map_studio", contextual = true, contextualOverride = true)
World world
) {
if (noGUI()) {
return;
}
if (!ImageMapStudioGUI.isAvailable()) {
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_YOU_MUST_HAVE_SERVER_LAUNCHED_GUIS_ENABLED_SETTINGS));
return;
}
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_YOU_NEED_BE_SPECIFY_IRIS_GENERATED_WORLD));
return;
}
Engine activeEngine = IrisToolbelt.access(world).getEngine();
ImageMapStudioGUI.launch(activeEngine);
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_OPENING_IMAGE_MAP_STUDIO));
}
@Director(description = "Show loot if a chest were right here", descriptionKey = "iris.director.commandstudio.director.show_loot_if_chest_were_right_here", origin = DirectorOrigin.PLAYER, sync = true)
public void loot(
@Param(description = "Fast insertion of items in virtual inventory (may cause performance drop)", descriptionKey = "iris.director.commandstudio.param.fast_insertion_items_virtual_inventory_may_cause_performance_drop", defaultValue = "false")
@@ -36,11 +36,14 @@ import art.arcane.iris.engine.framework.NativeStructureVolume;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisDimensionRuntimeContract;
import art.arcane.iris.engine.object.IrisWorld;
import art.arcane.iris.engine.object.IrisWorldBoundary;
import art.arcane.iris.platform.bukkit.BukkitWorldBinding;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.util.common.scheduling.J;
import art.arcane.volmlib.util.collection.KList;
import org.bukkit.World;
import org.bukkit.WorldBorder;
public final class BukkitEnginePlatformHooks implements EnginePlatformHooks {
@Override
@@ -80,6 +83,35 @@ public final class BukkitEnginePlatformHooks implements EnginePlatformHooks {
"iris");
}
@Override
public void applyWorldBoundary(Engine engine) {
IrisDimension expectedDimension = engine.getDimension();
IrisWorldBoundary configuredBoundary = expectedDimension.getWorldBoundary();
if (configuredBoundary == null) {
return;
}
IrisWorld expectedIrisWorld = engine.getWorld();
World expectedWorld = BukkitWorldBinding.world(expectedIrisWorld);
if (expectedWorld == null) {
return;
}
IrisWorldBoundary boundary;
try {
boundary = IrisWorldBoundary.snapshot(configuredBoundary);
} catch (Throwable error) {
IrisLogging.error("Invalid Iris world boundary for " + expectedWorld.getName() + ".");
IrisLogging.reportError(error);
throw propagateBoundaryFailure("Invalid Iris world boundary for '" + expectedWorld.getName() + "'.", error);
}
if (!J.runGlobal(() -> applyWorldBoundary(engine, expectedDimension, expectedIrisWorld, expectedWorld, boundary))) {
IllegalStateException failure = new IllegalStateException(
"Bukkit global scheduler rejected world-boundary application for '" + expectedWorld.getName() + "'.");
IrisLogging.error(failure.getMessage());
IrisLogging.reportError(failure);
throw failure;
}
}
@Override
public boolean isPregeneratorActive(Engine engine) {
IrisWorld world = engine.getWorld();
@@ -134,4 +166,43 @@ public final class BukkitEnginePlatformHooks implements EnginePlatformHooks {
World world = BukkitWorldBinding.world(engine.getWorld());
return world != null && IrisToolbelt.isWorldMaintenanceBypassingMantleStages(world);
}
static void applyWorldBoundary(WorldBorder worldBorder, IrisWorldBoundary boundary) {
if (boundary == null) {
return;
}
worldBorder.setCenter(boundary.getCenter().getX(), boundary.getCenter().getZ());
worldBorder.setSize(boundary.getSize());
worldBorder.setWarningDistance(boundary.getWarningDistance());
worldBorder.setDamageBuffer(boundary.getDamageBuffer());
worldBorder.setDamageAmount(boundary.getDamageAmount());
}
private static void applyWorldBoundary(Engine engine, IrisDimension expectedDimension,
IrisWorld expectedIrisWorld, World expectedWorld,
IrisWorldBoundary boundary) {
if (engine.isClosed() || engine.isClosing() || engine.getDimension() != expectedDimension
|| engine.getWorld() != expectedIrisWorld
|| BukkitWorldBinding.world(expectedIrisWorld) != expectedWorld) {
return;
}
try {
applyWorldBoundary(expectedWorld.getWorldBorder(), boundary);
} catch (Throwable error) {
IrisLogging.error("Failed to apply Iris world boundary to " + expectedWorld.getName() + ".");
IrisLogging.reportError(error);
throw propagateBoundaryFailure("Failed to apply Iris world boundary to '"
+ expectedWorld.getName() + "'.", error);
}
}
private static RuntimeException propagateBoundaryFailure(String message, Throwable error) {
if (error instanceof Error fatal) {
throw fatal;
}
if (error instanceof RuntimeException runtimeException) {
return runtimeException;
}
return new IllegalStateException(message, error);
}
}
@@ -62,6 +62,7 @@ import java.util.Optional;
import art.arcane.iris.core.localization.IrisLanguage;
import art.arcane.iris.core.localization.IrisMessages;
import art.arcane.volmlib.util.localization.MessageArgument;
import art.arcane.volmlib.util.plugin.ComponentMessenger;
public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, DirectorInvocationHook {
private static final String ROOT_COMMAND = "iris";
private static final String ROOT_PERMISSION = "iris.all";
@@ -169,7 +170,7 @@ public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, D
public void executeRoot(CommandSender sender, String label, String[] args) {
if (!sender.hasPermission(ROOT_PERMISSION)) {
sender.sendMessage(IrisLanguage.text(
ComponentMessenger.sendSection(sender, IrisLanguage.text(
IrisMessages.COMMAND_PERMISSION_DENIED,
MessageArgument.trusted("permission", ROOT_PERMISSION)
));
@@ -325,7 +326,7 @@ public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, D
@Override
public void sendMessage(String message) {
if (message != null && !message.trim().isEmpty()) {
sender.sendMessage(message);
ComponentMessenger.sendLiteral(sender, message);
}
}
}
@@ -65,7 +65,9 @@ public class IrisDiagnosticLogLevelTest {
assertTrue(bridge, bridge.contains("diagnosticLevel(target)"));
assertTrue(bridge, bridge.contains("diagnostic(diagnostic, message)"));
assertTrue(source.contains("plugin.getLogger().log(level, line)"));
String diagnostic = method(source, "private static void diagnostic(Level level, String message)");
assertTrue(diagnostic, diagnostic.contains("ComponentLog.log("));
assertTrue(diagnostic, diagnostic.contains("ComponentText.literal(line)"));
}
private static String method(String source, String signature) {
@@ -0,0 +1,44 @@
package art.arcane.iris.core.runtime;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisWorldBoundary;
import art.arcane.iris.engine.object.IrisWorldBoundaryCenter;
import org.bukkit.WorldBorder;
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class BukkitWorldBoundaryTest {
@Test
public void omittedBoundaryDoesNotTouchTheNativeWorld() {
Engine engine = mock(Engine.class);
when(engine.getDimension()).thenReturn(new IrisDimension());
new BukkitEnginePlatformHooks().applyWorldBoundary(engine);
verify(engine, never()).getWorld();
}
@Test
public void mapsEveryBoundaryValueToBukkit() {
WorldBorder worldBorder = mock(WorldBorder.class);
IrisWorldBoundary boundary = new IrisWorldBoundary()
.setCenter(new IrisWorldBoundaryCenter(12.5D, -7.25D))
.setSize(4096D)
.setWarningDistance(24)
.setDamageBuffer(6.5D)
.setDamageAmount(0.4D);
BukkitEnginePlatformHooks.applyWorldBoundary(worldBorder, boundary);
verify(worldBorder).setCenter(12.5D, -7.25D);
verify(worldBorder).setSize(4096D);
verify(worldBorder).setWarningDistance(24);
verify(worldBorder).setDamageBuffer(6.5D);
verify(worldBorder).setDamageAmount(0.4D);
}
}