diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 3423c04ef..93a84096a 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -49,7 +49,7 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { public BlockMaterial getMaterial(BlockType blockType) { Material type = BukkitAdapter.adapt(blockType); if (type == null) { - type = Material.AIR; + return new PassthroughBlockMaterial(null); } return materialMap.computeIfAbsent(type, m -> new BukkitBlockMaterial(BukkitBlockRegistry.super.getMaterial(blockType), m)); } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 198704f6b..f84ea9c88 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -123,6 +123,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { } public WorldEditPlugin(JavaPluginLoader loader, PluginDescriptionFile desc, File dataFolder, File jarFile) { + super(loader, desc, dataFolder, jarFile); init(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java b/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java index 0235e1f94..bd8ab2968 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java @@ -69,8 +69,13 @@ public abstract class FaweParser extends InputParser { switch (c) { case ',': case '&': - inputs.add(toParse.substring(last, i)); - and.add(c == '&'); + String result = toParse.substring(last, i); + if (!result.isEmpty()) { + inputs.add(result); + and.add(c == '&'); + } else { + throw new InputParseException("Invalid dangling character " + c); + } last = i + 1; continue outer; default: diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 8a250f790..981e610f4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2519,6 +2519,18 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int makePumpkinPatches(final Vector position, final int apothem) { + return makePumpkinPatches(position, apothem, 0.02); + } + + /** + * Makes pumpkin patches randomly in an area around the given position. + * + * @param position the base position + * @param apothem the apothem of the (square) area + * @return number of patches created + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makePumpkinPatches(final Vector position, final int apothem, double density) { // We want to generate pumpkins final GardenPatchGenerator generator = new GardenPatchGenerator(EditSession.this); generator.setPlant(GardenPatchGenerator.getPumpkinPattern()); @@ -2526,7 +2538,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, // In a region of the given radius final FlatRegion region = new CuboidRegion(EditSession.this.getWorld(), // Causes clamping of Y range position.add(-apothem, -5, -apothem), position.add(apothem, 10, apothem)); - final double density = 0.02; final GroundFunction ground = new GroundFunction(new ExistingBlockMask(EditSession.this), generator); final LayerVisitor visitor = new LayerVisitor(region, minimumBlockY(region), maximumBlockY(region), ground); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java index 072ed8a1a..16fea362a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockType.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.registry.state.PropertyGroup; import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; import jdk.nashorn.internal.ir.Block; import java.util.EnumMap; @@ -45,8 +46,70 @@ public class BlockType { return centralTopLimit(type.getDefaultState()); } + public static double centralBottomLimit(BlockStateHolder block) { + checkNotNull(block); + BlockTypes type = block.getBlockType(); + switch (type) { + case CREEPER_WALL_HEAD: + case DRAGON_WALL_HEAD: + case PLAYER_WALL_HEAD: + case ZOMBIE_WALL_HEAD: return 0.25; + case ACACIA_SLAB: + case BIRCH_SLAB: + case BRICK_SLAB: + case COBBLESTONE_SLAB: + case DARK_OAK_SLAB: + case DARK_PRISMARINE_SLAB: + case JUNGLE_SLAB: + case NETHER_BRICK_SLAB: + case OAK_SLAB: + case PETRIFIED_OAK_SLAB: + case PRISMARINE_BRICK_SLAB: + case PRISMARINE_SLAB: + case PURPUR_SLAB: + case QUARTZ_SLAB: + case RED_SANDSTONE_SLAB: + case SANDSTONE_SLAB: + case SPRUCE_SLAB: + case STONE_BRICK_SLAB: + case STONE_SLAB: { + String state = (String) block.getState(PropertyKey.TYPE); + if (state == null) return 0; + switch (state) { + case "double": + case "bottom": + return 0; + case "top": + return 0.5; + } + } + case ACACIA_TRAPDOOR: + case BIRCH_TRAPDOOR: + case DARK_OAK_TRAPDOOR: + case IRON_TRAPDOOR: + case JUNGLE_TRAPDOOR: + case OAK_TRAPDOOR: + case SPRUCE_TRAPDOOR: + if (block.getState(PropertyKey.OPEN) == Boolean.TRUE) { + return 1; + } else if ("bottom".equals(block.getState(PropertyKey.HALF))) { + return 0.8125; + } else { + return 0; + } + case ACACIA_FENCE_GATE: + case BIRCH_FENCE_GATE: + case DARK_OAK_FENCE_GATE: + case JUNGLE_FENCE_GATE: + case OAK_FENCE_GATE: + case SPRUCE_FENCE_GATE: return block.getState(PropertyKey.OPEN) == Boolean.TRUE ? 1 : 0; + default: + if (type.getMaterial().isMovementBlocker()) return 0; + return 1; + } + } + /** - * TODO FIXME use registry * Returns the y offset a player falls to when falling onto the top of a block at xp+0.5/zp+0.5. * * @param block the block @@ -54,7 +117,8 @@ public class BlockType { */ public static double centralTopLimit(BlockStateHolder block) { checkNotNull(block); - switch (block.getBlockType().getTypeEnum()) { + BlockTypes type = block.getBlockType(); + switch (type) { case BLACK_BED: case BLUE_BED: case BROWN_BED: @@ -111,7 +175,17 @@ public class BlockType { case SANDSTONE_SLAB: case SPRUCE_SLAB: case STONE_BRICK_SLAB: - case STONE_SLAB: return 0.5; + case STONE_SLAB: { + String state = (String) block.getState(PropertyKey.TYPE); + if (state == null) return 0.5; + switch (state) { + case "bottom": + return 0.5; + case "top": + case "double": + return 1; + } + } case LILY_PAD: return 0.015625; case REPEATER: return 0.125; case SOUL_SAND: return 0.875; @@ -142,7 +216,12 @@ public class BlockType { case OAK_FENCE_GATE: case SPRUCE_FENCE_GATE: return block.getState(PropertyKey.OPEN) == Boolean.TRUE ? 0 : 1.5; default: - return PropertyGroup.LEVEL.get(block); + if (type.hasProperty(PropertyKey.LAYERS)) { + return PropertyGroup.LEVEL.get(block) * 0.0625; + } + if (!type.getMaterial().isMovementBlocker()) return 0; + return 1; + } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index 8c95f1885..5adbe99f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -284,20 +284,20 @@ public class GenerationCommands extends MethodCommands { public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size, @Optional("tree") TreeType type, @Optional("5") double density) throws WorldEditException, ParameterException { density = density / 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); - player.print(affected + " trees created."); + player.print(BBC.getPrefix() + affected + " trees created."); } @Command( aliases = {"pumpkins"}, - usage = "[size]", + usage = "[size=10] [density=0.02]", desc = "Generate pumpkin patches", min = 0, - max = 1 + max = 2 ) @CommandPermissions("worldedit.generation.pumpkins") @Logging(POSITION) - public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem) throws WorldEditException, ParameterException { - int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem); + public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem, @Optional("0.02") double density) throws WorldEditException, ParameterException { + int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem, density); BBC.COMMAND_PUMPKIN.send(player, affected); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index 581dc53bd..0134c7fbc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.PlayerDirection; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockMaterial; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -157,36 +158,47 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { final int z = pos.getBlockZ(); final Extent world = pos.getExtent(); - byte free = 0; - byte spots = 0; + int maxY = world.getMaxY(); + if (y >= maxY) return false; - while (y <= world.getMaximumPoint().getY() + 2) { - if (!world.getBlock(new Vector(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { - ++free; - } else { - free = 0; - } + BlockMaterial initialMaterial = world.getBlockType(new Vector(x, y, z)).getMaterial(); - if (free == 2) { - ++spots; - if (spots == 2) { - final Vector platform = new Vector(x, y - 2, z); - final BlockStateHolder block = world.getBlock(platform); - final com.sk89q.worldedit.world.block.BlockType type = block.getBlockType(); + boolean lastState = initialMaterial.isMovementBlocker() && initialMaterial.isFullCube(); - // Don't get put in lava! - if (type == BlockTypes.LAVA) { - return false; - } + double height = 1.85; + double freeStart = -1; - setPosition(platform.add(0.5, BlockType.centralTopLimit(block), 0.5)); - return true; + for (int level = y + 1; level <= maxY + 2; level++) { + BlockState state; + if (level >= maxY) state = BlockTypes.VOID_AIR.getDefaultState(); + else state = world.getBlock(new Vector(x, level, z)); + BlockTypes type = state.getBlockType(); + BlockMaterial material = type.getMaterial(); + + if (!material.isFullCube() || !material.isMovementBlocker()) { + if (!lastState) { + lastState = BlockType.centralBottomLimit(state) != 1; + continue; } + if (freeStart == -1) { + freeStart = level + BlockType.centralTopLimit(state); + } else { + double bottomLimit = BlockType.centralBottomLimit(state); + double space = level + bottomLimit - freeStart; + if (space >= height) { + setPosition(new Vector(x + 0.5, freeStart, z + 0.5)); + return true; + } + // Not enough room, reset the free position + if (bottomLimit != 1) { + freeStart = -1; + } + } + } else { + freeStart = -1; + lastState = true; } - - ++y; } - return false; } @@ -194,48 +206,52 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { public boolean descendLevel() { final Location pos = getBlockIn(); final int x = pos.getBlockX(); - int y = Math.max(0, pos.getBlockY() - 1); + int y = Math.max(0, pos.getBlockY()); final int z = pos.getBlockZ(); final Extent world = pos.getExtent(); - byte free = 0; + BlockMaterial initialMaterial = world.getBlockType(new Vector(x, y, z)).getMaterial(); - while (y >= 1) { - if (!world.getBlock(new Vector(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { - ++free; - } else { - free = 0; - } + boolean lastState = initialMaterial.isMovementBlocker() && initialMaterial.isFullCube(); - if (free == 2) { - // So we've found a spot, but we have to drop the player - // lightly and also check to see if there's something to - // stand upon - while (y >= 0) { - final Vector platform = new Vector(x, y, z); - final BlockStateHolder block = world.getBlock(platform); - final com.sk89q.worldedit.world.block.BlockTypes type = block.getBlockType(); + double height = 1.85; + double freeEnd = -1; - // Don't want to end up in lava - switch (type) { - case AIR: - case CAVE_AIR: - case VOID_AIR: - case LAVA: - --y; - continue; - default: - // Found a block! - setPosition(platform.add(0.5, BlockType.centralTopLimit(block), 0.5)); - return true; + int maxY = world.getMaxY(); + if (y <= 2) return false; + + for (int level = y + 1; level > 0; level--) { + BlockState state; + if (level >= maxY) state = BlockTypes.VOID_AIR.getDefaultState(); + else state = world.getBlock(new Vector(x, level, z)); + BlockTypes type = state.getBlockType(); + BlockMaterial material = type.getMaterial(); + + if (!material.isFullCube() || !material.isMovementBlocker()) { + if (!lastState) { + lastState = BlockType.centralTopLimit(state) != 0; + continue; + } + if (freeEnd == -1) { + freeEnd = level + BlockType.centralBottomLimit(state); + } else { + double topLimit = BlockType.centralTopLimit(state); + double freeStart = level + topLimit; + double space = freeEnd - freeStart; + if (space >= height) { + setPosition(new Vector(x + 0.5, freeStart, z + 0.5)); + return true; + } + // Not enough room, reset the free position + if (topLimit != 0) { + freeEnd = -1; } } - return false; + } else { + lastState = true; + freeEnd = -1; } - - --y; } - return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index fb4aa4f0b..55bd12dac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -745,6 +745,7 @@ public enum BlockTypes implements BlockType { try { ReflectionUtils.setFailsafeFieldValue(BlockTypes.class.getDeclaredField("settings"), this, new Settings(this, id, internalId)); } catch (Throwable e) { + e.printStackTrace(); throw new RuntimeException(e); } } @@ -987,7 +988,8 @@ public enum BlockTypes implements BlockType { try { BlockStateHolder block = LegacyMapper.getInstance().getBlockFromLegacy(input); if (block != null) return (BlockTypes) block.getBlockType(); - } catch (NumberFormatException e) {} + } catch (NumberFormatException e) { + } catch (IndexOutOfBoundsException e) {} return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java index c2fd00ff6..ad34a0a86 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -144,9 +144,9 @@ public class BundledBlockData { } public static class BlockEntry { - private String id; + public String id; public String localizedName; - private SimpleBlockMaterial material = new SimpleBlockMaterial(); + public SimpleBlockMaterial material = new SimpleBlockMaterial(); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java index 2ba9a820d..66dfc7aa7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java @@ -21,7 +21,7 @@ package com.sk89q.worldedit.world.registry; import com.sk89q.worldedit.blocks.BlockMaterial; -class SimpleBlockMaterial implements BlockMaterial { +public class SimpleBlockMaterial implements BlockMaterial { private boolean isAir; private boolean fullCube;