From 7ed1718d214f90cc57be1f6115380e4811f453eb Mon Sep 17 00:00:00 2001 From: sk89q Date: Fri, 4 Apr 2014 22:40:29 -0700 Subject: [PATCH] Moved LocalWorld's members upwards to AbstractWorld and World. --- .../java/com/sk89q/worldedit/LocalPlayer.java | 456 +----------- .../java/com/sk89q/worldedit/LocalWorld.java | 661 +++--------------- .../com/sk89q/worldedit/entity/Entity.java | 14 +- .../com/sk89q/worldedit/entity/Player.java | 2 +- .../platform/AbstractPlayerActor.java | 483 +++++++++++++ .../com/sk89q/worldedit/util/TargetBlock.java | 16 +- .../sk89q/worldedit/world/AbstractWorld.java | 243 +++++++ .../java/com/sk89q/worldedit/world/World.java | 353 +++++++++- 8 files changed, 1189 insertions(+), 1039 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java create mode 100644 src/main/java/com/sk89q/worldedit/world/AbstractWorld.java diff --git a/src/main/java/com/sk89q/worldedit/LocalPlayer.java b/src/main/java/com/sk89q/worldedit/LocalPlayer.java index 57a779f3b..c284c3ffb 100644 --- a/src/main/java/com/sk89q/worldedit/LocalPlayer.java +++ b/src/main/java/com/sk89q/worldedit/LocalPlayer.java @@ -19,24 +19,17 @@ package com.sk89q.worldedit; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.blocks.ItemID; -import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.AbstractPlayerActor; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.internal.cui.CUIEvent; -import com.sk89q.worldedit.util.TargetBlock; - -import java.io.File; /** - * Represents a player that uses WorldEdit. In the future, this type - * will be completely replaced by {@link Actor}. + * Represents a player that uses WorldEdit. + * + * @deprecated Use {@link Actor} (or {@link Player}, etc.) instead (and {@link AbstractPlayerActor} to extend) */ -public abstract class LocalPlayer implements Actor, Entity { - - protected ServerInterface server; +@Deprecated +public abstract class LocalPlayer extends AbstractPlayerActor { /** * Construct the object. @@ -44,440 +37,7 @@ public abstract class LocalPlayer implements Actor, Entity { * @param server A reference to the server this player is on */ protected LocalPlayer(ServerInterface server) { - this.server = server; + super(server); } - @Override - public boolean isHoldingPickAxe() { - int item = getItemInHand(); - return item == ItemID.IRON_PICK - || item == ItemID.WOOD_PICKAXE - || item == ItemID.STONE_PICKAXE - || item == ItemID.DIAMOND_PICKAXE - || item == ItemID.GOLD_PICKAXE; - } - - @Override - public void findFreePosition(WorldVector searchPos) { - LocalWorld world = searchPos.getWorld(); - int x = searchPos.getBlockX(); - int y = Math.max(0, searchPos.getBlockY()); - int origY = y; - int z = searchPos.getBlockZ(); - - byte free = 0; - - while (y <= world.getMaxY() + 2) { - if (BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { - ++free; - } else { - free = 0; - } - - if (free == 2) { - if (y - 1 != origY) { - final Vector pos = new Vector(x, y - 2, z); - final int id = world.getBlockType(pos); - final int data = world.getBlockData(pos); - setPosition(new Vector(x + 0.5, y - 2 + BlockType.centralTopLimit(id, data), z + 0.5)); - } - - return; - } - - ++y; - } - } - - @Override - public void setOnGround(WorldVector searchPos) { - LocalWorld world = searchPos.getWorld(); - int x = searchPos.getBlockX(); - int y = Math.max(0, searchPos.getBlockY()); - int z = searchPos.getBlockZ(); - - while (y >= 0) { - final Vector pos = new Vector(x, y, z); - final int id = world.getBlockType(pos); - final int data = world.getBlockData(pos); - if (!BlockType.canPassThrough(id, data)) { - setPosition(new Vector(x + 0.5, y + BlockType.centralTopLimit(id, data), z + 0.5)); - return; - } - - --y; - } - } - - @Override - public void findFreePosition() { - findFreePosition(getBlockIn()); - } - - @Override - public boolean ascendLevel() { - final WorldVector pos = getBlockIn(); - final int x = pos.getBlockX(); - int y = Math.max(0, pos.getBlockY()); - final int z = pos.getBlockZ(); - final LocalWorld world = pos.getWorld(); - - byte free = 0; - byte spots = 0; - - while (y <= world.getMaxY() + 2) { - if (BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { - ++free; - } else { - free = 0; - } - - if (free == 2) { - ++spots; - if (spots == 2) { - final Vector platform = new Vector(x, y - 2, z); - final BaseBlock block = world.getBlock(platform); - final int type = block.getId(); - - // Don't get put in lava! - if (type == BlockID.LAVA || type == BlockID.STATIONARY_LAVA) { - return false; - } - - setPosition(platform.add(0.5, BlockType.centralTopLimit(block), 0.5)); - return true; - } - } - - ++y; - } - - return false; - } - - @Override - public boolean descendLevel() { - final WorldVector pos = getBlockIn(); - final int x = pos.getBlockX(); - int y = Math.max(0, pos.getBlockY() - 1); - final int z = pos.getBlockZ(); - final LocalWorld world = pos.getWorld(); - - byte free = 0; - - while (y >= 1) { - if (BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { - ++free; - } else { - free = 0; - } - - 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 BaseBlock block = world.getBlock(platform); - final int type = block.getId(); - - // Don't want to end up in lava - if (type != BlockID.AIR && type != BlockID.LAVA && type != BlockID.STATIONARY_LAVA) { - // Found a block! - setPosition(platform.add(0.5, BlockType.centralTopLimit(block), 0.5)); - return true; - } - - --y; - } - - return false; - } - - --y; - } - - return false; - } - - @Override - public boolean ascendToCeiling(int clearance) { - return ascendToCeiling(clearance, true); - } - - @Override - public boolean ascendToCeiling(int clearance, boolean alwaysGlass) { - Vector pos = getBlockIn(); - int x = pos.getBlockX(); - int initialY = Math.max(0, pos.getBlockY()); - int y = Math.max(0, pos.getBlockY() + 2); - int z = pos.getBlockZ(); - LocalWorld world = getPosition().getWorld(); - - // No free space above - if (world.getBlockType(new Vector(x, y, z)) != 0) { - return false; - } - - while (y <= world.getMaxY()) { - // Found a ceiling! - if (!BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { - int platformY = Math.max(initialY, y - 3 - clearance); - floatAt(x, platformY + 1, z, alwaysGlass); - return true; - } - - ++y; - } - - return false; - } - - @Override - public boolean ascendUpwards(int distance) { - return ascendUpwards(distance, true); - } - - @Override - public boolean ascendUpwards(int distance, boolean alwaysGlass) { - final Vector pos = getBlockIn(); - final int x = pos.getBlockX(); - final int initialY = Math.max(0, pos.getBlockY()); - int y = Math.max(0, pos.getBlockY() + 1); - final int z = pos.getBlockZ(); - final int maxY = Math.min(getWorld().getMaxY() + 1, initialY + distance); - final LocalWorld world = getPosition().getWorld(); - - while (y <= world.getMaxY() + 2) { - if (!BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { - break; // Hit something - } else if (y > maxY + 1) { - break; - } else if (y == maxY + 1) { - floatAt(x, y - 1, z, alwaysGlass); - return true; - } - - ++y; - } - - return false; - } - - @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - getPosition().getWorld().setBlockType(new Vector(x, y - 1, z), BlockID.GLASS); - setPosition(new Vector(x + 0.5, y, z + 0.5)); - } - - @Override - public WorldVector getBlockIn() { - WorldVector pos = getPosition(); - return WorldVector.toBlockPoint(pos.getWorld(), pos.getX(), - pos.getY(), pos.getZ()); - } - - @Override - public WorldVector getBlockOn() { - WorldVector pos = getPosition(); - return WorldVector.toBlockPoint(pos.getWorld(), pos.getX(), - pos.getY() - 1, pos.getZ()); - } - - @Override - public WorldVector getBlockTrace(int range, boolean useLastBlock) { - TargetBlock tb = new TargetBlock(this, range, 0.2); - return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); - } - - @Override - public WorldVectorFace getBlockTraceFace(int range, boolean useLastBlock) { - TargetBlock tb = new TargetBlock(this, range, 0.2); - return (useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace()); - } - - @Override - public WorldVector getBlockTrace(int range) { - return getBlockTrace(range, false); - } - - @Override - public WorldVector getSolidBlockTrace(int range) { - TargetBlock tb = new TargetBlock(this, range, 0.2); - return tb.getSolidTargetBlock(); - } - - @Override - public PlayerDirection getCardinalDirection() { - return getCardinalDirection(0); - } - - @Override - public PlayerDirection getCardinalDirection(int yawOffset) { - if (getPitch() > 67.5) { - return PlayerDirection.DOWN; - } - if (getPitch() < -67.5) { - return PlayerDirection.UP; - } - - // From hey0's code - double rot = (getYaw() + yawOffset) % 360; //let's use real yaw now - if (rot < 0) { - rot += 360.0; - } - return getDirection(rot); - } - - /** - * Returns direction according to rotation. May return null. - * - * @param rot yaw - * @return the direction - */ - private static PlayerDirection getDirection(double rot) { - if (0 <= rot && rot < 22.5) { - return PlayerDirection.SOUTH; - } else if (22.5 <= rot && rot < 67.5) { - return PlayerDirection.SOUTH_WEST; - } else if (67.5 <= rot && rot < 112.5) { - return PlayerDirection.WEST; - } else if (112.5 <= rot && rot < 157.5) { - return PlayerDirection.NORTH_WEST; - } else if (157.5 <= rot && rot < 202.5) { - return PlayerDirection.NORTH; - } else if (202.5 <= rot && rot < 247.5) { - return PlayerDirection.NORTH_EAST; - } else if (247.5 <= rot && rot < 292.5) { - return PlayerDirection.EAST; - } else if (292.5 <= rot && rot < 337.5) { - return PlayerDirection.SOUTH_EAST; - } else if (337.5 <= rot && rot < 360.0) { - return PlayerDirection.SOUTH; - } else { - return null; - } - } - - @Override - public BaseBlock getBlockInHand() throws WorldEditException { - final int typeId = getItemInHand(); - if (!getWorld().isValidBlockType(typeId)) { - throw new NotABlockException(typeId); - } - return new BaseBlock(typeId); - } - - /** - * Get the player's view pitch. - * - * @return pitch - */ - - /** - * Get the player's view yaw. - * - * @return yaw - */ - - @Override - public boolean passThroughForwardWall(int range) { - int searchDist = 0; - TargetBlock hitBlox = new TargetBlock(this, range, 0.2); - LocalWorld world = getPosition().getWorld(); - BlockWorldVector block; - boolean firstBlock = true; - int freeToFind = 2; - boolean inFree = false; - - while ((block = hitBlox.getNextBlock()) != null) { - boolean free = BlockType.canPassThrough(world.getBlock(block)); - - if (firstBlock) { - firstBlock = false; - - if (!free) { - --freeToFind; - continue; - } - } - - ++searchDist; - if (searchDist > 20) { - return false; - } - - if (inFree != free) { - if (free) { - --freeToFind; - } - } - - if (freeToFind == 0) { - setOnGround(block); - return true; - } - - inFree = free; - } - - return false; - } - - @Override - public void setPosition(Vector pos) { - setPosition(pos, (float) getPitch(), (float) getYaw()); - } - - @Override - public File openFileOpenDialog(String[] extensions) { - printError("File dialogs are not supported in your environment."); - return null; - } - - @Override - public File openFileSaveDialog(String[] extensions) { - printError("File dialogs are not supported in your environment."); - return null; - } - - @Override - public boolean canDestroyBedrock() { - return hasPermission("worldedit.override.bedrock"); - } - - @Override - public void dispatchCUIEvent(CUIEvent event) { - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof LocalPlayer)) { - return false; - } - LocalPlayer other2 = (LocalPlayer) other; - return other2.getName().equals(getName()); - } - - @Override - public int hashCode() { - return getName().hashCode(); - } - - @Override - public void checkPermission(String permission) throws WorldEditPermissionException { - if (!hasPermission(permission)) { - throw new WorldEditPermissionException(); - } - } - - @Override - public boolean isPlayer() { - return true; - } - - @Override - public boolean hasCreativeMode() { - return false; - } } diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java index 622e190c2..787902173 100644 --- a/src/main/java/com/sk89q/worldedit/LocalWorld.java +++ b/src/main/java/com/sk89q/worldedit/LocalWorld.java @@ -20,28 +20,25 @@ package com.sk89q.worldedit; import com.sk89q.worldedit.blocks.*; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.function.mask.BlockMask; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.AbstractWorld; +import com.sk89q.worldedit.world.World; -import javax.annotation.Nullable; -import java.util.PriorityQueue; import java.util.Random; /** - * Represents a world. + * A legacy abstract implementation of {@link World}. New implementations + * should use {@link AbstractWorld} when possible. * - * @author sk89q + * @deprecated Replace with {@link World} wherever appropriate */ -public abstract class LocalWorld implements World, Extent { +@Deprecated +public abstract class LocalWorld extends AbstractWorld { /** * Named flags to use as parameters to {@link LocalWorld#killMobs(Vector, double, int)} */ + @SuppressWarnings("PointlessBitwiseExpression") public final class KillFlags { public static final int PETS = 1 << 0; public static final int NPCS = 1 << 1; @@ -56,246 +53,123 @@ public abstract class LocalWorld implements World, Extent { } /** - * Random generator. + * @deprecated Don't use this anymore. It will be removed */ + @SuppressWarnings("ProtectedField") + @Deprecated protected Random random = new Random(); - /** - * Get the name of the world. - * - * @return - */ - public abstract String getName(); + @Override + public BaseBlock getBlock(Vector pt) { + checkLoadedChunk(pt); - /** - * Set block type. - * - * @param pt - * @param type - * @return - */ - @Deprecated - public abstract boolean setBlockType(Vector pt, int type); + @SuppressWarnings("deprecation") int type = getBlockType(pt); + @SuppressWarnings("deprecation") int data = getBlockData(pt); - /** - * Set block type. - * - * @param pt - * @param type - * @return - */ - @Deprecated - public boolean setBlockTypeFast(Vector pt, int type) { - return setBlockType(pt, type); + switch (type) { + case BlockID.WALL_SIGN: + case BlockID.SIGN_POST: { + SignBlock block = new SignBlock(type, data); + copyFromWorld(pt, block); + return block; + } + + case BlockID.CHEST: { + ChestBlock block = new ChestBlock(data); + copyFromWorld(pt, block); + return block; + } + + case BlockID.FURNACE: + case BlockID.BURNING_FURNACE: { + FurnaceBlock block = new FurnaceBlock(type, data); + copyFromWorld(pt, block); + return block; + } + + case BlockID.DISPENSER: { + DispenserBlock block = new DispenserBlock(data); + copyFromWorld(pt, block); + return block; + } + + case BlockID.MOB_SPAWNER: { + MobSpawnerBlock block = new MobSpawnerBlock(data); + copyFromWorld(pt, block); + return block; + } + + case BlockID.NOTE_BLOCK: { + NoteBlock block = new NoteBlock(data); + copyFromWorld(pt, block); + return block; + } + + case BlockID.HEAD: { + SkullBlock block = new SkullBlock(data); + copyFromWorld(pt, block); + return block; + } + + default: + return new BaseBlock(type, data); + } } /** - * Get block type. + * Given a block and a position, copy data from the world to the block + * based on the type of block. + *

+ * The provided {@link BaseBlock} should match that of the one in the + * world. * - * @param pt - * @return + * @param position the position + * @param block the block + * @return true if the copy operation succeeded, false otherwise */ - @Deprecated - public abstract int getBlockType(Vector pt); + public abstract boolean copyFromWorld(Vector position, BaseBlock block); - /** - * Set block data. - * - * @param pt - * @param data - */ - @Deprecated - public abstract void setBlockData(Vector pt, int data); + @Override + public BaseBlock getLazyBlock(Vector position) { + return getBlock(position); + } - /** - * Set block data. - * - * @param pt - * @param data - */ - @Deprecated - public abstract void setBlockDataFast(Vector pt, int data); + @Override + public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) { + boolean successful; - /** - * Get biome type - * - * @param pt The (x, z) location to check the biome at - * @return The biome type at the location - */ - public abstract BiomeType getBiome(Vector2D pt); + // Default implementation will call the old deprecated methods + if (notifyAdjacent) { + successful = setTypeIdAndData(pt, block.getId(), block.getData()); + } else { + successful = setTypeIdAndDataFast(pt, block.getId(), block.getData()); + } - /** - * Set the biome type - * @param pt The (x, z) location to set the biome at - * @param biome The biome type to set to - */ - public abstract void setBiome(Vector2D pt, BiomeType biome); + copyToWorld(pt, block); - /** - * set block type & data - * @param pt - * @param type - * @param data - * @return - */ - @Deprecated - public boolean setTypeIdAndData(Vector pt, int type, int data) { - boolean ret = setBlockType(pt, type); - setBlockData(pt, data); - return ret; + return successful; } /** - * set block type & data - * @param pt - * @param type - * @param data - * @return + * Given a block and a position, copy data to the world from the block + * based on the type of block. + *

+ * The provided {@link BaseBlock} should match that of the one in the + * world. + * + * @param position the position + * @param block the block + * @return true if the copy operation succeeded, false otherwise */ - @Deprecated - public boolean setTypeIdAndDataFast(Vector pt, int type, int data) { - boolean ret = setBlockTypeFast(pt, type); - setBlockDataFast(pt, data); - return ret; + public abstract boolean copyToWorld(Vector position, BaseBlock block); + + @Override + public boolean setBlock(Vector pt, BaseBlock block) { + return setBlock(pt, block, true); } - /** - * Get block data. - * - * @param pt - * @return - */ - @Deprecated - public abstract int getBlockData(Vector pt); - - /** - * Get block light level. - * - * @param pt - * @return - */ - public abstract int getBlockLightLevel(Vector pt); - - /** - * Regenerate an area. - * - * @param region - * @param editSession - * @return - */ - public abstract boolean regenerate(Region region, EditSession editSession); - - /** - * Attempts to accurately copy a BaseBlock's extra data to the world. - * - * @param pt - * @param block - * @return - */ - public abstract boolean copyToWorld(Vector pt, BaseBlock block); - - /** - * Attempts to read a BaseBlock's extra data from the world. - * - * @param pt - * @param block - * @return - */ - public abstract boolean copyFromWorld(Vector pt, BaseBlock block); - - /** - * Clear a chest's contents. - * - * @param pt - * @return - */ - public abstract boolean clearContainerBlockContents(Vector pt); - - /** - * Generate a tree at a location. - * - * @param editSession - * @param pt - * @return - * @throws MaxChangedBlocksException - * @deprecated use {@link #generateTree(com.sk89q.worldedit.util.TreeGenerator.TreeType, EditSession, Vector)} instead - */ - @Deprecated - public boolean generateTree(EditSession editSession, Vector pt) - throws MaxChangedBlocksException { - return false; - } - - /** - * Generate a big tree at a location. - * - * @param editSession - * @param pt - * @return - * @throws MaxChangedBlocksException - * @deprecated use {@link #generateTree(com.sk89q.worldedit.util.TreeGenerator.TreeType, EditSession, Vector)} instead - */ - @Deprecated - public boolean generateBigTree(EditSession editSession, Vector pt) - throws MaxChangedBlocksException { - return false; - } - - /** - * Generate a birch tree at a location. - * - * @param editSession - * @param pt - * @return - * @throws MaxChangedBlocksException - * @deprecated use {@link #generateTree(com.sk89q.worldedit.util.TreeGenerator.TreeType, EditSession, Vector)} instead - */ - @Deprecated - public boolean generateBirchTree(EditSession editSession, Vector pt) - throws MaxChangedBlocksException { - return false; - } - - /** - * Generate a redwood tree at a location. - * - * @param editSession - * @param pt - * @return - * @throws MaxChangedBlocksException - * @deprecated use {@link #generateTree(com.sk89q.worldedit.util.TreeGenerator.TreeType, EditSession, Vector)} instead - */ - @Deprecated - public boolean generateRedwoodTree(EditSession editSession, Vector pt) - throws MaxChangedBlocksException { - return false; - } - - /** - * Generate a tall redwood tree at a location. - * - * @param editSession - * @param pt - * @return - * @throws MaxChangedBlocksException - * @deprecated use {@link #generateTree(com.sk89q.worldedit.util.TreeGenerator.TreeType, EditSession, Vector)} instead - */ - @Deprecated - public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) - throws MaxChangedBlocksException { - return false; - } - - /** - * Generates a tree - * @param type The type of tree to generate - * @param editSession The EditSession to pass block changes through - * @param pt The point where the base of the tree should be located - * @return Whether the tree generation was successful - * @throws MaxChangedBlocksException if too many blocks were changed by the EditSession - */ - public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector pt) - throws MaxChangedBlocksException { + @Override + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector pt) throws MaxChangedBlocksException { switch (type) { case BIG_TREE: return generateBigTree(editSession, pt); @@ -311,336 +185,29 @@ public abstract class LocalWorld implements World, Extent { } } - /** - * Drop an item. - * - * @param pt - * @param item - * @param times - */ - public void dropItem(Vector pt, BaseItemStack item, int times) { - for (int i = 0; i < times; ++i) { - dropItem(pt, item); - } - } - - /** - * Drop an item. - * - * @param pt - * @param item - */ - public abstract void dropItem(Vector pt, BaseItemStack item); - - /** - * Simulate a block being mined. - * - * @param pt - */ - public void simulateBlockMine(Vector pt) { - BaseItemStack stack = BlockType.getBlockDrop(getBlockType(pt), (short) getBlockData(pt)); - if (stack == null) { - return; - } - - final int amount = stack.getAmount(); - if (amount > 1) { - dropItem(pt, new BaseItemStack(stack.getType(), 1, stack.getData()), amount); - } else { - dropItem(pt, stack, amount); - } - } - - /** - * Kill mobs in an area, excluding pet wolves. - * - * @param origin The center of the area to kill mobs in - * @param radius -1 for the whole world - * @return number of mobs killed - */ - @Deprecated - public int killMobs(Vector origin, int radius) { - return killMobs(origin, radius, false); - } - - /** - * Kill mobs in an area. - * - * @param origin The center of the area to kill mobs in - * @param radius -1 for all mobs - * @param killPets whether to kill pets - * @return number of mobs killed - */ - @Deprecated - public int killMobs(Vector origin, int radius, boolean killPets) { - return killMobs(origin, radius, killPets ? KillFlags.PETS : 0); - } - - /** - * Kill mobs in an area. - * - * @param origin The center of the area to kill mobs in - * @param radius -1 for all mobs - * @param flags various flags that determine what to kill - * @return number of mobs killed - */ - public int killMobs(Vector origin, double radius, int flags) { - return killMobs(origin, (int) radius, (flags & KillFlags.PETS) != 0); - } - - /** - * Remove entities in an area. - * - * @param type - * @param origin - * @param radius - * @return - */ - public abstract int removeEntities(EntityType type, Vector origin, int radius); - - /** - * Returns whether a block has a valid ID. - * - * @param type - * @return - */ - public boolean isValidBlockType(int type) { - return BlockType.fromID(type) != null; - } - - /** - * Returns whether a block uses its data value. - * - * @param type block ID type - * @return true if the block uses data value - */ - public boolean usesBlockData(int type) { - // We future proof here by assuming all unknown blocks use data - return BlockType.usesData(type) || BlockType.fromID(type) == null; - } - - /** - * Checks if the chunk pt is in is loaded. if not, loads the chunk - * - * @param pt Position to check - */ - public void checkLoadedChunk(Vector pt) { - } - - /** - * Compare if the other world is equal. - * - * @param other - * @return - */ @Override - public abstract boolean equals(Object other); - - /** - * Hash code. - * - * @return - */ - @Override - public abstract int hashCode(); - - /** - * Get the world's height - * - * @return - */ - public int getMaxY() { - return 255; - } - - /** - * Does some post-processing. Should be called after using fast mode - * - * @param chunks the chunks to fix - */ - public void fixAfterFastMode(Iterable chunks) { - } - - public void fixLighting(Iterable chunks) { - } - - /** - * Plays the minecraft effect with the given type and data at the given position. - * - * @param position - * @param type - * @param data - */ - public boolean playEffect(Vector position, int type, int data) { + public boolean generateTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { return false; } - private class QueuedEffect implements Comparable { - private final Vector position; - private final int blockId; - private final double priority; - public QueuedEffect(Vector position, int blockId, double priority) { - this.position = position; - this.blockId = blockId; - this.priority = priority; - } - - public void play() { - playEffect(position, 2001, blockId); - } - - @Override - public int compareTo(QueuedEffect other) { - return Double.compare(priority, other.priority); - } - } - - private final PriorityQueue effectQueue = new PriorityQueue(); - private int taskId = -1; - public boolean queueBlockBreakEffect(ServerInterface server, Vector position, int blockId, double priority) { - if (taskId == -1) { - taskId = server.schedule(0, 1, new Runnable() { - @Override - public void run() { - int max = Math.max(1, Math.min(30, effectQueue.size() / 3)); - for (int i = 0; i < max; ++i) { - if (effectQueue.isEmpty()) return; - - effectQueue.poll().play(); - } - } - }); - } - - if (taskId == -1) { - return false; - } - - effectQueue.offer(new QueuedEffect(position, blockId, priority)); - - return true; - } - - public LocalEntity[] getEntities(Region region) { - return new LocalEntity[0]; - } - - public int killEntities(LocalEntity... entities) { - return 0; + @Override + public boolean generateBigTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return false; } @Override - public boolean setBlock(Vector pt, BaseBlock block) { - return setBlock(pt, block, true); - } - - @Override - public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) { - boolean successful; - - // Default implementation will call the old deprecated methods - if (notifyAdjacent) { - successful = setTypeIdAndData(pt, block.getId(), block.getData()); - } else { - successful = setTypeIdAndDataFast(pt, block.getId(), block.getData()); - } - - if (block instanceof BaseBlock) { - copyToWorld(pt, (BaseBlock) block); - } - - return successful; + public boolean generateBirchTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return false; } @Override - public BaseBlock getLazyBlock(Vector position) { - return getBlock(position); + public boolean generateRedwoodTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return false; } @Override - public BaseBlock getBlock(Vector pt) { - checkLoadedChunk(pt); - - int type = getBlockType(pt); - int data = getBlockData(pt); - - switch (type) { - case BlockID.WALL_SIGN: - case BlockID.SIGN_POST: { - SignBlock block = new SignBlock(type, data); - copyFromWorld(pt, block); - return block; - } - - case BlockID.CHEST: { - ChestBlock block = new ChestBlock(data); - copyFromWorld(pt, block); - return block; - } - - case BlockID.FURNACE: - case BlockID.BURNING_FURNACE: { - FurnaceBlock block = new FurnaceBlock(type, data); - copyFromWorld(pt, block); - return block; - } - - case BlockID.DISPENSER: { - DispenserBlock block = new DispenserBlock(data); - copyFromWorld(pt, block); - return block; - } - - case BlockID.MOB_SPAWNER: { - MobSpawnerBlock block = new MobSpawnerBlock(data); - copyFromWorld(pt, block); - return block; - } - - case BlockID.NOTE_BLOCK: { - NoteBlock block = new NoteBlock(data); - copyFromWorld(pt, block); - return block; - } - - case BlockID.HEAD: { - SkullBlock block = new SkullBlock(data); - copyFromWorld(pt, block); - return block; - } - - default: - return new BaseBlock(type, data); - } + public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return false; } - /** - * Create a mask that matches all liquids. - *

- * Implementations should override this so that custom liquids are supported. - * - * @return a mask - */ - public Mask createLiquidMask() { - return new BlockMask(this, - new BaseBlock(BlockID.STATIONARY_LAVA, -1), - new BaseBlock(BlockID.LAVA, -1), - new BaseBlock(BlockID.STATIONARY_WATER, -1), - new BaseBlock(BlockID.WATER, -1)); - } - - @Override - public Vector getMaximumPoint() { - return new Vector(30000000, 30000000, 30000000); - } - - @Override - public Vector getMinimumPoint() { - return new Vector(-30000000, -30000000, -30000000); - } - - @Override - public @Nullable Operation commit() { - return null; - } } diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java index 960c8923e..b40b27790 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -19,10 +19,7 @@ package com.sk89q.worldedit.entity; -import com.sk89q.worldedit.PlayerDirection; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.WorldVectorFace; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.extent.Extent; /** @@ -35,7 +32,7 @@ import com.sk89q.worldedit.extent.Extent; * can then be used to spawn new instances of that particular entity * description. */ -public interface Entity extends Player { +public interface Entity { /** * Find a position for the actor to stand that is not inside a block. @@ -215,4 +212,11 @@ public interface Entity extends Player { */ void setPosition(Vector pos); + /** + * Get the world that this entity is on. + * + * @return the world + */ + LocalWorld getWorld(); + } diff --git a/src/main/java/com/sk89q/worldedit/entity/Player.java b/src/main/java/com/sk89q/worldedit/entity/Player.java index cad0865a8..4d5a5b601 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -27,7 +27,7 @@ import com.sk89q.worldedit.extent.inventory.BlockBag; /** * A player. */ -public interface Player { +public interface Player extends Entity { /** * Returns true if the entity is holding a pick axe. diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java new file mode 100644 index 000000000..fafafc86a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -0,0 +1,483 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.blocks.ItemID; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.util.TargetBlock; + +import java.io.File; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract implementation of both a {@link Actor} and a {@link Player} + * that is intended for implementations of WorldEdit to use to wrap + * players that make use of WorldEdit. + */ +public abstract class AbstractPlayerActor implements Actor, Player { + + private final Platform platform; + + /** + * Create a new instance. + * + * @param platform the platform + */ + protected AbstractPlayerActor(Platform platform) { + checkNotNull(platform); + + this.platform = platform; + } + + /** + * Returns direction according to rotation. May return null. + * + * @param rot yaw + * @return the direction + */ + private static PlayerDirection getDirection(double rot) { + if (0 <= rot && rot < 22.5) { + return PlayerDirection.SOUTH; + } else if (22.5 <= rot && rot < 67.5) { + return PlayerDirection.SOUTH_WEST; + } else if (67.5 <= rot && rot < 112.5) { + return PlayerDirection.WEST; + } else if (112.5 <= rot && rot < 157.5) { + return PlayerDirection.NORTH_WEST; + } else if (157.5 <= rot && rot < 202.5) { + return PlayerDirection.NORTH; + } else if (202.5 <= rot && rot < 247.5) { + return PlayerDirection.NORTH_EAST; + } else if (247.5 <= rot && rot < 292.5) { + return PlayerDirection.EAST; + } else if (292.5 <= rot && rot < 337.5) { + return PlayerDirection.SOUTH_EAST; + } else if (337.5 <= rot && rot < 360.0) { + return PlayerDirection.SOUTH; + } else { + return null; + } + } + + @Override + public boolean isHoldingPickAxe() { + int item = getItemInHand(); + return item == ItemID.IRON_PICK + || item == ItemID.WOOD_PICKAXE + || item == ItemID.STONE_PICKAXE + || item == ItemID.DIAMOND_PICKAXE + || item == ItemID.GOLD_PICKAXE; + } + + @Override + public void findFreePosition(WorldVector searchPos) { + LocalWorld world = searchPos.getWorld(); + int x = searchPos.getBlockX(); + int y = Math.max(0, searchPos.getBlockY()); + int origY = y; + int z = searchPos.getBlockZ(); + + byte free = 0; + + while (y <= world.getMaxY() + 2) { + if (BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { + ++free; + } else { + free = 0; + } + + if (free == 2) { + if (y - 1 != origY) { + final Vector pos = new Vector(x, y - 2, z); + final int id = world.getBlockType(pos); + final int data = world.getBlockData(pos); + setPosition(new Vector(x + 0.5, y - 2 + BlockType.centralTopLimit(id, data), z + 0.5)); + } + + return; + } + + ++y; + } + } + + @Override + public void setOnGround(WorldVector searchPos) { + LocalWorld world = searchPos.getWorld(); + int x = searchPos.getBlockX(); + int y = Math.max(0, searchPos.getBlockY()); + int z = searchPos.getBlockZ(); + + while (y >= 0) { + final Vector pos = new Vector(x, y, z); + final int id = world.getBlockType(pos); + final int data = world.getBlockData(pos); + if (!BlockType.canPassThrough(id, data)) { + setPosition(new Vector(x + 0.5, y + BlockType.centralTopLimit(id, data), z + 0.5)); + return; + } + + --y; + } + } + + @Override + public void findFreePosition() { + findFreePosition(getBlockIn()); + } + + @Override + public boolean ascendLevel() { + final WorldVector pos = getBlockIn(); + final int x = pos.getBlockX(); + int y = Math.max(0, pos.getBlockY()); + final int z = pos.getBlockZ(); + final LocalWorld world = pos.getWorld(); + + byte free = 0; + byte spots = 0; + + while (y <= world.getMaxY() + 2) { + if (BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { + ++free; + } else { + free = 0; + } + + if (free == 2) { + ++spots; + if (spots == 2) { + final Vector platform = new Vector(x, y - 2, z); + final BaseBlock block = world.getBlock(platform); + final int type = block.getId(); + + // Don't get put in lava! + if (type == BlockID.LAVA || type == BlockID.STATIONARY_LAVA) { + return false; + } + + setPosition(platform.add(0.5, BlockType.centralTopLimit(block), 0.5)); + return true; + } + } + + ++y; + } + + return false; + } + + @Override + public boolean descendLevel() { + final WorldVector pos = getBlockIn(); + final int x = pos.getBlockX(); + int y = Math.max(0, pos.getBlockY() - 1); + final int z = pos.getBlockZ(); + final LocalWorld world = pos.getWorld(); + + byte free = 0; + + while (y >= 1) { + if (BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { + ++free; + } else { + free = 0; + } + + 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 BaseBlock block = world.getBlock(platform); + final int type = block.getId(); + + // Don't want to end up in lava + if (type != BlockID.AIR && type != BlockID.LAVA && type != BlockID.STATIONARY_LAVA) { + // Found a block! + setPosition(platform.add(0.5, BlockType.centralTopLimit(block), 0.5)); + return true; + } + + --y; + } + + return false; + } + + --y; + } + + return false; + } + + @Override + public boolean ascendToCeiling(int clearance) { + return ascendToCeiling(clearance, true); + } + + @Override + public boolean ascendToCeiling(int clearance, boolean alwaysGlass) { + Vector pos = getBlockIn(); + int x = pos.getBlockX(); + int initialY = Math.max(0, pos.getBlockY()); + int y = Math.max(0, pos.getBlockY() + 2); + int z = pos.getBlockZ(); + LocalWorld world = getPosition().getWorld(); + + // No free space above + if (world.getBlockType(new Vector(x, y, z)) != 0) { + return false; + } + + while (y <= world.getMaxY()) { + // Found a ceiling! + if (!BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { + int platformY = Math.max(initialY, y - 3 - clearance); + floatAt(x, platformY + 1, z, alwaysGlass); + return true; + } + + ++y; + } + + return false; + } + + @Override + public boolean ascendUpwards(int distance) { + return ascendUpwards(distance, true); + } + + @Override + public boolean ascendUpwards(int distance, boolean alwaysGlass) { + final Vector pos = getBlockIn(); + final int x = pos.getBlockX(); + final int initialY = Math.max(0, pos.getBlockY()); + int y = Math.max(0, pos.getBlockY() + 1); + final int z = pos.getBlockZ(); + final int maxY = Math.min(getWorld().getMaxY() + 1, initialY + distance); + final LocalWorld world = getPosition().getWorld(); + + while (y <= world.getMaxY() + 2) { + if (!BlockType.canPassThrough(world.getBlock(new Vector(x, y, z)))) { + break; // Hit something + } else if (y > maxY + 1) { + break; + } else if (y == maxY + 1) { + floatAt(x, y - 1, z, alwaysGlass); + return true; + } + + ++y; + } + + return false; + } + + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + getPosition().getWorld().setBlockType(new Vector(x, y - 1, z), BlockID.GLASS); + setPosition(new Vector(x + 0.5, y, z + 0.5)); + } + + @Override + public WorldVector getBlockIn() { + WorldVector pos = getPosition(); + return WorldVector.toBlockPoint(pos.getWorld(), pos.getX(), + pos.getY(), pos.getZ()); + } + + @Override + public WorldVector getBlockOn() { + WorldVector pos = getPosition(); + return WorldVector.toBlockPoint(pos.getWorld(), pos.getX(), + pos.getY() - 1, pos.getZ()); + } + + @Override + public WorldVector getBlockTrace(int range, boolean useLastBlock) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); + } + + @Override + public WorldVectorFace getBlockTraceFace(int range, boolean useLastBlock) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return (useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace()); + } + + @Override + public WorldVector getBlockTrace(int range) { + return getBlockTrace(range, false); + } + + @Override + public WorldVector getSolidBlockTrace(int range) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return tb.getSolidTargetBlock(); + } + + @Override + public PlayerDirection getCardinalDirection() { + return getCardinalDirection(0); + } + + @Override + public PlayerDirection getCardinalDirection(int yawOffset) { + if (getPitch() > 67.5) { + return PlayerDirection.DOWN; + } + if (getPitch() < -67.5) { + return PlayerDirection.UP; + } + + // From hey0's code + double rot = (getYaw() + yawOffset) % 360; //let's use real yaw now + if (rot < 0) { + rot += 360.0; + } + return getDirection(rot); + } + + @Override + public BaseBlock getBlockInHand() throws WorldEditException { + final int typeId = getItemInHand(); + if (!getWorld().isValidBlockType(typeId)) { + throw new NotABlockException(typeId); + } + return new BaseBlock(typeId); + } + + /** + * Get the player's view yaw. + * + * @return yaw + */ + + @Override + public boolean passThroughForwardWall(int range) { + int searchDist = 0; + TargetBlock hitBlox = new TargetBlock(this, range, 0.2); + LocalWorld world = getPosition().getWorld(); + BlockWorldVector block; + boolean firstBlock = true; + int freeToFind = 2; + boolean inFree = false; + + while ((block = hitBlox.getNextBlock()) != null) { + boolean free = BlockType.canPassThrough(world.getBlock(block)); + + if (firstBlock) { + firstBlock = false; + + if (!free) { + --freeToFind; + continue; + } + } + + ++searchDist; + if (searchDist > 20) { + return false; + } + + if (inFree != free) { + if (free) { + --freeToFind; + } + } + + if (freeToFind == 0) { + setOnGround(block); + return true; + } + + inFree = free; + } + + return false; + } + + @Override + public void setPosition(Vector pos) { + setPosition(pos, (float) getPitch(), (float) getYaw()); + } + + @Override + public File openFileOpenDialog(String[] extensions) { + printError("File dialogs are not supported in your environment."); + return null; + } + + @Override + public File openFileSaveDialog(String[] extensions) { + printError("File dialogs are not supported in your environment."); + return null; + } + + @Override + public boolean canDestroyBedrock() { + return hasPermission("worldedit.override.bedrock"); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof LocalPlayer)) { + return false; + } + LocalPlayer other2 = (LocalPlayer) other; + return other2.getName().equals(getName()); + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public void checkPermission(String permission) throws WorldEditPermissionException { + if (!hasPermission(permission)) { + throw new WorldEditPermissionException(); + } + } + + @Override + public boolean isPlayer() { + return true; + } + + @Override + public boolean hasCreativeMode() { + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java index d85e00eb0..761fc4227 100644 --- a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java +++ b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVectorFace; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.entity.Entity; /** * This class uses an inefficient method to figure out what block a player @@ -58,12 +59,23 @@ public class TargetBlock { /** * Constructor requiring a player, max distance and a checking distance - * + * * @param player LocalPlayer to work with * @param maxDistance how far it checks for blocks * @param checkDistance how often to check for blocks, the smaller the more precise */ public TargetBlock(LocalPlayer player, int maxDistance, double checkDistance) { + this((Entity) player, maxDistance, checkDistance); + } + + /** + * Constructor requiring a player, max distance and a checking distance + * + * @param player LocalPlayer to work with + * @param maxDistance how far it checks for blocks + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + public TargetBlock(Entity player, int maxDistance, double checkDistance) { this.world = player.getWorld(); this.setValues(player.getPosition(), player.getYaw(), player.getPitch(), maxDistance, 1.65, checkDistance); @@ -76,7 +88,7 @@ public class TargetBlock { * @param xRotation * @param yRotation * @param maxDistance how far it checks for blocks - * @param viewPos where the view is positioned in y-axis + * @param viewHeight where the view is positioned in y-axis * @param checkDistance how often to check for blocks, the smaller the more precise */ private void setValues(Vector loc, double xRotation, double yRotation, diff --git a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java new file mode 100644 index 000000000..453e1bf93 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -0,0 +1,243 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.LocalWorld.KillFlags; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; + +import javax.annotation.Nullable; +import java.util.PriorityQueue; + +/** + * An abstract implementation of {@link World}. + */ +public abstract class AbstractWorld implements World { + + private final PriorityQueue effectQueue = new PriorityQueue(); + private int taskId = -1; + + @Override + public int getMaxY() { + return 255; + } + + @Override + public boolean isValidBlockType(int type) { + return BlockType.fromID(type) != null; + } + + @Override + public boolean usesBlockData(int type) { + // We future proof here by assuming all unknown blocks use data + return BlockType.usesData(type) || BlockType.fromID(type) == null; + } + + @Override + public Mask createLiquidMask() { + return new BlockMask(this, + new BaseBlock(BlockID.STATIONARY_LAVA, -1), + new BaseBlock(BlockID.LAVA, -1), + new BaseBlock(BlockID.STATIONARY_WATER, -1), + new BaseBlock(BlockID.WATER, -1)); + } + + @SuppressWarnings("deprecation") + @Override + public boolean setBlockTypeFast(Vector pt, int type) { + return setBlockType(pt, type); + } + + @SuppressWarnings("deprecation") + @Override + public boolean setTypeIdAndData(Vector pt, int type, int data) { + boolean ret = setBlockType(pt, type); + setBlockData(pt, data); + return ret; + } + + @SuppressWarnings("deprecation") + @Override + public boolean setTypeIdAndDataFast(Vector pt, int type, int data) { + boolean ret = setBlockTypeFast(pt, type); + setBlockDataFast(pt, data); + return ret; + } + + @Override + public void dropItem(Vector pt, BaseItemStack item, int times) { + for (int i = 0; i < times; ++i) { + dropItem(pt, item); + } + } + + @Override + public void simulateBlockMine(Vector pt) { + BaseBlock block = getLazyBlock(pt); + BaseItemStack stack = BlockType.getBlockDrop(block.getId(), (short) block.getData()); + if (stack == null) { + return; + } + + final int amount = stack.getAmount(); + if (amount > 1) { + dropItem(pt, new BaseItemStack(stack.getType(), 1, stack.getData()), amount); + } else { + dropItem(pt, stack, amount); + } + } + + @Override + public LocalEntity[] getEntities(Region region) { + return new LocalEntity[0]; + } + + @Override + public int killEntities(LocalEntity... entities) { + return 0; + } + + @Override + public int killMobs(Vector origin, int radius) { + return killMobs(origin, radius, false); + } + + @Override + public int killMobs(Vector origin, int radius, boolean killPets) { + return killMobs(origin, radius, killPets ? KillFlags.PETS : 0); + } + + @Override + public int killMobs(Vector origin, double radius, int flags) { + return killMobs(origin, (int) radius, (flags & KillFlags.PETS) != 0); + } + + @Override + public boolean generateTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return generateTree(TreeType.TREE, editSession, pt); + } + + @Override + public boolean generateBigTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return generateTree(TreeType.BIG_TREE, editSession, pt); + } + + @Override + public boolean generateBirchTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return generateTree(TreeType.BIRCH, editSession, pt); + } + + @Override + public boolean generateRedwoodTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return generateTree(TreeType.REDWOOD, editSession, pt); + } + + @Override + public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { + return generateTree(TreeType.TALL_REDWOOD, editSession, pt); + } + + @Override + public void checkLoadedChunk(Vector pt) { + } + + @Override + public void fixAfterFastMode(Iterable chunks) { + } + + @Override + public void fixLighting(Iterable chunks) { + } + + @Override + public boolean playEffect(Vector position, int type, int data) { + return false; + } + + @SuppressWarnings("deprecation") + @Override + public boolean queueBlockBreakEffect(ServerInterface server, Vector position, int blockId, double priority) { + if (taskId == -1) { + taskId = server.schedule(0, 1, new Runnable() { + @Override + public void run() { + int max = Math.max(1, Math.min(30, effectQueue.size() / 3)); + for (int i = 0; i < max; ++i) { + if (effectQueue.isEmpty()) return; + + effectQueue.poll().play(); + } + } + }); + } + + if (taskId == -1) { + return false; + } + + effectQueue.offer(new QueuedEffect(position, blockId, priority)); + + return true; + } + + @Override + public Vector getMinimumPoint() { + return new Vector(-30000000, 0, -30000000); + } + + @Override + public Vector getMaximumPoint() { + return new Vector(30000000, getMaxY(), 30000000); + } + + @Override + public @Nullable Operation commit() { + return null; + } + + private class QueuedEffect implements Comparable { + private final Vector position; + private final int blockId; + private final double priority; + public QueuedEffect(Vector position, int blockId, double priority) { + this.position = position; + this.blockId = blockId; + this.priority = priority; + } + + public void play() { + playEffect(position, 2001, blockId); + } + + @Override + public int compareTo(@Nullable QueuedEffect other) { + return Double.compare(priority, other != null ? other.priority : 0); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index df362f970..d6daca3e1 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -19,54 +19,335 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.foundation.Block; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; /** - * Represents a world instance that can be modified. The world instance could be - * loaded in-game or loaded in a stand-alone editor. - *

- * This class is meant to replace {@link LocalWorld} eventually, once this class has been - * fleshed out with the required methods and it has been decided that it is time to - * start breaking some API compatibility. + * Represents a world (dimension). */ -public interface World { +public interface World extends Extent { /** - * Change the block at the given location to the given block. The operation may - * not tie the given {@link BaseBlock} to the world, so future changes to the - * {@link BaseBlock} do not affect the world until this method is called again. - *

- * Implementations may or may not consider the value of the notifyAdjacent - * parameter, and implementations may to choose to either apply physics anyway or - * to not apply any physics (particularly in a stand-alone implementation). - *

- * The return value of this method indicates whether the change "went through," as - * in the block was changed in the world in any way. If the new block is no different - * than the block already at the position in the world, 'false' would be returned. - * If the position is invalid (out of bounds, for example), then nothing should - * occur and 'false' should be returned. If possible, the return value should be - * accurate as possible, but implementations may choose to not provide an accurate - * value if it is not possible to know. + * Get the name of the world. * - * @param location location of the block + * @return a name for the world + */ + String getName(); + + /** + * Get the maximum Y. + * + * @return the maximum Y + */ + int getMaxY(); + + /** + * Checks whether the given block ID is a valid block ID. + * + * @param id the block ID + * @return true if the block ID is a valid one + */ + boolean isValidBlockType(int id); + + /** + * Checks whether the given block ID uses data values for differentiating + * types of blocks. + * + * @param id the block ID + * @return true if the block uses data values + */ + boolean usesBlockData(int id); + + /** + * Create a mask that matches all liquids. + *

+ * Implementations should override this so that custom liquids are supported. + * + * @return a mask + */ + Mask createLiquidMask(); + + /** + * @deprecated Use {@link #getLazyBlock(Vector)} + */ + @Deprecated + int getBlockType(Vector pt); + + /** + * @deprecated Use {@link #getLazyBlock(Vector)} + */ + @Deprecated + int getBlockData(Vector pt); + + /** + * Similar to {@link Extent#setBlock(Vector, BaseBlock)} but a + * {@code notifyAndLight} parameter indicates whether adjacent blocks + * should be notified that changes have been made and lighting operations + * should be executed. + *

+ * If it's not possible to skip lighting, or if it's not possible to + * avoid notifying adjacent blocks, then attempt to meet the + * specification as best as possible. + *

+ * On implementations where the world is not simulated, the + * {@code notifyAndLight} parameter has no effect either way. + * + * @param position position of the block * @param block block to set - * @param notifyAdjacent true to to notify adjacent (perform physics) + * @param notifyAndLight true to to notify and light * @return true if the block was successfully set (return value may not be accurate) */ - boolean setBlock(Vector location, BaseBlock block, boolean notifyAdjacent); + boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight); /** - * Get a copy of the block at the given location. May return null if the location - * given is out of bounds. The returned block must not be tied to any real block - * in the world, so changes to the returned {@link Block} have no effect until - * {@link #setBlock(Vector, BaseBlock, boolean)} is called. - * - * @param location location of the block - * @return the block, or null if the block does not exist + * @deprecated Use {@link #setBlock(Vector, BaseBlock)} */ - BaseBlock getBlock(Vector location); + @Deprecated + boolean setBlockType(Vector position, int type); + + /** + * @deprecated Use {@link #setBlock(Vector, BaseBlock)} + */ + @Deprecated + boolean setBlockTypeFast(Vector position, int type); + + /** + * @deprecated Use {@link #setBlock(Vector, BaseBlock)} + */ + @Deprecated + void setBlockData(Vector position, int data); + + /** + * @deprecated Use {@link #setBlock(Vector, BaseBlock)} + */ + @Deprecated + void setBlockDataFast(Vector position, int data); + + /** + * @deprecated Use {@link #setBlock(Vector, BaseBlock)} + */ + @Deprecated + boolean setTypeIdAndData(Vector position, int type, int data); + + /** + * @deprecated Use {@link #setBlock(Vector, BaseBlock)} + */ + @Deprecated + boolean setTypeIdAndDataFast(Vector position, int type, int data); + + /** + * Get the light level at the given block. + * + * @param position the position + * @return the light level (0-15) + */ + int getBlockLightLevel(Vector position); + + /** + * Clear a chest's contents. + * + * @param position the position + * @return true if the container was cleared + */ + boolean clearContainerBlockContents(Vector position); + + /** + * Get the biome type. + * + * @param position the (x, z) location to check the biome at + * @return the biome type at the location + */ + BiomeType getBiome(Vector2D position); + + /** + * Set the biome type. + * + * @param position the (x, z) location to set the biome at + * @param biome the biome type to set to + */ + void setBiome(Vector2D position, BiomeType biome); + + /** + * Drop an item at the given position. + * + * @param position the position + * @param item the item to drop + * @param count the number of individual stacks to drop (number of item entities) + */ + void dropItem(Vector position, BaseItemStack item, int count); + + /** + * Drop one stack of the item at the given position. + * + * @param position the position + * @param item the item to drop + * @see #dropItem(Vector, BaseItemStack, int) shortcut method to specify the number of stacks + */ + void dropItem(Vector position, BaseItemStack item); + + /** + * Simulate a block being mined at the given position. + * + * @param position the position + */ + void simulateBlockMine(Vector position); + + /** + * Get a list of entities in the given region. + * + * @param region the region + * @return a list of entities + */ + LocalEntity[] getEntities(Region region); + + /** + * Kill the entities listed in the provided array. + * + * @param entity an array of entities + * @return the number of entities that were removed + */ + int killEntities(LocalEntity... entity); + + /** + * @deprecated Use {@link #killMobs(Vector, double, int)} + */ + @Deprecated + int killMobs(Vector origin, int radius); + + /** + * @deprecated Use {@link #killMobs(Vector, double, int)} + */ + @Deprecated + int killMobs(Vector origin, int radius, boolean killPets); + + /** + * Kill mobs at the given location with the given radius. + * + * @param origin the origin + * @param radius the radius + * @param flags kill flags (see {@link LocalWorld.KillFlags}) + * @return the number of mobs that were killed + */ + int killMobs(Vector origin, double radius, int flags); + + /** + * Remove entities in an area. + * + * @param type the type of entity + * @param origin the origin + * @param radius the radius + * @return the number of mobs that were killed + */ + int removeEntities(EntityType type, Vector origin, int radius); + + /** + * Regenerate an area. + * + * @param region the region + * @param editSession the {@link EditSession} + * @return true if re-generation was successful + */ + boolean regenerate(Region region, EditSession editSession); + + /** + * Generate a tree at the given position. + * + * @param type the tree type + * @param editSession the {@link EditSession} + * @param position the position + * @return true if generation was successful + * @throws MaxChangedBlocksException thrown if too many blocks were changed + */ + boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector position) throws MaxChangedBlocksException; + + /** + * @deprecated Use {@link #generateTree(TreeType, EditSession, Vector)} + */ + @Deprecated + boolean generateTree(EditSession editSession, Vector position) throws MaxChangedBlocksException; + + /** + * @deprecated Use {@link #generateTree(TreeType, EditSession, Vector)} + */ + @Deprecated + boolean generateBigTree(EditSession editSession, Vector position) throws MaxChangedBlocksException; + + /** + * @deprecated Use {@link #generateTree(TreeType, EditSession, Vector)} + */ + @Deprecated + boolean generateBirchTree(EditSession editSession, Vector position) throws MaxChangedBlocksException; + + /** + * @deprecated Use {@link #generateTree(TreeType, EditSession, Vector)} + */ + @Deprecated + boolean generateRedwoodTree(EditSession editSession, Vector position) throws MaxChangedBlocksException; + + /** + * @deprecated Use {@link #generateTree(TreeType, EditSession, Vector)} + */ + @Deprecated + boolean generateTallRedwoodTree(EditSession editSession, Vector position) throws MaxChangedBlocksException; + + /** + * Load the chunk at the given position if it isn't loaded. + * + * @param position the position + */ + void checkLoadedChunk(Vector position); + + /** + * Fix the given chunks after fast mode was used. + *

+ * Fast mode makes calls to {@link #setBlock(Vector, BaseBlock, boolean)} + * with {@code false} for the {@code notifyAndLight} parameter, which + * may causes lighting errors to accumulate. Use of this method, if + * it is implemented by the underlying world, corrects those lighting + * errors and may trigger block change notifications. + * + * @param chunks a list of chunk coordinates to fix + */ + void fixAfterFastMode(Iterable chunks); + + /** + * Relight the given chunks if possible. + * + * @param chunks a list of chunk coordinates to fix + */ + void fixLighting(Iterable chunks); + + /** + * Play the given effect. + * + * @param position the position + * @param type the effect type + * @param data the effect data + * @return true if the effect was played + */ + boolean playEffect(Vector position, int type, int data); + + /** + * Queue a block break effect. + * + * @param server the server + * @param position the position + * @param blockId the block ID + * @param priority the priority + * @return true if the effect was played + */ + boolean queueBlockBreakEffect(ServerInterface server, Vector position, int blockId, double priority); + + @Override + boolean equals(Object other); + + @Override + int hashCode(); }