diff --git a/src/main/java/com/thevoxelbox/voxelsniper/Message.java b/src/main/java/com/thevoxelbox/voxelsniper/Message.java index 063c7d8d..ab7e041f 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/Message.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/Message.java @@ -24,6 +24,7 @@ */ package com.thevoxelbox.voxelsniper; +import com.thevoxelbox.voxelsniper.brush.PerformBrush; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; import org.spongepowered.api.text.Text; @@ -62,7 +63,8 @@ public void brushName(String brushName) { * Display Center Parameter. */ public void center() { - this.snipeData.sendMessage(TextColors.DARK_BLUE, "Brush Center: ", TextColors.DARK_RED, this.snipeData.getcCen()); + this.snipeData.sendMessage(TextColors.DARK_BLUE, "Brush Center: ", + TextColors.DARK_RED, this.snipeData.getCylinderCenter()); } /** @@ -86,19 +88,53 @@ public void height() { } /** - * Display performer. + * Display performer data. * - * @param performerName + * @param placeMethod + * @param replaceMethod + * @param usePhysics */ - public void performerName(String performerName) { - this.snipeData.sendMessage(TextColors.DARK_PURPLE, "Performer: ", TextColors.DARK_GREEN, performerName); + public void performerData(PerformBrush.PerformerType placeMethod, + PerformBrush.PerformerType replaceMethod, + boolean usePhysics) { + String physics = usePhysics ? "On" : "Off"; + this.snipeData.sendMessage( + TextColors.DARK_PURPLE, + "Performers:", + TextColors.GREEN, + " place=", + TextColors.AQUA, + performerTypeToString(placeMethod), + TextColors.GREEN, + " replace=", + TextColors.AQUA, + performerTypeToString(replaceMethod), + TextColors.GREEN, + " physics=", + TextColors.AQUA, + physics); + } + + private String performerTypeToString(PerformBrush.PerformerType type) { + switch (type) { + case TRAITS: + return "Ink"; + case TYPE: + return "Material"; + case COMBO: + return "Combo"; + case NONE: + return "None"; + } + + return "Unkown"; } /** * Display replace material. */ public void replace() { - this.snipeData.sendMessage(TextColors.AQUA, "Replace Material: ", TextColors.RED, this.snipeData.getReplaceId()); + this.snipeData.sendMessage(TextColors.DARK_BLUE, "Replace Material: ", TextColors.RED, this.snipeData.getReplaceId()); } /** diff --git a/src/main/java/com/thevoxelbox/voxelsniper/SnipeData.java b/src/main/java/com/thevoxelbox/voxelsniper/SnipeData.java index a9429a26..156686c7 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/SnipeData.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/SnipeData.java @@ -24,41 +24,55 @@ */ package com.thevoxelbox.voxelsniper; +import com.thevoxelbox.voxelsniper.util.BlockHelper; import com.thevoxelbox.voxelsniper.util.VoxelList; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockTypes; -import org.spongepowered.api.data.key.Key; -import org.spongepowered.api.data.value.BaseValue; +import org.spongepowered.api.block.trait.BlockTrait; import org.spongepowered.api.text.Text; import org.spongepowered.api.world.World; -import java.util.Optional; +import java.util.*; public class SnipeData { private Sniper owner; private Message voxelMessage; - private double brushSize = VoxelSniperConfiguration.DEFAULT_BRUSH_SIZE; - private BlockState voxelId = Sponge.getRegistry().getType(BlockState.class, VoxelSniperConfiguration.DEFAULT_VOXEL_ID).orElse(BlockTypes.AIR.getDefaultState()); - private BlockState replaceId = - Sponge.getRegistry().getType(BlockState.class, VoxelSniperConfiguration.DEFAULT_REPLACE_ID).orElse(BlockTypes.AIR.getDefaultState()); - private VoxelList voxelList = new VoxelList(); - private Key voxelInkKey = null; - private Object voxelInkValue = null; - private Key replaceInkKey = null; - private Object replaceInkValue = null; - - private int voxelHeight = VoxelSniperConfiguration.DEFAULT_VOXEL_HEIGHT; - private int cCen = VoxelSniperConfiguration.DEFAULT_CYLINDER_CENTER; - private int range = 0; - private boolean ranged = false; - private boolean lightning = false; + private double brushSize; + private BlockState voxelState; + private BlockState replaceState; + private VoxelList voxelList; + private Map, Object> voxelInkTraits; + private Map, Object> replaceInkTraits; + + private int voxelHeight; + private int cCen; + private int range; + private boolean ranged; + private boolean lightning; public SnipeData(Sniper vs) { - this.owner = vs; + owner = vs; + + voxelState = Sponge.getRegistry().getType(BlockState.class, VoxelSniperConfiguration.DEFAULT_VOXEL_ID) + .orElse(BlockTypes.AIR.getDefaultState()); + replaceState = Sponge.getRegistry().getType(BlockState.class, VoxelSniperConfiguration.DEFAULT_REPLACE_ID) + .orElse(BlockTypes.AIR.getDefaultState()); + + brushSize = VoxelSniperConfiguration.DEFAULT_BRUSH_SIZE; + voxelList = new VoxelList(); + voxelHeight = VoxelSniperConfiguration.DEFAULT_VOXEL_HEIGHT; + cCen = VoxelSniperConfiguration.DEFAULT_CYLINDER_CENTER; + range = 0; + + ranged = false; + lightning = false; + + voxelInkTraits = new HashMap<>(); + replaceInkTraits = new HashMap<>(); } // @Cleanup these method names are all over the place @@ -71,11 +85,11 @@ public void setBrushSize(double brushSize) { this.brushSize = brushSize; } - public int getcCen() { + public int getCylinderCenter() { return this.cCen; } - public void setcCen(int cCen) { + public void setCylinderCenter(int cCen) { this.cCen = cCen; } @@ -88,24 +102,17 @@ public void setRange(int range) { } public String getReplaceId() { - return this.replaceId.getId(); + return this.replaceState.getId(); } - public BlockState getReplaceIdState() { - return this.replaceId; + public BlockState getReplaceState() { + return this.replaceState; } - public boolean setReplaceId(String replaceId) { - Optional state = Sponge.getRegistry().getType(BlockState.class, replaceId); - if (state.isPresent()) { - this.replaceId = state.get(); - return true; - } - return false; - } - - public void setReplaceId(BlockState state) { - this.replaceId = state; + public void setReplaceState(BlockState state) { + replaceState = state; + replaceInkTraits.clear(); + replaceInkTraits.putAll(state.getTraitMap()); } public int getVoxelHeight() { @@ -117,28 +124,21 @@ public void setVoxelHeight(int voxelHeight) { } public String getVoxelId() { - return this.voxelId.getId(); + return voxelState.getId(); } - public BlockState getVoxelIdState() { - return this.voxelId; + public BlockState getVoxelState() { + return voxelState; } - public boolean setVoxelId(String voxelId) { - Optional state = Sponge.getRegistry().getType(BlockState.class, voxelId); - if (state.isPresent()) { - this.voxelId = state.get(); - return true; - } - return false; - } - - public void setVoxelId(BlockState state) { - this.voxelId = state; + public void setVoxelState(BlockState state) { + voxelState = state; + voxelInkTraits.clear(); + voxelInkTraits.putAll(state.getTraitMap()); } public VoxelList getVoxelList() { - return this.voxelList; + return voxelList; } public void setVoxelList(VoxelList voxelList) { @@ -146,7 +146,7 @@ public void setVoxelList(VoxelList voxelList) { } public Message getVoxelMessage() { - return this.voxelMessage; + return voxelMessage; } public void setVoxelMessage(Message voxelMessage) { @@ -154,11 +154,11 @@ public void setVoxelMessage(Message voxelMessage) { } public World getWorld() { - return this.owner.getPlayer().getWorld(); + return owner.getPlayer().getWorld(); } public boolean isLightningEnabled() { - return this.lightning; + return lightning; } public void setLightningEnabled(boolean lightning) { @@ -166,59 +166,47 @@ public void setLightningEnabled(boolean lightning) { } public boolean isRanged() { - return this.ranged; + return ranged; } public void setRanged(boolean ranged) { this.ranged = ranged; } - public Key> getVoxelInkKey() { - return this.voxelInkKey; - } - - public Object getVoxelInkValue() { - return this.voxelInkValue; - } - - public , T> void setVoxelInk(Key key, T value) { - this.voxelInkKey = key; - this.voxelInkValue = value; + public Map, Object> getVoxelInkTraits() { + return Collections.unmodifiableMap(voxelInkTraits); } - public Key> getReplaceInkKey() { - return this.replaceInkKey; + // Attempts to add the traitValues as the current placement ink. If the trait values can't be used with the current + // voxel state, no changes are made. + public void setVoxelInkTraits(Map, Object> traitValues) { + Optional optState = BlockHelper.addTraits(voxelState.getType().getDefaultState(), traitValues); + if (optState.isPresent()) { + voxelState = optState.get(); + voxelInkTraits.clear(); + voxelInkTraits.putAll(traitValues); + } } - public Object getReplaceInkValue() { - return this.replaceInkValue; + public Map, Object> getReplaceInkTraits() { + return Collections.unmodifiableMap(replaceInkTraits); } - public , T> void setReplaceInk(Key key, T value) { - this.replaceInkKey = key; - this.replaceInkValue = value; + // Attempts to add the traitValues as the current replacement ink. If the trait values can't be used with the + // current replacement state, no changes are made. + public void setReplaceInkTraits(Map, Object> traitValues) { + Optional optState = BlockHelper.addTraits(replaceState.getType().getDefaultState(), traitValues); + if (optState.isPresent()) { + replaceState = optState.get(); + replaceInkTraits.clear(); + replaceInkTraits.putAll(traitValues); + } } public Sniper owner() { return this.owner; } - /** - * Reset to default values. - */ - public void reset() { - this.voxelId = Sponge.getRegistry().getType(BlockState.class, VoxelSniperConfiguration.DEFAULT_VOXEL_ID).orElse(BlockTypes.AIR.getDefaultState()); - this.replaceId = Sponge.getRegistry().getType(BlockState.class, VoxelSniperConfiguration.DEFAULT_REPLACE_ID).orElse(BlockTypes.AIR.getDefaultState()); - this.brushSize = VoxelSniperConfiguration.DEFAULT_BRUSH_SIZE; - this.voxelHeight = VoxelSniperConfiguration.DEFAULT_VOXEL_HEIGHT; - this.cCen = VoxelSniperConfiguration.DEFAULT_CYLINDER_CENTER; - this.voxelList = new VoxelList(); - - this.voxelInkKey = null; - this.voxelInkValue = null; - this.replaceInkKey = null; - this.replaceInkValue = null; - } public void sendMessage(Object... args) { this.owner.getPlayer().sendMessage(Text.of(args)); diff --git a/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java b/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java index a0ffe694..58c159c4 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java @@ -47,6 +47,7 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; +import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import java.util.Map; import java.util.UUID; @@ -127,8 +128,7 @@ public boolean snipe(InteractionType action, ItemStack itemInHand) { } SnipeData snipeData = sniperTool.getSnipeData(); - if (player.get(Keys.IS_SNEAKING).orElse(false)) { - Location targetBlock = null; + if (player.getOrElse(Keys.IS_SNEAKING, false)) { SnipeAction snipeAction = sniperTool.getActionAssigned(itemInHand.getType()); Predicate> filter = BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1); @@ -137,6 +137,7 @@ public boolean snipe(InteractionType action, ItemStack itemInHand) { rayBuilder.distanceLimit(snipeData.getRange()); } BlockRay ray = rayBuilder.build(); + Location targetBlock = null; while (ray.hasNext()) { targetBlock = ray.next().getLocation(); } @@ -146,21 +147,11 @@ public boolean snipe(InteractionType action, ItemStack itemInHand) { case PRIMARY_OFFHAND: switch (snipeAction) { case ARROW: -// int originalVoxel = snipeData.getVoxelId(); - snipeData.setVoxelId(targetBlock.getBlockType().getDefaultState()); -// SniperMaterialChangedEvent event = -// new SniperMaterialChangedEvent(this, toolId, new MaterialData(originalVoxel, snipeData.getData()), -// new MaterialData(snipeData.getVoxelId(), snipeData.getData())); -// Bukkit.getPluginManager().callEvent(event); + snipeData.setVoxelState(targetBlock.getBlockType().getDefaultState()); snipeData.getVoxelMessage().voxel(); return true; case GUNPOWDER: -// byte originalData = snipeData.getData(); - snipeData.setVoxelId(targetBlock.getBlock()); -// SniperMaterialChangedEvent event = -// new SniperMaterialChangedEvent(this, toolId, new MaterialData(snipeData.getVoxelId(), originalData), -// new MaterialData(snipeData.getVoxelId(), snipeData.getData())); -// Bukkit.getPluginManager().callEvent(event); + snipeData.setVoxelState(targetBlock.getBlock()); snipeData.getVoxelMessage().voxel(); return true; default: @@ -171,21 +162,11 @@ public boolean snipe(InteractionType action, ItemStack itemInHand) { case SECONDARY_OFFHAND: switch (snipeAction) { case ARROW: -// int originalId = snipeData.getReplaceId(); - snipeData.setReplaceId(targetBlock.getBlockType().getDefaultState()); -// SniperReplaceMaterialChangedEvent event = new SniperReplaceMaterialChangedEvent(this, toolId, -// new MaterialData(originalId, snipeData.getReplaceData()), -// new MaterialData(snipeData.getReplaceId(), snipeData.getReplaceData())); -// Bukkit.getPluginManager().callEvent(event); + snipeData.setReplaceState(targetBlock.getBlockType().getDefaultState()); snipeData.getVoxelMessage().replace(); return true; case GUNPOWDER: -// byte originalData = snipeData.getReplaceData(); - snipeData.setReplaceId(targetBlock.getBlock()); -// SniperReplaceMaterialChangedEvent event = new SniperReplaceMaterialChangedEvent(this, toolId, -// new MaterialData(snipeData.getReplaceId(), originalData), -// new MaterialData(snipeData.getReplaceId(), snipeData.getReplaceData())); -// Bukkit.getPluginManager().callEvent(event); + snipeData.setReplaceState(targetBlock.getBlock()); snipeData.getVoxelMessage().replace(); return true; default: @@ -453,10 +434,11 @@ public IBrush previousBrush() { private IBrush instanciateBrush(Class brush) { try { - return brush.newInstance(); - } catch (InstantiationException e) { - return null; - } catch (IllegalAccessException e) { + return brush.getConstructor().newInstance(); + } catch (InstantiationException | + IllegalAccessException | + NoSuchMethodException | + InvocationTargetException e) { return null; } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/PerformBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/PerformBrush.java index 99561803..efadf102 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/PerformBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/PerformBrush.java @@ -30,69 +30,77 @@ import com.thevoxelbox.voxelsniper.Message; import com.thevoxelbox.voxelsniper.SnipeData; +import com.thevoxelbox.voxelsniper.util.BlockHelper; +import jdk.nashorn.internal.ir.Block; +import org.checkerframework.checker.nullness.Opt; import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.block.trait.BlockTrait; import org.spongepowered.api.data.key.Key; +import org.spongepowered.api.data.value.BaseValue; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.world.BlockChangeFlag; import org.spongepowered.api.world.BlockChangeFlags; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; import java.util.Arrays; +import java.util.IllegalFormatException; +import java.util.Map; import java.util.Optional; +import java.util.regex.Matcher; import java.util.regex.Pattern; public abstract class PerformBrush extends Brush { - private static final Pattern PERFORMER = Pattern.compile("[mMcC][mMcC]?[pP]?"); + private static final Pattern PERFORMER = Pattern.compile("([mic])([mic]?)(p?)"); - protected PerformerType place = PerformerType.TYPE; - protected PerformerType replace = PerformerType.NONE; - protected boolean physics = true; + protected PerformerType placeMethod = PerformerType.TYPE; + protected PerformerType replaceMethod = PerformerType.NONE; + protected boolean usePhysics = true; public void parse(String[] args, SnipeData v) { - String handle = args[0]; - if (PERFORMER.matcher(handle).matches()) { - char p = handle.charAt(0); - if (p == 'm' || p == 'M') { - this.place = PerformerType.TYPE; - } else if (p == 'c' || p == 'C') { - this.place = PerformerType.COMBO; - } - int i = 1; - if (handle.length() >= 2) { - char r = handle.charAt(i); - i = 2; - if (r == 'm' || r == 'M') { - this.replace = PerformerType.TYPE; - } else if (r == 'c' || r == 'C') { - this.replace = PerformerType.COMBO; - } else { - i = 1; - this.replace = PerformerType.NONE; - } - } - if (handle.length() >= i + 1) { - char e = handle.charAt(i); - if (e == 'p' || e == 'P') { - this.physics = false; - } else { - this.physics = true; - } + String handle = args[0].toLowerCase(); + Matcher performersMatch = PERFORMER.matcher(handle); + + if (performersMatch.matches()) { + placeMethod = stringToMethod(performersMatch.group(1)); + if (placeMethod == PerformerType.NONE) { + throw new IllegalArgumentException("Unknown placement method '" + performersMatch.group(1) + "'"); } + + replaceMethod = stringToMethod(performersMatch.group(2)); + usePhysics = !performersMatch.group(3).equals("p"); + parameters(Arrays.copyOfRange(args, 1, args.length), v); } else { parameters(args, v); } + + v.getVoxelMessage().performerData(placeMethod, replaceMethod, usePhysics); + } + + private PerformerType stringToMethod(String rawMethod) { + switch (rawMethod) { + case "m": + return PerformerType.TYPE; + case "i": + return PerformerType.TRAITS; + case "c": + return PerformerType.COMBO; + } + return PerformerType.NONE; } public void showInfo(Message vm) { - String name = this.place.name().toLowerCase(); - if (this.replace != PerformerType.NONE) { - name += " " + this.replace.name().toLowerCase(); + String name = placeMethod.name().toLowerCase(); + if (replaceMethod != PerformerType.NONE) { + name += replaceMethod.name().toLowerCase(); } - vm.performerName(name); + vm.performerData(placeMethod, replaceMethod, usePhysics); vm.voxel(); - if (this.replace != PerformerType.NONE) { + if (replaceMethod != PerformerType.NONE) { vm.replace(); } } @@ -105,53 +113,59 @@ protected boolean perform(SnipeData v, int x, int y, int z) { if (y < 0 || y >= Brush.WORLD_HEIGHT) { return false; } - if (this.replace != PerformerType.NONE) { - BlockState current = this.world.getBlock(x, y, z); - switch (this.replace) { + + BlockState current = this.world.getBlock(x, y, z); + switch (replaceMethod) { case TYPE: - if (current.getType() != v.getReplaceIdState().getType()) { + if (!sameBlockType(current, v.getReplaceState())) { return false; } break; - case STATE: - // @Todo filter by key and value + case TRAITS: + if (!BlockHelper.hasTraits(current, v.getReplaceInkTraits())) { + return false; + } break; case COMBO: - if (current != v.getReplaceIdState()) { + if (!sameBlockType(current, v.getReplaceState()) || + !BlockHelper.hasTraits(current, v.getReplaceInkTraits())) { return false; } break; case NONE: default: break; - } } - switch (this.place) { - case TYPE: - setBlockType(x, y, z, v.getVoxelIdState().getType(), this.physics ? BlockChangeFlags.ALL : BlockChangeFlags.NONE); - break; - case STATE: - BlockState current = this.world.getBlock(x, y, z); - @SuppressWarnings({"unchecked", "rawtypes"}) - Optional place = current.with((Key) v.getVoxelInkKey(), v.getVoxelInkValue()); - if (!place.isPresent()) { - return false; - } - setBlockState(x, y, z, place.get(), this.physics ? BlockChangeFlags.ALL : BlockChangeFlags.NONE); - break; - case COMBO: - setBlockState(x, y, z, v.getVoxelIdState(), this.physics ? BlockChangeFlags.ALL : BlockChangeFlags.NONE); - break; - case NONE: - default: - throw new IllegalStateException("Unsupported place type " + this.place.name()); + + BlockChangeFlag physicsFlags = usePhysics ? BlockChangeFlags.ALL : BlockChangeFlags.NONE; + switch (placeMethod) { + case TYPE: + setBlockType(x, y, z, v.getVoxelState().getType(), physicsFlags); + break; + case TRAITS: + Optional place = BlockHelper.addTraits(current, v.getVoxelInkTraits()); + if (!place.isPresent()) { + return false; + } + setBlockState(x, y, z, place.get(), physicsFlags); + break; + case COMBO: + setBlockState(x, y, z, v.getVoxelState(), physicsFlags); + break; + case NONE: + default: + throw new IllegalStateException("Unsupported place type " + placeMethod.name()); } return true; } - public static enum PerformerType { + private boolean sameBlockType(BlockState a, BlockState b) { + return a.getType().equals(b.getType()); + } + + public enum PerformerType { TYPE, - STATE, + TRAITS, COMBO, NONE; } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/CanyonBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/CanyonBrush.java index 3115fb2c..3757f587 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/CanyonBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/CanyonBrush.java @@ -60,7 +60,7 @@ protected void storeUndo(SnipeData v) { protected void operate(SnipeData v, Chunk chunk) { int minx = chunk.getBlockMin().getX(); int minz = chunk.getBlockMin().getZ(); - BlockState fillBlock = v.getVoxelIdState(); + BlockState fillBlock = v.getVoxelState(); if (fillBlock.getType() == BlockTypes.AIR) { fillBlock = BlockTypes.STONE.getDefaultState(); } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/OceanBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/OceanBrush.java index c75da63b..2eab91c6 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/OceanBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/chunk/OceanBrush.java @@ -102,7 +102,7 @@ private int getHeight(final int bx, final int bz, int start) { protected void operate(SnipeData v, Chunk chunk) { int minx = chunk.getBlockMin().getX(); int minz = chunk.getBlockMin().getZ(); - BlockState fillBlock = v.getVoxelIdState(); + BlockState fillBlock = v.getVoxelState(); if (fillBlock.getType() == BlockTypes.AIR) { fillBlock = BlockTypes.DIRT.getDefaultState(); } @@ -130,7 +130,7 @@ protected void operate(SnipeData v, Chunk chunk) { setBlockType(x0, y, z0, BlockTypes.WATER); } if(this.coverFloor) { - setBlockState(x0, y, z0, v.getVoxelIdState()); + setBlockState(x0, y, z0, v.getVoxelState()); } } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/EntityBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/EntityBrush.java index 98f03296..f73d3378 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/EntityBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/EntityBrush.java @@ -51,7 +51,7 @@ public EntityBrush() { private void spawn(final SnipeData v) { try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) { - Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.PLUGIN); + frame.addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.PLUGIN); for (int x = 0; x < v.getBrushSize(); x++) { Entity e = this.world.createEntity(this.entityType, this.lastBlock.getBlockPosition()); this.world.spawnEntity(e); diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/RulerBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/RulerBrush.java index d69bf8b1..b3d4d250 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/RulerBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/misc/RulerBrush.java @@ -57,7 +57,7 @@ protected final void arrow(final SnipeData v) { final Undo undo = new Undo(1); Location target = this.targetBlock.add(this.xOff, this.yOff, this.zOff); undo.put(target); - target.setBlock(v.getVoxelIdState()); + target.setBlock(v.getVoxelState()); v.owner().storeUndo(undo); } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/CylinderBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/CylinderBrush.java index f0047909..292af653 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/CylinderBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/CylinderBrush.java @@ -43,8 +43,8 @@ public CylinderBrush() { } private void cylinder(SnipeData v, Location targetBlock) { - int yStartingPoint = targetBlock.getBlockY() + v.getcCen(); - int yEndPoint = targetBlock.getBlockY() + v.getVoxelHeight() + v.getcCen(); + int yStartingPoint = targetBlock.getBlockY() + v.getCylinderCenter(); + int yEndPoint = targetBlock.getBlockY() + v.getVoxelHeight() + v.getCylinderCenter(); if (yEndPoint < yStartingPoint) { yEndPoint = yStartingPoint; @@ -129,8 +129,8 @@ public final void parameters(final String[] par, final SnipeData v) { } } else if (parameter.startsWith("c")) { try { - v.setcCen((int) Double.parseDouble(parameter.replace("c", ""))); - v.sendMessage(TextColors.AQUA + "Cylinder origin set to: " + v.getcCen()); + v.setCylinderCenter((int) Double.parseDouble(parameter.replace("c", ""))); + v.sendMessage(TextColors.AQUA + "Cylinder origin set to: " + v.getCylinderCenter()); } catch (NumberFormatException e) { v.sendMessage(TextColors.RED, "Invalid origin given."); } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ExtrudeBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ExtrudeBrush.java index 39a48f38..f5365fd3 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ExtrudeBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ExtrudeBrush.java @@ -55,7 +55,7 @@ private void extrude(final SnipeData v, Location targetBlock, Direction a if (x * x + z * z < brushSizeSquared) { if (v.getVoxelList().contains(get(x, z, axis, targetBlock))) { for (int y = 0; y < v.getVoxelHeight(); y++) { - set(x, z, axis, targetBlock, v.getVoxelIdState(), y); + set(x, z, axis, targetBlock, v.getVoxelState(), y); } } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/FillDownBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/FillDownBrush.java index 2c662830..0ca39f88 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/FillDownBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/FillDownBrush.java @@ -66,14 +66,14 @@ private void fillDown(SnipeData v, Location targetBlock) { int y = targetBlock.getBlockY(); if (this.fromExisting) { for (int y0 = -v.getVoxelHeight(); y0 < v.getVoxelHeight(); y0++) { - if (this.world.getBlock(x, y + y0, z) != v.getReplaceIdState()) { + if (this.world.getBlock(x, y + y0, z) != v.getReplaceState()) { y += y0 - 1; break; } } } for (; y >= 0; y--) { - if (this.replace != PerformerType.NONE) { + if (replaceMethod != PerformerType.NONE) { if (!perform(v, x, y, z)) { break; } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/OverlayBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/OverlayBrush.java index d9d7dc41..e72f5b6c 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/OverlayBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/OverlayBrush.java @@ -51,8 +51,8 @@ private void overlay(SnipeData v, Location targetBlock, int offset) { double brushSize = v.getBrushSize(); double brushSizeSquared = brushSize * brushSize; - int tx = this.targetBlock.getBlockX(); - int tz = this.targetBlock.getBlockZ(); + int targetX = this.targetBlock.getBlockX(); + int targetZ = this.targetBlock.getBlockZ(); int minx = GenericMath.floor(targetBlock.getBlockX() - brushSize); int maxx = GenericMath.floor(targetBlock.getBlockX() + brushSize) + 1; @@ -64,29 +64,27 @@ private void overlay(SnipeData v, Location targetBlock, int offset) { // @Cleanup Should wrap this within a block worker so that it works // better with the cause tracker for (int x = minx; x <= maxx; x++) { - double xs = (tx - x) * (tx - x); - outer: + double xs = (targetX - x) * (targetX - x); for (int z = minz; z <= maxz; z++) { - double zs = (tz - z) * (tz - z); + double zs = (targetZ - z) * (targetZ - z); if (xs + zs < brushSizeSquared) { int y = Math.min(targetBlock.getBlockY() + offset, WORLD_HEIGHT); - for (; y >= 0; y--) { - if (this.world.getBlockType(x, y, z) != BlockTypes.AIR) { - break; - } + while (y >= 0 && this.world.getBlockType(x, y, z) == BlockTypes.AIR) { + y--; } - if (y == targetBlock.getBlockY() && y < WORLD_HEIGHT) { - if (this.world.getBlockType(x, y + 1, z) != BlockTypes.AIR) { - // if theres no air above our start block then don't - // perform - continue outer; - } + + if (y == targetBlock.getBlockY() && + y < WORLD_HEIGHT && + this.world.getBlockType(x, y + 1, z) != BlockTypes.AIR) { + // if there's no air above our start block then don't + // perform + continue; } - for (int y0 = Math.min(y + offset, WORLD_HEIGHT); y0 > y - this.depth; y0--) { - if(y0 <= y && this.world.getBlockType(x, y0, z) == BlockTypes.AIR) { - break; - } + + int y0 = Math.min(y + offset, WORLD_HEIGHT); + while (y0 > y - this.depth && !(y0 <= y && this.world.getBlockType(x, y0, z) == BlockTypes.AIR)) { perform(v, x, y0, z); + y0--; } } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellBallBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellBallBrush.java index e97e412f..24149f0a 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellBallBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellBallBrush.java @@ -62,30 +62,30 @@ private void bShell(final SnipeData v, Location targetBlock) { if (y <= 0 || y >= WORLD_HEIGHT) { continue; } - if (this.world.getBlock(x0, y0, z0) != v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0, z0) != v.getReplaceState()) { continue; } int blocks = 0; - if (this.world.getBlock(x0 + 1, y0, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0 + 1, y0, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0 - 1, y0, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0 - 1, y0, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0 + 1, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0 + 1, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0 - 1, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0 - 1, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0, z0 + 1) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0, z0 + 1) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0, z0 - 1) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0, z0 - 1) == v.getReplaceState()) { blocks++; } if (blocks == 6) { - buffer.set(x, y, z, v.getVoxelIdState()); + buffer.set(x, y, z, v.getVoxelState()); } } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellSetBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellSetBrush.java index be981117..3a6fc5a2 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellSetBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellSetBrush.java @@ -61,30 +61,30 @@ private void sShell(final SnipeData v, Vector3i pos1, Vector3i pos2) { if (y <= 0 || y >= WORLD_HEIGHT) { continue; } - if (this.world.getBlock(x, y, z) != v.getReplaceIdState()) { + if (this.world.getBlock(x, y, z) != v.getReplaceState()) { continue; } int blocks = 0; - if (this.world.getBlock(x + 1, y, z) == v.getReplaceIdState()) { + if (this.world.getBlock(x + 1, y, z) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x - 1, y, z) == v.getReplaceIdState()) { + if (this.world.getBlock(x - 1, y, z) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x, y + 1, z) == v.getReplaceIdState()) { + if (this.world.getBlock(x, y + 1, z) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x, y - 1, z) == v.getReplaceIdState()) { + if (this.world.getBlock(x, y - 1, z) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x, y, z + 1) == v.getReplaceIdState()) { + if (this.world.getBlock(x, y, z + 1) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x, y, z - 1) == v.getReplaceIdState()) { + if (this.world.getBlock(x, y, z - 1) == v.getReplaceState()) { blocks++; } if (blocks == 6) { - buffer.set(x, y, z, v.getVoxelIdState()); + buffer.set(x, y, z, v.getVoxelState()); } } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellVoxelBrush.java b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellVoxelBrush.java index dc490891..c8de6ce8 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellVoxelBrush.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/brush/shape/ShellVoxelBrush.java @@ -60,30 +60,30 @@ private void vShell(final SnipeData v, Location targetBlock) { if (y <= 0 || y >= WORLD_HEIGHT) { continue; } - if (this.world.getBlock(x0, y0, z0) != v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0, z0) != v.getReplaceState()) { continue; } int blocks = 0; - if (this.world.getBlock(x0 + 1, y0, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0 + 1, y0, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0 - 1, y0, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0 - 1, y0, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0 + 1, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0 + 1, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0 - 1, z0) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0 - 1, z0) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0, z0 + 1) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0, z0 + 1) == v.getReplaceState()) { blocks++; } - if (this.world.getBlock(x0, y0, z0 - 1) == v.getReplaceIdState()) { + if (this.world.getBlock(x0, y0, z0 - 1) == v.getReplaceState()) { blocks++; } if (blocks == 6) { - buffer.set(x, y, z, v.getVoxelIdState()); + buffer.set(x, y, z, v.getVoxelState()); } } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelCenterCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelCenterCommand.java index b17cda6f..0c754e51 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelCenterCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelCenterCommand.java @@ -54,7 +54,7 @@ public CommandResult execute(CommandSource src, CommandContext gargs) throws Com Player player = (Player) gargs.getOne("sniper").get(); Sniper sniper = SniperManager.get().getSniperForPlayer(player); SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); - snipeData.setcCen((int) gargs.getOne("center").get()); + snipeData.setCylinderCenter((int) gargs.getOne("center").get()); snipeData.getVoxelMessage().center(); return CommandResult.success(); } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkCommand.java index 13ea2f72..59b82c36 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkCommand.java @@ -24,10 +24,13 @@ */ package com.thevoxelbox.voxelsniper.command; -import com.thevoxelbox.voxelsniper.Sniper; -import com.thevoxelbox.voxelsniper.SniperManager; -import com.thevoxelbox.voxelsniper.VoxelSniperConfiguration; +import com.thevoxelbox.voxelsniper.*; +import com.thevoxelbox.voxelsniper.util.BlockTraitHelper; +import jdk.nashorn.internal.ir.Block; +import org.spongepowered.api.CatalogTypes; import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.trait.BlockTrait; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -35,47 +38,62 @@ import org.spongepowered.api.command.args.GenericArguments; import org.spongepowered.api.command.spec.CommandExecutor; import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.data.key.Key; +import org.spongepowered.api.data.type.DyeColor; +import org.spongepowered.api.data.value.BaseValue; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; public class VoxelInkCommand implements CommandExecutor { public static void setup(Object plugin) { Sponge.getCommandManager().register(plugin, CommandSpec.builder() - .arguments(GenericArguments.playerOrSource(Text.of("sniper")), GenericArguments.string(Text.of("key")), - GenericArguments.literal(Text.of("equals"), "="), GenericArguments.string(Text.of("value"))) - .executor(new VoxelInkCommand()).permission(VoxelSniperConfiguration.PERMISSION_SNIPER) - .description(Text.of("VoxelSniper Ink selection")).build(), "vi"); + .arguments(GenericArguments.playerOrSource(Text.of("sniper")), + GenericArguments.allOf( + GenericArguments.string(Text.of("key=value")) + )) + .executor(new VoxelInkCommand()) + .permission(VoxelSniperConfiguration.PERMISSION_SNIPER) + .description(usageText()) + .build(), "vi"); } @Override - public CommandResult execute(CommandSource src, CommandContext gargs) throws CommandException { + public CommandResult execute(CommandSource src, CommandContext gargs) { Player player = (Player) gargs.getOne("sniper").get(); Sniper sniper = SniperManager.get().getSniperForPlayer(player); + SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); + + Collection keyValues = gargs.getAll("key=value"); + if (keyValues.size() == 0) { + src.sendMessage(usageText()); + return CommandResult.success(); + } + + Optional, Object>> optInkTraits = + BlockTraitHelper.parseKeyValues(keyValues, snipeData.getVoxelState(), src); + if (optInkTraits.isPresent()) { + snipeData.setVoxelInkTraits(optInkTraits.get()); + snipeData.getVoxelMessage().voxel(); + } - String key = (String) gargs.getOne("key").get(); - String value = (String) gargs.getOne("value").get(); - - // @Spongify turn these into a key and value for a blockstate -// if (args.length == 0) { -// Block targetBlock = new RangeBlockHelper(player, player.getWorld()).getTargetBlock(); -// if (targetBlock != null) { -// dataValue = targetBlock.getData(); -// } else { -// return true; -// } -// } else { -// try { -// dataValue = Byte.parseByte(args[0]); -// } catch (NumberFormatException exception) { -// player.sendMessage("Couldn't parse input."); -// return true; -// } -// } -// -// SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); -// snipeData.setData(dataValue); -// snipeData.getVoxelMessage().data(); return CommandResult.success(); } + + private static Text usageText() { + return Text.of( + TextColors.RED, + "Voxel ink selection\n" + + "Pass one or more block property in the form key=value separated by a space. " + + "These properties will be applied to blocks when placing them. E.g, passing " + + "color=blue when your voxel is wool will place blue wool. Voxel ink won't " + + "be used unless you set the place method to ink or combo." + ); + } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkReplaceCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkReplaceCommand.java index cd2eb2d6..04c9f8ba 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkReplaceCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelInkReplaceCommand.java @@ -24,10 +24,10 @@ */ package com.thevoxelbox.voxelsniper.command; -import com.thevoxelbox.voxelsniper.Sniper; -import com.thevoxelbox.voxelsniper.SniperManager; -import com.thevoxelbox.voxelsniper.VoxelSniperConfiguration; +import com.thevoxelbox.voxelsniper.*; +import com.thevoxelbox.voxelsniper.util.BlockTraitHelper; import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.trait.BlockTrait; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; @@ -37,13 +37,20 @@ import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; public class VoxelInkReplaceCommand implements CommandExecutor { public static void setup(Object plugin) { Sponge.getCommandManager().register(plugin, CommandSpec.builder() - .arguments(GenericArguments.playerOrSource(Text.of("sniper")), GenericArguments.string(Text.of("key")), - GenericArguments.literal(Text.of("equals"), "="), GenericArguments.string(Text.of("value"))) + .arguments(GenericArguments.playerOrSource(Text.of("sniper")), + GenericArguments.allOf( + GenericArguments.string(Text.of("key=value")) + )) .executor(new VoxelInkReplaceCommand()).permission(VoxelSniperConfiguration.PERMISSION_SNIPER) .description(Text.of("VoxelSniper Replace Ink selection")).build(), "vir"); } @@ -52,39 +59,31 @@ public static void setup(Object plugin) { public CommandResult execute(CommandSource src, CommandContext gargs) throws CommandException { Player player = (Player) gargs.getOne("sniper").get(); Sniper sniper = SniperManager.get().getSniperForPlayer(player); + SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); - String key = (String) gargs.getOne("key").get(); - String value = (String) gargs.getOne("value").get(); + Collection keyValues = gargs.getAll("key=value"); + if (keyValues.size() == 0) { + src.sendMessage(usageText()); + return CommandResult.success(); + } - // @Spongify turn these into a key and value for block state -// if (args.length == 0) -// { -// Block targetBlock = new RangeBlockHelper(player, player.getWorld()).getTargetBlock(); -// if (targetBlock != null) -// { -// dataValue = targetBlock.getData(); -// } -// else -// { -// return true; -// } -// } -// else -// { -// try -// { -// dataValue = Byte.parseByte(args[0]); -// } -// catch (NumberFormatException exception) -// { -// player.sendMessage("Couldn't parse input."); -// return true; -// } -// } -// -// SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); -// snipeData.setReplaceData(dataValue); -// snipeData.getVoxelMessage().replaceData(); + Optional, Object>> optInkTraits = + BlockTraitHelper.parseKeyValues(keyValues, snipeData.getReplaceState(), src); + if (optInkTraits.isPresent()) { + snipeData.setReplaceInkTraits(optInkTraits.get()); + snipeData.getVoxelMessage().replace(); + } return CommandResult.success(); } + + private static Text usageText() { + return Text.of( + TextColors.RED, + "Voxel replace ink selection\n" + + "Pass one or more block property in the form key=value separated by a space. " + + "These properties will used to check blocks when replacing them. E.g, passing " + + "color=blue will only replace blocks with blue color attribute. To use the " + + "replace ink make sure you set the replace method to ink or combo." + ); + } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelListCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelListCommand.java index acadbe04..867f0d89 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelListCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelListCommand.java @@ -28,6 +28,7 @@ import com.thevoxelbox.voxelsniper.Sniper; import com.thevoxelbox.voxelsniper.SniperManager; import com.thevoxelbox.voxelsniper.VoxelSniperConfiguration; +import com.thevoxelbox.voxelsniper.util.BlockHelper; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; @@ -67,13 +68,7 @@ public CommandResult execute(CommandSource src, CommandContext gargs) throws Com Optional oargs = gargs.getOne("args"); SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); if (!oargs.isPresent()) { - Location targetBlock = null; - BlockRayBuilder rayBuilder = BlockRay.from(player).stopFilter(BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1)); - BlockRay ray = rayBuilder.build(); - while (ray.hasNext()) { - targetBlock = ray.next().getLocation(); - } - snipeData.getVoxelList().add(targetBlock.getBlock()); + snipeData.getVoxelList().add(BlockHelper.stateOrWhereLooking(Optional.empty(), player).get()); snipeData.getVoxelMessage().voxelList(); return CommandResult.success(); } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelPerformerCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelPerformerCommand.java index 34337393..1fd85935 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelPerformerCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelPerformerCommand.java @@ -48,13 +48,13 @@ public static void setup(Object plugin) { Sponge.getCommandManager().register(plugin, CommandSpec.builder().arguments(GenericArguments.playerOrSource(Text.of("sniper")), GenericArguments.string(Text.of("performer"))) .executor(new VoxelPerformerCommand()).permission(VoxelSniperConfiguration.PERMISSION_SNIPER) - .description(Text.of("VoxelSniper performer selection")).build(), + .description(usageText()).build(), "p"); } @Override public CommandResult execute(CommandSource src, CommandContext gargs) throws CommandException { - Player player = (Player) gargs.getOne("sniper").get(); + Player player = gargs.getOne("sniper").get(); Sniper sniper = SniperManager.get().getSniperForPlayer(player); SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); @@ -62,10 +62,29 @@ public CommandResult execute(CommandSource src, CommandContext gargs) throws Com IBrush brush = sniper.getBrush(sniper.getCurrentToolId()); if (brush instanceof PerformBrush) { - ((PerformBrush) brush).parse(new String[] { performer }, snipeData); + PerformBrush pBrush = (PerformBrush) brush; + pBrush.parse(new String[] { performer }, snipeData); } else { player.sendMessage(Text.of(TextColors.RED, "This brush is not a performer brush.")); } return CommandResult.success(); } + + private static Text usageText() { + return Text.of( + TextColors.RED, + "Performer takes in a string of up to three characters. The first\n" + + "is required and describes the placement method. The second describes\n" + + "the replacement method and is optional. The third letter must be a p\n" + + "and if present means that physics will not be applied when placing\n" + + "blocks. The either two must be one of: \n\n" + + " - m for material. Placing/replacing is solely done based on the base\n" + + " block you have selected.\n\n" + + " - i for ink. Blocks in the affected area will only have their properties\n" + + " changed when placing or will only be replace if their properties match\n" + + " the current ink\n\n" + + " - c for combo. As the name suggests, placement and replacement will use\n" + + " both the block type and ink values for placing/replacing." + ); + } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelReplaceCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelReplaceCommand.java index 5d58300a..87909450 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelReplaceCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelReplaceCommand.java @@ -24,10 +24,9 @@ */ package com.thevoxelbox.voxelsniper.command; -import com.thevoxelbox.voxelsniper.SnipeData; -import com.thevoxelbox.voxelsniper.Sniper; -import com.thevoxelbox.voxelsniper.SniperManager; -import com.thevoxelbox.voxelsniper.VoxelSniperConfiguration; +import com.thevoxelbox.voxelsniper.*; +import com.thevoxelbox.voxelsniper.util.BlockHelper; +import org.spongepowered.api.CatalogTypes; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; @@ -62,38 +61,19 @@ public static void setup(Object plugin) { @Override public CommandResult execute(CommandSource src, CommandContext gargs) throws CommandException { - Player player = (Player) gargs.getOne("sniper").get(); + Player player = gargs.getOne("sniper").get(); Sniper sniper = SniperManager.get().getSniperForPlayer(player); SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); Optional material = gargs.getOne("material"); - if (!material.isPresent()) { - Location targetBlock = null; - BlockRayBuilder rayBuilder = BlockRay.from(player).stopFilter(BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1)); - BlockRay ray = rayBuilder.build(); - while (ray.hasNext()) { - targetBlock = ray.next().getLocation(); - } - snipeData.setReplaceId(targetBlock.getBlock()); - snipeData.getVoxelMessage().replace(); + + Optional newState = BlockHelper.stateOrWhereLooking(material, player); + if (!newState.isPresent() && material.isPresent()) { + src.sendMessage(Text.of(TextColors.RED, "Unknown block ", material.get())); return CommandResult.success(); } - String materialName = material.get(); - if (!materialName.contains(":")) { - materialName = "minecraft:" + materialName; - } - Optional type = Sponge.getRegistry().getType(BlockType.class, materialName); - if (type.isPresent()) { - snipeData.setReplaceId(type.get().getDefaultState()); - snipeData.getVoxelMessage().replace(); - } else { - Optional state = Sponge.getRegistry().getType(BlockState.class, materialName); - if (state.isPresent()) { - snipeData.setReplaceId(state.get()); - snipeData.getVoxelMessage().replace(); - } else { - player.sendMessage(Text.of(TextColors.RED, "Material not found.")); - } - } + snipeData.setReplaceState(newState.get()); + snipeData.getVoxelMessage().replace(); + return CommandResult.success(); } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelVoxelCommand.java b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelVoxelCommand.java index 0940c9ea..1406056a 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelVoxelCommand.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/command/VoxelVoxelCommand.java @@ -28,6 +28,10 @@ import com.thevoxelbox.voxelsniper.Sniper; import com.thevoxelbox.voxelsniper.SniperManager; import com.thevoxelbox.voxelsniper.VoxelSniperConfiguration; +import com.thevoxelbox.voxelsniper.util.BlockHelper; +import jdk.nashorn.internal.ir.Block; +import org.spongepowered.api.CatalogType; +import org.spongepowered.api.CatalogTypes; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; @@ -62,38 +66,19 @@ public static void setup(Object plugin) { @Override public CommandResult execute(CommandSource src, CommandContext gargs) throws CommandException { - Player player = (Player) gargs.getOne("sniper").get(); + Player player = gargs.getOne("sniper").get(); Sniper sniper = SniperManager.get().getSniperForPlayer(player); SnipeData snipeData = sniper.getSnipeData(sniper.getCurrentToolId()); Optional material = gargs.getOne("material"); - if (!material.isPresent()) { - Location targetBlock = null; - BlockRayBuilder rayBuilder = BlockRay.from(player).stopFilter(BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1)); - BlockRay ray = rayBuilder.build(); - while (ray.hasNext()) { - targetBlock = ray.next().getLocation(); - } - snipeData.setVoxelId(targetBlock.getBlock()); - snipeData.getVoxelMessage().voxel(); + + Optional newState = BlockHelper.stateOrWhereLooking(material, player); + if (!newState.isPresent() && material.isPresent()) { + src.sendMessage(Text.of(TextColors.RED, "Unknown block ", material.get())); return CommandResult.success(); } - String materialName = material.get(); - if (!materialName.contains(":")) { - materialName = "minecraft:" + materialName; - } - Optional type = Sponge.getRegistry().getType(BlockType.class, materialName); - if (type.isPresent()) { - snipeData.setVoxelId(type.get().getDefaultState()); - snipeData.getVoxelMessage().voxel(); - } else { - Optional state = Sponge.getRegistry().getType(BlockState.class, materialName); - if (state.isPresent()) { - snipeData.setVoxelId(state.get()); - snipeData.getVoxelMessage().voxel(); - } else { - player.sendMessage(Text.of(TextColors.RED, "Material not found.")); - } - } + snipeData.setVoxelState(newState.get()); + snipeData.getVoxelMessage().voxel(); + return CommandResult.success(); } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/util/BlockHelper.java b/src/main/java/com/thevoxelbox/voxelsniper/util/BlockHelper.java index c555cda7..8f57d865 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/util/BlockHelper.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/util/BlockHelper.java @@ -24,11 +24,19 @@ */ package com.thevoxelbox.voxelsniper.util; +import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.trait.BlockTrait; import org.spongepowered.api.data.property.block.MatterProperty; import org.spongepowered.api.data.property.block.MatterProperty.Matter; import org.spongepowered.api.data.property.block.SolidCubeProperty; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.util.blockray.BlockRay; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; +import javax.swing.text.html.Option; +import java.util.Map; import java.util.Optional; public class BlockHelper { @@ -63,4 +71,42 @@ public static boolean isSolid(BlockState state) { return false; } + public static boolean hasTraits(BlockState state, Map, Object> traits) { + for (Map.Entry, ?> trait : state.getTraitMap().entrySet()) { + Object expectedValue = traits.get(trait.getKey()); + if (!trait.getValue().equals(expectedValue)) { + return false; + } + } + + return true; + } + + public static Optional addTraits(BlockState state, Map, Object> traits) { + Optional newState = Optional.of(state); + for (Map.Entry, Object> traitEntry : traits.entrySet()) { + newState = newState.get().withTrait(traitEntry.getKey(), traitEntry.getValue()); + if (!newState.isPresent()) { + return newState; + } + } + + return newState; + } + + public static Optional stateOrWhereLooking(Optional rawState, Player player) { + if (rawState.isPresent()) { + return Sponge.getRegistry().getType(BlockState.class, rawState.get()); + } + + Location targetBlock = null; + BlockRay.BlockRayBuilder rayBuilder = + BlockRay.from(player).stopFilter(BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1)); + BlockRay ray = rayBuilder.build(); + while (ray.hasNext()) { + targetBlock = ray.next().getLocation(); + } + + return Optional.of(targetBlock.getBlock()); + } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/util/BlockTraitHelper.java b/src/main/java/com/thevoxelbox/voxelsniper/util/BlockTraitHelper.java index bdd159f8..fb5ae5a9 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/util/BlockTraitHelper.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/util/BlockTraitHelper.java @@ -1,4 +1,50 @@ package com.thevoxelbox.voxelsniper.util; +import org.checkerframework.checker.nullness.Opt; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.trait.BlockTrait; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.text.Text; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + public class BlockTraitHelper { + // Attempts to parse all block traits in rawKeyValues. If a failure occurs, sends an error message to src and + // returns empty. Otherwise, returns a mapping from the BlockTraits to the parsed values. + public static Optional, Object>> parseKeyValues(Collection rawKeyValues, + BlockState target, + CommandSource src) { + assert rawKeyValues != null; + Map, Object> traitMap = new HashMap, Object>(); + for (String rawKeyValue : rawKeyValues) { + if (rawKeyValue.indexOf('=') == -1) { + src.sendMessage(Text.of("Unable to parse")); + return Optional.empty(); + } + + String[] params = rawKeyValue.split("="); + String key = params[0]; + String value = params[1]; + + Optional> optTrait = target.getTrait(key); + if (!optTrait.isPresent()) { + src.sendMessage(Text.of("Unknown block trait '", key, "'")); + return Optional.empty(); + } + + BlockTrait trait = optTrait.get(); + Optional optValue = trait.parseValue(value); + if (!optValue.isPresent()) { + src.sendMessage(Text.of("Unknown value '", value, "' for key '", key, "'")); + return Optional.empty(); + } + traitMap.put(optTrait.get(), optValue.get()); + } + + return Optional.of(traitMap); + } } diff --git a/src/main/java/com/thevoxelbox/voxelsniper/util/StencilUpdater.java b/src/main/java/com/thevoxelbox/voxelsniper/util/StencilUpdater.java index 131b8780..a7683207 100644 --- a/src/main/java/com/thevoxelbox/voxelsniper/util/StencilUpdater.java +++ b/src/main/java/com/thevoxelbox/voxelsniper/util/StencilUpdater.java @@ -30,12 +30,7 @@ import org.spongepowered.api.data.DataView.SafetyMode; import org.spongepowered.api.data.persistence.DataFormats; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.*; import java.util.zip.GZIPOutputStream; /**