Oh sounds like fun, how about VoxelSniper in 50 lines.
Supports balls, discs and voxels, sizes can be floating point numbers.
Your brush/size/material is set by the command ‘/brush (ball|disc|voxel):size:material’.
For example ‘/brush ball:25:dirt’ will place down balls of dirt with a radius of 25 blocks whereever you click.
As an aside: something funky is up with one of EyeLocationData or BlockRay.from(Entity), as far as I can tell the eye location is supposted to be the entity location + the eye offset, but I was always just getting the offset when using the BlockRay. So a minor fix is needed there for this to work. I changed BlockRay:501 to
position = location.getPosition().add(data.get().eyeLocation().get());
But I’m pretty sure the eye location is supposed to be the correct location so some investigation is needed for that. Otherwise enjoy, although I do think this would be more fun as a code golf-styled challenge with a character limit rather than a line limit.
package com.thevoxelbox.voxelsniperlite;
import org.spongepowered.api.block.*;
import org.spongepowered.api.text.Texts;
import org.spongepowered.api.util.blockray.*;
import org.spongepowered.api.util.command.*;
import org.spongepowered.api.util.command.args.*;
import org.spongepowered.api.util.command.spec.*;
@org.spongepowered.api.plugin.Plugin(id = "vs-lite", name = "VoxelSniper-Lite", version = "0.0.1")
public class VoxelSniperLite {
@com.google.inject.Inject private org.spongepowered.api.Game game;
private final java.util.Map<java.util.UUID, String> brushes = com.google.common.collect.Maps.newHashMap();
@org.spongepowered.api.event.Listener
public void onStart(org.spongepowered.api.event.game.state.GameInitializationEvent event) {
event.getGame().getCommandDispatcher().register(this, CommandSpec.builder().arguments(GenericArguments.string(Texts.of("brush")))
.executor(new CommandExecutor() {
public CommandResult execute(CommandSource src, CommandContext args) throws CommandException {
if (!java.util.regex.Pattern.matches("(ball|voxel|disc):[\\d]+(\\.[\\d]+)?:[a-z]+", args.getOne("brush").get().toString())) {
src.sendMessage(Texts.of("Invalid brush, must match (ball|voxel|disc):size:material"));
return CommandResult.empty();
}
brushes.put(((org.spongepowered.api.entity.living.player.Player) src).getUniqueId(), args.getOne("brush").get().toString());
src.sendMessage(Texts.of("Brush has been set to " + args.getOne("brush").get().toString()));
return CommandResult.success();
}
}).build(), "brush");
}
@org.spongepowered.api.event.Listener
public void onInteract(org.spongepowered.api.event.action.InteractEvent e) {
org.spongepowered.api.entity.living.player.Player p = e.getCause().first(org.spongepowered.api.entity.living.player.Player.class).orNull();
if (p != null && p.getItemInHand().isPresent() && p.getItemInHand().get().getItem().equals(org.spongepowered.api.item.ItemTypes.ARROW)) {
String brush = brushes.get(p.getUniqueId());
if (brush == null || !java.util.regex.Pattern.matches("(ball|voxel|disc):[\\d]+(:?\\.[\\d]+)?:[a-z]+", brush)) brush = "ball:1:stone";
BlockRayHit<org.spongepowered.api.world.World> target = BlockRay.from(p).filter(BlockRay.onlyAirFilter()).end().get();
double size = Double.parseDouble(brush.split(":")[1]) - 0.5;
BlockState mat = game.getRegistry().getType(BlockType.class, brush.split(":")[2]).or(BlockTypes.STONE).getDefaultState();
for (int x = com.flowpowered.math.GenericMath.floor(-size); x < size; x++) {
for (int z = com.flowpowered.math.GenericMath.floor(-size); z < size; z++) {
for (int y = com.flowpowered.math.GenericMath.floor(-size); y < size; y++) {
if (brush.startsWith("disc") && y != 0) continue;
if (brush.startsWith("voxel") || x * x + y * y + z * z < size * size)
p.getWorld().setBlock(target.getBlockX() + x, target.getBlockY() + y, target.getBlockZ() + z, mat);
}
}
}
}
}
}
Exactly 50 lines, and yes the maximum line length is 150.