Wand fix for WE

This commit is contained in:
Brian Neumann-Fopiano
2026-09-05 20:24:01 -04:00
parent 064ec0cae9
commit c53e9f8261
6 changed files with 194 additions and 31 deletions
@@ -527,21 +527,19 @@ public class CommandObject implements DirectorExecutor {
return;
}
if (WandSVC.isHoldingIrisWand(player)) {
Location[] g = WandSVC.getCuboid(player);
Location[] g = WandSVC.getCuboid(player);
if (g == null) {
return;
}
if (!here) {
// TODO: WARNING HEIGHT
g[0] = player.getTargetBlock(null, 256).getLocation().clone();
} else {
g[0] = player.getLocation().getBlock().getLocation().clone().add(0, -1, 0);
}
player.getInventory().setItemInMainHand(WandSVC.createWand(g[0], g[1]));
if (g == null) {
return;
}
if (!here) {
// TODO: WARNING HEIGHT
g[0] = player.getTargetBlock(null, 256).getLocation().clone();
} else {
g[0] = player.getLocation().getBlock().getLocation().clone().add(0, -1, 0);
}
player.getInventory().setItemInMainHand(WandSVC.createWand(g[0], g[1]));
});
}
@@ -27,11 +27,9 @@ import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.World;
import art.arcane.iris.Iris;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.localization.IrisLanguage;
import art.arcane.iris.core.localization.RuntimeUiMessages;
import art.arcane.iris.core.edit.DustRevealer;
import art.arcane.iris.core.link.WorldEditLink;
import art.arcane.iris.core.wand.WandSelection;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.iris.util.project.matter.WorldMatter;
@@ -333,26 +331,14 @@ public class WandSVC implements IrisService {
}
public static Location[] getCuboid(Player p) {
if (isHoldingIrisWand(p)) {
if (isHoldingWand(p)) {
return getCuboidFromItem(p.getInventory().getItemInMainHand());
}
if (IrisSettings.get().getWorld().worldEditWandCUI) {
Cuboid c = WorldEditLink.getSelection(p);
if (c != null) {
return new Location[]{c.getLowerNE(), c.getUpperSW()};
}
}
return null;
}
public static boolean isHoldingWand(Player p) {
return isHoldingIrisWand(p) || (IrisSettings.get().getWorld().worldEditWandCUI && WorldEditLink.getSelection(p) != null);
}
public static boolean isHoldingIrisWand(Player p) {
ItemStack is = p.getInventory().getItemInMainHand();
return is != null && isWand(is);
}
@@ -567,7 +553,7 @@ public class WandSVC implements IrisService {
if (e.getHand() != EquipmentSlot.HAND)
return;
try {
if (isHoldingIrisWand(e.getPlayer())) {
if (isHoldingWand(e.getPlayer())) {
activePlayers.put(e.getPlayer().getUniqueId(), e.getPlayer());
if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
e.setCancelled(true);
@@ -123,7 +123,7 @@ public class WandSelection {
p.spawnParticle(REDSTONE, x, y, z,
0, 0, 0, 0, 1,
new Particle.DustOptions(org.bukkit.Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()),
(float) dist * 3f));
Math.clamp((float) dist * 3f, 0.01f, 4f)));
}
private static double square(double value) {
@@ -0,0 +1,108 @@
package art.arcane.iris.core.service;
import art.arcane.iris.Iris;
import art.arcane.iris.core.link.WorldEditLink;
import art.arcane.volmlib.util.bukkit.WorldIdentity;
import art.arcane.volmlib.util.data.Cuboid;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
import java.util.List;
import java.util.Optional;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
public class WandSVCTest {
private Iris previousPlugin;
private Player player;
private PlayerInventory inventory;
@Before
public void installPlugin() {
previousPlugin = Iris.instance;
Iris plugin = mock(Iris.class);
when(plugin.namespace()).thenReturn("iris");
Iris.instance = plugin;
player = mock(Player.class);
inventory = mock(PlayerInventory.class);
when(player.getInventory()).thenReturn(inventory);
}
@After
public void restorePlugin() {
Iris.instance = previousPlugin;
}
@Test
public void ignoresWorldEditSelectionWhileHoldingAnOrdinaryAxe() {
ItemStack axe = wandItem(false);
when(inventory.getItemInMainHand()).thenReturn(axe);
Cuboid selection = mock(Cuboid.class);
try (MockedStatic<WorldEditLink> worldEdit = mockStatic(WorldEditLink.class)) {
worldEdit.when(() -> WorldEditLink.getSelection(player)).thenReturn(selection);
assertFalse(WandSVC.isHoldingWand(player));
assertNull(WandSVC.getCuboid(player));
}
}
@Test
public void ignoresWorldEditSelectionWithAnEmptyHand() {
Cuboid selection = mock(Cuboid.class);
try (MockedStatic<WorldEditLink> worldEdit = mockStatic(WorldEditLink.class)) {
worldEdit.when(() -> WorldEditLink.getSelection(player)).thenReturn(selection);
assertFalse(WandSVC.isHoldingWand(player));
assertNull(WandSVC.getCuboid(player));
}
}
@Test
public void readsSelectionFromAnIrisMarkedWand() {
ItemStack wand = wandItem(true);
when(inventory.getItemInMainHand()).thenReturn(wand);
World world = mock(World.class);
try (MockedStatic<WorldIdentity> worlds = mockStatic(WorldIdentity.class)) {
worlds.when(() -> WorldIdentity.resolve("minecraft:overworld")).thenReturn(Optional.of(world));
assertTrue(WandSVC.isHoldingWand(player));
assertArrayEquals(new Location[]{new Location(world, 1D, 64D, 2D), new Location(world, 3D, 68D, 4D)},
WandSVC.getCuboid(player));
}
}
private ItemStack wandItem(boolean marked) {
ItemStack item = mock(ItemStack.class);
ItemMeta meta = mock(ItemMeta.class);
PersistentDataContainer data = mock(PersistentDataContainer.class);
when(item.getType()).thenReturn(marked ? Material.BLAZE_ROD : Material.WOODEN_AXE);
when(item.getItemMeta()).thenReturn(meta);
when(meta.getPersistentDataContainer()).thenReturn(data);
when(meta.getLore()).thenReturn(List.of("1,64,2 in minecraft:overworld", "3,68,4 in minecraft:overworld"));
if (marked) {
when(data.get(new NamespacedKey("iris", "wand"), PersistentDataType.BYTE)).thenReturn((byte) 1);
}
return item;
}
}
@@ -0,0 +1,72 @@
package art.arcane.iris.core.wand;
import art.arcane.iris.util.common.data.registry.RegistryUtil;
import art.arcane.volmlib.util.data.Cuboid;
import art.arcane.volmlib.util.math.M;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class WandSelectionTest {
@Test
public void capsEmittedDustSizeAtLongDistances() {
for (double distance : new double[]{64D, 128D, 255.9D}) {
Player player = drawAt(distance);
ArgumentCaptor<Particle.DustOptions> options = ArgumentCaptor.forClass(Particle.DustOptions.class);
verify(player, atLeastOnce()).spawnParticle(eq(Particle.DUST), anyDouble(), anyDouble(), anyDouble(),
eq(0), eq(0D), eq(0D), eq(0D), eq(1D), options.capture());
for (Particle.DustOptions dust : options.getAllValues()) {
assertEquals("Dust size at distance " + distance, 4f, dust.getSize(), 0f);
}
}
}
@Test
public void retainsNearbyDustSize() {
Player player = drawAt(0D);
ArgumentCaptor<Particle.DustOptions> options = ArgumentCaptor.forClass(Particle.DustOptions.class);
verify(player, atLeastOnce()).spawnParticle(eq(Particle.DUST), eq(0D), eq(0D), eq(0D),
eq(0), eq(0D), eq(0D), eq(0D), eq(1D), options.capture());
for (Particle.DustOptions dust : options.getAllValues()) {
assertEquals(0.375f, dust.getSize(), 0f);
}
}
private Player drawAt(double distance) {
Player player = mock(Player.class);
World world = mock(World.class);
Cuboid cuboid = mock(Cuboid.class);
when(player.getLocation()).thenReturn(new Location(world, distance, 0D, 0D));
when(cuboid.getWorld()).thenReturn(world);
try (MockedStatic<M> math = mockStatic(M.class, CALLS_REAL_METHODS);
MockedStatic<RegistryUtil> registry = mockStatic(RegistryUtil.class)) {
math.when(() -> M.r(anyDouble())).thenReturn(false);
registry.when(() -> RegistryUtil.find(Particle.class, "crit_magic", "crit")).thenReturn(Particle.CRIT);
registry.when(() -> RegistryUtil.find(Particle.class, "redstone", "dust")).thenReturn(Particle.DUST);
registry.when(() -> RegistryUtil.find(Particle.class, "item_crack", "item")).thenReturn(Particle.ITEM);
new WandSelection(cuboid, player).draw();
}
return player;
}
}
@@ -199,7 +199,6 @@ public class IrisSettings {
public double targetSpawnEntitiesPerChunk = 0.95;
public boolean markerEntitySpawningSystem = true;
public boolean effectSystem = true;
public boolean worldEditWandCUI = true;
public boolean globalPregenCache = false;
}