From 354d819872706ecfa0aa3f0ea261a5473643f98f Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 26 Apr 2014 21:57:45 -0700 Subject: [PATCH 01/56] Added a new preliminary mapping + metadata framework. The eventual goal is to add: 1. Support for mapping block, etc. names (minecraft:stone, etc.) 2. Proper support for entities in WorldEdit 3. Support for querying for metadata about a block, entity, etc. 4. Extent support to biomes, structures, and so on --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 61 ++++++ .../sk89q/worldedit/bukkit/BukkitEntity.java | 60 ++++++ .../sk89q/worldedit/bukkit/BukkitWorld.java | 37 ++++ .../worldedit/bukkit/TameableAdapter.java | 40 ++++ .../com/sk89q/worldedit/forge/ForgeWorld.java | 32 +++ .../com/sk89q/worldedit/entity/Entity.java | 182 ------------------ .../com/sk89q/worldedit/entity/Player.java | 181 ++++++++++++++++- .../worldedit/entity/metadata/Tameable.java | 34 ++++ .../worldedit/internal/LocalWorldAdapter.java | 30 +++ .../internal/util/AbstractAdapter.java | 52 +++++ .../com/sk89q/worldedit/util/TargetBlock.java | 6 +- .../com/sk89q/worldedit/world/NullWorld.java | 33 ++++ .../java/com/sk89q/worldedit/world/World.java | 3 +- .../worldedit/world/mapping/Mapping.java | 114 +++++++++++ .../worldedit/world/mapping/NullResolver.java | 44 +++++ .../worldedit/world/mapping/Resolver.java | 56 ++++++ 16 files changed, 777 insertions(+), 188 deletions(-) create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/TameableAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java create mode 100644 src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java create mode 100644 src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java new file mode 100644 index 000000000..42b3eecbf --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -0,0 +1,61 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.Vectors; +import com.sk89q.worldedit.world.World; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Adapts between Bukkit and WorldEdit equivalent objects. + */ +final class BukkitAdapter { + + private BukkitAdapter() { + } + + /** + * Create a WorldEdit world from a Bukkit world. + * + * @param world the Bukkit world + * @return a WorldEdit world + */ + public static World adapt(org.bukkit.World world) { + checkNotNull(world); + return new BukkitWorld(world); + } + + /** + * Create a WorldEdit location from a Bukkit location. + * + * @param location the Bukkit location + * @return a WorldEdit location + */ + public static Location adapt(org.bukkit.Location location) { + checkNotNull(location); + Vector position = BukkitUtil.toVector(location); + Vector direction = Vectors.fromEulerDeg(location.getYaw(), location.getPitch()); + return new com.sk89q.worldedit.util.Location(adapt(location.getWorld()), position, direction); + } + +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java new file mode 100644 index 000000000..a2b749248 --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -0,0 +1,60 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.Tameable; +import com.sk89q.worldedit.internal.util.AbstractAdapter; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.World; + +/** + * An adapter to adapt a Bukkit entity into a WorldEdit one. + */ +class BukkitEntity extends AbstractAdapter implements Entity { + + /** + * Create a new instance. + * + * @param entity the entity + */ + BukkitEntity(org.bukkit.entity.Entity entity) { + super(entity); + } + + @SuppressWarnings("unchecked") + T getMetaData(Class metaDataClass) { + if (metaDataClass == Tameable.class && getHandle() instanceof org.bukkit.entity.Tameable) { + return (T) new TameableAdapter((org.bukkit.entity.Tameable) getHandle()); + } else { + return null; + } + } + + @Override + public World getWorld() { + return BukkitAdapter.adapt(getHandle().getWorld()); + } + + @Override + public Location getLocation() { + return BukkitAdapter.adapt(getHandle().getLocation()); + } +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 3617df143..d8ac86841 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -26,8 +26,11 @@ import com.sk89q.worldedit.blocks.*; import com.sk89q.worldedit.blocks.ContainerBlock; import com.sk89q.worldedit.blocks.NoteBlock; import com.sk89q.worldedit.bukkit.entity.BukkitEntity; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.mapping.NullResolver; +import com.sk89q.worldedit.world.mapping.Resolver; import org.bukkit.*; import org.bukkit.Location; import org.bukkit.block.*; @@ -38,6 +41,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; +import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; @@ -1248,4 +1252,37 @@ public class BukkitWorld extends LocalWorld { return super.setBlock(pt, block, notifyAdjacent); } + + @Override + public Resolver getBlockMapping() { + return new NullResolver(); + } + + @Override + public Resolver getEntityMapping() { + return new NullResolver(); + } + + @Nullable + @Override + public T getMetaData(BaseBlock block, Class metaDataClass) { + return null; + } + + @Nullable + @Override + public T getMetaData(com.sk89q.worldedit.entity.Entity entity, Class metaDataClass) { + if (entity instanceof com.sk89q.worldedit.bukkit.BukkitEntity) { + return ((com.sk89q.worldedit.bukkit.BukkitEntity) entity).getMetaData(metaDataClass); + } + + return null; + } + + @Nullable + @Override + public T getMetaData(BaseEntity entity, Class metaDataClass) { + return null; + } + } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/TameableAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/TameableAdapter.java new file mode 100644 index 000000000..b514f1b29 --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/TameableAdapter.java @@ -0,0 +1,40 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.entity.metadata.Tameable; +import com.sk89q.worldedit.internal.util.AbstractAdapter; + +/** + * Adapts a Bukkit {@link org.bukkit.entity.Tameable} into a WorldEdit + * equivalent. + */ +public class TameableAdapter extends AbstractAdapter implements Tameable { + + TameableAdapter(org.bukkit.entity.Tameable entity) { + super(entity); + } + + @Override + public boolean isTamed() { + return getHandle().isTamed(); + } + +} diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 2f64a1f82..2b3a91eb6 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -24,9 +24,12 @@ import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; +import com.sk89q.worldedit.world.mapping.NullResolver; +import com.sk89q.worldedit.world.mapping.Resolver; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityHanging; @@ -48,6 +51,7 @@ import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.gen.ChunkProviderServer; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.List; @@ -469,6 +473,34 @@ public class ForgeWorld extends AbstractWorld { } } + @Override + public Resolver getBlockMapping() { + return new NullResolver(); + } + + @Override + public Resolver getEntityMapping() { + return new NullResolver(); + } + + @Nullable + @Override + public T getMetaData(BaseBlock block, Class metaDataClass) { + return null; + } + + @Nullable + @Override + public T getMetaData(com.sk89q.worldedit.entity.Entity entity, Class metaDataClass) { + return null; + } + + @Nullable + @Override + public T getMetaData(BaseEntity entity, Class metaDataClass) { + return null; + } + /** * Thrown when the reference to the world is lost. */ diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java index 950557bc3..8f3c4be73 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -19,10 +19,6 @@ 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.extent.Extent; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; @@ -39,137 +35,6 @@ import com.sk89q.worldedit.world.World; */ public interface Entity { - /** - * Find a position for the actor to stand that is not inside a block. - * Blocks above the player will be iteratively tested until there is - * a series of two free blocks. The actor will be teleported to - * that free position. - * - * @param searchPos search position - */ - void findFreePosition(WorldVector searchPos); - - /** - * Set the actor on the ground. - * - * @param searchPos The location to start searching from - */ - void setOnGround(WorldVector searchPos); - - /** - * Find a position for the player to stand that is not inside a block. - * Blocks above the player will be iteratively tested until there is - * a series of two free blocks. The player will be teleported to - * that free position. - */ - void findFreePosition(); - - /** - * Go up one level to the next free space above. - * - * @return true if a spot was found - */ - boolean ascendLevel(); - - /** - * Go up one level to the next free space above. - * - * @return true if a spot was found - */ - boolean descendLevel(); - - /** - * Ascend to the ceiling above. - * - * @param clearance How many blocks to leave above the player's head - * @return whether the player was moved - */ - boolean ascendToCeiling(int clearance); - - /** - * Ascend to the ceiling above. - * - * @param clearance How many blocks to leave above the player's head - * @param alwaysGlass Always put glass under the player - * @return whether the player was moved - */ - boolean ascendToCeiling(int clearance, boolean alwaysGlass); - - /** - * Just go up. - * - * @param distance How far up to teleport - * @return whether the player was moved - */ - boolean ascendUpwards(int distance); - - /** - * Just go up. - * - * @param distance How far up to teleport - * @param alwaysGlass Always put glass under the player - * @return whether the player was moved - */ - boolean ascendUpwards(int distance, boolean alwaysGlass); - - /** - * Make the player float in the given blocks. - * - * @param x The X coordinate of the block to float in - * @param y The Y coordinate of the block to float in - * @param z The Z coordinate of the block to float in - */ - void floatAt(int x, int y, int z, boolean alwaysGlass); - - /** - * Get the point of the block that is being stood in. - * - * @return point - */ - WorldVector getBlockIn(); - - /** - * Get the point of the block that is being stood upon. - * - * @return point - */ - WorldVector getBlockOn(); - - /** - * Get the point of the block being looked at. May return null. - * Will return the farthest away air block if useLastBlock is true and no other block is found. - * - * @param range How far to checks for blocks - * @param useLastBlock Try to return the last valid air block found. - * @return point - */ - WorldVector getBlockTrace(int range, boolean useLastBlock); - - WorldVectorFace getBlockTraceFace(int range, boolean useLastBlock); - - /** - * Get the point of the block being looked at. May return null. - * - * @param range How far to checks for blocks - * @return point - */ - WorldVector getBlockTrace(int range); - - /** - * Get the point of the block being looked at. May return null. - * - * @param range How far to checks for blocks - * @return point - */ - WorldVector getSolidBlockTrace(int range); - - /** - * Get the player's cardinal direction (N, W, NW, etc.). May return null. - * - * @return the direction - */ - PlayerDirection getCardinalDirection(); - /** * Get the location of this entity. * @@ -177,53 +42,6 @@ public interface Entity { */ Location getLocation(); - /** - * Get the actor's position. - *

- * If the actor has no permission, then return a dummy location. - * - * @return the actor's position - */ - WorldVector getPosition(); - - /** - * Get the player's view pitch. - * - * @return pitch - */ - double getPitch(); - - /** - * Get the player's view yaw. - * - * @return yaw - */ - double getYaw(); - - /** - * Pass through the wall that you are looking at. - * - * @param range How far to checks for blocks - * @return whether the player was pass through - */ - boolean passThroughForwardWall(int range); - - /** - * Move the player. - * - * @param pos Where to move them - * @param pitch The pitch (up/down) of the player's view - * @param yaw The yaw (left/right) of the player's view - */ - void setPosition(Vector pos, float pitch, float yaw); - - /** - * Move the player. - * - * @param pos Where to move them - */ - void setPosition(Vector pos); - /** * Get the world that this entity is on. * diff --git a/src/main/java/com/sk89q/worldedit/entity/Player.java b/src/main/java/com/sk89q/worldedit/entity/Player.java index 4d5a5b601..175c6617d 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -19,8 +19,7 @@ package com.sk89q.worldedit.entity; -import com.sk89q.worldedit.PlayerDirection; -import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -80,4 +79,182 @@ public interface Player extends Entity { */ boolean hasCreativeMode(); + /** + * Find a position for the actor to stand that is not inside a block. + * Blocks above the player will be iteratively tested until there is + * a series of two free blocks. The actor will be teleported to + * that free position. + * + * @param searchPos search position + */ + void findFreePosition(WorldVector searchPos); + + /** + * Set the actor on the ground. + * + * @param searchPos The location to start searching from + */ + void setOnGround(WorldVector searchPos); + + /** + * Find a position for the player to stand that is not inside a block. + * Blocks above the player will be iteratively tested until there is + * a series of two free blocks. The player will be teleported to + * that free position. + */ + void findFreePosition(); + + /** + * Go up one level to the next free space above. + * + * @return true if a spot was found + */ + boolean ascendLevel(); + + /** + * Go up one level to the next free space above. + * + * @return true if a spot was found + */ + boolean descendLevel(); + + /** + * Ascend to the ceiling above. + * + * @param clearance How many blocks to leave above the player's head + * @return whether the player was moved + */ + boolean ascendToCeiling(int clearance); + + /** + * Ascend to the ceiling above. + * + * @param clearance How many blocks to leave above the player's head + * @param alwaysGlass Always put glass under the player + * @return whether the player was moved + */ + boolean ascendToCeiling(int clearance, boolean alwaysGlass); + + /** + * Just go up. + * + * @param distance How far up to teleport + * @return whether the player was moved + */ + boolean ascendUpwards(int distance); + + /** + * Just go up. + * + * @param distance How far up to teleport + * @param alwaysGlass Always put glass under the player + * @return whether the player was moved + */ + boolean ascendUpwards(int distance, boolean alwaysGlass); + + /** + * Make the player float in the given blocks. + * + * @param x The X coordinate of the block to float in + * @param y The Y coordinate of the block to float in + * @param z The Z coordinate of the block to float in + */ + void floatAt(int x, int y, int z, boolean alwaysGlass); + + /** + * Get the point of the block that is being stood in. + * + * @return point + */ + WorldVector getBlockIn(); + + /** + * Get the point of the block that is being stood upon. + * + * @return point + */ + WorldVector getBlockOn(); + + /** + * Get the point of the block being looked at. May return null. + * Will return the farthest away air block if useLastBlock is true and no other block is found. + * + * @param range How far to checks for blocks + * @param useLastBlock Try to return the last valid air block found. + * @return point + */ + WorldVector getBlockTrace(int range, boolean useLastBlock); + + WorldVectorFace getBlockTraceFace(int range, boolean useLastBlock); + + /** + * Get the point of the block being looked at. May return null. + * + * @param range How far to checks for blocks + * @return point + */ + WorldVector getBlockTrace(int range); + + /** + * Get the point of the block being looked at. May return null. + * + * @param range How far to checks for blocks + * @return point + */ + WorldVector getSolidBlockTrace(int range); + + /** + * Get the player's cardinal direction (N, W, NW, etc.). May return null. + * + * @return the direction + */ + PlayerDirection getCardinalDirection(); + + /** + * Get the actor's position. + *

+ * If the actor has no permission, then return a dummy location. + * + * @return the actor's position + */ + WorldVector getPosition(); + + /** + * Get the player's view pitch. + * + * @return pitch + */ + double getPitch(); + + /** + * Get the player's view yaw. + * + * @return yaw + */ + double getYaw(); + + /** + * Pass through the wall that you are looking at. + * + * @param range How far to checks for blocks + * @return whether the player was pass through + */ + boolean passThroughForwardWall(int range); + + /** + * Move the player. + * + * @param pos Where to move them + * @param pitch The pitch (up/down) of the player's view + * @param yaw The yaw (left/right) of the player's view + */ + void setPosition(Vector pos, float pitch, float yaw); + + /** + * Move the player. + * + * @param pos Where to move them + */ + void setPosition(Vector pos); + } diff --git a/src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java b/src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java new file mode 100644 index 000000000..6f288a00f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java @@ -0,0 +1,34 @@ +/* + * 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.entity.metadata; + +/** + * Indicates a creature that can be tamed. + */ +public interface Tameable { + + /** + * Returns whether the creature is tamed. + * + * @return true if the creature is tamed + */ + boolean isTamed(); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index 3e061de36..9dc583878 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -22,11 +22,14 @@ package com.sk89q.worldedit.internal; import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; 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 com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.mapping.Resolver; import javax.annotation.Nullable; @@ -308,6 +311,33 @@ public class LocalWorldAdapter extends LocalWorld { public Operation commit() { return world.commit(); } + @Override + public Resolver getBlockMapping() { + return world.getBlockMapping(); + } + + @Override + public Resolver getEntityMapping() { + return world.getEntityMapping(); + } + + @Override + @Nullable + public T getMetaData(BaseBlock block, Class metaDataClass) { + return world.getMetaData(block, metaDataClass); + } + + @Override + @Nullable + public T getMetaData(Entity entity, Class metaDataClass) { + return world.getMetaData(entity, metaDataClass); + } + + @Override + @Nullable + public T getMetaData(BaseEntity entity, Class metaDataClass) { + return world.getMetaData(entity, metaDataClass); + } public static LocalWorldAdapter wrap(World world) { return new LocalWorldAdapter(world); diff --git a/src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java b/src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java new file mode 100644 index 000000000..c4ab6305e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java @@ -0,0 +1,52 @@ +/* + * 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.internal.util; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstract class for adapters. + * + * @param class of adapted objects + */ +public abstract class AbstractAdapter { + + private final E object; + + /** + * Create a new instance. + * + * @param object the object to adapt + */ + public AbstractAdapter(E object) { + checkNotNull(object); + this.object = object; + } + + /** + * Get the object. + * + * @return the object + */ + public E getHandle() { + return object; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java index 700dce3f8..e5d474f72 100644 --- a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java +++ b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.util; import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.internal.LocalWorldAdapter; /** @@ -62,7 +62,7 @@ public class TargetBlock { * @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); + this((Player) player, maxDistance, checkDistance); } /** @@ -72,7 +72,7 @@ public class TargetBlock { * @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) { + public TargetBlock(Player player, int maxDistance, double checkDistance) { this.world = LocalWorldAdapter.wrap(player.getWorld()); this.setValues(player.getPosition(), player.getYaw(), player.getPitch(), maxDistance, 1.65, checkDistance); diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 62edc3352..ba7b9d0d7 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -23,8 +23,14 @@ import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.world.mapping.NullResolver; +import com.sk89q.worldedit.world.mapping.Resolver; + +import javax.annotation.Nullable; /** * A null implementation of {@link World} that drops all changes and @@ -95,4 +101,31 @@ public class NullWorld extends AbstractWorld { return new BaseBlock(BlockID.AIR); } + @Override + public Resolver getBlockMapping() { + return new NullResolver(); + } + + @Override + public Resolver getEntityMapping() { + return new NullResolver(); + } + + @Nullable + @Override + public T getMetaData(BaseBlock block, Class metaDataClass) { + return null; + } + + @Nullable + @Override + public T getMetaData(Entity entity, Class metaDataClass) { + return null; + } + + @Nullable + @Override + public T getMetaData(BaseEntity entity, Class metaDataClass) { + return null; + } } diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index 9f69b122e..c711bcdf2 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -27,11 +27,12 @@ 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; +import com.sk89q.worldedit.world.mapping.Mapping; /** * Represents a world (dimension). */ -public interface World extends Extent { +public interface World extends Extent, Mapping { /** * Get the name of the world. diff --git a/src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java b/src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java new file mode 100644 index 000000000..401ab94a7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java @@ -0,0 +1,114 @@ +/* + * 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.mapping; + +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.Tameable; + +import javax.annotation.Nullable; + +/** + * A mapping can create state objects (such as {@link BaseBlock}) + * from implementation-independent identifiers (such as "minecraft.stone"), + * as well as perform the opposite task of retrieving + * the identifier for a given state object (whenever possible at least, because + * a mapping may not be compatible with a set of state objects that may have + * come from another implementation). In addition, a mapping may be able to + * retrieve a variety of metadata objects (such as {@link Tameable}) to + * describe a given state object. + *

+ * However, it may be possible that a mapping be "dumb" and not be able to, + * for example, return a {@link Tameable} for a "Horse" entity, simply because + * it has not be implemented. Any code that queries a mapping must be + * aware of this and act accordingly. + */ +public interface Mapping { + + /** + * Get the mapping for block identifiers. + * + * @return a block mapping + */ + Resolver getBlockMapping(); + + /** + * Get the mapping for entity identifiers. + * + * @return an entity mapping + */ + Resolver getEntityMapping(); + + /** + * Attempt to return an instance of the given class for the given block. + * For example, {@code getMetaData(block, Inventory.class)} might return + * an instance if the block happens to contain an inventory. + *

+ * If the given block is not of the given class (i.e. a dirt block does + * not have an inventory) or if the information is simply not available, + * {@code null} will be returned. + *

+ * Mutator methods on the returned instance should change the block. + * + * @param block the block + * @param metaDataClass the metadata class for the returned instance + * @param the metadata class + * @return an instance of the given class, otherwise null + */ + @Nullable T getMetaData(BaseBlock block, Class metaDataClass); + + /** + * Attempt to return an instance of the given class for the given entity. + * For example, {@code getMetaData(entity, Creature.class)} might return + * an instance if the entity happens to be a creature. + *

+ * If the given entity is not of the given class (i.e. a painting is + * not a creature) or if the information is simply not available, + * {@code null} will be returned. + *

+ * Mutator methods on the returned instance should change the entity. + * + * @param entity the entity + * @param metaDataClass the metadata class for the returned instance + * @param the metadata class + * @return an instance of the given class, otherwise null + */ + @Nullable T getMetaData(Entity entity, Class metaDataClass); + + /** + * Attempt to return an instance of the given class for the given entity. + * For example, {@code getMetaData(entity, Creature.class)} might return + * an instance if the entity happens to be a creature. + *

+ * If the given entity is not of the given class (i.e. a painting is + * not a creature) or if the information is simply not available, + * {@code null} will be returned. + *

+ * Mutator methods on the returned instance should change the entity. + * + * @param entity the entity + * @param metaDataClass the metadata class for the returned instance + * @param the metadata class + * @return an instance of the given class, otherwise null + */ + @Nullable T getMetaData(BaseEntity entity, Class metaDataClass); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java b/src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java new file mode 100644 index 000000000..c59beefdb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java @@ -0,0 +1,44 @@ +/* + * 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.mapping; + +import javax.annotation.Nullable; + +/** + * An implementation of a {@link Resolver} that knows nothing and returns + * {@code null} in all cases. + * + * @param the object to resolve + */ +public class NullResolver implements Resolver { + + @Nullable + @Override + public E create(String id) { + return null; + } + + @Nullable + @Override + public String getId(E object) { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java b/src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java new file mode 100644 index 000000000..3acd80ab4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java @@ -0,0 +1,56 @@ +/* + * 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.mapping; + +import com.sk89q.worldedit.blocks.BaseBlock; + +import javax.annotation.Nullable; + +/** + * A resolver can create state objects (such as {@link BaseBlock}) from + * universal identifiers, but also get the universal identifier for + * a given state object (at least when it is known). + *

+ * Identifiers may be case-sensitive. Routines that work with IDs should + * not make changes to the casing of the IDs or perform case-insensitive + * comparisons. Implementations may normalize the casing of IDs if it + * is appropriate. + * + * @param the type of state object + */ +public interface Resolver { + + /** + * Create an instance of the state object from the given ID. + * + * @param id the ID + * @return an instance, otherwise null if an instance cannot be created + */ + @Nullable E create(String id); + + /** + * Get the ID for the given object. + * + * @param object the object + * @return the ID, otherwise null if it is not known + */ + @Nullable String getId(E object); + +} From a5c3238876984f5e33501560b93fd3d8da7c5285 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 27 Apr 2014 23:31:42 -0700 Subject: [PATCH 02/56] Added Creature metadata interface. --- .../worldedit/entity/metadata/Creature.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/com/sk89q/worldedit/entity/metadata/Creature.java diff --git a/src/main/java/com/sk89q/worldedit/entity/metadata/Creature.java b/src/main/java/com/sk89q/worldedit/entity/metadata/Creature.java new file mode 100644 index 000000000..66ca80b17 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/metadata/Creature.java @@ -0,0 +1,56 @@ +/* + * 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.entity.metadata; + +/** + * Describes a creature. + */ +public interface Creature { + + /** + * Returns whether the creature is a non-player character, such as + * a NPC human or a villager. + * + * @return true if the creature is an NPC + */ + boolean isNpc(); + + /** + * Returns whether the creature can be tamed. + * + * @return true if the creature can be tamed + */ + boolean isTameable(); + + /** + * Returns whether the creature is hostile. + * + * @return true if the creature is hostile + */ + boolean isHostile(); + + /** + * Returns whether the creature is passive. + * + * @return true if the creature is passive + */ + boolean isPassive(); + +} From c4c19017bb65c906612e4370a8fb5a6859862639 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 27 Apr 2014 23:34:39 -0700 Subject: [PATCH 03/56] Added incomplete entity support to all Extents. The Bukkit implementation supports the new entity API, but it has not yet been tested. The Forge implementation does not support the entity API yet. At the moment, an UnsupportedOperationException is thrown for Entity.getState() in some implementations, but use of an exception should probably not be allowed. BaseEntity is now an interface. It should not be possible to create instances of BaseEntity because it may be implementation-specific. --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 54 ++++++++++++++ .../worldedit/bukkit/BukkitBaseEntity.java | 44 ++++++++++++ .../worldedit/bukkit/BukkitCommandSender.java | 6 ++ .../sk89q/worldedit/bukkit/BukkitEntity.java | 34 +++++++-- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 6 ++ .../sk89q/worldedit/bukkit/BukkitWorld.java | 24 ++++++- .../sk89q/worldedit/forge/ForgePlayer.java | 6 ++ .../com/sk89q/worldedit/forge/ForgeWorld.java | 13 ++++ .../java/com/sk89q/worldedit/EditSession.java | 16 ++++- .../worldedit/entity/AbstractBaseEntity.java | 51 ++++++++++++++ .../sk89q/worldedit/entity/BaseEntity.java | 70 +------------------ .../com/sk89q/worldedit/entity/Entity.java | 7 ++ .../extent/AbstractDelegateExtent.java | 16 +++++ .../com/sk89q/worldedit/extent/Extent.java | 26 +++++++ .../sk89q/worldedit/extent/NullExtent.java | 16 +++++ .../worldedit/internal/LocalWorldAdapter.java | 12 ++++ .../com/sk89q/worldedit/world/NullWorld.java | 14 ++++ 17 files changed, 336 insertions(+), 79 deletions(-) create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 42b3eecbf..6ba9d5eaf 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -20,9 +20,11 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Vectors; import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; import static com.google.common.base.Preconditions.checkNotNull; @@ -45,6 +47,26 @@ final class BukkitAdapter { return new BukkitWorld(world); } + /** + * Create a Bukkit world from a WorldEdit world. + * + * @param world the WorldEdit world + * @return a Bukkit world + */ + public static org.bukkit.World adapt(World world) { + checkNotNull(world); + if (world instanceof BukkitWorld) { + return ((BukkitWorld) world).getWorld(); + } else { + org.bukkit.World match = Bukkit.getServer().getWorld(world.getName()); + if (match != null) { + return match; + } else { + throw new IllegalArgumentException("Can't find a Bukkit world for " + world); + } + } + } + /** * Create a WorldEdit location from a Bukkit location. * @@ -58,4 +80,36 @@ final class BukkitAdapter { return new com.sk89q.worldedit.util.Location(adapt(location.getWorld()), position, direction); } + /** + * Create a Bukkit location from a WorldEdit location. + * + * @param location the WorldEdit location + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(Location location) { + checkNotNull(location); + Vector position = location.toVector(); + Vector direction = location.getDirection(); + final double eyeX = direction.getX(); + final double eyeZ = direction.getZ(); + final float yaw = (float) Math.toDegrees(Math.atan2(-eyeX, eyeZ)); + final double length = Math.sqrt(eyeX * eyeX + eyeZ * eyeZ); + final float pitch = (float) Math.toDegrees(Math.atan2(-direction.getY(), length)); + return new org.bukkit.Location( + adapt(location.getWorld()), + position.getX(), position.getY(), position.getZ(), + yaw, pitch); + } + + /** + * Create a WorldEdit entity from a Bukkit entity. + * + * @param entity the Bukkit entity + * @return a WorldEdit entity + */ + public static Entity adapt(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + return new BukkitEntity(entity); + } + } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java new file mode 100644 index 000000000..25fe7c4f4 --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java @@ -0,0 +1,44 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.entity.AbstractBaseEntity; +import com.sk89q.worldedit.entity.BaseEntity; +import org.bukkit.entity.EntityType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of a {@link BaseEntity} for Bukkit. + */ +public class BukkitBaseEntity extends AbstractBaseEntity { + + private final EntityType type; + + public BukkitBaseEntity(EntityType type) { + checkNotNull(type); + this.type = type; + } + + public EntityType getBukkitType() { + return type; + } + +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index e2067fd90..842eb4c55 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.util.Location; import org.bukkit.command.CommandSender; @@ -92,6 +93,11 @@ public class BukkitCommandSender extends LocalPlayer { throw new PlayerNeededException(); } + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Cannot create a state from this object"); + } + @Override public Location getLocation() { throw new PlayerNeededException(); diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index a2b749248..247135b47 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -19,16 +19,20 @@ package com.sk89q.worldedit.bukkit; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.metadata.Tameable; -import com.sk89q.worldedit.internal.util.AbstractAdapter; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; +import static com.google.common.base.Preconditions.checkNotNull; + /** * An adapter to adapt a Bukkit entity into a WorldEdit one. */ -class BukkitEntity extends AbstractAdapter implements Entity { +class BukkitEntity implements Entity { + + private final org.bukkit.entity.Entity entity; /** * Create a new instance. @@ -36,13 +40,23 @@ class BukkitEntity extends AbstractAdapter implements * @param entity the entity */ BukkitEntity(org.bukkit.entity.Entity entity) { - super(entity); + checkNotNull(entity); + this.entity = entity; + } + + /** + * Get the underlying Bukkit entity. + * + * @return the Bukkit entity + */ + protected org.bukkit.entity.Entity getEntity() { + return entity; } @SuppressWarnings("unchecked") T getMetaData(Class metaDataClass) { - if (metaDataClass == Tameable.class && getHandle() instanceof org.bukkit.entity.Tameable) { - return (T) new TameableAdapter((org.bukkit.entity.Tameable) getHandle()); + if (metaDataClass == Tameable.class && getEntity() instanceof org.bukkit.entity.Tameable) { + return (T) new TameableAdapter((org.bukkit.entity.Tameable) getEntity()); } else { return null; } @@ -50,11 +64,17 @@ class BukkitEntity extends AbstractAdapter implements @Override public World getWorld() { - return BukkitAdapter.adapt(getHandle().getWorld()); + return BukkitAdapter.adapt(getEntity().getWorld()); } @Override public Location getLocation() { - return BukkitAdapter.adapt(getHandle().getLocation()); + return BukkitAdapter.adapt(getEntity().getLocation()); } + + @Override + public BaseEntity getState() { + return new BukkitBaseEntity(getEntity().getType()); + } + } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 1499cd09f..7d3dbdeeb 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.util.Vectors; import org.bukkit.GameMode; import org.bukkit.Location; @@ -170,6 +171,11 @@ public class BukkitPlayer extends LocalPlayer { player.setFlying(true); } + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Cannot create a state from this object"); + } + @Override public com.sk89q.worldedit.util.Location getLocation() { Location nativeLocation = player.getLocation(); diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index d8ac86841..7aab7e8fd 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -26,7 +26,7 @@ import com.sk89q.worldedit.blocks.*; import com.sk89q.worldedit.blocks.ContainerBlock; import com.sk89q.worldedit.blocks.NoteBlock; import com.sk89q.worldedit.bukkit.entity.BukkitEntity; -import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.*; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.mapping.NullResolver; @@ -36,6 +36,7 @@ import org.bukkit.Location; import org.bukkit.block.*; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; +import org.bukkit.entity.Entity; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -171,6 +172,27 @@ public class BukkitWorld extends LocalWorld { } } + @Override + public List getEntities() { + List list = new ArrayList(); + for (Entity entity : getWorld().getEntities()) { + list.add(BukkitAdapter.adapt(entity)); + } + return list; + } + + @Nullable + @Override + public com.sk89q.worldedit.entity.Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + if (entity instanceof BukkitBaseEntity) { + BukkitBaseEntity bukkitBaseEntity = (BukkitBaseEntity) entity; + Entity nativeEntity = getWorld().spawnEntity(BukkitAdapter.adapt(location), bukkitBaseEntity.getBukkitType()); + return BukkitAdapter.adapt(nativeEntity); + } else { + return null; + } + } + private class NmsBlockClassLoader extends ClassLoader { public File searchDir; public NmsBlockClassLoader(ClassLoader parent, File searchDir) { diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java index 01e178f71..20ca43ad3 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.LocalWorldAdapter; import com.sk89q.worldedit.internal.cui.CUIEvent; @@ -51,6 +52,11 @@ public class ForgePlayer extends LocalPlayer { return this.player.username; } + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Cannot create a state from this object"); + } + @Override public Location getLocation() { Vector position = new Vector(this.player.posX, this.player.posY, this.player.posZ); diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 2b3a91eb6..ebb90d33d 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.mapping.NullResolver; @@ -54,6 +55,7 @@ import net.minecraft.world.gen.ChunkProviderServer; import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -501,6 +503,17 @@ public class ForgeWorld extends AbstractWorld { return null; } + @Override + public List getEntities() { + return Collections.emptyList(); + } + + @Nullable + @Override + public com.sk89q.worldedit.entity.Entity createEntity(Location location, BaseEntity entity) { + return null; + } + /** * Thrown when the reference to the world is lost. */ diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 487395cd1..d246b3893 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -22,6 +22,8 @@ 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.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; @@ -70,8 +72,7 @@ import com.sk89q.worldedit.regions.shape.ArbitraryBiomeShape; import com.sk89q.worldedit.regions.shape.ArbitraryShape; import com.sk89q.worldedit.regions.shape.RegionShape; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; -import com.sk89q.worldedit.util.Countable; -import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.*; import com.sk89q.worldedit.util.collection.DoubleArrayList; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.world.NullWorld; @@ -572,6 +573,17 @@ public class EditSession implements Extent { return getBlock(position).isAir() && setBlock(position, block); } + @Override + public List getEntities() { + return world.getEntities(); + } + + @Override + @Nullable + public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + return world.createEntity(location, entity); + } + /** * Insert a contrived block change into the history. * diff --git a/src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java b/src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java new file mode 100644 index 000000000..c1c4bca1b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java @@ -0,0 +1,51 @@ +/* + * 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.entity; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.DataException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract implementation of {@link BaseEntity} that implementations can + * subclass to simplify implementation. + */ +public abstract class AbstractBaseEntity implements BaseEntity { + + private CompoundTag nbtData; + + @Override + public boolean hasNbtData() { + return getNbtData() != null; + } + + @Override + public CompoundTag getNbtData() { + return nbtData; + } + + @Override + public void setNbtData(CompoundTag nbtData) throws DataException { + checkNotNull(nbtData); + this.nbtData = nbtData; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java index 2cb248a69..2b1fb2193 100644 --- a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java +++ b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -19,79 +19,11 @@ package com.sk89q.worldedit.entity; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.NbtValued; -import java.util.HashMap; -import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; - /** * A snapshot of an entity that can be reused and passed around. */ -public class BaseEntity implements NbtValued { - - private CompoundTag nbtData; - - /** - * Create a new entity with the given entity ID. - * - * @param id the ID of the entity, which determines its type - */ - public BaseEntity(String id) { - checkNotNull(id); - Map map = new HashMap(); - map.put("id", new StringTag("id", id)); - this.nbtData = new CompoundTag("", map); - } - - /** - * Create a new entity with the given NBT data. - * - * @param nbtData the NBT data - */ - public BaseEntity(CompoundTag nbtData) { - checkNotNull(nbtData); - this.nbtData = nbtData; - } - - /** - * Get the ID of the entity, which determines the type of entity. - * An example of an entity ID would be "CaveSpider". - * - * @return the entity ID, which may be an empty string - */ - public String getEntityId() { - CompoundTag nbtData = getNbtData(); - if (nbtData == null) { - return ""; - } - Tag idTag = nbtData.getValue().get("id"); - if (idTag != null && idTag instanceof StringTag) { - return ((StringTag) idTag).getValue(); - } else { - return ""; - } - } - - @Override - public boolean hasNbtData() { - return getNbtData() != null; - } - - @Override - public CompoundTag getNbtData() { - return nbtData; - } - - @Override - public void setNbtData(CompoundTag nbtData) throws DataException { - checkNotNull(nbtData); - this.nbtData = nbtData; - } +public interface BaseEntity extends NbtValued { } diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java index 8f3c4be73..88473d6f8 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -35,6 +35,13 @@ import com.sk89q.worldedit.world.World; */ public interface Entity { + /** + * Get a copy of the entity's state. + * + * @return the entity's state + */ + BaseEntity getState(); + /** * Get the location of this entity. * diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index b9c4c1158..666c33872 100644 --- a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -22,11 +22,16 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; +import java.util.List; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -70,6 +75,17 @@ public abstract class AbstractDelegateExtent implements Extent { return extent.setBlock(location, block); } + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return extent.createEntity(location, entity); + } + + @Override + public List getEntities() { + return extent.getEntities(); + } + @Override public Vector getMinimumPoint() { return extent.getMinimumPoint(); diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java index 34d86d298..14bacb425 100644 --- a/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -20,6 +20,12 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; +import java.util.List; /** * A world, portion of a world, clipboard, or other object that can have blocks @@ -50,4 +56,24 @@ public interface Extent extends InputExtent, OutputExtent { */ Vector getMaximumPoint(); + /** + * Get a list of all entities. + *

+ * If the extent is not wholly loaded (i.e. a world being simulated in the + * game will not have every chunk loaded), then this list may not be + * incomplete. + * + * @return a list of entities + */ + List getEntities(); + + /** + * Create an entity at the given location. + * + * @param entity the entity + * @param location the location + * @return a reference to the created entity, or null if the entity could not be created + */ + @Nullable Entity createEntity(Location location, BaseEntity entity); + } diff --git a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index f291bc2f2..5f8f84644 100644 --- a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -22,9 +22,14 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; /** * An extent that returns air blocks for all blocks and does not @@ -44,6 +49,17 @@ public class NullExtent implements Extent { return nullPoint; } + @Override + public List getEntities() { + return Collections.emptyList(); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + return null; + } + @Override public BaseBlock getBlock(Vector position) { return new BaseBlock(0); diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index 9dc583878..9ed250c7f 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.mapping.Resolver; import javax.annotation.Nullable; +import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -339,6 +340,17 @@ public class LocalWorldAdapter extends LocalWorld { return world.getMetaData(entity, metaDataClass); } + @Override + @Nullable + public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + return world.createEntity(location, entity); + } + + @Override + public List getEntities() { + return world.getEntities(); + } + public static LocalWorldAdapter wrap(World world) { return new LocalWorldAdapter(world); } diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index ba7b9d0d7..35cc1a863 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -26,11 +26,14 @@ import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.mapping.NullResolver; import com.sk89q.worldedit.world.mapping.Resolver; import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; /** * A null implementation of {@link World} that drops all changes and @@ -128,4 +131,15 @@ public class NullWorld extends AbstractWorld { public T getMetaData(BaseEntity entity, Class metaDataClass) { return null; } + + @Override + public List getEntities() { + return Collections.emptyList(); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + return null; + } } From c9612c05a792b6474b2bf83db1d5c93d840bfc85 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 28 Jun 2014 22:43:41 -0700 Subject: [PATCH 04/56] Fixed formatting error in BukkitEntity. --- src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index 247135b47..810709603 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -55,7 +55,7 @@ class BukkitEntity implements Entity { @SuppressWarnings("unchecked") T getMetaData(Class metaDataClass) { - if (metaDataClass == Tameable.class && getEntity() instanceof org.bukkit.entity.Tameable) { + if (metaDataClass == Tameable.class && getEntity() instanceof org.bukkit.entity.Tameable) { return (T) new TameableAdapter((org.bukkit.entity.Tameable) getEntity()); } else { return null; From eee2c5d9f4bab9ca7f1cd90776df65626dfe61a1 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 29 Jun 2014 15:36:41 -0700 Subject: [PATCH 05/56] Changed Location to use Extents rather than worlds and overhauled the new Entity code a bit. --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 2 +- .../worldedit/bukkit/BukkitCommandSender.java | 2 - .../sk89q/worldedit/bukkit/BukkitEntity.java | 11 ++- .../sk89q/worldedit/bukkit/BukkitWorld.java | 8 +- .../sk89q/worldedit/forge/ForgeAdapter.java} | 29 +++---- .../sk89q/worldedit/forge/ForgeEntity.java | 67 ++++++++++++++++ .../com/sk89q/worldedit/forge/ForgeWorld.java | 34 +++++--- .../java/com/sk89q/worldedit/WorldVector.java | 3 +- .../worldedit/command/tool/AreaPickaxe.java | 5 +- .../command/tool/BlockDataCyler.java | 2 +- .../worldedit/command/tool/BlockReplacer.java | 4 +- .../command/tool/FloatingTreeRemover.java | 2 +- .../worldedit/command/tool/FloodFillTool.java | 2 +- .../worldedit/command/tool/QueryTool.java | 2 +- .../command/tool/RecursivePickaxe.java | 2 +- .../worldedit/command/tool/SinglePickaxe.java | 2 +- .../worldedit/entity/AbstractBaseEntity.java | 51 ------------ .../sk89q/worldedit/entity/BaseEntity.java | 65 ++++++++++++++- .../com/sk89q/worldedit/entity/Entity.java | 14 +++- .../com/sk89q/worldedit/entity/Player.java | 14 +++- .../platform/AbstractPlayerActor.java | 29 ++++++- .../internal/command/WorldEditBinding.java | 32 ++++++-- .../com/sk89q/worldedit/util/Location.java | 80 +++++++++---------- .../sk89q/worldedit/util/LocationTest.java | 8 +- 24 files changed, 312 insertions(+), 158 deletions(-) rename src/{bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java => forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java} (60%) create mode 100644 src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java delete mode 100644 src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 6ba9d5eaf..3fba70a8e 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -96,7 +96,7 @@ final class BukkitAdapter { final double length = Math.sqrt(eyeX * eyeX + eyeZ * eyeZ); final float pitch = (float) Math.toDegrees(Math.atan2(-direction.getY(), length)); return new org.bukkit.Location( - adapt(location.getWorld()), + adapt((World) location.getExtent()), position.getX(), position.getY(), position.getZ(), yaw, pitch); } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index a8dc5adc2..1e57ffa54 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.PlayerNeededException; import com.sk89q.worldedit.WorldEditPermissionException; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index 810709603..1625c572a 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -22,8 +22,8 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.metadata.Tameable; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.World; import static com.google.common.base.Preconditions.checkNotNull; @@ -63,7 +63,7 @@ class BukkitEntity implements Entity { } @Override - public World getWorld() { + public Extent getExtent() { return BukkitAdapter.adapt(getEntity().getWorld()); } @@ -74,7 +74,12 @@ class BukkitEntity implements Entity { @Override public BaseEntity getState() { - return new BukkitBaseEntity(getEntity().getType()); + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override + public boolean remove() { + return false; } } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index dfafb852f..67d2152b1 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -184,13 +184,7 @@ public class BukkitWorld extends LocalWorld { @Nullable @Override public com.sk89q.worldedit.entity.Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { - if (entity instanceof BukkitBaseEntity) { - BukkitBaseEntity bukkitBaseEntity = (BukkitBaseEntity) entity; - Entity nativeEntity = getWorld().spawnEntity(BukkitAdapter.adapt(location), bukkitBaseEntity.getBukkitType()); - return BukkitAdapter.adapt(nativeEntity); - } else { - return null; - } + throw new UnsupportedOperationException("Not implemented yet"); } private class NmsBlockClassLoader extends ClassLoader { diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java similarity index 60% rename from src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java rename to src/forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java index 25fe7c4f4..5a1d6120f 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBaseEntity.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -17,28 +17,23 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit; +package com.sk89q.worldedit.forge; -import com.sk89q.worldedit.entity.AbstractBaseEntity; -import com.sk89q.worldedit.entity.BaseEntity; -import org.bukkit.entity.EntityType; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.world.World; +import net.minecraft.util.Vec3; -import static com.google.common.base.Preconditions.checkNotNull; +final class ForgeAdapter { -/** - * An implementation of a {@link BaseEntity} for Bukkit. - */ -public class BukkitBaseEntity extends AbstractBaseEntity { - - private final EntityType type; - - public BukkitBaseEntity(EntityType type) { - checkNotNull(type); - this.type = type; + private ForgeAdapter() { } - public EntityType getBukkitType() { - return type; + public static World adapt(net.minecraft.world.World world) { + return new ForgeWorld(world); + } + + public static Vector adapt(Vec3 vector) { + return new Vector(vector.xCoord, vector.yCoord, vector.zCoord); } } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java new file mode 100644 index 000000000..75f1d9b09 --- /dev/null +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -0,0 +1,67 @@ +/* + * 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.forge; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; +import net.minecraft.entity.EntityList; +import net.minecraft.nbt.NBTTagCompound; + +import static com.google.common.base.Preconditions.checkNotNull; + +class ForgeEntity implements Entity { + + private final net.minecraft.entity.Entity entity; + + ForgeEntity(net.minecraft.entity.Entity entity) { + checkNotNull(entity); + this.entity = entity; + } + + @Override + public BaseEntity getState() { + NBTTagCompound tag = new NBTTagCompound(); + entity.writeToNBT(tag); + return new BaseEntity(EntityList.getEntityString(entity), NBTConverter.fromNative(tag)); + } + + @Override + public Location getLocation() { + return new Location( + ForgeAdapter.adapt(entity.worldObj), + new Vector(entity.posX, entity.posY, entity.posZ), + ForgeAdapter.adapt(entity.getLookVec())); + } + + @Override + public Extent getExtent() { + return ForgeAdapter.adapt(entity.worldObj); + } + + @Override + public boolean remove() { + entity.setDead(); + return true; + } + +} diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index e9f712d09..60f229bf0 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; @@ -32,8 +33,8 @@ import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.mapping.NullResolver; import com.sk89q.worldedit.world.mapping.Resolver; import net.minecraft.block.Block; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityHanging; +import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.IProjectile; import net.minecraft.entity.item.*; @@ -55,7 +56,7 @@ import net.minecraft.world.gen.ChunkProviderServer; import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -227,7 +228,7 @@ public class ForgeWorld extends AbstractWorld { int num = 0; double radiusSq = radius * radius; - for (Entity obj : (Iterable) getWorld().loadedEntityList) { + for (net.minecraft.entity.Entity obj : (Iterable) getWorld().loadedEntityList) { if ((obj instanceof EntityLiving)) { EntityLiving ent = (EntityLiving) obj; @@ -270,7 +271,7 @@ public class ForgeWorld extends AbstractWorld { int num = 0; double radiusSq = Math.pow(radius, 2.0D); - for (Entity ent : (Iterable) getWorld().loadedEntityList) { + for (net.minecraft.entity.Entity ent : (Iterable) getWorld().loadedEntityList) { if ((radius != -1) && (origin.distanceSq(new Vector(ent.posX, ent.posY, ent.posZ)) > radiusSq)) { continue; } @@ -497,7 +498,7 @@ public class ForgeWorld extends AbstractWorld { @Nullable @Override - public T getMetaData(com.sk89q.worldedit.entity.Entity entity, Class metaDataClass) { + public T getMetaData(Entity entity, Class metaDataClass) { return null; } @@ -508,14 +509,29 @@ public class ForgeWorld extends AbstractWorld { } @Override - public List getEntities() { - return Collections.emptyList(); + public List getEntities() { + List entities = new ArrayList(); + for (Object entity : getWorld().getLoadedEntityList()) { + entities.add(new ForgeEntity((net.minecraft.entity.Entity) entity)); + } + return entities; } @Nullable @Override - public com.sk89q.worldedit.entity.Entity createEntity(Location location, BaseEntity entity) { - return null; + public Entity createEntity(Location location, BaseEntity entity) { + World world = getWorld(); + net.minecraft.entity.Entity createdEntity = EntityList.createEntityByName(entity.getTypeId(), world); + if (createdEntity != null) { + CompoundTag tag = entity.getNbtData(); + if (tag != null) { + createdEntity.readFromNBT(NBTConverter.toNative(entity.getNbtData())); + } + world.spawnEntityInWorld(createdEntity); + return new ForgeEntity(createdEntity); + } else { + return null; + } } /** diff --git a/src/main/java/com/sk89q/worldedit/WorldVector.java b/src/main/java/com/sk89q/worldedit/WorldVector.java index 5e3d12b2e..d03137a69 100644 --- a/src/main/java/com/sk89q/worldedit/WorldVector.java +++ b/src/main/java/com/sk89q/worldedit/WorldVector.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit; import com.sk89q.worldedit.internal.LocalWorldAdapter; +import com.sk89q.worldedit.world.World; /** * @deprecated Use {@link com.sk89q.worldedit.util.Location} wherever possible @@ -97,7 +98,7 @@ public class WorldVector extends Vector { * @param location the location */ public WorldVector(com.sk89q.worldedit.util.Location location) { - this(LocalWorldAdapter.adapt(location.getWorld()), location.getX(), location.getY(), location.getZ()); + this(LocalWorldAdapter.adapt((World) location.getExtent()), location.getX(), location.getY(), location.getZ()); } /** diff --git a/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index fffa9a0be..04a25443a 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.world.World; /** * A super pickaxe mode that will remove blocks in an area. @@ -48,7 +49,7 @@ public class AreaPickaxe implements BlockTool { int ox = clicked.getBlockX(); int oy = clicked.getBlockY(); int oz = clicked.getBlockZ(); - int initialType = clicked.getWorld().getBlockType(clicked.toVector()); + int initialType = ((World) clicked.getExtent()).getBlockType(clicked.toVector()); if (initialType == 0) { return true; @@ -70,7 +71,7 @@ public class AreaPickaxe implements BlockTool { continue; } - clicked.getWorld().queueBlockBreakEffect(server, pos, initialType, clicked.toVector().distanceSq(pos)); + ((World) clicked.getExtent()).queueBlockBreakEffect(server, pos, initialType, clicked.toVector().distanceSq(pos)); editSession.setBlock(pos, air); } diff --git a/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 252823561..41bff5f2a 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -41,7 +41,7 @@ public class BlockDataCyler implements DoubleActionBlockTool { private boolean handleCycle(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, boolean forward) { - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); int type = world.getBlockType(clicked.toVector()); int data = world.getBlockData(clicked.toVector()); diff --git a/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index 19abb8ea3..d1af045bb 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -48,7 +48,7 @@ public class BlockReplacer implements DoubleActionBlockTool { public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { BlockBag bag = session.getBlockBag(player); - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1, bag, player); try { @@ -67,7 +67,7 @@ BlockBag bag = session.getBlockBag(player); @Override public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1, player); targetBlock = (editSession).getBlock(clicked.toVector()); BlockType type = BlockType.fromID(targetBlock.getType()); diff --git a/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java b/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java index df92fb5f0..14785c392 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java @@ -53,7 +53,7 @@ public class FloatingTreeRemover implements BlockTool { public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { - final World world = clicked.getWorld(); + final World world = (World) clicked.getExtent(); switch (world.getBlockType(clicked.toVector())) { case BlockID.LOG: diff --git a/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java b/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java index 4ccead8cf..3d484b18e 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java @@ -51,7 +51,7 @@ public class FloodFillTool implements BlockTool { @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); int initialType = world.getBlockType(clicked.toVector()); diff --git a/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java b/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java index a68031f74..6aa5262a0 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java @@ -42,7 +42,7 @@ public class QueryTool implements BlockTool { @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 0, player); BaseBlock block = (editSession).rawGetBlock(clicked.toVector()); BlockType type = BlockType.fromID(block.getType()); diff --git a/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java index e551b9f2e..7a8589b4c 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java @@ -50,7 +50,7 @@ public class RecursivePickaxe implements BlockTool { @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); int initialType = world.getBlockType(clicked.toVector()); diff --git a/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index 202c04c95..246a6f633 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -42,7 +42,7 @@ public class SinglePickaxe implements BlockTool { @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { - World world = clicked.getWorld(); + World world = (World) clicked.getExtent(); final int blockType = world.getBlockType(clicked.toVector()); if (blockType == BlockID.BEDROCK && !player.canDestroyBedrock()) { diff --git a/src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java b/src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java deleted file mode 100644 index c1c4bca1b..000000000 --- a/src/main/java/com/sk89q/worldedit/entity/AbstractBaseEntity.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.entity; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.DataException; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * An abstract implementation of {@link BaseEntity} that implementations can - * subclass to simplify implementation. - */ -public abstract class AbstractBaseEntity implements BaseEntity { - - private CompoundTag nbtData; - - @Override - public boolean hasNbtData() { - return getNbtData() != null; - } - - @Override - public CompoundTag getNbtData() { - return nbtData; - } - - @Override - public void setNbtData(CompoundTag nbtData) throws DataException { - checkNotNull(nbtData); - this.nbtData = nbtData; - } - -} diff --git a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java index 2b1fb2193..b1f8b0a91 100644 --- a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java +++ b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -19,11 +19,74 @@ package com.sk89q.worldedit.entity; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.NbtValued; +import static com.google.common.base.Preconditions.checkNotNull; + /** * A snapshot of an entity that can be reused and passed around. */ -public interface BaseEntity extends NbtValued { +public class BaseEntity implements NbtValued { + + private String id; + private CompoundTag nbtData; + + /** + * Create a new base entity. + * + * @param id the entity type ID + * @param nbtData NBT data + */ + public BaseEntity(String id, CompoundTag nbtData) { + setTypeId(id); + setNbtData(nbtData); + } + + /** + * Make a clone of a {@link BaseEntity}. + * + * @param other the object to clone + */ + public BaseEntity(BaseEntity other) { + checkNotNull(other); + setTypeId(other.getTypeId()); + setNbtData(other.getNbtData()); + } + + @Override + public boolean hasNbtData() { + return true; + } + + @Override + public CompoundTag getNbtData() { + return nbtData; + } + + @Override + public void setNbtData(CompoundTag nbtData) { + checkNotNull(nbtData); + this.nbtData = nbtData; + } + + /** + * Get the entity that determines the type of entity. + * + * @return the entity ID + */ + public String getTypeId() { + return id; + } + + /** + * Set the entity ID that determines the type of entity. + * + * @param id the id + */ + public void setTypeId(String id) { + checkNotNull(id); + this.id = id; + } } diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java index 88473d6f8..800f61c72 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.World; /** * A reference to an instance of an entity that exists in an {@link Extent} @@ -50,10 +49,17 @@ public interface Entity { Location getLocation(); /** - * Get the world that this entity is on. + * Get the extent that this entity is on. * - * @return the world + * @return the extent */ - World getWorld(); + Extent getExtent(); + + /** + * Remove this entity from it container. + * + * @return true if removal was successful + */ + boolean remove(); } diff --git a/src/main/java/com/sk89q/worldedit/entity/Player.java b/src/main/java/com/sk89q/worldedit/entity/Player.java index 9f09a4b5b..c5e2e333e 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -19,16 +19,28 @@ package com.sk89q.worldedit.entity; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.PlayerDirection; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.WorldVectorFace; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.world.World; /** * A player. */ public interface Player extends Entity, Actor { + /** + * Return the world that the player is on. + * + * @return the world + */ + World getWorld(); + /** * 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 index e329baf22..6cc034891 100644 --- a/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -19,12 +19,21 @@ package com.sk89q.worldedit.extension.platform; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BlockWorldVector; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.PlayerDirection; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.WorldEditPermissionException; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.WorldVectorFace; 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.extent.Extent; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.util.TargetBlock; import com.sk89q.worldedit.world.World; @@ -36,7 +45,12 @@ import java.io.File; * that is intended for implementations of WorldEdit to use to wrap * players that make use of WorldEdit. */ -public abstract class AbstractPlayerActor implements Actor, Player { +public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { + + @Override + public final Extent getExtent() { + return getWorld(); + } /** * Returns direction according to rotation. May return null. @@ -466,4 +480,15 @@ public abstract class AbstractPlayerActor implements Actor, Player { return false; } + @SuppressWarnings("CloneDoesntCallSuperClone") + @Override + public Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException("Not supported"); + } + + @Override + public boolean remove() { + return false; + } + } diff --git a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java index ed29e8fb5..019c1cc72 100644 --- a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java +++ b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java @@ -19,13 +19,21 @@ package com.sk89q.worldedit.internal.command; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.annotation.Direction; @@ -33,7 +41,12 @@ import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.util.command.parametric.*; +import com.sk89q.worldedit.util.command.parametric.ArgumentStack; +import com.sk89q.worldedit.util.command.parametric.BindingBehavior; +import com.sk89q.worldedit.util.command.parametric.BindingHelper; +import com.sk89q.worldedit.util.command.parametric.BindingMatch; +import com.sk89q.worldedit.util.command.parametric.ParameterException; +import com.sk89q.worldedit.world.World; import java.util.Arrays; @@ -158,7 +171,10 @@ public class WorldEditBinding extends BindingHelper { ParserContext parserContext = new ParserContext(); parserContext.setActor(context.getContext().getLocals().get(Actor.class)); if (actor instanceof Entity) { - parserContext.setWorld(((Entity) actor).getWorld()); + Extent extent = ((Entity) actor).getExtent(); + if (extent instanceof World) { + parserContext.setWorld((World) extent); + } } parserContext.setSession(worldEdit.getSessionManager().get(actor)); try { @@ -184,7 +200,10 @@ public class WorldEditBinding extends BindingHelper { ParserContext parserContext = new ParserContext(); parserContext.setActor(context.getContext().getLocals().get(Actor.class)); if (actor instanceof Entity) { - parserContext.setWorld(((Entity) actor).getWorld()); + Extent extent = ((Entity) actor).getExtent(); + if (extent instanceof World) { + parserContext.setWorld((World) extent); + } } parserContext.setSession(worldEdit.getSessionManager().get(actor)); try { @@ -210,7 +229,10 @@ public class WorldEditBinding extends BindingHelper { ParserContext parserContext = new ParserContext(); parserContext.setActor(context.getContext().getLocals().get(Actor.class)); if (actor instanceof Entity) { - parserContext.setWorld(((Entity) actor).getWorld()); + Extent extent = ((Entity) actor).getExtent(); + if (extent instanceof World) { + parserContext.setWorld((World) extent); + } } parserContext.setSession(worldEdit.getSessionManager().get(actor)); try { diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java index e5ae26909..d6ee8c468 100644 --- a/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/src/main/java/com/sk89q/worldedit/util/Location.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.util; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.extent.Extent; import static com.google.common.base.Preconditions.checkNotNull; @@ -36,92 +36,92 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class Location { - private final World world; + private final Extent extent; private final Vector position; private final Vector direction; /** - * Create a new instance in the given world at 0, 0, 0 with a + * Create a new instance in the given extent at 0, 0, 0 with a * direction vector of 0, 0, 0. * - * @param world the world + * @param extent the extent */ - public Location(World world) { - this(world, new Vector(), new Vector()); + public Location(Extent extent) { + this(extent, new Vector(), new Vector()); } /** - * Create a new instance in the given world with the given coordinates + * Create a new instance in the given extent with the given coordinates * with a direction vector of 0, 0, 0. * - * @param world the world + * @param extent the extent * @param x the X coordinate * @param y the Y coordinate * @param z the Z coordinate */ - public Location(World world, double x, double y, double z) { - this(world, new Vector(x, y, z), new Vector()); + public Location(Extent extent, double x, double y, double z) { + this(extent, new Vector(x, y, z), new Vector()); } /** - * Create a new instance in the given world with the given position + * Create a new instance in the given extent with the given position * vector and a direction vector of 0, 0, 0. * - * @param world the world + * @param extent the extent * @param position the position vector */ - public Location(World world, Vector position) { - this(world, position, new Vector()); + public Location(Extent extent, Vector position) { + this(extent, position, new Vector()); } /** - * Create a new instance in the given world with the given coordinates + * Create a new instance in the given extent with the given coordinates * and the given direction vector. * - * @param world the world + * @param extent the extent * @param x the X coordinate * @param y the Y coordinate * @param z the Z coordinate * @param direction the direction vector */ - public Location(World world, double x, double y, double z, Vector direction) { - this(world, new Vector(x, y, z), direction); + public Location(Extent extent, double x, double y, double z, Vector direction) { + this(extent, new Vector(x, y, z), direction); } /** - * Create a new instance in the given world with the given position vector + * Create a new instance in the given extent with the given position vector * and the given direction vector. * - * @param world the world + * @param extent the extent * @param position the position vector * @param direction the direction vector */ - public Location(World world, Vector position, Vector direction) { - checkNotNull(world); + public Location(Extent extent, Vector position, Vector direction) { + checkNotNull(extent); checkNotNull(position); checkNotNull(direction); - this.world = world; + this.extent = extent; this.position = position; this.direction = direction; } /** - * Get the world. + * Get the extent. * - * @return the world + * @return the extent */ - public World getWorld() { - return world; + public Extent getExtent() { + return extent; } /** - * Create a clone of this object with the given world. + * Create a clone of this object with the given extent. * - * @param world the new world + * @param extent the new extent * @return the new instance */ - public Location setWorld(World world) { - return new Location(world, position, getDirection()); + public Location setExtent(Extent extent) { + return new Location(extent, position, getDirection()); } /** @@ -143,7 +143,7 @@ public class Location { * @return the new instance */ public Location setDirection(Vector direction) { - return new Location(world, position, direction); + return new Location(extent, position, direction); } /** @@ -181,7 +181,7 @@ public class Location { * @return a new immutable instance */ public Location setX(double x) { - return new Location(world, position.setX(x), direction); + return new Location(extent, position.setX(x), direction); } /** @@ -192,7 +192,7 @@ public class Location { * @return a new immutable instance */ public Location setX(int x) { - return new Location(world, position.setX(x), direction); + return new Location(extent, position.setX(x), direction); } /** @@ -221,7 +221,7 @@ public class Location { * @return a new immutable instance */ public Location setY(double y) { - return new Location(world, position.setY(y), direction); + return new Location(extent, position.setY(y), direction); } /** @@ -232,7 +232,7 @@ public class Location { * @return a new immutable instance */ public Location setY(int y) { - return new Location(world, position.setY(y), direction); + return new Location(extent, position.setY(y), direction); } /** @@ -261,7 +261,7 @@ public class Location { * @return a new immutable instance */ public Location setZ(double z) { - return new Location(world, position.setZ(z), direction); + return new Location(extent, position.setZ(z), direction); } /** @@ -272,7 +272,7 @@ public class Location { * @return a new immutable instance */ public Location setZ(int z) { - return new Location(world, position.setZ(z), direction); + return new Location(extent, position.setZ(z), direction); } @Override @@ -284,14 +284,14 @@ public class Location { if (!direction.equals(location.direction)) return false; if (!position.equals(location.position)) return false; - if (!world.equals(location.world)) return false; + if (!extent.equals(location.extent)) return false; return true; } @Override public int hashCode() { - int result = world.hashCode(); + int result = extent.hashCode(); result = 31 * result + position.hashCode(); result = 31 * result + direction.hashCode(); return result; diff --git a/src/test/java/com/sk89q/worldedit/util/LocationTest.java b/src/test/java/com/sk89q/worldedit/util/LocationTest.java index ecf3bc327..06d546e32 100644 --- a/src/test/java/com/sk89q/worldedit/util/LocationTest.java +++ b/src/test/java/com/sk89q/worldedit/util/LocationTest.java @@ -38,7 +38,7 @@ public class LocationTest { public void testGetWorld() throws Exception { World world = mock(World.class); Location location = new Location(world); - assertEquals(world, location.getWorld()); + assertEquals(world, location.getExtent()); } @Test @@ -46,9 +46,9 @@ public class LocationTest { World world1 = mock(World.class); World world2 = mock(World.class); Location location1 = new Location(world1); - Location location2 = location1.setWorld(world2); - assertEquals(world1, location1.getWorld()); - assertEquals(world2, location2.getWorld()); + Location location2 = location1.setExtent(world2); + assertEquals(world1, location1.getExtent()); + assertEquals(world2, location2.getExtent()); } @Test From 09eb36dc5ea316bc8a06c0a24282020e10f770f0 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 29 Jun 2014 17:47:08 -0700 Subject: [PATCH 06/56] Added new Extent-compatible Clipboard and BlockArrayClipboard classes. The goal is to replace use of CuboidClipboard with these new classes. Support for entities, //flip, //rotate, and //distr still needs to be re-implemented. DataException was also removed from BaseBlock because The Base(...) classes should be "dumb" blocks without any validation. --- .../worldedit/bukkit/DefaultNmsBlock.java | 2 +- .../worldedit/forge/TileEntityBaseBlock.java | 6 +- .../com/sk89q/worldedit/LocalSession.java | 7 +- .../com/sk89q/worldedit/blocks/BaseBlock.java | 19 ++- .../sk89q/worldedit/blocks/ChestBlock.java | 35 ++-- .../worldedit/blocks/DispenserBlock.java | 52 +++--- .../sk89q/worldedit/blocks/FurnaceBlock.java | 65 +++---- .../com/sk89q/worldedit/blocks/LazyBlock.java | 9 +- .../worldedit/blocks/MobSpawnerBlock.java | 23 ++- .../com/sk89q/worldedit/blocks/NoteBlock.java | 14 +- .../com/sk89q/worldedit/blocks/SignBlock.java | 14 +- .../sk89q/worldedit/blocks/SkullBlock.java | 14 +- .../worldedit/command/BrushCommands.java | 23 ++- .../worldedit/command/ClipboardCommands.java | 151 ++++++----------- .../worldedit/command/SchematicCommands.java | 118 ++----------- .../worldedit/command/SelectionCommands.java | 56 +++--- .../command/tool/brush/ClipboardBrush.java | 19 ++- .../extent/clipboard/BlockArrayClipboard.java | 160 ++++++++++++++++++ .../worldedit/extent/clipboard/Clipboard.java | 58 +++++++ .../extent/clipboard/StoredEntity.java | 76 +++++++++ .../function/pattern/ClipboardPattern.java | 15 +- 21 files changed, 571 insertions(+), 365 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java index 23d5e64e8..8b738923b 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java @@ -134,7 +134,7 @@ public class DefaultNmsBlock extends NmsBlock { } @Override - public void setNbtData(CompoundTag tag) throws DataException { + public void setNbtData(CompoundTag tag) { if (tag == null) { this.nbtData = null; } diff --git a/src/forge/java/com/sk89q/worldedit/forge/TileEntityBaseBlock.java b/src/forge/java/com/sk89q/worldedit/forge/TileEntityBaseBlock.java index 1a46607a8..a17ac5d43 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/TileEntityBaseBlock.java +++ b/src/forge/java/com/sk89q/worldedit/forge/TileEntityBaseBlock.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.world.DataException; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -29,10 +28,7 @@ public class TileEntityBaseBlock extends BaseBlock implements TileEntityBlock { public TileEntityBaseBlock(int type, int data, TileEntity tile) { super(type, data); - try { - setNbtData(NBTConverter.fromNative(copyNbtData(tile))); - } catch (DataException ignored) { - } + setNbtData(NBTConverter.fromNative(copyNbtData(tile))); } private static NBTTagCompound copyNbtData(TileEntity tile) { diff --git a/src/main/java/com/sk89q/worldedit/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java index df38b58a5..17b86f3b4 100644 --- a/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -29,6 +29,7 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -62,7 +63,7 @@ public class LocalSession { private boolean placeAtPos1 = false; private LinkedList history = new LinkedList(); private int historyPointer = 0; - private CuboidClipboard clipboard; + private Clipboard clipboard; private boolean toolControl = true; private boolean superPickaxe = false; private BlockTool pickaxeMode = new SinglePickaxe(); @@ -326,7 +327,7 @@ public class LocalSession { * @return clipboard, may be null * @throws EmptyClipboardException */ - public CuboidClipboard getClipboard() throws EmptyClipboardException { + public Clipboard getClipboard() throws EmptyClipboardException { if (clipboard == null) { throw new EmptyClipboardException(); } @@ -338,7 +339,7 @@ public class LocalSession { * * @param clipboard */ - public void setClipboard(CuboidClipboard clipboard) { + public void setClipboard(Clipboard clipboard) { this.clipboard = clipboard; } diff --git a/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java b/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java index 497839125..d89ff8e03 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java @@ -100,17 +100,27 @@ public class BaseBlock extends Block implements TileEntityBlock { * @see #setData(int) * @see #setNbtData(CompoundTag) */ - public BaseBlock(int id, int data, CompoundTag nbtData) throws DataException { + public BaseBlock(int id, int data, CompoundTag nbtData) { setId(id); setData(data); setNbtData(nbtData); } + /** + * Create a clone of another block. + * + * @param other the other block + */ + public BaseBlock(BaseBlock other) { + this(other.getId(), other.getData(), other.getNbtData()); + } + /** * Get the ID of the block. * * @return ID (between 0 and {@link #MAX_ID}) */ + @Override public int getId() { return id; } @@ -138,6 +148,7 @@ public class BaseBlock extends Block implements TileEntityBlock { * * @param id block id (between 0 and {@link #MAX_ID}). */ + @Override public void setId(int id) { internalSetId(id); } @@ -147,6 +158,7 @@ public class BaseBlock extends Block implements TileEntityBlock { * * @return data value (0-15) */ + @Override public int getData() { return data; } @@ -175,6 +187,7 @@ public class BaseBlock extends Block implements TileEntityBlock { * * @param data block data value (between 0 and {@link #MAX_DATA}). */ + @Override public void setData(int data) { internalSetData(data); } @@ -187,6 +200,7 @@ public class BaseBlock extends Block implements TileEntityBlock { * @see #setId(int) * @see #setData(int) */ + @Override public void setIdAndData(int id, int data) { setId(id); setData(data); @@ -198,6 +212,7 @@ public class BaseBlock extends Block implements TileEntityBlock { * * @return true if the data value is -1 */ + @Override public boolean hasWildcardData() { return getData() == -1; } @@ -227,7 +242,7 @@ public class BaseBlock extends Block implements TileEntityBlock { } @Override - public void setNbtData(CompoundTag nbtData) throws DataException { + public void setNbtData(CompoundTag nbtData) { this.nbtData = nbtData; } diff --git a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java b/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java index fcc9f0a32..d5547e661 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java @@ -19,17 +19,18 @@ package com.sk89q.worldedit.blocks; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Represents a chest block. @@ -78,7 +79,7 @@ public class ChestBlock extends ContainerBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { + public void setNbtData(CompoundTag rootTag) { if (rootTag == null) { return; } @@ -87,19 +88,25 @@ public class ChestBlock extends ContainerBlock { Tag t = values.get("id"); if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Chest")) { - throw new DataException("'Chest' tile entity expected"); + throw new RuntimeException("'Chest' tile entity expected"); } List items = new ArrayList(); - - for (Tag tag : NBTUtils.getChildTag(values, "Items", ListTag.class).getValue()) { - if (!(tag instanceof CompoundTag)) { - throw new DataException("CompoundTag expected as child tag of Chest's Items"); + + try { + for (Tag tag : NBTUtils.getChildTag(values, "Items", ListTag.class).getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new RuntimeException("CompoundTag expected as child tag of Chest's Items"); + } + + items.add((CompoundTag) tag); } - items.add((CompoundTag) tag); + setItems(deserializeInventory(items)); + } catch (InvalidFormatException e) { + throw new RuntimeException(e); + } catch (DataException e) { + throw new RuntimeException(e); } - - setItems(deserializeInventory(items)); } } diff --git a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java b/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java index 0608e4935..ea1392924 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java @@ -19,11 +19,6 @@ package com.sk89q.worldedit.blocks; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; @@ -31,6 +26,11 @@ import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.world.DataException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Represents dispensers. * @@ -79,27 +79,31 @@ public class DispenserBlock extends ContainerBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { - if (rootTag == null) { - return; - } - - Map values = rootTag.getValue(); - - Tag t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Trap")) { - throw new DataException("'Trap' tile entity expected"); - } - - List items = new ArrayList(); - for (Tag tag : NBTUtils.getChildTag(values, "Items", ListTag.class).getValue()) { - if (!(tag instanceof CompoundTag)) { - throw new DataException("CompoundTag expected as child tag of Trap Items"); + public void setNbtData(CompoundTag rootTag) { + try { + if (rootTag == null) { + return; } - items.add((CompoundTag) tag); - } + Map values = rootTag.getValue(); - setItems(deserializeInventory(items)); + Tag t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Trap")) { + throw new DataException("'Trap' tile entity expected"); + } + + List items = new ArrayList(); + for (Tag tag : NBTUtils.getChildTag(values, "Items", ListTag.class).getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new DataException("CompoundTag expected as child tag of Trap Items"); + } + + items.add((CompoundTag) tag); + } + + setItems(deserializeInventory(items)); + } catch (DataException e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java b/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java index db4d3e210..24e241dbd 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java @@ -19,11 +19,6 @@ package com.sk89q.worldedit.blocks; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; @@ -32,6 +27,11 @@ import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.world.DataException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Represents a furnace block. * @@ -125,40 +125,43 @@ public class FurnaceBlock extends ContainerBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { + public void setNbtData(CompoundTag rootTag) { if (rootTag == null) { return; } - - Map values = rootTag.getValue(); - Tag t = values.get("id"); - if (!(t instanceof StringTag) - || !((StringTag) t).getValue().equals("Furnace")) { - throw new DataException("'Furnace' tile entity expected"); - } + try { + Map values = rootTag.getValue(); - ListTag items = NBTUtils.getChildTag(values, "Items", ListTag.class); - - List compound = new ArrayList(); - - for (Tag tag : items.getValue()) { - if (!(tag instanceof CompoundTag)) { - throw new DataException( - "CompoundTag expected as child tag of Furnace Items"); + Tag t = values.get("id"); + if (!(t instanceof StringTag) + || !((StringTag) t).getValue().equals("Furnace")) { + throw new RuntimeException("'Furnace' tile entity expected"); } - compound.add((CompoundTag) tag); - } - setItems(deserializeInventory(compound)); - t = values.get("BurnTime"); - if (t instanceof ShortTag) { - burnTime = ((ShortTag) t).getValue(); - } + ListTag items = NBTUtils.getChildTag(values, "Items", ListTag.class); - t = values.get("CookTime"); - if (t instanceof ShortTag) { - cookTime = ((ShortTag) t).getValue(); + List compound = new ArrayList(); + + for (Tag tag : items.getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new RuntimeException("CompoundTag expected as child tag of Furnace Items"); + } + compound.add((CompoundTag) tag); + } + setItems(deserializeInventory(compound)); + + t = values.get("BurnTime"); + if (t instanceof ShortTag) { + burnTime = ((ShortTag) t).getValue(); + } + + t = values.get("CookTime"); + if (t instanceof ShortTag) { + cookTime = ((ShortTag) t).getValue(); + } + } catch (DataException e) { + throw new RuntimeException(e); } } } diff --git a/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java b/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java index 591744fac..bf9ad5d19 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.blocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.extent.Extent; import static com.google.common.base.Preconditions.checkNotNull; @@ -88,17 +87,13 @@ public class LazyBlock extends BaseBlock { public CompoundTag getNbtData() { if (!loaded) { BaseBlock loadedBlock = extent.getBlock(position); - try { - super.setNbtData(loadedBlock.getNbtData()); - } catch (DataException e) { - throw new RuntimeException(e); - } + super.setNbtData(loadedBlock.getNbtData()); } return super.getNbtData(); } @Override - public void setNbtData(CompoundTag nbtData) throws DataException { + public void setNbtData(CompoundTag nbtData) { throw new UnsupportedOperationException("This object is immutable"); } diff --git a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index 0004f4210..ed38b5bc8 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -19,9 +19,13 @@ package com.sk89q.worldedit.blocks; -import com.sk89q.jnbt.*; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.MobType; -import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.storage.InvalidFormatException; import java.util.HashMap; @@ -153,7 +157,7 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { + public void setNbtData(CompoundTag rootTag) { if (rootTag == null) { return; } @@ -162,11 +166,18 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock { Tag t = values.get("id"); if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("MobSpawner")) { - throw new DataException("'MobSpawner' tile entity expected"); + throw new RuntimeException("'MobSpawner' tile entity expected"); } - StringTag mobTypeTag = NBTUtils.getChildTag(values, "EntityId", StringTag.class); - ShortTag delayTag = NBTUtils.getChildTag(values, "Delay", ShortTag.class); + StringTag mobTypeTag; + ShortTag delayTag; + + try { + mobTypeTag = NBTUtils.getChildTag(values, "EntityId", StringTag.class); + delayTag = NBTUtils.getChildTag(values, "Delay", ShortTag.class); + } catch (InvalidFormatException ignored) { + throw new RuntimeException("Invalid mob spawner data: no EntityId and/or no Delay"); + } this.mobType = mobTypeTag.getValue(); this.delay = delayTag.getValue(); diff --git a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java b/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java index 19d3dc150..32e1cdb18 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java @@ -19,14 +19,13 @@ package com.sk89q.worldedit.blocks; -import java.util.HashMap; -import java.util.Map; - import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; + +import java.util.HashMap; +import java.util.Map; /** * A note block. @@ -102,7 +101,7 @@ public class NoteBlock extends BaseBlock implements TileEntityBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { + public void setNbtData(CompoundTag rootTag) { if (rootTag == null) { return; } @@ -112,9 +111,8 @@ public class NoteBlock extends BaseBlock implements TileEntityBlock { Tag t; t = values.get("id"); - if (!(t instanceof StringTag) - || !((StringTag) t).getValue().equals("Music")) { - throw new DataException("'Music' tile entity expected"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Music")) { + throw new RuntimeException("'Music' tile entity expected"); } t = values.get("note"); diff --git a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java b/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java index 8afff7001..e4d36c0d2 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -19,13 +19,12 @@ package com.sk89q.worldedit.blocks; -import java.util.HashMap; -import java.util.Map; - import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; + +import java.util.HashMap; +import java.util.Map; /** * Represents a sign block. @@ -104,7 +103,7 @@ public class SignBlock extends BaseBlock implements TileEntityBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { + public void setNbtData(CompoundTag rootTag) { if (rootTag == null) { return; } @@ -116,9 +115,8 @@ public class SignBlock extends BaseBlock implements TileEntityBlock { text = new String[] { "", "", "", "" }; t = values.get("id"); - if (!(t instanceof StringTag) - || !((StringTag) t).getValue().equals("Sign")) { - throw new DataException("'Sign' tile entity expected"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Sign")) { + throw new RuntimeException("'Sign' tile entity expected"); } t = values.get("Text1"); diff --git a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java b/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java index 02ab5ac6e..981a339ec 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -19,14 +19,13 @@ package com.sk89q.worldedit.blocks; -import java.util.HashMap; -import java.util.Map; - import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; + +import java.util.HashMap; +import java.util.Map; /** * A skull block. @@ -165,7 +164,7 @@ public class SkullBlock extends BaseBlock implements TileEntityBlock { } @Override - public void setNbtData(CompoundTag rootTag) throws DataException { + public void setNbtData(CompoundTag rootTag) { if (rootTag == null) { return; } @@ -175,9 +174,8 @@ public class SkullBlock extends BaseBlock implements TileEntityBlock { Tag t; t = values.get("id"); - if (!(t instanceof StringTag) - || !((StringTag) t).getValue().equals("Skull")) { - throw new DataException("'Skull' tile entity expected"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Skull")) { + throw new RuntimeException("'Skull' tile entity expected"); } t = values.get("SkullType"); diff --git a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index f954e26d8..2d9739dd0 100644 --- a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -22,17 +22,31 @@ package com.sk89q.worldedit.command; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalWorld.KillFlags; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.command.UtilityCommands.FlagContainer; import com.sk89q.worldedit.command.tool.BrushTool; -import com.sk89q.worldedit.command.tool.brush.*; +import com.sk89q.worldedit.command.tool.brush.ButcherBrush; +import com.sk89q.worldedit.command.tool.brush.ClipboardBrush; +import com.sk89q.worldedit.command.tool.brush.CylinderBrush; +import com.sk89q.worldedit.command.tool.brush.GravityBrush; +import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; +import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; +import com.sk89q.worldedit.command.tool.brush.SmoothBrush; +import com.sk89q.worldedit.command.tool.brush.SphereBrush; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; @@ -128,14 +142,15 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.clipboard") public void clipboardBrush(Player player, LocalSession session, EditSession editSession, @Switch('a') boolean ignoreAir) throws WorldEditException { - CuboidClipboard clipboard = session.getClipboard(); + Clipboard clipboard = session.getClipboard(); if (clipboard == null) { player.printError("Copy something first."); return; } - Vector size = clipboard.getSize(); + Region region = clipboard.getRegion(); + Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); worldEdit.checkMaxBrushRadius(size.getBlockX()); worldEdit.checkMaxBrushRadius(size.getBlockY()); diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index ffc765095..acbb1cfcc 100644 --- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -21,18 +21,29 @@ package com.sk89q.worldedit.command; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; -import com.sk89q.worldedit.world.World; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; @@ -67,31 +78,16 @@ public class ClipboardCommands { max = 0 ) @CommandPermissions("worldedit.clipboard.copy") - public void copy(Player player, LocalSession session, EditSession editSession, @Switch('e') boolean copyEntities) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - Vector pos = session.getPlacementPosition(player); - - CuboidClipboard clipboard = new CuboidClipboard( - max.subtract(min).add(Vector.ONE), - min, min.subtract(pos)); - - if (region instanceof CuboidRegion) { - clipboard.copy(editSession); - } else { - clipboard.copy(editSession, region); - } - - if (copyEntities) { - for (LocalEntity entity : player.getWorld().getEntities(region)) { - clipboard.storeEntity(entity); - } - } + public void copy(Player player, LocalSession session, EditSession editSession, + @Selection Region region, @Switch('e') boolean copyEntities) throws WorldEditException { + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOffset(region.getMinimumPoint().subtract(session.getPlacementPosition(player))); + ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); + Operations.completeLegacy(copy); session.setClipboard(clipboard); - player.print("Block(s) copied."); + player.print(region.getArea() + " block(s) were copied."); } @Command( @@ -108,36 +104,17 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) - public void cut(Player player, LocalSession session, EditSession editSession, @Optional("air") BaseBlock block, @Switch('e') boolean copyEntities) throws WorldEditException { - World world = player.getWorld(); - - Region region = session.getSelection(world); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - Vector pos = session.getPlacementPosition(player); - - CuboidClipboard clipboard = new CuboidClipboard( - max.subtract(min).add(Vector.ONE), - min, min.subtract(pos)); - - if (region instanceof CuboidRegion) { - clipboard.copy(editSession); - } else { - clipboard.copy(editSession, region); - } - - if (copyEntities) { - LocalEntity[] entities = world.getEntities(region); - for (LocalEntity entity : entities) { - clipboard.storeEntity(entity); - } - world.killEntities(entities); - } + public void cut(Player player, LocalSession session, EditSession editSession, + @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities) throws WorldEditException { + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOffset(region.getMinimumPoint().subtract(session.getPlacementPosition(player))); + ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); + copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); + Operations.completeLegacy(copy); session.setClipboard(clipboard); - editSession.setBlocks(region, block); - player.print("Block(s) cut."); + player.print(region.getArea() + " block(s) were copied."); } @Command( @@ -156,38 +133,28 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) - public void paste(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + public void paste(Player player, LocalSession session, EditSession editSession, + @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, + @Switch('s') boolean selectPasted) throws WorldEditException { - boolean atOrigin = args.hasFlag('o'); - boolean pasteNoAir = args.hasFlag('a'); + Clipboard clipboard = session.getClipboard(); + Vector to = atOrigin ? clipboard.getRegion().getMinimumPoint(): session.getPlacementPosition(player).add(clipboard.getOffset()); + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), editSession, to); + if (ignoreAirBlocks) { + copy.setSourceMask(new ExistingBlockMask(clipboard)); + } + Operations.completeLegacy(copy); - CuboidClipboard clipboard = session.getClipboard(); - - Vector pos = atOrigin ? session.getClipboard().getOrigin() - : session.getPlacementPosition(player); - - if (atOrigin) { - clipboard.place(editSession, pos, pasteNoAir); - clipboard.pasteEntities(pos); - player.findFreePosition(); - player.print("Pasted to copy origin. Undo with //undo"); - } else { - clipboard.paste(editSession, pos, pasteNoAir, true); - player.findFreePosition(); - player.print("Pasted relative to you. Undo with //undo"); + if (selectPasted) { + Region region = clipboard.getRegion(); + Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint())); + RegionSelector selector = new CuboidRegionSelector(player.getWorld(), to, max); + session.setRegionSelector(player.getWorld(), selector); + selector.learnChanges(); + selector.explainRegionAdjust(player, session); } - if (args.hasFlag('s')) { - World world = player.getWorld(); - Vector pos2 = pos.add(clipboard.getSize().subtract(1, 1, 1)); - if (!atOrigin) { - pos2 = pos2.add(clipboard.getOffset()); - pos = pos.add(clipboard.getOffset()); - } - session.setRegionSelector(world, new CuboidRegionSelector(world, pos, pos2)); - session.getRegionSelector(world).learnChanges(); - session.getRegionSelector(world).explainRegionAdjust(player, session); - } + player.print("The clipboard has been pasted at " + to.add(clipboard.getRegion().getMinimumPoint())); } @Command( @@ -198,17 +165,9 @@ public class ClipboardCommands { max = 1 ) @CommandPermissions("worldedit.clipboard.rotate") - public void rotate(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - int angle = args.getInteger(0); - - if (angle % 90 == 0) { - CuboidClipboard clipboard = session.getClipboard(); - clipboard.rotate2D(angle); - player.print("Clipboard rotated by " + angle + " degrees."); - } else { - player.printError("Angles must be divisible by 90 degrees."); - } + public void rotate(Player player, LocalSession session, EditSession editSession, CommandContext args) throws CommandException { + // TODO: Update for new clipboard + throw new CommandException("Needs to be re-written again"); } @Command( @@ -224,11 +183,9 @@ public class ClipboardCommands { max = 1 ) @CommandPermissions("worldedit.clipboard.flip") - public void flip(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - CuboidClipboard.FlipDirection dir = worldEdit.getFlipDirection(player, args.argsLength() > 0 ? args.getString(0).toLowerCase() : "me"); - CuboidClipboard clipboard = session.getClipboard(); - clipboard.flip(dir, args.hasFlag('p')); - player.print("Clipboard flipped."); + public void flip(Player player, LocalSession session, EditSession editSession, CommandContext args) throws CommandException { + // TODO: Update for new clipboard + throw new CommandException("Needs to be re-written again"); } @Command( diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 61ea46fb8..6198ddb43 100644 --- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -19,16 +19,22 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.*; -import com.sk89q.worldedit.*; +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.FilenameResolutionException; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.schematic.SchematicFormat; -import com.sk89q.worldedit.world.DataException; import java.io.File; import java.io.FileFilter; -import java.io.IOException; import java.util.Arrays; import java.util.Comparator; @@ -64,58 +70,9 @@ public class SchematicCommands { max = 2 ) @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) // TODO: Remove 'clipboard' perm - public void load(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - LocalConfiguration config = worldEdit.getConfiguration(); - String fileName; - String formatName; - - if (args.argsLength() == 1) { - formatName = null; - fileName = args.getString(0); - } else { - formatName = args.getString(0); - fileName = args.getString(1); - } - File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); - File f = worldEdit.getSafeOpenFile(player, dir, fileName, "schematic", "schematic"); - - if (!f.exists()) { - player.printError("Schematic " + fileName + " does not exist!"); - return; - } - - SchematicFormat format = formatName == null ? null : SchematicFormat.getFormat(formatName); - if (format == null) { - format = SchematicFormat.getFormat(f); - } - - if (format == null) { - player.printError("Unknown schematic format: " + formatName); - return; - } - - if (!format.isOfFormat(f) && !args.hasFlag('f')) { - player.printError(fileName + " is not of the " + format.getName() + " schematic format!"); - return; - } - - try { - String filePath = f.getCanonicalPath(); - String dirPath = dir.getCanonicalPath(); - - if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { - player.printError("Schematic could not read or it does not exist."); - } else { - session.setClipboard(format.load(f)); - WorldEdit.logger.info(player.getName() + " loaded " + filePath); - player.print(fileName + " loaded. Paste it with //paste"); - } - } catch (DataException e) { - player.printError("Load error: " + e.getMessage()); - } catch (IOException e) { - player.printError("Schematic could not read or it does not exist: " + e.getMessage()); - } + public void load(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { + // TODO: Update for new clipboard + throw new CommandException("Needs to be re-written again"); } @Command( @@ -129,53 +86,8 @@ public class SchematicCommands { ) @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"}) // TODO: Remove 'clipboard' perm public void save(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { - - LocalConfiguration config = worldEdit.getConfiguration(); - SchematicFormat format; - if (args.argsLength() == 1) { - if (SchematicFormat.getFormats().size() == 1) { - format = SchematicFormat.getFormats().iterator().next(); - } else { - player.printError("More than one schematic format is available. Please provide the desired format"); - return; - } - } else { - format = SchematicFormat.getFormat(args.getString(0)); - if (format == null) { - player.printError("Unknown schematic format: " + args.getString(0)); - return; - } - } - - String filename = args.getString(args.argsLength() - 1); - - File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); - File f = worldEdit.getSafeSaveFile(player, dir, filename, "schematic", "schematic"); - - if (!dir.exists()) { - if (!dir.mkdir()) { - player.printError("The storage folder could not be created."); - return; - } - } - - try { - // Create parent directories - File parent = f.getParentFile(); - if (parent != null && !parent.exists()) { - if (!parent.mkdirs()) { - throw new CommandException("Could not create folder for schematics!"); - } - } - - format.save(session.getClipboard(), f); - WorldEdit.logger.info(player.getName() + " saved " + f.getCanonicalPath()); - player.print(filename + " saved."); - } catch (DataException se) { - player.printError("Save error: " + se.getMessage()); - } catch (IOException e) { - player.printError("Schematic could not written: " + e.getMessage()); - } + // TODO: Update for new clipboard + throw new CommandException("Needs to be re-written again"); } @Command( diff --git a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 20cfba116..23e13cc3c 100644 --- a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -19,23 +19,13 @@ package com.sk89q.worldedit.command; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandAlias; import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.util.Countable; -import com.sk89q.worldedit.CuboidClipboard; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -43,18 +33,28 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.selector.CylinderRegionSelector; import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector; import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector; import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionOperationException; -import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.SphereRegionSelector; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; /** * Selection commands. @@ -584,15 +584,15 @@ public class SelectionCommands { public void size(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { if (args.hasFlag('c')) { - CuboidClipboard clipboard = session.getClipboard(); - Vector size = clipboard.getSize(); + Clipboard clipboard = session.getClipboard(); + Region region = clipboard.getRegion(); + Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); Vector offset = clipboard.getOffset(); - player.print("Size: " + size); + player.print("Cuboid dimensions (max - min): " + size); player.print("Offset: " + offset); player.print("Cuboid distance: " + size.distance(Vector.ONE)); - player.print("# of blocks: " - + (int) (size.getX() * size.getY() * size.getZ())); + player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ())); return; } @@ -610,8 +610,7 @@ public class SelectionCommands { } player.print("Size: " + size); - player.print("Cuboid distance: " + region.getMaximumPoint() - .distance(region.getMinimumPoint())); + player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); player.print("# of blocks: " + region.getArea()); } @@ -655,7 +654,7 @@ public class SelectionCommands { max = 0 ) @CommandPermissions("worldedit.analysis.distr") - public void distr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + public void distr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { int size; boolean useData = args.hasFlag('d'); @@ -663,13 +662,8 @@ public class SelectionCommands { List> distributionData = null; if (args.hasFlag('c')) { - CuboidClipboard clip = session.getClipboard(); - if (useData) { - distributionData = clip.getBlockDistributionWithData(); - } else { - distribution = clip.getBlockDistribution(); - } - size = clip.getHeight() * clip.getLength() * clip.getWidth(); + // TODO: Update for new clipboard + throw new CommandException("Needs to be re-written again"); } else { if (useData) { distributionData = editSession.getBlockDistributionWithData(session.getSelection(player.getWorld())); diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java index ef5fffbcc..e200fcb66 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -19,24 +19,35 @@ package com.sk89q.worldedit.command.tool.brush; -import com.sk89q.worldedit.CuboidClipboard; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.Region; public class ClipboardBrush implements Brush { - private CuboidClipboard clipboard; + private Clipboard clipboard; private boolean noAir; - public ClipboardBrush(CuboidClipboard clipboard, boolean noAir) { + public ClipboardBrush(Clipboard clipboard, boolean noAir) { this.clipboard = clipboard; this.noAir = noAir; } + @Override public void build(EditSession editSession, Vector pos, Pattern mat, double size) throws MaxChangedBlocksException { - clipboard.place(editSession, pos.subtract(clipboard.getSize().divide(2)), noAir); + Region region = clipboard.getRegion(); + Vector centerOffset = region.getCenter().subtract(region.getMinimumPoint()); + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), editSession, pos.subtract(centerOffset)); + if (noAir) { + copy.setSourceMask(new ExistingBlockMask(clipboard)); + } + Operations.completeLegacy(copy); } } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java new file mode 100644 index 000000000..bce5511aa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -0,0 +1,160 @@ +/* + * 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.extent.clipboard; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores block data as a multi-dimensional array of {@link BaseBlock}s and + * other data as lists or maps. + */ +public class BlockArrayClipboard implements Clipboard { + + private final Region region; + private Vector offset = new Vector(); + private final BaseBlock[][][] blocks; + private final List entities = new ArrayList(); + + /** + * Create a new instance. + * + * @param region the bounding region + */ + public BlockArrayClipboard(Region region) { + checkNotNull(region); + checkNotNull(offset); + this.region = region.clone(); + + Vector dimensions = getDimensions(); + blocks = new BaseBlock[dimensions.getBlockX()][dimensions.getBlockY()][dimensions.getBlockZ()]; + } + + @Override + public Region getRegion() { + return region.clone(); + } + + @Override + public Vector getOffset() { + return offset; + } + + @Override + public void setOffset(Vector offset) { + checkNotNull(offset); + this.offset = offset; + } + + /** + * Get the dimensions of the copy, which is at minimum (1, 1, 1). + * + * @return the dimensions + */ + private Vector getDimensions() { + return region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + } + + @Override + public Vector getMinimumPoint() { + return region.getMinimumPoint(); + } + + @Override + public Vector getMaximumPoint() { + return region.getMaximumPoint(); + } + + @Override + public List getEntities() { + return new ArrayList(entities); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + ClipboardEntity ret = new ClipboardEntity(location, entity); + entities.add(ret); + return ret; + } + + @Override + public BaseBlock getBlock(Vector position) { + if (region.contains(position)) { + Vector v = position.subtract(region.getMinimumPoint()); + BaseBlock block = blocks[v.getBlockX()][v.getBlockY()][v.getBlockZ()]; + if (block != null) { + return new BaseBlock(block); + } + } + + return new BaseBlock(BlockID.AIR); + } + + @Override + public BaseBlock getLazyBlock(Vector position) { + return getBlock(position); + } + + @Override + public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { + if (region.contains(position)) { + Vector v = position.subtract(region.getMinimumPoint()); + blocks[v.getBlockX()][v.getBlockY()][v.getBlockZ()] = new BaseBlock(block); + return true; + } else { + return false; + } + } + + @Nullable + @Override + public Operation commit() { + return null; + } + + /** + * Stores entity data. + */ + private class ClipboardEntity extends StoredEntity { + ClipboardEntity(Location location, BaseEntity entity) { + super(location, entity); + } + + @Override + public boolean remove() { + return entities.remove(this); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java new file mode 100644 index 000000000..a8e4f27b6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -0,0 +1,58 @@ +/* + * 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.extent.clipboard; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.regions.Region; + +/** + * Specifies an object that implements something suitable as a "clipboard." + */ +public interface Clipboard extends Extent { + + /** + * Get the bounding region of this extent. + *

+ * Implementations should return a copy of the region. + * + * @return the bounding region + */ + Region getRegion(); + + /** + * Get the offset at which the area was copied from. + *

+ * The offset is not utilized by clipboards but it can be used + * to store, for example, the relative location from which the copy + * was made. + * + * @return the offset + */ + Vector getOffset(); + + /** + * Set the offset at which the area was copied from. + * + * @param offset the offset + */ + void setOffset(Vector offset); + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java new file mode 100644 index 000000000..a38d2d412 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java @@ -0,0 +1,76 @@ +/* + * 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.extent.clipboard; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of {@link Entity} that stores a {@link BaseEntity} with it. + *

+ * Calls to {@link #getState()} return a clone. + */ +abstract class StoredEntity implements Entity { + + private final Location location; + private final BaseEntity entity; + + /** + * Create a new instance. + * + * @param location the location + * @param entity the entity (which will be copied) + */ + StoredEntity(Location location, BaseEntity entity) { + checkNotNull(location); + checkNotNull(entity); + this.location = location; + this.entity = new BaseEntity(entity); + } + + /** + * Get the entity state. This is not a copy. + * + * @return the entity + */ + BaseEntity getEntity() { + return entity; + } + + @Override + public BaseEntity getState() { + return new BaseEntity(entity); + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public Extent getExtent() { + return location.getExtent(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java index 21df293d5..c16718330 100644 --- a/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java +++ b/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java @@ -19,21 +19,18 @@ package com.sk89q.worldedit.function.pattern; -import com.sk89q.worldedit.CuboidClipboard; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import static com.google.common.base.Preconditions.checkNotNull; /** - * A pattern that reads from {@link CuboidClipboard}. - * - * @deprecated May be removed without notice, but there is no direct replacement yet + * A pattern that reads from {@link Clipboard}. */ -@Deprecated public class ClipboardPattern extends AbstractPattern { - private final CuboidClipboard clipboard; + private final Clipboard clipboard; private final Vector size; /** @@ -41,10 +38,10 @@ public class ClipboardPattern extends AbstractPattern { * * @param clipboard the clipboard */ - public ClipboardPattern(CuboidClipboard clipboard) { + public ClipboardPattern(Clipboard clipboard) { checkNotNull(clipboard); this.clipboard = clipboard; - this.size = clipboard.getSize(); + this.size = clipboard.getMaximumPoint().subtract(clipboard.getMinimumPoint()).add(1, 1, 1); } @Override @@ -53,7 +50,7 @@ public class ClipboardPattern extends AbstractPattern { int yp = Math.abs(position.getBlockY()) % size.getBlockY(); int zp = Math.abs(position.getBlockZ()) % size.getBlockZ(); - return clipboard.getPoint(new Vector(xp, yp, zp)); + return clipboard.getBlock(clipboard.getMinimumPoint().add(new Vector(xp, yp, zp))); } } From dd924d806ba82ecb617c74aa40d67f344f301dfd Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 29 Jun 2014 17:47:29 -0700 Subject: [PATCH 07/56] Fixed RepeatingExtentPattern repeating a (1, 1, 1) smaller region. --- .../worldedit/function/pattern/RepeatingExtentPattern.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java index ae9d37221..024c674fa 100644 --- a/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java +++ b/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -85,7 +85,7 @@ public class RepeatingExtentPattern extends AbstractPattern { @Override public BaseBlock apply(Vector position) { Vector base = position.add(offset); - Vector size = extent.getMaximumPoint().subtract(extent.getMinimumPoint()); + Vector size = extent.getMaximumPoint().subtract(extent.getMinimumPoint()).add(1, 1, 1); int x = base.getBlockX() % size.getBlockX(); int y = base.getBlockY() % size.getBlockY(); int z = base.getBlockZ() % size.getBlockZ(); From c5bd8704eabe7686986b3db01a24bf70326ab554 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 1 Jul 2014 13:03:01 -0700 Subject: [PATCH 08/56] Added TransformRegion to transform another Region. --- .../worldedit/regions/TransformRegion.java | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 src/main/java/com/sk89q/worldedit/regions/TransformRegion.java diff --git a/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java b/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java new file mode 100644 index 000000000..b024bf867 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java @@ -0,0 +1,190 @@ +/* + * 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.regions; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Transforms another region according to a provided vector {@code Transform}. + * + * @see Transform + */ +public class TransformRegion extends AbstractRegion { + + private final Region region; + private Transform transform = new Identity(); + + /** + * Create a new instance. + * + * @param region the region + * @param transform the transform + */ + public TransformRegion(Region region, Transform transform) { + this(null, region, transform); + } + + /** + * Create a new instance. + * + * @param world the world, which may be null + * @param region the region + * @param transform the transform + */ + public TransformRegion(@Nullable World world, Region region, Transform transform) { + super(world); + checkNotNull(region); + checkNotNull(transform); + this.region = region; + this.transform = transform; + } + + /** + * Get the untransformed, base region. + * + * @return the base region + */ + public Region getRegion() { + return region; + } + + /** + * Get the transform that is applied. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + + /** + * Set the transform that is applied. + * + * @param transform the transform + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + @Override + public Vector getMinimumPoint() { + return transform.apply(region.getMinimumPoint()); + } + + @Override + public Vector getMaximumPoint() { + return transform.apply(region.getMaximumPoint()); + } + + @Override + public Vector getCenter() { + return transform.apply(region.getCenter()); + } + + @Override + public int getArea() { + return region.getArea(); // Cannot transform this + } + + @Override + public int getWidth() { + return getMaximumPoint().subtract(getMinimumPoint()).getBlockX() + 1; + } + + @Override + public int getHeight() { + return getMaximumPoint().subtract(getMinimumPoint()).getBlockY() + 1; + } + + @Override + public int getLength() { + return getMaximumPoint().subtract(getMinimumPoint()).getBlockZ() + 1; + } + + @Override + public void expand(Vector... changes) throws RegionOperationException { + throw new RegionOperationException("Can't expand a TransformedRegion"); + } + + @Override + public void contract(Vector... changes) throws RegionOperationException { + throw new RegionOperationException("Can't contract a TransformedRegion"); + } + + @Override + public void shift(Vector change) throws RegionOperationException { + throw new RegionOperationException("Can't change a TransformedRegion"); + } + + @Override + public boolean contains(Vector pt) { + return region.contains(transform.inverse().apply(pt)); + } + + @Override + public List polygonize(int maxPoints) { + List origPoints = region.polygonize(maxPoints); + List transformedPoints = new ArrayList(); + for (BlockVector2D vector : origPoints) { + transformedPoints.add(transform.apply(vector.toVector(0)).toVector2D().toBlockVector2D()); + } + return transformedPoints; + } + + @Override + public Iterator iterator() { + final Iterator it = region.iterator(); + + return new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public BlockVector next() { + BlockVector next = it.next(); + if (next != null) { + return transform.apply(next).toBlockVector(); + } else { + return null; + } + } + + @Override + public void remove() { + it.remove(); + } + }; + } +} From 83e141bfb02efff754cdab1a2d827910ed61401f Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 2 Jul 2014 02:54:48 -0700 Subject: [PATCH 09/56] Added AffineTransform.scale(Vector). --- .../sk89q/worldedit/math/transform/AffineTransform.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index df50071f3..63e3d8ded 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -280,6 +280,10 @@ public class AffineTransform implements Transform { return concatenate(new AffineTransform(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0)); } + public AffineTransform scale(Vector vec) { + return scale(vec.getX(), vec.getY(), vec.getZ()); + } + @Override public Vector apply(Vector vector) { return new Vector( @@ -296,4 +300,9 @@ public class AffineTransform implements Transform { return new CombinedTransform(this, other); } } + + @Override + public String toString() { + return String.format("Affine[%g %g %g %g, %g %g %g %g, %g %g %g %g]}", m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23); + } } \ No newline at end of file From 9e8b2d1875b5be6ac41fb51a017a053e4ecb4916 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 2 Jul 2014 02:55:02 -0700 Subject: [PATCH 10/56] Fix compile error in Transforms caused by merge. --- .../java/com/sk89q/worldedit/math/transform/Transforms.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java b/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java index 35f8a3df8..cfb6356af 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java @@ -43,7 +43,7 @@ public final class Transforms { public static Location transform(Location location, Transform transform) { checkNotNull(location); checkNotNull(transform); - return new Location(location.getWorld(), transform.apply(location.toVector()), location.getDirection()); + return new Location(location.getExtent(), transform.apply(location.toVector()), location.getDirection()); } } From aad7bb47d6d1a5e43e4b683c582890ef60437947 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 2 Jul 2014 02:56:21 -0700 Subject: [PATCH 11/56] Added new preliminary non-destructive //rotate and //flip implementations. Blocks themselves are not yet rotated/flip. //flip now only flips across the player. -p was removed. --- .../com/sk89q/worldedit/LocalSession.java | 9 ++- .../worldedit/command/BrushCommands.java | 15 ++-- .../worldedit/command/ClipboardCommands.java | 72 ++++++++++------- .../worldedit/command/SelectionCommands.java | 8 +- .../command/tool/brush/ClipboardBrush.java | 13 ++-- .../registry/HashTagPatternParser.java | 6 +- .../extent/clipboard/BlockArrayClipboard.java | 23 +++--- .../worldedit/extent/clipboard/Clipboard.java | 23 +++--- .../function/block/ExtentBlockCopy.java | 4 +- .../function/operation/ForwardExtentCopy.java | 24 +++++- .../worldedit/session/ClipboardHolder.java | 77 +++++++++++++++++++ 11 files changed, 197 insertions(+), 77 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java diff --git a/src/main/java/com/sk89q/worldedit/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java index 17b86f3b4..650e29a16 100644 --- a/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -39,6 +39,7 @@ import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.snapshot.Snapshot; @@ -63,7 +64,7 @@ public class LocalSession { private boolean placeAtPos1 = false; private LinkedList history = new LinkedList(); private int historyPointer = 0; - private Clipboard clipboard; + private ClipboardHolder clipboard; private boolean toolControl = true; private boolean superPickaxe = false; private BlockTool pickaxeMode = new SinglePickaxe(); @@ -327,7 +328,7 @@ public class LocalSession { * @return clipboard, may be null * @throws EmptyClipboardException */ - public Clipboard getClipboard() throws EmptyClipboardException { + public ClipboardHolder getClipboard() throws EmptyClipboardException { if (clipboard == null) { throw new EmptyClipboardException(); } @@ -339,8 +340,8 @@ public class LocalSession { * * @param clipboard */ - public void setClipboard(Clipboard clipboard) { - this.clipboard = clipboard; + public ClipboardHolder replaceClipboard(Clipboard clipboard) { + return this.clipboard = new ClipboardHolder(clipboard); } /** diff --git a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 2d9739dd0..8520cdfdf 100644 --- a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -47,6 +47,7 @@ import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; @@ -141,23 +142,17 @@ public class BrushCommands { ) @CommandPermissions("worldedit.brush.clipboard") public void clipboardBrush(Player player, LocalSession session, EditSession editSession, @Switch('a') boolean ignoreAir) throws WorldEditException { + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); - Clipboard clipboard = session.getClipboard(); - - if (clipboard == null) { - player.printError("Copy something first."); - return; - } - - Region region = clipboard.getRegion(); - Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); + Vector size = clipboard.getDimensions(); worldEdit.checkMaxBrushRadius(size.getBlockX()); worldEdit.checkMaxBrushRadius(size.getBlockY()); worldEdit.checkMaxBrushRadius(size.getBlockZ()); BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setBrush(new ClipboardBrush(clipboard, ignoreAir), "worldedit.brush.clipboard"); + tool.setBrush(new ClipboardBrush(holder, ignoreAir), "worldedit.brush.clipboard"); player.print("Clipboard brush shape equipped."); } diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index acbb1cfcc..ebdf04df0 100644 --- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -20,8 +20,6 @@ package com.sk89q.worldedit.command; import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; @@ -38,10 +36,13 @@ import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; @@ -82,10 +83,10 @@ public class ClipboardCommands { @Selection Region region, @Switch('e') boolean copyEntities) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - clipboard.setOffset(region.getMinimumPoint().subtract(session.getPlacementPosition(player))); + clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); Operations.completeLegacy(copy); - session.setClipboard(clipboard); + session.replaceClipboard(clipboard); player.print(region.getArea() + " block(s) were copied."); } @@ -108,11 +109,11 @@ public class ClipboardCommands { @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - clipboard.setOffset(region.getMinimumPoint().subtract(session.getPlacementPosition(player))); + clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); Operations.completeLegacy(copy); - session.setClipboard(clipboard); + session.replaceClipboard(clipboard); player.print(region.getArea() + " block(s) were copied."); } @@ -137,16 +138,19 @@ public class ClipboardCommands { @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, @Switch('s') boolean selectPasted) throws WorldEditException { - Clipboard clipboard = session.getClipboard(); - Vector to = atOrigin ? clipboard.getRegion().getMinimumPoint(): session.getPlacementPosition(player).add(clipboard.getOffset()); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), editSession, to); + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + Region region = clipboard.getRegion(); + + Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, region, clipboard.getOrigin(), editSession, to); + copy.setTransform(holder.getTransform()); if (ignoreAirBlocks) { copy.setSourceMask(new ExistingBlockMask(clipboard)); } Operations.completeLegacy(copy); if (selectPasted) { - Region region = clipboard.getRegion(); Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint())); RegionSelector selector = new CuboidRegionSelector(player.getWorld(), to, max); session.setRegionSelector(player.getWorld(), selector); @@ -154,38 +158,52 @@ public class ClipboardCommands { selector.explainRegionAdjust(player, session); } - player.print("The clipboard has been pasted at " + to.add(clipboard.getRegion().getMinimumPoint())); + player.print("The clipboard has been pasted at " + to.add(region.getMinimumPoint())); } @Command( aliases = { "/rotate" }, - usage = "", + usage = " [] []", desc = "Rotate the contents of the clipboard", - min = 1, - max = 1 + help = "Non-destructively rotate the contents of the clipboard.\n" + + "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " + + "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n" ) @CommandPermissions("worldedit.clipboard.rotate") - public void rotate(Player player, LocalSession session, EditSession editSession, CommandContext args) throws CommandException { - // TODO: Update for new clipboard - throw new CommandException("Needs to be re-written again"); + public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException { + if ((yRotate != null && Math.abs(yRotate % 90) > 0.001) || + xRotate != null && Math.abs(xRotate % 90) > 0.001 || + zRotate != null && Math.abs(zRotate % 90) > 0.001) { + player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended."); + } + + ClipboardHolder holder = session.getClipboard(); + AffineTransform transform = new AffineTransform(); + transform = transform.rotateY(Math.toRadians(yRotate != null ? yRotate : 0)); + transform = transform.rotateX(Math.toRadians(xRotate != null ? xRotate : 0)); + transform = transform.rotateZ(Math.toRadians(zRotate != null ? zRotate : 0)); + holder.setTransform(holder.getTransform().combine(transform)); + player.print("The clipboard copy has been rotated."); } @Command( aliases = { "/flip" }, - usage = "[dir]", - flags = "p", - desc = "Flip the contents of the clipboard.", + usage = "[]", + desc = "Flip the contents of the clipboard", help = - "Flips the contents of the clipboard.\n" + - "The -p flag flips the selection around the player,\n" + - "instead of the selections center.", + "Flips the contents of the clipboard across the point from which the copy was made.\n", min = 0, max = 1 ) @CommandPermissions("worldedit.clipboard.flip") - public void flip(Player player, LocalSession session, EditSession editSession, CommandContext args) throws CommandException { - // TODO: Update for new clipboard - throw new CommandException("Needs to be re-written again"); + public void flip(Player player, LocalSession session, EditSession editSession, + @Optional(Direction.AIM) @Direction Vector direction) throws WorldEditException { + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + AffineTransform transform = new AffineTransform(); + transform = transform.scale(direction.positive().multiply(-2).add(1, 1, 1)); + holder.setTransform(holder.getTransform().combine(transform)); + player.print("The clipboard copy has been flipped."); } @Command( @@ -223,7 +241,7 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.clear") public void clearClipboard(Player player, LocalSession session, EditSession editSession) throws WorldEditException { - session.setClipboard(null); + session.replaceClipboard(null); player.print("Clipboard cleared."); } } diff --git a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 23e13cc3c..4a4acaa84 100644 --- a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -45,6 +45,7 @@ import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector; import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector; import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; import com.sk89q.worldedit.regions.selector.SphereRegionSelector; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.ChunkStore; @@ -584,13 +585,14 @@ public class SelectionCommands { public void size(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { if (args.hasFlag('c')) { - Clipboard clipboard = session.getClipboard(); + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); - Vector offset = clipboard.getOffset(); + Vector origin = clipboard.getOrigin(); player.print("Cuboid dimensions (max - min): " + size); - player.print("Offset: " + offset); + player.print("Offset: " + origin); player.print("Cuboid distance: " + size.distance(Vector.ONE)); player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ())); return; diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java index e200fcb66..9a792ee7b 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -28,22 +28,25 @@ import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; public class ClipboardBrush implements Brush { - private Clipboard clipboard; + private ClipboardHolder holder; private boolean noAir; - public ClipboardBrush(Clipboard clipboard, boolean noAir) { - this.clipboard = clipboard; + public ClipboardBrush(ClipboardHolder holder, boolean noAir) { + this.holder = holder; this.noAir = noAir; } @Override public void build(EditSession editSession, Vector pos, Pattern mat, double size) throws MaxChangedBlocksException { + Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); - Vector centerOffset = region.getCenter().subtract(region.getMinimumPoint()); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), editSession, pos.subtract(centerOffset)); + Vector centerOffset = region.getCenter().subtract(clipboard.getOrigin()); + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, region, clipboard.getOrigin(), editSession, pos.subtract(centerOffset)); + copy.setTransform(holder.getTransform()); if (noAir) { copy.setSourceMask(new ExistingBlockMask(clipboard)); } diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java index 1d4f66d35..63da1c402 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java @@ -23,10 +23,12 @@ import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.pattern.ClipboardPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.session.ClipboardHolder; class HashTagPatternParser extends InputParser { @@ -45,7 +47,9 @@ class HashTagPatternParser extends InputParser { if (session != null) { try { - return new ClipboardPattern(session.getClipboard()); + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + return new ClipboardPattern(clipboard); } catch (EmptyClipboardException e) { throw new InputParseException("To use #clipboard, please first copy something to your clipboard"); } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index bce5511aa..5c40d42e2 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -42,19 +42,21 @@ import static com.google.common.base.Preconditions.checkNotNull; public class BlockArrayClipboard implements Clipboard { private final Region region; - private Vector offset = new Vector(); + private Vector origin = new Vector(); private final BaseBlock[][][] blocks; private final List entities = new ArrayList(); /** * Create a new instance. + *

+ * The origin will be placed at the region's lowest minimum point. * * @param region the bounding region */ public BlockArrayClipboard(Region region) { checkNotNull(region); - checkNotNull(offset); this.region = region.clone(); + this.origin = region.getMinimumPoint(); Vector dimensions = getDimensions(); blocks = new BaseBlock[dimensions.getBlockX()][dimensions.getBlockY()][dimensions.getBlockZ()]; @@ -66,22 +68,17 @@ public class BlockArrayClipboard implements Clipboard { } @Override - public Vector getOffset() { - return offset; + public Vector getOrigin() { + return origin; } @Override - public void setOffset(Vector offset) { - checkNotNull(offset); - this.offset = offset; + public void setOrigin(Vector origin) { + this.origin = origin; } - /** - * Get the dimensions of the copy, which is at minimum (1, 1, 1). - * - * @return the dimensions - */ - private Vector getDimensions() { + @Override + public Vector getDimensions() { return region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index a8e4f27b6..e68d5b2c0 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -38,21 +38,24 @@ public interface Clipboard extends Extent { Region getRegion(); /** - * Get the offset at which the area was copied from. - *

- * The offset is not utilized by clipboards but it can be used - * to store, for example, the relative location from which the copy - * was made. + * Get the dimensions of the copy, which is at minimum (1, 1, 1). * - * @return the offset + * @return the dimensions */ - Vector getOffset(); + Vector getDimensions(); /** - * Set the offset at which the area was copied from. + * Get the origin point from which the copy was made from. * - * @param offset the offset + * @return the origin */ - void setOffset(Vector offset); + Vector getOrigin(); + + /** + * Set the origin point from which the copy was made from. + * + * @param origin the origin + */ + void setOrigin(Vector origin); } diff --git a/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java index b8d50bcc0..f7bdf8e11 100644 --- a/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java +++ b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -64,7 +64,9 @@ public class ExtentBlockCopy implements RegionFunction { @Override public boolean apply(Vector position) throws WorldEditException { BaseBlock block = source.getBlock(position); - return destination.setBlock(transform.apply(position.subtract(from)).add(to), block); + Vector orig = position.subtract(from); + Vector transformed = transform.apply(orig); + return destination.setBlock(transformed.add(to), block); } } diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java index 2c3c5aee8..ce0f80248 100644 --- a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java +++ b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -48,6 +48,7 @@ public class ForwardExtentCopy implements Operation { private final Extent source; private final Extent destination; private final Region region; + private final Vector from; private final Vector to; private int repetitions = 1; private Mask sourceMask = Masks.alwaysTrue(); @@ -58,21 +59,38 @@ public class ForwardExtentCopy implements Operation { private int affected; /** - * Create a new copy. + * Create a new copy using the region's lowest minimum point as the + * "from" position. * * @param source the source extent * @param region the region to copy * @param destination the destination extent - * @param to the destination position, starting from the the lowest X, Y, Z + * @param to the destination position + * @see #ForwardExtentCopy(Extent, Region, Vector, Extent, Vector) the main constructor */ public ForwardExtentCopy(Extent source, Region region, Extent destination, Vector to) { + this(source, region, region.getMinimumPoint(), destination, to); + } + + /** + * Create a new copy. + * + * @param source the source extent + * @param region the region to copy + * @param from the source position + * @param destination the destination extent + * @param to the destination position + */ + public ForwardExtentCopy(Extent source, Region region, Vector from, Extent destination, Vector to) { checkNotNull(source); checkNotNull(region); + checkNotNull(from); checkNotNull(destination); checkNotNull(to); this.source = source; this.destination = destination; this.region = region; + this.from = from; this.to = to; } @@ -182,7 +200,7 @@ public class ForwardExtentCopy implements Operation { currentTransform = transform; } - ExtentBlockCopy copy = new ExtentBlockCopy(source, region.getMinimumPoint(), destination, to, currentTransform); + ExtentBlockCopy copy = new ExtentBlockCopy(source, from, destination, to, currentTransform); RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, copy); RegionFunction function = sourceFunction != null ? new CombinedRegionFunction(filter, sourceFunction) : filter; RegionVisitor visitor = new RegionVisitor(region, function); diff --git a/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java b/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java new file mode 100644 index 000000000..b2b10561f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java @@ -0,0 +1,77 @@ +/* + * 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.session; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Holds the clipboard and the current transform on the clipboard. + */ +public class ClipboardHolder { + + private final Clipboard clipboard; + private Transform transform = new Identity(); + + /** + * Create a new instance with the given clipboard. + * + * @param clipboard the clipboard + */ + public ClipboardHolder(Clipboard clipboard) { + checkNotNull(clipboard); + this.clipboard = clipboard; + } + + /** + * Get the clipboard. + *

+ * If there is a transformation applied, the returned clipboard will + * not contain its effect. + * + * @return the clipboard + */ + public Clipboard getClipboard() { + return clipboard; + } + + /** + * Set the transform. + * + * @param transform the transform + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the transform. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + +} From d3aa6c86a8376d50d6376d0f355fba35692d1c2b Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 2 Jul 2014 12:55:18 -0700 Subject: [PATCH 12/56] Added -m for //cut and //copy to set a source mask. --- .../worldedit/command/ClipboardCommands.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index ebdf04df0..ad7edfa6a 100644 --- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; @@ -69,22 +70,27 @@ public class ClipboardCommands { @Command( aliases = { "/copy" }, - flags = "e", + flags = "em", desc = "Copy the selection to the clipboard", help = "Copy the selection to the clipboard\n" + "Flags:\n" + " -e controls whether entities are copied\n" + + " -m sets a source mask so that excluded blocks become air\n" + "WARNING: Pasting entities cannot yet be undone!", min = 0, max = 0 ) @CommandPermissions("worldedit.clipboard.copy") public void copy(Player player, LocalSession session, EditSession editSession, - @Selection Region region, @Switch('e') boolean copyEntities) throws WorldEditException { + @Selection Region region, @Switch('e') boolean copyEntities, + @Switch('m') Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); + if (mask != null) { + copy.setSourceMask(mask); + } Operations.completeLegacy(copy); session.replaceClipboard(clipboard); @@ -93,25 +99,30 @@ public class ClipboardCommands { @Command( aliases = { "/cut" }, + flags = "em", usage = "[leave-id]", desc = "Cut the selection to the clipboard", help = "Copy the selection to the clipboard\n" + "Flags:\n" + " -e controls whether entities are copied\n" + + " -m sets a source mask so that excluded blocks become air\n" + "WARNING: Cutting and pasting entities cannot yet be undone!", - flags = "e", min = 0, max = 1 ) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) public void cut(Player player, LocalSession session, EditSession editSession, - @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities) throws WorldEditException { + @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities, + @Switch('m') Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); + if (mask != null) { + copy.setSourceMask(mask); + } Operations.completeLegacy(copy); session.replaceClipboard(clipboard); From 7463fdef79b457ec4948277f6c621e2b1eca04b1 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 8 Jul 2014 17:39:33 -0700 Subject: [PATCH 13/56] BlockRegistry, MaskRegistry, PatternRegistry -> *Factory 'Registry' will need to be used for the block, entity, item, and so on registries. --- .../java/com/sk89q/worldedit/WorldEdit.java | 60 +++++++++---------- .../BlockFactory.java} | 10 ++-- .../DefaultBlockParser.java | 2 +- .../DefaultMaskParser.java | 4 +- .../HashTagPatternParser.java | 2 +- .../MaskFactory.java} | 10 ++-- .../PatternFactory.java} | 10 ++-- .../RandomPatternParser.java | 4 +- .../SingleBlockPatternParser.java | 4 +- .../extension/input/ParserContext.java | 4 +- .../internal/command/WorldEditBinding.java | 6 +- ...ractRegistry.java => AbstractFactory.java} | 10 ++-- .../internal/registry/InputParser.java | 2 +- 13 files changed, 64 insertions(+), 64 deletions(-) rename src/main/java/com/sk89q/worldedit/extension/{registry/BlockRegistry.java => factory/BlockFactory.java} (88%) rename src/main/java/com/sk89q/worldedit/extension/{registry => factory}/DefaultBlockParser.java (99%) rename src/main/java/com/sk89q/worldedit/extension/{registry => factory}/DefaultMaskParser.java (97%) rename src/main/java/com/sk89q/worldedit/extension/{registry => factory}/HashTagPatternParser.java (98%) rename src/main/java/com/sk89q/worldedit/extension/{registry/MaskRegistry.java => factory/MaskFactory.java} (82%) rename src/main/java/com/sk89q/worldedit/extension/{registry/PatternRegistry.java => factory/PatternFactory.java} (83%) rename src/main/java/com/sk89q/worldedit/extension/{registry => factory}/RandomPatternParser.java (95%) rename src/main/java/com/sk89q/worldedit/extension/{registry => factory}/SingleBlockPatternParser.java (91%) rename src/main/java/com/sk89q/worldedit/internal/registry/{AbstractRegistry.java => AbstractFactory.java} (88%) diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java index 1a0d25a5e..2b451409d 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -27,13 +27,13 @@ import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.event.platform.BlockInteractEvent; import com.sk89q.worldedit.event.platform.InputType; import com.sk89q.worldedit.event.platform.PlayerInputEvent; +import com.sk89q.worldedit.extension.factory.BlockFactory; +import com.sk89q.worldedit.extension.factory.MaskFactory; +import com.sk89q.worldedit.extension.factory.PatternFactory; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.PlatformManager; -import com.sk89q.worldedit.extension.registry.BlockRegistry; -import com.sk89q.worldedit.extension.registry.MaskRegistry; -import com.sk89q.worldedit.extension.registry.PatternRegistry; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.pattern.Patterns; @@ -84,9 +84,9 @@ public class WorldEdit { private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus); private final SessionManager sessions = new SessionManager(this); - private final BlockRegistry blockRegistry = new BlockRegistry(this); - private final MaskRegistry maskRegistry = new MaskRegistry(this); - private final PatternRegistry patternRegistry = new PatternRegistry(this); + private final BlockFactory blockFactory = new BlockFactory(this); + private final MaskFactory maskFactory = new MaskFactory(this); + private final PatternFactory patternFactory = new PatternFactory(this); static { WorldEditPrefixHandler.register("com.sk89q.worldedit"); @@ -132,33 +132,33 @@ public class WorldEdit { } /** - * Get the block registry from which new {@link BaseBlock}s can be + * Get the block factory from which new {@link BaseBlock}s can be * constructed. * - * @return the block registry + * @return the block factory */ - public BlockRegistry getBlockRegistry() { - return blockRegistry; + public BlockFactory getBlockFactory() { + return blockFactory; } /** - * Get the mask registry from which new {@link com.sk89q.worldedit.function.mask.Mask}s + * Get the mask factory from which new {@link com.sk89q.worldedit.function.mask.Mask}s * can be constructed. * - * @return the mask registry + * @return the mask factory */ - public MaskRegistry getMaskRegistry() { - return maskRegistry; + public MaskFactory getMaskFactory() { + return maskFactory; } /** - * Get the pattern registry from which new {@link com.sk89q.worldedit.function.pattern.Pattern}s + * Get the pattern factory from which new {@link com.sk89q.worldedit.function.pattern.Pattern}s * can be constructed. * - * @return the pattern registry + * @return the pattern factory */ - public PatternRegistry getPatternRegistry() { - return patternRegistry; + public PatternFactory getPatternFactory() { + return patternFactory; } /** @@ -211,7 +211,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromInput(String, ParserContext)} */ @SuppressWarnings("deprecation") @Deprecated @@ -220,7 +220,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromInput(String, ParserContext)} */ @SuppressWarnings("deprecation") @Deprecated @@ -231,11 +231,11 @@ public class WorldEdit { context.setSession(getSession(player)); context.setRestricted(!allAllowed); context.setPreferringWildcard(allowNoData); - return getBlockRegistry().parseFromInput(arg, context); + return getBlockFactory().parseFromInput(arg, context); } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromInput(String, ParserContext)} */ @SuppressWarnings("deprecation") @Deprecated @@ -244,7 +244,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromListInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromListInput(String, ParserContext)} */ @Deprecated @SuppressWarnings("deprecation") @@ -258,7 +258,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromInput(String, ParserContext)} */ @Deprecated @SuppressWarnings("deprecation") @@ -267,7 +267,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromListInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromListInput(String, ParserContext)} */ @Deprecated @SuppressWarnings("deprecation") @@ -276,7 +276,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromListInput(String, ParserContext)} + * @deprecated Use {@link #getBlockFactory()} and {@link BlockFactory#parseFromListInput(String, ParserContext)} */ @Deprecated @SuppressWarnings("deprecation") @@ -290,7 +290,7 @@ public class WorldEdit { } /** - * @deprecated Use {@link #getPatternRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + * @deprecated Use {@link #getPatternFactory()} and {@link BlockFactory#parseFromInput(String, ParserContext)} */ @Deprecated @SuppressWarnings("deprecation") @@ -299,11 +299,11 @@ public class WorldEdit { context.setActor(player); context.setWorld(player.getWorld()); context.setSession(getSession(player)); - return Patterns.wrap(getPatternRegistry().parseFromInput(input, context)); + return Patterns.wrap(getPatternFactory().parseFromInput(input, context)); } /** - * @deprecated Use {@link #getMaskRegistry()} ()} and {@link MaskRegistry#parseFromInput(String, ParserContext)} + * @deprecated Use {@link #getMaskFactory()} ()} and {@link MaskFactory#parseFromInput(String, ParserContext)} */ @Deprecated @SuppressWarnings("deprecation") @@ -312,7 +312,7 @@ public class WorldEdit { context.setActor(player); context.setWorld(player.getWorld()); context.setSession(session); - return Masks.wrap(getMaskRegistry().parseFromInput(input, context)); + return Masks.wrap(getMaskFactory().parseFromInput(input, context)); } /** diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/BlockRegistry.java b/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/extension/registry/BlockRegistry.java rename to src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java index 2bd118015..2cb5c9d1d 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/BlockRegistry.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java @@ -17,13 +17,13 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.InputParseException; -import com.sk89q.worldedit.internal.registry.AbstractRegistry; +import com.sk89q.worldedit.internal.registry.AbstractFactory; import java.util.HashSet; import java.util.Set; @@ -33,16 +33,16 @@ import java.util.Set; * new blocks from input. *

* Instances of this class can be taken from - * {@link WorldEdit#getBlockRegistry()}. + * {@link WorldEdit#getBlockFactory()}. */ -public class BlockRegistry extends AbstractRegistry { +public class BlockFactory extends AbstractFactory { /** * Create a new instance. * * @param worldEdit the WorldEdit instance. */ - public BlockRegistry(WorldEdit worldEdit) { + public BlockFactory(WorldEdit worldEdit) { super(worldEdit); parsers.add(new DefaultBlockParser(worldEdit)); diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultBlockParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java similarity index 99% rename from src/main/java/com/sk89q/worldedit/extension/registry/DefaultBlockParser.java rename to src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java index fe7a63b09..3ecbc15fb 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultBlockParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.*; diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java rename to src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java index 304a49b60..9b6dfdf94 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.*; import com.sk89q.worldedit.extension.input.InputParseException; @@ -135,7 +135,7 @@ class DefaultMaskParser extends InputParser { ParserContext tempContext = new ParserContext(context); tempContext.setRestricted(false); tempContext.setPreferringWildcard(true); - return new BlockMask(extent, worldEdit.getBlockRegistry().parseFromListInput(component, tempContext)); + return new BlockMask(extent, worldEdit.getBlockFactory().parseFromListInput(component, tempContext)); } } diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java rename to src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java index 63da1c402..1c7a0d646 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.LocalSession; diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/MaskRegistry.java b/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java similarity index 82% rename from src/main/java/com/sk89q/worldedit/extension/registry/MaskRegistry.java rename to src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index fa4fb9e58..309992bcb 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/MaskRegistry.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -17,27 +17,27 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.internal.registry.AbstractRegistry; +import com.sk89q.worldedit.internal.registry.AbstractFactory; /** * A registry of known {@link Mask}s. Provides methods to instantiate * new masks from input. *

* Instances of this class can be taken from - * {@link WorldEdit#getMaskRegistry()}. + * {@link WorldEdit#getMaskFactory()}. */ -public final class MaskRegistry extends AbstractRegistry { +public final class MaskFactory extends AbstractFactory { /** * Create a new mask registry. * * @param worldEdit the WorldEdit instance */ - public MaskRegistry(WorldEdit worldEdit) { + public MaskFactory(WorldEdit worldEdit) { super(worldEdit); parsers.add(new DefaultMaskParser(worldEdit)); diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/PatternRegistry.java b/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java similarity index 83% rename from src/main/java/com/sk89q/worldedit/extension/registry/PatternRegistry.java rename to src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index daab33cac..e19891148 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/PatternRegistry.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -17,27 +17,27 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.internal.registry.AbstractRegistry; +import com.sk89q.worldedit.internal.registry.AbstractFactory; /** * A registry of known {@link Pattern}s. Provides methods to instantiate * new patterns from input. *

* Instances of this class can be taken from - * {@link WorldEdit#getPatternRegistry()}. + * {@link WorldEdit#getPatternFactory()}. */ -public final class PatternRegistry extends AbstractRegistry { +public final class PatternFactory extends AbstractFactory { /** * Create a new instance. * * @param worldEdit the WorldEdit instance */ - public PatternRegistry(WorldEdit worldEdit) { + public PatternFactory(WorldEdit worldEdit) { super(worldEdit); parsers.add(new HashTagPatternParser(worldEdit)); diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/RandomPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/RandomPatternParser.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/extension/registry/RandomPatternParser.java rename to src/main/java/com/sk89q/worldedit/extension/factory/RandomPatternParser.java index d07f94e03..a850b98ff 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/RandomPatternParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/RandomPatternParser.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseBlock; @@ -36,7 +36,7 @@ class RandomPatternParser extends InputParser { @Override public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { - BlockRegistry blockRegistry = worldEdit.getBlockRegistry(); + BlockFactory blockRegistry = worldEdit.getBlockFactory(); RandomPattern randomPattern = new RandomPattern(); for (String token : input.split(",")) { diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/SingleBlockPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/SingleBlockPatternParser.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/extension/registry/SingleBlockPatternParser.java rename to src/main/java/com/sk89q/worldedit/extension/factory/SingleBlockPatternParser.java index a1a11fa10..17833cf97 100644 --- a/src/main/java/com/sk89q/worldedit/extension/registry/SingleBlockPatternParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/SingleBlockPatternParser.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extension.registry; +package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.ParserContext; @@ -37,7 +37,7 @@ class SingleBlockPatternParser extends InputParser { String[] items = input.split(","); if (items.length == 1) { - return new BlockPattern(worldEdit.getBlockRegistry().parseFromInput(items[0], context)); + return new BlockPattern(worldEdit.getBlockFactory().parseFromInput(items[0], context)); } else { return null; } diff --git a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java index 9d2b56f19..383ee280e 100644 --- a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java +++ b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java @@ -20,8 +20,8 @@ package com.sk89q.worldedit.extension.input; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.factory.MaskFactory; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extension.registry.MaskRegistry; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.World; @@ -29,7 +29,7 @@ import javax.annotation.Nullable; /** * Contains contextual information that may be useful when constructing - * objects from a registry (such as {@link MaskRegistry}). + * objects from a registry (such as {@link MaskFactory}). *

* By default, {@link #isRestricted()} will return true. */ diff --git a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java index 019c1cc72..7a6aa4ad3 100644 --- a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java +++ b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java @@ -178,7 +178,7 @@ public class WorldEditBinding extends BindingHelper { } parserContext.setSession(worldEdit.getSessionManager().get(actor)); try { - return worldEdit.getBlockRegistry().parseFromInput(context.next(), parserContext); + return worldEdit.getBlockFactory().parseFromInput(context.next(), parserContext); } catch (NoMatchException e) { throw new ParameterException(e.getMessage(), e); } @@ -207,7 +207,7 @@ public class WorldEditBinding extends BindingHelper { } parserContext.setSession(worldEdit.getSessionManager().get(actor)); try { - return worldEdit.getPatternRegistry().parseFromInput(context.next(), parserContext); + return worldEdit.getPatternFactory().parseFromInput(context.next(), parserContext); } catch (NoMatchException e) { throw new ParameterException(e.getMessage(), e); } @@ -236,7 +236,7 @@ public class WorldEditBinding extends BindingHelper { } parserContext.setSession(worldEdit.getSessionManager().get(actor)); try { - return worldEdit.getMaskRegistry().parseFromInput(context.next(), parserContext); + return worldEdit.getMaskFactory().parseFromInput(context.next(), parserContext); } catch (NoMatchException e) { throw new ParameterException(e.getMessage(), e); } diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/AbstractRegistry.java b/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/internal/registry/AbstractRegistry.java rename to src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index b466b5bb9..95563fcc0 100644 --- a/src/main/java/com/sk89q/worldedit/internal/registry/AbstractRegistry.java +++ b/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -30,22 +30,22 @@ import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; /** - * An abstract implementation of a registry for internal usage. + * An abstract implementation of a factory for internal usage. * - * @param the element that the registry returns + * @param the element that the factory returns */ @SuppressWarnings("ProtectedField") -public abstract class AbstractRegistry { +public abstract class AbstractFactory { protected final WorldEdit worldEdit; protected final List> parsers = new ArrayList>(); /** - * Create a new registry. + * Create a new factory. * * @param worldEdit the WorldEdit instance */ - protected AbstractRegistry(WorldEdit worldEdit) { + protected AbstractFactory(WorldEdit worldEdit) { checkNotNull(worldEdit); this.worldEdit = worldEdit; } diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index afe702852..059c95ba4 100644 --- a/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java +++ b/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -24,7 +24,7 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.InputParseException; /** - * Input parser interface for {@link AbstractRegistry}. + * Input parser interface for {@link AbstractFactory}. * * @param the element */ From 6ef4f7b7cccc80f3e22b1b86b438367157819fcb Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 8 Jul 2014 20:08:43 -0700 Subject: [PATCH 14/56] Moved legacy block classes to the legacy source root. --- .../sk89q/worldedit/blocks/ChestBlock.java | 0 .../worldedit/blocks/ContainerBlock.java | 284 ++++++------- .../worldedit/blocks/DispenserBlock.java | 218 +++++----- .../sk89q/worldedit/blocks/FurnaceBlock.java | 334 +++++++-------- .../com/sk89q/worldedit/blocks/LazyBlock.java | 0 .../worldedit/blocks/MobSpawnerBlock.java | 0 .../com/sk89q/worldedit/blocks/NoteBlock.java | 246 +++++------ .../com/sk89q/worldedit/blocks/SignBlock.java | 0 .../sk89q/worldedit/blocks/SkullBlock.java | 388 +++++++++--------- 9 files changed, 735 insertions(+), 735 deletions(-) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/ChestBlock.java (100%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/ContainerBlock.java (97%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/DispenserBlock.java (96%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/FurnaceBlock.java (96%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/LazyBlock.java (100%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java (100%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/NoteBlock.java (96%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/SignBlock.java (100%) rename src/{main => legacy}/java/com/sk89q/worldedit/blocks/SkullBlock.java (96%) diff --git a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/ChestBlock.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/ChestBlock.java diff --git a/src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/ContainerBlock.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/ContainerBlock.java index 9e0d69fb1..aae973c44 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java +++ b/src/legacy/java/com/sk89q/worldedit/blocks/ContainerBlock.java @@ -1,142 +1,142 @@ -/* - * 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.blocks; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; - -/** - * Represents a block that stores items. - * - * @author sk89q - */ -public abstract class ContainerBlock extends BaseBlock implements TileEntityBlock { - - private BaseItemStack[] items; - - public ContainerBlock(int type, int inventorySize) { - super(type); - this.items = new BaseItemStack[inventorySize]; - } - - public ContainerBlock(int type, int data, int inventorySize) { - super(type, data); - this.items = new BaseItemStack[inventorySize]; - } - - /** - * Get the list of items. - * - * @return - */ - public BaseItemStack[] getItems() { - return this.items; - } - - /** - * Set the list of items. - * - * @param items - */ - public void setItems(BaseItemStack[] items) { - this.items = items; - } - - @Override - public boolean hasNbtData() { - return true; - } - - public Map serializeItem(BaseItemStack item) { - Map data = new HashMap(); - data.put("id", new ShortTag("id", (short) item.getType())); - data.put("Damage", new ShortTag("Damage", item.getData())); - data.put("Count", new ByteTag("Count", (byte) item.getAmount())); - if (item.getEnchantments().size() > 0) { - List enchantmentList = new ArrayList(); - for(Map.Entry entry : item.getEnchantments().entrySet()) { - Map enchantment = new HashMap(); - enchantment.put("id", new ShortTag("id", entry.getKey().shortValue())); - enchantment.put("lvl", new ShortTag("lvl", entry.getValue().shortValue())); - enchantmentList.add(new CompoundTag(null, enchantment)); - } - - Map auxData = new HashMap(); - auxData.put("ench", new ListTag("ench", CompoundTag.class, enchantmentList)); - data.put("tag", new CompoundTag("tag", auxData)); - } - return data; - } - - public BaseItemStack deserializeItem(Map data) throws DataException { - short id = NBTUtils.getChildTag(data, "id", ShortTag.class).getValue(); - short damage = NBTUtils.getChildTag(data, "Damage", ShortTag.class).getValue(); - byte count = NBTUtils.getChildTag(data, "Count", ByteTag.class).getValue(); - - BaseItemStack stack = new BaseItemStack(id, count, damage); - - if (data.containsKey("tag")) { - Map auxData = NBTUtils.getChildTag(data, "tag", CompoundTag.class).getValue(); - ListTag ench = (ListTag)auxData.get("ench"); - for(Tag e : ench.getValue()) { - Map vars = ((CompoundTag) e).getValue(); - short enchId = NBTUtils.getChildTag(vars, "id", ShortTag.class).getValue(); - short enchLevel = NBTUtils.getChildTag(vars, "lvl", ShortTag.class).getValue(); - stack.getEnchantments().put((int) enchId, (int) enchLevel); - } - } - return stack; - } - - public BaseItemStack[] deserializeInventory(List items) throws DataException { - BaseItemStack[] stacks = new BaseItemStack[items.size()]; - for (CompoundTag tag : items) { - Map item = tag.getValue(); - BaseItemStack stack = deserializeItem(item); - byte slot = NBTUtils.getChildTag(item, "Slot", ByteTag.class).getValue(); - if (slot >= 0 && slot < stacks.length) { - stacks[slot] = stack; - } - } - return stacks; - } - - public List serializeInventory(BaseItemStack[] items) { - List tags = new ArrayList(); - for (int i = 0; i < items.length; ++i) { - if (items[i] != null) { - Map tagData = serializeItem(items[i]); - tagData.put("Slot", new ByteTag("Slot", (byte) i)); - tags.add(new CompoundTag("", tagData)); - } - } - return tags; - } -} +/* + * 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.blocks; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.DataException; + +/** + * Represents a block that stores items. + * + * @author sk89q + */ +public abstract class ContainerBlock extends BaseBlock implements TileEntityBlock { + + private BaseItemStack[] items; + + public ContainerBlock(int type, int inventorySize) { + super(type); + this.items = new BaseItemStack[inventorySize]; + } + + public ContainerBlock(int type, int data, int inventorySize) { + super(type, data); + this.items = new BaseItemStack[inventorySize]; + } + + /** + * Get the list of items. + * + * @return + */ + public BaseItemStack[] getItems() { + return this.items; + } + + /** + * Set the list of items. + * + * @param items + */ + public void setItems(BaseItemStack[] items) { + this.items = items; + } + + @Override + public boolean hasNbtData() { + return true; + } + + public Map serializeItem(BaseItemStack item) { + Map data = new HashMap(); + data.put("id", new ShortTag("id", (short) item.getType())); + data.put("Damage", new ShortTag("Damage", item.getData())); + data.put("Count", new ByteTag("Count", (byte) item.getAmount())); + if (item.getEnchantments().size() > 0) { + List enchantmentList = new ArrayList(); + for(Map.Entry entry : item.getEnchantments().entrySet()) { + Map enchantment = new HashMap(); + enchantment.put("id", new ShortTag("id", entry.getKey().shortValue())); + enchantment.put("lvl", new ShortTag("lvl", entry.getValue().shortValue())); + enchantmentList.add(new CompoundTag(null, enchantment)); + } + + Map auxData = new HashMap(); + auxData.put("ench", new ListTag("ench", CompoundTag.class, enchantmentList)); + data.put("tag", new CompoundTag("tag", auxData)); + } + return data; + } + + public BaseItemStack deserializeItem(Map data) throws DataException { + short id = NBTUtils.getChildTag(data, "id", ShortTag.class).getValue(); + short damage = NBTUtils.getChildTag(data, "Damage", ShortTag.class).getValue(); + byte count = NBTUtils.getChildTag(data, "Count", ByteTag.class).getValue(); + + BaseItemStack stack = new BaseItemStack(id, count, damage); + + if (data.containsKey("tag")) { + Map auxData = NBTUtils.getChildTag(data, "tag", CompoundTag.class).getValue(); + ListTag ench = (ListTag)auxData.get("ench"); + for(Tag e : ench.getValue()) { + Map vars = ((CompoundTag) e).getValue(); + short enchId = NBTUtils.getChildTag(vars, "id", ShortTag.class).getValue(); + short enchLevel = NBTUtils.getChildTag(vars, "lvl", ShortTag.class).getValue(); + stack.getEnchantments().put((int) enchId, (int) enchLevel); + } + } + return stack; + } + + public BaseItemStack[] deserializeInventory(List items) throws DataException { + BaseItemStack[] stacks = new BaseItemStack[items.size()]; + for (CompoundTag tag : items) { + Map item = tag.getValue(); + BaseItemStack stack = deserializeItem(item); + byte slot = NBTUtils.getChildTag(item, "Slot", ByteTag.class).getValue(); + if (slot >= 0 && slot < stacks.length) { + stacks[slot] = stack; + } + } + return stacks; + } + + public List serializeInventory(BaseItemStack[] items) { + List tags = new ArrayList(); + for (int i = 0; i < items.length; ++i) { + if (items[i] != null) { + Map tagData = serializeItem(items[i]); + tagData.put("Slot", new ByteTag("Slot", (byte) i)); + tags.add(new CompoundTag("", tagData)); + } + } + return tags; + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/DispenserBlock.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/DispenserBlock.java index ea1392924..c13c7f163 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java +++ b/src/legacy/java/com/sk89q/worldedit/blocks/DispenserBlock.java @@ -1,109 +1,109 @@ -/* - * 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.blocks; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Represents dispensers. - * - * @author sk89q - */ -public class DispenserBlock extends ContainerBlock { - - /** - * Construct an empty dispenser block. - */ - public DispenserBlock() { - super(BlockID.DISPENSER, 9); - } - - /** - * Construct an empty dispenser block. - * - * @param data data value (orientation) - */ - public DispenserBlock(int data) { - super(BlockID.DISPENSER, data, 9); - } - - /** - * Construct a dispenser block with the given orientation and inventory. - * - * @param data data value (orientation) - * @param items array of items in the inventory - */ - public DispenserBlock(int data, BaseItemStack[] items) { - super(BlockID.DISPENSER, data, 9); - this.setItems(items); - } - - @Override - public String getNbtId() { - return "Trap"; - } - - @Override - public CompoundTag getNbtData() { - Map values = new HashMap(); - values.put("Items", new ListTag("Items", CompoundTag.class, - serializeInventory(getItems()))); - return new CompoundTag(getNbtId(), values); - } - - @Override - public void setNbtData(CompoundTag rootTag) { - try { - if (rootTag == null) { - return; - } - - Map values = rootTag.getValue(); - - Tag t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Trap")) { - throw new DataException("'Trap' tile entity expected"); - } - - List items = new ArrayList(); - for (Tag tag : NBTUtils.getChildTag(values, "Items", ListTag.class).getValue()) { - if (!(tag instanceof CompoundTag)) { - throw new DataException("CompoundTag expected as child tag of Trap Items"); - } - - items.add((CompoundTag) tag); - } - - setItems(deserializeInventory(items)); - } catch (DataException e) { - throw new RuntimeException(e); - } - } -} +/* + * 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.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.DataException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents dispensers. + * + * @author sk89q + */ +public class DispenserBlock extends ContainerBlock { + + /** + * Construct an empty dispenser block. + */ + public DispenserBlock() { + super(BlockID.DISPENSER, 9); + } + + /** + * Construct an empty dispenser block. + * + * @param data data value (orientation) + */ + public DispenserBlock(int data) { + super(BlockID.DISPENSER, data, 9); + } + + /** + * Construct a dispenser block with the given orientation and inventory. + * + * @param data data value (orientation) + * @param items array of items in the inventory + */ + public DispenserBlock(int data, BaseItemStack[] items) { + super(BlockID.DISPENSER, data, 9); + this.setItems(items); + } + + @Override + public String getNbtId() { + return "Trap"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap(); + values.put("Items", new ListTag("Items", CompoundTag.class, + serializeInventory(getItems()))); + return new CompoundTag(getNbtId(), values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + try { + if (rootTag == null) { + return; + } + + Map values = rootTag.getValue(); + + Tag t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Trap")) { + throw new DataException("'Trap' tile entity expected"); + } + + List items = new ArrayList(); + for (Tag tag : NBTUtils.getChildTag(values, "Items", ListTag.class).getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new DataException("CompoundTag expected as child tag of Trap Items"); + } + + items.add((CompoundTag) tag); + } + + setItems(deserializeInventory(items)); + } catch (DataException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/FurnaceBlock.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/FurnaceBlock.java index 24e241dbd..07b38c78b 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java +++ b/src/legacy/java/com/sk89q/worldedit/blocks/FurnaceBlock.java @@ -1,167 +1,167 @@ -/* - * 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.blocks; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.DataException; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Represents a furnace block. - * - * @author sk89q - */ -public class FurnaceBlock extends ContainerBlock { - - private short burnTime; - private short cookTime; - - /** - * Construct an empty furnace block with the default orientation. - * - * @param type type ID - */ - public FurnaceBlock(int type) { - super(type, 2); - } - - /** - * Construct an empty furnace block with a given orientation. - * - * @param type type ID - * @param data orientation - */ - public FurnaceBlock(int type, int data) { - super(type, data, 2); - } - - /** - * Construct an furnace block with a given orientation and inventory. - * - * @param type type ID - * @param data orientation - * @param items inventory items - */ - public FurnaceBlock(int type, int data, BaseItemStack[] items) { - super(type, data, 2); - setItems(items); - } - - /** - * Get the burn time. - * - * @return the burn time - */ - public short getBurnTime() { - return burnTime; - } - - /** - * Set the burn time. - * - * @param burnTime the burn time - */ - public void setBurnTime(short burnTime) { - this.burnTime = burnTime; - } - - /** - * Get the cook time. - * - * @return the cook time - */ - public short getCookTime() { - return cookTime; - } - - /** - * Set the cook time. - * - * @param cookTime the cook time to set - */ - public void setCookTime(short cookTime) { - this.cookTime = cookTime; - } - - @Override - public String getNbtId() { - return "Furnace"; - } - - @Override - public CompoundTag getNbtData() { - Map values = new HashMap(); - values.put("Items", new ListTag("Items", CompoundTag.class, - serializeInventory(getItems()))); - values.put("BurnTime", new ShortTag("BurnTime", burnTime)); - values.put("CookTime", new ShortTag("CookTime", cookTime)); - return new CompoundTag(getNbtId(), values); - } - - @Override - public void setNbtData(CompoundTag rootTag) { - if (rootTag == null) { - return; - } - - try { - Map values = rootTag.getValue(); - - Tag t = values.get("id"); - if (!(t instanceof StringTag) - || !((StringTag) t).getValue().equals("Furnace")) { - throw new RuntimeException("'Furnace' tile entity expected"); - } - - ListTag items = NBTUtils.getChildTag(values, "Items", ListTag.class); - - List compound = new ArrayList(); - - for (Tag tag : items.getValue()) { - if (!(tag instanceof CompoundTag)) { - throw new RuntimeException("CompoundTag expected as child tag of Furnace Items"); - } - compound.add((CompoundTag) tag); - } - setItems(deserializeInventory(compound)); - - t = values.get("BurnTime"); - if (t instanceof ShortTag) { - burnTime = ((ShortTag) t).getValue(); - } - - t = values.get("CookTime"); - if (t instanceof ShortTag) { - cookTime = ((ShortTag) t).getValue(); - } - } catch (DataException e) { - throw new RuntimeException(e); - } - } -} +/* + * 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.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.DataException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a furnace block. + * + * @author sk89q + */ +public class FurnaceBlock extends ContainerBlock { + + private short burnTime; + private short cookTime; + + /** + * Construct an empty furnace block with the default orientation. + * + * @param type type ID + */ + public FurnaceBlock(int type) { + super(type, 2); + } + + /** + * Construct an empty furnace block with a given orientation. + * + * @param type type ID + * @param data orientation + */ + public FurnaceBlock(int type, int data) { + super(type, data, 2); + } + + /** + * Construct an furnace block with a given orientation and inventory. + * + * @param type type ID + * @param data orientation + * @param items inventory items + */ + public FurnaceBlock(int type, int data, BaseItemStack[] items) { + super(type, data, 2); + setItems(items); + } + + /** + * Get the burn time. + * + * @return the burn time + */ + public short getBurnTime() { + return burnTime; + } + + /** + * Set the burn time. + * + * @param burnTime the burn time + */ + public void setBurnTime(short burnTime) { + this.burnTime = burnTime; + } + + /** + * Get the cook time. + * + * @return the cook time + */ + public short getCookTime() { + return cookTime; + } + + /** + * Set the cook time. + * + * @param cookTime the cook time to set + */ + public void setCookTime(short cookTime) { + this.cookTime = cookTime; + } + + @Override + public String getNbtId() { + return "Furnace"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap(); + values.put("Items", new ListTag("Items", CompoundTag.class, + serializeInventory(getItems()))); + values.put("BurnTime", new ShortTag("BurnTime", burnTime)); + values.put("CookTime", new ShortTag("CookTime", cookTime)); + return new CompoundTag(getNbtId(), values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + if (rootTag == null) { + return; + } + + try { + Map values = rootTag.getValue(); + + Tag t = values.get("id"); + if (!(t instanceof StringTag) + || !((StringTag) t).getValue().equals("Furnace")) { + throw new RuntimeException("'Furnace' tile entity expected"); + } + + ListTag items = NBTUtils.getChildTag(values, "Items", ListTag.class); + + List compound = new ArrayList(); + + for (Tag tag : items.getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new RuntimeException("CompoundTag expected as child tag of Furnace Items"); + } + compound.add((CompoundTag) tag); + } + setItems(deserializeInventory(compound)); + + t = values.get("BurnTime"); + if (t instanceof ShortTag) { + burnTime = ((ShortTag) t).getValue(); + } + + t = values.get("CookTime"); + if (t instanceof ShortTag) { + cookTime = ((ShortTag) t).getValue(); + } + } catch (DataException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java diff --git a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java diff --git a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/NoteBlock.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/NoteBlock.java index 32e1cdb18..0f5c819e3 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java +++ b/src/legacy/java/com/sk89q/worldedit/blocks/NoteBlock.java @@ -1,123 +1,123 @@ -/* - * 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.blocks; - -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; - -import java.util.HashMap; -import java.util.Map; - -/** - * A note block. - * - * @author sk89q - */ -public class NoteBlock extends BaseBlock implements TileEntityBlock { - - private byte note; - - /** - * Construct the note block with a data value of 0. - */ - public NoteBlock() { - super(BlockID.NOTE_BLOCK); - this.note = 0; - } - - /** - * Construct the note block with a given data value. - * - * @param data data value - */ - public NoteBlock(int data) { - super(BlockID.NOTE_BLOCK, data); - this.note = 0; - } - - /** - * Construct the note block with a given data value and note. - * - * @param data data value - * @param note note - */ - public NoteBlock(int data, byte note) { - super(BlockID.NOTE_BLOCK, data); - this.note = note; - } - - /** - * Get the note. - * - * @return the note - */ - public byte getNote() { - return note; - } - - /** - * Set the note. - * - * @param note the note to set - */ - public void setNote(byte note) { - this.note = note; - } - - @Override - public boolean hasNbtData() { - return true; - } - - @Override - public String getNbtId() { - return "Music"; - } - - @Override - public CompoundTag getNbtData() { - Map values = new HashMap(); - values.put("note", new ByteTag("note", note)); - return new CompoundTag(getNbtId(), values); - } - - @Override - public void setNbtData(CompoundTag rootTag) { - if (rootTag == null) { - return; - } - - Map values = rootTag.getValue(); - - Tag t; - - t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Music")) { - throw new RuntimeException("'Music' tile entity expected"); - } - - t = values.get("note"); - if (t instanceof ByteTag) { - note = ((ByteTag) t).getValue(); - } - } -} +/* + * 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.blocks; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; + +import java.util.HashMap; +import java.util.Map; + +/** + * A note block. + * + * @author sk89q + */ +public class NoteBlock extends BaseBlock implements TileEntityBlock { + + private byte note; + + /** + * Construct the note block with a data value of 0. + */ + public NoteBlock() { + super(BlockID.NOTE_BLOCK); + this.note = 0; + } + + /** + * Construct the note block with a given data value. + * + * @param data data value + */ + public NoteBlock(int data) { + super(BlockID.NOTE_BLOCK, data); + this.note = 0; + } + + /** + * Construct the note block with a given data value and note. + * + * @param data data value + * @param note note + */ + public NoteBlock(int data, byte note) { + super(BlockID.NOTE_BLOCK, data); + this.note = note; + } + + /** + * Get the note. + * + * @return the note + */ + public byte getNote() { + return note; + } + + /** + * Set the note. + * + * @param note the note to set + */ + public void setNote(byte note) { + this.note = note; + } + + @Override + public boolean hasNbtData() { + return true; + } + + @Override + public String getNbtId() { + return "Music"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap(); + values.put("note", new ByteTag("note", note)); + return new CompoundTag(getNbtId(), values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + if (rootTag == null) { + return; + } + + Map values = rootTag.getValue(); + + Tag t; + + t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Music")) { + throw new RuntimeException("'Music' tile entity expected"); + } + + t = values.get("note"); + if (t instanceof ByteTag) { + note = ((ByteTag) t).getValue(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/blocks/SignBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java diff --git a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java rename to src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java index 981a339ec..ac62da26c 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -1,194 +1,194 @@ -/* - * 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.blocks; - -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; - -import java.util.HashMap; -import java.util.Map; - -/** - * A skull block. - */ -public class SkullBlock extends BaseBlock implements TileEntityBlock { - - private String owner = ""; // notchian - private byte skullType; // stored here for block, in damage value for item - private byte rot; // only matters if block data == 0x1 (on floor) - - /** - * Construct the skull block with a default type of skelton. - * @param data data value to set, controls placement - */ - public SkullBlock(int data) { - this(data, (byte) 0); - } - - /** - * Construct the skull block with a given type. - * 0 - skeleton - * 1 - wither skelly - * 2 - zombie - * 3 - human - * 4 - creeper - * @param data data value to set, controls placement - * @param type type of skull - */ - public SkullBlock(int data, byte type) { - this(data, type, (byte) 0); - } - - /** - * Construct the skull block with a given type and rotation. - * @param data data value to set, controls placement - * @param type type of skull - * @param rot rotation (if on floor) - */ - public SkullBlock(int data, byte type, byte rot) { - super(BlockID.HEAD, data); - if (type < (byte) 0 || type > (byte) 4) { - this.skullType = (byte) 0; - } else { - this.skullType = type; - } - this.rot = rot; - this.owner = ""; - } - - /** - * Construct the skull block with a given rotation and owner. - * The type is assumed to be player unless owner is null or empty. - * @param data data value to set, controls placement - * @param rot rotation of skull - * @param owner name of player - */ - public SkullBlock(int data, byte rot, String owner) { - super(BlockID.HEAD, data); - this.rot = rot; - this.setOwner(owner); - if (owner == null || owner.isEmpty()) this.skullType = (byte) 0; - } - - /** - * Set the skull's owner. Automatically sets type to player if not empty or null. - * @param owner player name to set the skull to - */ - public void setOwner(String owner) { - if (owner == null) { - this.owner = ""; - } else { - if (owner.length() > 16 || owner.isEmpty()) this.owner = ""; - else this.owner = owner; - } - if (this.owner != null && !this.owner.isEmpty()) this.skullType = (byte) 3; - } - - /** - * Get the skull's owner. Returns null if unset. - * @return player name or null - */ - public String getOwner() { - return owner; - } - - /** - * Get the type of skull. - * @return the skullType - */ - public byte getSkullType() { - return skullType; - } - - /** - * Set the type of skull; - * @param skullType the skullType to set - */ - public void setSkullType(byte skullType) { - this.skullType = skullType; - } - - /** - * Get rotation of skull. This only means anything if the block data is 1. - * @return the rotation - */ - public byte getRot() { - return rot; - } - - /** - * Set the rotation of skull. - * @param rot the rotation to set - */ - public void setRot(byte rot) { - this.rot = rot; - } - - @Override - public boolean hasNbtData() { - return true; - } - - @Override - public String getNbtId() { - return "Skull"; - } - - @Override - public CompoundTag getNbtData() { - Map values = new HashMap(); - values.put("SkullType", new ByteTag("SkullType", skullType)); - if (owner == null) owner = ""; - values.put("ExtraType", new StringTag("ExtraType", owner)); - values.put("Rot", new ByteTag("Rot", rot)); - return new CompoundTag(getNbtId(), values); - } - - @Override - public void setNbtData(CompoundTag rootTag) { - if (rootTag == null) { - return; - } - - Map values = rootTag.getValue(); - - Tag t; - - t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Skull")) { - throw new RuntimeException("'Skull' tile entity expected"); - } - - t = values.get("SkullType"); - if (t instanceof ByteTag) { - skullType = ((ByteTag) t).getValue(); - } - t = values.get("ExtraType"); - if (t != null && t instanceof StringTag) { - owner = ((StringTag) t).getValue(); - } - t = values.get("Rot"); - if (t instanceof ByteTag) { - rot = ((ByteTag) t).getValue(); - } - } -} +/* + * 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.blocks; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; + +import java.util.HashMap; +import java.util.Map; + +/** + * A skull block. + */ +public class SkullBlock extends BaseBlock implements TileEntityBlock { + + private String owner = ""; // notchian + private byte skullType; // stored here for block, in damage value for item + private byte rot; // only matters if block data == 0x1 (on floor) + + /** + * Construct the skull block with a default type of skelton. + * @param data data value to set, controls placement + */ + public SkullBlock(int data) { + this(data, (byte) 0); + } + + /** + * Construct the skull block with a given type. + * 0 - skeleton + * 1 - wither skelly + * 2 - zombie + * 3 - human + * 4 - creeper + * @param data data value to set, controls placement + * @param type type of skull + */ + public SkullBlock(int data, byte type) { + this(data, type, (byte) 0); + } + + /** + * Construct the skull block with a given type and rotation. + * @param data data value to set, controls placement + * @param type type of skull + * @param rot rotation (if on floor) + */ + public SkullBlock(int data, byte type, byte rot) { + super(BlockID.HEAD, data); + if (type < (byte) 0 || type > (byte) 4) { + this.skullType = (byte) 0; + } else { + this.skullType = type; + } + this.rot = rot; + this.owner = ""; + } + + /** + * Construct the skull block with a given rotation and owner. + * The type is assumed to be player unless owner is null or empty. + * @param data data value to set, controls placement + * @param rot rotation of skull + * @param owner name of player + */ + public SkullBlock(int data, byte rot, String owner) { + super(BlockID.HEAD, data); + this.rot = rot; + this.setOwner(owner); + if (owner == null || owner.isEmpty()) this.skullType = (byte) 0; + } + + /** + * Set the skull's owner. Automatically sets type to player if not empty or null. + * @param owner player name to set the skull to + */ + public void setOwner(String owner) { + if (owner == null) { + this.owner = ""; + } else { + if (owner.length() > 16 || owner.isEmpty()) this.owner = ""; + else this.owner = owner; + } + if (this.owner != null && !this.owner.isEmpty()) this.skullType = (byte) 3; + } + + /** + * Get the skull's owner. Returns null if unset. + * @return player name or null + */ + public String getOwner() { + return owner; + } + + /** + * Get the type of skull. + * @return the skullType + */ + public byte getSkullType() { + return skullType; + } + + /** + * Set the type of skull; + * @param skullType the skullType to set + */ + public void setSkullType(byte skullType) { + this.skullType = skullType; + } + + /** + * Get rotation of skull. This only means anything if the block data is 1. + * @return the rotation + */ + public byte getRot() { + return rot; + } + + /** + * Set the rotation of skull. + * @param rot the rotation to set + */ + public void setRot(byte rot) { + this.rot = rot; + } + + @Override + public boolean hasNbtData() { + return true; + } + + @Override + public String getNbtId() { + return "Skull"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap(); + values.put("SkullType", new ByteTag("SkullType", skullType)); + if (owner == null) owner = ""; + values.put("ExtraType", new StringTag("ExtraType", owner)); + values.put("Rot", new ByteTag("Rot", rot)); + return new CompoundTag(getNbtId(), values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + if (rootTag == null) { + return; + } + + Map values = rootTag.getValue(); + + Tag t; + + t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Skull")) { + throw new RuntimeException("'Skull' tile entity expected"); + } + + t = values.get("SkullType"); + if (t instanceof ByteTag) { + skullType = ((ByteTag) t).getValue(); + } + t = values.get("ExtraType"); + if (t != null && t instanceof StringTag) { + owner = ((StringTag) t).getValue(); + } + t = values.get("Rot"); + if (t instanceof ByteTag) { + rot = ((ByteTag) t).getValue(); + } + } +} From 22dceb5614c29bec27d2ff79df82504fd17f1ad6 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 14:05:52 -0700 Subject: [PATCH 15/56] Added GSON, Trove as dependencies and enabled minimizeJar for shading. --- pom.xml | 29 +++++++++++++++++++++++++++++ src/main/build/import-control.xml | 2 ++ 2 files changed, 31 insertions(+) diff --git a/pom.xml b/pom.xml index 24b512526..f0a66b601 100644 --- a/pom.xml +++ b/pom.xml @@ -142,6 +142,22 @@ jar + + + com.google.code.gson + gson + 2.2.4 + true + + + + + net.sf.trove4j + trove4j + 3.0.3 + true + + com.google.code.findbugs @@ -367,12 +383,25 @@ shade + true com.sk89q:jchronic com.thoughtworks.paranamer:paranamer + com.google.code.gson:gson + net.sf.trove4j:trove4j + + + gnu.trove + com.sk89q.worldedit.internal.trove + + + com.google.gson + com.sk89q.worldedit.internal.gson + + diff --git a/src/main/build/import-control.xml b/src/main/build/import-control.xml index 9ef48920d..9bb8d7a3d 100644 --- a/src/main/build/import-control.xml +++ b/src/main/build/import-control.xml @@ -10,6 +10,8 @@ + + From 56b349ead808cf86357a6b7d4cfbf023a94d582e Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 14:14:17 -0700 Subject: [PATCH 16/56] Add a new block metadata framework and fix //rotate and //flip. Remove the previous Mapping interfaces. --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 105 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 55 +- .../com/sk89q/worldedit/LocalSession.java | 18 +- .../java/com/sk89q/worldedit/WorldEdit.java | 8 +- .../sk89q/worldedit/blocks/BlockMaterial.java | 71 + .../worldedit/command/ClipboardCommands.java | 22 +- .../command/tool/brush/ClipboardBrush.java | 23 +- .../transform/BlockTransformExtent.java | 181 + .../worldedit/internal/LocalWorldAdapter.java | 45 +- .../com/sk89q/worldedit/math/MathUtils.java | 9 + .../math/transform/AffineTransform.java | 6 + .../worldedit/math/transform/Transform.java | 11 +- .../worldedit/session/ClipboardHolder.java | 26 +- .../sk89q/worldedit/session/PasteBuilder.java | 102 + .../worldedit/util/gson/VectorAdapter.java | 49 + .../com/sk89q/worldedit/world/NullWorld.java | 37 +- .../java/com/sk89q/worldedit/world/World.java | 22 +- .../worldedit/world/mapping/Mapping.java | 114 - .../world/registry/BlockRegistry.java | 69 + .../world/registry/BundledBlockData.java | 189 + .../world/registry/LegacyBlockRegistry.java | 63 + .../world/registry/LegacyWorldData.java | 51 + .../world/registry/SimpleBlockMaterial.java | 246 + .../worldedit/world/registry/SimpleState.java | 71 + .../world/registry/SimpleStateValue.java | 55 + .../Resolver.java => registry/State.java} | 43 +- .../worldedit/world/registry/StateValue.java | 56 + .../WorldData.java} | 29 +- .../worldedit/world/registry/blocks.json | 5968 +++++++++++++++++ 29 files changed, 7425 insertions(+), 319 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/session/PasteBuilder.java create mode 100644 src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java delete mode 100644 src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/LegacyBlockRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/SimpleState.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/SimpleStateValue.java rename src/main/java/com/sk89q/worldedit/world/{mapping/Resolver.java => registry/State.java} (51%) create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/StateValue.java rename src/main/java/com/sk89q/worldedit/world/{mapping/NullResolver.java => registry/WorldData.java} (64%) create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.json diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 458aa8477..72a774ede 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -19,24 +19,67 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EntityType; +import com.sk89q.worldedit.LocalEntity; +import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.ContainerBlock; +import com.sk89q.worldedit.blocks.FurnaceBlock; +import com.sk89q.worldedit.blocks.LazyBlock; +import com.sk89q.worldedit.blocks.MobSpawnerBlock; import com.sk89q.worldedit.blocks.NoteBlock; +import com.sk89q.worldedit.blocks.SignBlock; +import com.sk89q.worldedit.blocks.SkullBlock; import com.sk89q.worldedit.bukkit.entity.BukkitEntity; -import com.sk89q.worldedit.entity.*; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.world.mapping.NullResolver; -import com.sk89q.worldedit.world.mapping.Resolver; -import org.bukkit.*; +import com.sk89q.worldedit.world.registry.LegacyWorldData; +import com.sk89q.worldedit.world.registry.WorldData; +import org.bukkit.Bukkit; +import org.bukkit.Effect; import org.bukkit.Location; -import org.bukkit.block.*; +import org.bukkit.Material; +import org.bukkit.SkullType; +import org.bukkit.TreeType; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.Chest; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.block.Furnace; +import org.bukkit.block.Sign; +import org.bukkit.block.Skull; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.*; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Boat; import org.bukkit.entity.Entity; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Golem; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Item; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Painting; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Villager; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -49,7 +92,14 @@ import java.io.InputStream; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -1180,6 +1230,11 @@ public class BukkitWorld extends LocalWorld { return true; } + @Override + public WorldData getWorldData() { + return LegacyWorldData.getInstance(); + } + @Override public void simulateBlockMine(Vector pt) { getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); @@ -1280,38 +1335,6 @@ public class BukkitWorld extends LocalWorld { return super.setBlock(pt, block, notifyAdjacent); } - @Override - public Resolver getBlockMapping() { - return new NullResolver(); - } - - @Override - public Resolver getEntityMapping() { - return new NullResolver(); - } - - @Nullable - @Override - public T getMetaData(BaseBlock block, Class metaDataClass) { - return null; - } - - @Nullable - @Override - public T getMetaData(com.sk89q.worldedit.entity.Entity entity, Class metaDataClass) { - if (entity instanceof com.sk89q.worldedit.bukkit.BukkitEntity) { - return ((com.sk89q.worldedit.bukkit.BukkitEntity) entity).getMetaData(metaDataClass); - } - - return null; - } - - @Nullable - @Override - public T getMetaData(BaseEntity entity, Class metaDataClass) { - return null; - } - /** * @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)} */ diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 60f229bf0..5087799a7 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -20,7 +20,13 @@ package com.sk89q.worldedit.forge; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EntityType; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; @@ -30,14 +36,22 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; -import com.sk89q.worldedit.world.mapping.NullResolver; -import com.sk89q.worldedit.world.mapping.Resolver; +import com.sk89q.worldedit.world.registry.LegacyWorldData; +import com.sk89q.worldedit.world.registry.WorldData; import net.minecraft.block.Block; import net.minecraft.entity.EntityHanging; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.IProjectile; -import net.minecraft.entity.item.*; +import net.minecraft.entity.item.EntityBoat; +import net.minecraft.entity.item.EntityEnderEye; +import net.minecraft.entity.item.EntityFallingSand; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.EntityItemFrame; +import net.minecraft.entity.item.EntityMinecart; +import net.minecraft.entity.item.EntityPainting; +import net.minecraft.entity.item.EntityTNTPrimed; +import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.entity.monster.EntityGolem; import net.minecraft.entity.passive.EntityAmbientCreature; import net.minecraft.entity.passive.EntityAnimal; @@ -432,6 +446,11 @@ public class ForgeWorld extends AbstractWorld { return false; } + @Override + public WorldData getWorldData() { + return LegacyWorldData.getInstance(); + } + @Override public boolean isValidBlockType(int id) { return (id == 0) || (net.minecraft.block.Block.blocksList[id] != null); @@ -480,34 +499,6 @@ public class ForgeWorld extends AbstractWorld { } } - @Override - public Resolver getBlockMapping() { - return new NullResolver(); - } - - @Override - public Resolver getEntityMapping() { - return new NullResolver(); - } - - @Nullable - @Override - public T getMetaData(BaseBlock block, Class metaDataClass) { - return null; - } - - @Nullable - @Override - public T getMetaData(Entity entity, Class metaDataClass) { - return null; - } - - @Nullable - @Override - public T getMetaData(BaseEntity entity, Class metaDataClass) { - return null; - } - @Override public List getEntities() { List entities = new ArrayList(); diff --git a/src/main/java/com/sk89q/worldedit/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java index 650e29a16..0bf0bfeb3 100644 --- a/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -29,7 +29,6 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -44,7 +43,12 @@ import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.snapshot.Snapshot; -import java.util.*; +import javax.annotation.Nullable; +import java.util.Calendar; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.TimeZone; /** * An instance of this represents the WorldEdit session of a user. A session @@ -326,7 +330,7 @@ public class LocalSession { * Gets the clipboard. * * @return clipboard, may be null - * @throws EmptyClipboardException + * @throws EmptyClipboardException thrown if no clipboard is set */ public ClipboardHolder getClipboard() throws EmptyClipboardException { if (clipboard == null) { @@ -338,10 +342,12 @@ public class LocalSession { /** * Sets the clipboard. * - * @param clipboard + *

Pass {@code null} to clear the clipboard.

+ * + * @param clipboard the clipboard, or null if the clipboard is to be cleared */ - public ClipboardHolder replaceClipboard(Clipboard clipboard) { - return this.clipboard = new ClipboardHolder(clipboard); + public void setClipboard(@Nullable ClipboardHolder clipboard) { + this.clipboard = clipboard; } /** diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java index 2b451409d..2e3a4d2df 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -46,9 +46,14 @@ import com.sk89q.worldedit.session.SessionManager; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.logging.WorldEditPrefixHandler; +import com.sk89q.worldedit.world.registry.BundledBlockData; import javax.script.ScriptException; -import java.io.*; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -91,6 +96,7 @@ public class WorldEdit { static { WorldEditPrefixHandler.register("com.sk89q.worldedit"); getVersion(); + BundledBlockData.getInstance(); // Load block registry } private WorldEdit() { diff --git a/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java b/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java new file mode 100644 index 000000000..09c9f8716 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java @@ -0,0 +1,71 @@ +/* + * 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.blocks; + +/** + * Describes the material for a block. + */ +public interface BlockMaterial { + + boolean isRenderedAsNormalBlock(); + + boolean isFullCube(); + + boolean isOpaque(); + + boolean isPowerSource(); + + boolean isLiquid(); + + boolean isSolid(); + + float getHardness(); + + float getResistance(); + + float getSlipperiness(); + + boolean isGrassBlocking(); + + float getAmbientOcclusionLightValue(); + + int getLightOpacity(); + + int getLightValue(); + + boolean isFragileWhenPushed(); + + boolean isUnpushable(); + + boolean isAdventureModeExempt(); + + boolean isTicksRandomly(); + + boolean isUsingNeighborLight(); + + boolean isMovementBlocker(); + + boolean isBurnable(); + + boolean isToolRequired(); + + boolean isReplacedDuringPlacement(); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index ad7edfa6a..bc6ed59e9 100644 --- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -32,9 +32,9 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockReplace; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.annotation.Direction; @@ -92,7 +92,7 @@ public class ClipboardCommands { copy.setSourceMask(mask); } Operations.completeLegacy(copy); - session.replaceClipboard(clipboard); + session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData())); player.print(region.getArea() + " block(s) were copied."); } @@ -124,7 +124,7 @@ public class ClipboardCommands { copy.setSourceMask(mask); } Operations.completeLegacy(copy); - session.replaceClipboard(clipboard); + session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData())); player.print(region.getArea() + " block(s) were copied."); } @@ -154,12 +154,12 @@ public class ClipboardCommands { Region region = clipboard.getRegion(); Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, region, clipboard.getOrigin(), editSession, to); - copy.setTransform(holder.getTransform()); - if (ignoreAirBlocks) { - copy.setSourceMask(new ExistingBlockMask(clipboard)); - } - Operations.completeLegacy(copy); + Operation operation = holder + .createPaste(editSession, editSession.getWorld().getWorldData()) + .to(to) + .ignoreAirBlocks(ignoreAirBlocks) + .build(); + Operations.completeLegacy(operation); if (selectPasted) { Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint())); @@ -169,7 +169,7 @@ public class ClipboardCommands { selector.explainRegionAdjust(player, session); } - player.print("The clipboard has been pasted at " + to.add(region.getMinimumPoint())); + player.print("The clipboard has been pasted at " + to); } @Command( @@ -252,7 +252,7 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.clear") public void clearClipboard(Player player, LocalSession session, EditSession editSession) throws WorldEditException { - session.replaceClipboard(null); + session.setClipboard(null); player.print("Clipboard cleared."); } } diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java index 9a792ee7b..a5692265e 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -23,8 +23,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; -import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.Region; @@ -33,11 +32,11 @@ import com.sk89q.worldedit.session.ClipboardHolder; public class ClipboardBrush implements Brush { private ClipboardHolder holder; - private boolean noAir; + private boolean ignoreAirBlocks; - public ClipboardBrush(ClipboardHolder holder, boolean noAir) { + public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks) { this.holder = holder; - this.noAir = noAir; + this.ignoreAirBlocks = ignoreAirBlocks; } @Override @@ -45,12 +44,14 @@ public class ClipboardBrush implements Brush { Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); Vector centerOffset = region.getCenter().subtract(clipboard.getOrigin()); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, region, clipboard.getOrigin(), editSession, pos.subtract(centerOffset)); - copy.setTransform(holder.getTransform()); - if (noAir) { - copy.setSourceMask(new ExistingBlockMask(clipboard)); - } - Operations.completeLegacy(copy); + + Operation operation = holder + .createPaste(editSession, editSession.getWorld().getWorldData()) + .to(pos.subtract(centerOffset)) + .ignoreAirBlocks(ignoreAirBlocks) + .build(); + + Operations.completeLegacy(operation); } } diff --git a/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java new file mode 100644 index 000000000..cf9e9d85e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -0,0 +1,181 @@ +/* + * 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.extent.transform; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import com.sk89q.worldedit.world.registry.State; +import com.sk89q.worldedit.world.registry.StateValue; + +import javax.annotation.Nullable; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Transforms blocks themselves (but not their position) according to a + * given transform. + */ +public class BlockTransformExtent extends AbstractDelegateExtent { + + private static final double RIGHT_ANGLE = Math.toRadians(90); + + private final Transform transform; + private final BlockRegistry blockRegistry; + + /** + * Create a new instance. + * + * @param extent the extent + * @param blockRegistry the block registry used for block direction data + */ + public BlockTransformExtent(Extent extent, Transform transform, BlockRegistry blockRegistry) { + super(extent); + checkNotNull(transform); + checkNotNull(blockRegistry); + this.transform = transform; + this.blockRegistry = blockRegistry; + } + + /** + * Get the transform. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + + /** + * Transform a block without making a copy. + * + * @param block the block + * @param reverse true to transform in the opposite direction + * @return the same block + */ + private BaseBlock transformBlock(BaseBlock block, boolean reverse) { + transform(block, reverse ? transform.inverse() : transform, blockRegistry); + return block; + } + + @Override + public BaseBlock getBlock(Vector position) { + return transformBlock(super.getBlock(position), false); + } + + @Override + public BaseBlock getLazyBlock(Vector position) { + return transformBlock(super.getLazyBlock(position), false); + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + return super.setBlock(location, transformBlock(new BaseBlock(block), true)); + } + + + /** + * Transform the given block using the given transform. + * + *

The provided block is modified.

+ * + * @param block the block + * @param transform the transform + * @param registry the registry + * @return the same block + */ + private static BaseBlock transform(BaseBlock block, Transform transform, BlockRegistry registry) { + return transform(block, transform, registry, block); + } + + /** + * Transform the given block using the given transform. + * + * @param block the block + * @param transform the transform + * @param registry the registry + * @param changedBlock the block to change + * @return the changed block + */ + private static BaseBlock transform(BaseBlock block, Transform transform, BlockRegistry registry, BaseBlock changedBlock) { + checkNotNull(block); + checkNotNull(transform); + checkNotNull(registry); + + Map states = registry.getStates(block); + + if (states == null) { + return changedBlock; + } + + for (State state : states.values()) { + if (state.hasDirection()) { + StateValue value = state.getValue(block); + if (value != null && value.getDirection() != null) { + StateValue newValue = getNewStateValue(state, transform, value.getDirection()); + if (newValue != null) { + newValue.set(changedBlock); + } + } + } + } + + return changedBlock; + } + + /** + * Get the new value with the transformed direction. + * + * @param state the state + * @param transform the transform + * @param oldDirection the old direction to transform + * @return a new state or null if none could be found + */ + @Nullable + private static StateValue getNewStateValue(State state, Transform transform, Vector oldDirection) { + Vector newDirection = transform.apply(oldDirection).normalize(); + StateValue newValue = null; + double closest = -2; + boolean found = false; + + for (StateValue v : state.valueMap().values()) { + if (v.getDirection() != null) { + double dot = v.getDirection().normalize().dot(newDirection); + if (dot >= closest) { + closest = dot; + newValue = v; + found = true; + } + } + } + + if (found) { + return newValue; + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index 3b7025003..dd04767b5 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -19,7 +19,16 @@ package com.sk89q.worldedit.internal; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EntityType; +import com.sk89q.worldedit.LocalEntity; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; @@ -30,7 +39,7 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.mapping.Resolver; +import com.sk89q.worldedit.world.registry.WorldData; import javax.annotation.Nullable; import java.util.List; @@ -259,6 +268,11 @@ public class LocalWorldAdapter extends LocalWorld { return world.queueBlockBreakEffect(server, position, blockId, priority); } + @Override + public WorldData getWorldData() { + return world.getWorldData(); + } + @Override public boolean equals(Object other) { return world.equals(other); @@ -313,33 +327,6 @@ public class LocalWorldAdapter extends LocalWorld { public Operation commit() { return world.commit(); } - @Override - public Resolver getBlockMapping() { - return world.getBlockMapping(); - } - - @Override - public Resolver getEntityMapping() { - return world.getEntityMapping(); - } - - @Override - @Nullable - public T getMetaData(BaseBlock block, Class metaDataClass) { - return world.getMetaData(block, metaDataClass); - } - - @Override - @Nullable - public T getMetaData(Entity entity, Class metaDataClass) { - return world.getMetaData(entity, metaDataClass); - } - - @Override - @Nullable - public T getMetaData(BaseEntity entity, Class metaDataClass) { - return world.getMetaData(entity, metaDataClass); - } @Override @Nullable diff --git a/src/main/java/com/sk89q/worldedit/math/MathUtils.java b/src/main/java/com/sk89q/worldedit/math/MathUtils.java index 992a5e955..568019499 100644 --- a/src/main/java/com/sk89q/worldedit/math/MathUtils.java +++ b/src/main/java/com/sk89q/worldedit/math/MathUtils.java @@ -24,6 +24,15 @@ package com.sk89q.worldedit.math; */ public final class MathUtils { + /** + * Safe minimum, such that 1 / SAFE_MIN does not overflow. + *

+ * In IEEE 754 arithmetic, this is also the smallest normalized number + * 2-1022. The value of this constant is from Apache Commons + * Math 2.2. + */ + public static final double SAFE_MIN = 0x1.0p-1022; + private MathUtils() { } diff --git a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index 63e3d8ded..eecdcc6cc 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -292,6 +292,10 @@ public class AffineTransform implements Transform { vector.getX() * m20 + vector.getY() * m21 + vector.getZ() * m22 + m23); } + public AffineTransform combine(AffineTransform other) { + return concatenate(other); + } + @Override public Transform combine(Transform other) { if (other instanceof AffineTransform) { @@ -305,4 +309,6 @@ public class AffineTransform implements Transform { public String toString() { return String.format("Affine[%g %g %g %g, %g %g %g %g, %g %g %g %g]}", m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23); } + + } \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Transform.java b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java index 05a7d5196..cb3109879 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/Transform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java @@ -19,13 +19,20 @@ package com.sk89q.worldedit.math.transform; -import com.google.common.base.Function; import com.sk89q.worldedit.Vector; /** * Makes a transformation of {@link Vector}s. */ -public interface Transform extends Function { +public interface Transform { + + /** + * Returns the result of applying the function to the input. + * + * @param input the input + * @return the result + */ + Vector apply(Vector input); /** * Create a new inverse transform. diff --git a/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java b/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java index b2b10561f..37bb50de8 100644 --- a/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java +++ b/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java @@ -19,9 +19,11 @@ package com.sk89q.worldedit.session; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.registry.WorldData; import static com.google.common.base.Preconditions.checkNotNull; @@ -30,6 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class ClipboardHolder { + private final WorldData worldData; private final Clipboard clipboard; private Transform transform = new Identity(); @@ -37,10 +40,22 @@ public class ClipboardHolder { * Create a new instance with the given clipboard. * * @param clipboard the clipboard + * @param worldData the mapping of blocks, entities, and so on */ - public ClipboardHolder(Clipboard clipboard) { + public ClipboardHolder(Clipboard clipboard, WorldData worldData) { checkNotNull(clipboard); + checkNotNull(worldData); this.clipboard = clipboard; + this.worldData = worldData; + } + + /** + * Get the mapping used for blocks, entities, and so on. + * + * @return the mapping + */ + public WorldData getWorldData() { + return worldData; } /** @@ -74,4 +89,13 @@ public class ClipboardHolder { return transform; } + /** + * Create a builder for an operation to paste this clipboard. + * + * @return a builder + */ + public PasteBuilder createPaste(Extent targetExtent, WorldData targetWorldData) { + return new PasteBuilder(this, targetExtent, targetWorldData); + } + } diff --git a/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java b/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java new file mode 100644 index 000000000..571387cf5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java @@ -0,0 +1,102 @@ +/* + * 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.session; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.registry.WorldData; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Builds an operation to paste the contents of a clipboard. + */ +public class PasteBuilder { + + private final Clipboard clipboard; + private final WorldData worldData; + private final Transform transform; + private final Extent targetExtent; + private final WorldData targetWorldData; + + private Vector to = new Vector(); + private boolean ignoreAirBlocks; + + /** + * Create a new instance. + * + * @param holder the clipboard holder + * @param targetExtent + * @param targetWorldData + */ + PasteBuilder(ClipboardHolder holder, Extent targetExtent, WorldData targetWorldData) { + checkNotNull(holder); + checkNotNull(targetExtent); + checkNotNull(targetWorldData); + this.clipboard = holder.getClipboard(); + this.worldData = holder.getWorldData(); + this.transform = holder.getTransform(); + this.targetExtent = targetExtent; + this.targetWorldData = targetWorldData; + } + + /** + * Set the target location. + * + * @param to the target location + * @return this builder instance + */ + public PasteBuilder to(Vector to) { + this.to = to; + return this; + } + + /** + * Set whether air blocks in the source are skipped over when pasting. + * + * @return this builder instance + */ + public PasteBuilder ignoreAirBlocks(boolean ignoreAirBlocks) { + this.ignoreAirBlocks = ignoreAirBlocks; + return this; + } + + /** + * Build the operation. + * + * @return the operation + */ + public Operation build() { + BlockTransformExtent extent = new BlockTransformExtent(clipboard, transform, targetWorldData.getBlockRegistry()); + ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to); + copy.setTransform(transform); + if (ignoreAirBlocks) { + copy.setSourceMask(new ExistingBlockMask(clipboard)); + } + return copy; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java b/src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java new file mode 100644 index 000000000..a1e876dfe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java @@ -0,0 +1,49 @@ +/* + * 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.util.gson; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.sk89q.worldedit.Vector; + +import java.lang.reflect.Type; + +/** + * Deserializes {@code Vector}s for GSON. + */ +public class VectorAdapter implements JsonDeserializer { + + @Override + public Vector deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonArray jsonArray = json.getAsJsonArray(); + if (jsonArray.size() != 3) { + throw new JsonParseException("Expected array of 3 length for Vector"); + } + + double x = jsonArray.get(0).getAsDouble(); + double y = jsonArray.get(1).getAsDouble(); + double z = jsonArray.get(2).getAsDouble(); + + return new Vector(x, y, z); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 35cc1a863..937ba9c3b 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -28,8 +28,8 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.world.mapping.NullResolver; -import com.sk89q.worldedit.world.mapping.Resolver; +import com.sk89q.worldedit.world.registry.LegacyWorldData; +import com.sk89q.worldedit.world.registry.WorldData; import javax.annotation.Nullable; import java.util.Collections; @@ -94,6 +94,11 @@ public class NullWorld extends AbstractWorld { return false; } + @Override + public WorldData getWorldData() { + return LegacyWorldData.getInstance(); + } + @Override public BaseBlock getBlock(Vector position) { return new BaseBlock(BlockID.AIR); @@ -104,34 +109,6 @@ public class NullWorld extends AbstractWorld { return new BaseBlock(BlockID.AIR); } - @Override - public Resolver getBlockMapping() { - return new NullResolver(); - } - - @Override - public Resolver getEntityMapping() { - return new NullResolver(); - } - - @Nullable - @Override - public T getMetaData(BaseBlock block, Class metaDataClass) { - return null; - } - - @Nullable - @Override - public T getMetaData(Entity entity, Class metaDataClass) { - return null; - } - - @Nullable - @Override - public T getMetaData(BaseEntity entity, Class metaDataClass) { - return null; - } - @Override public List getEntities() { return Collections.emptyList(); diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index 3bd5fd97a..eb12f7f71 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -19,7 +19,16 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EntityType; +import com.sk89q.worldedit.LocalEntity; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Platform; @@ -28,12 +37,12 @@ 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; -import com.sk89q.worldedit.world.mapping.Mapping; +import com.sk89q.worldedit.world.registry.WorldData; /** * Represents a world (dimension). */ -public interface World extends Extent, Mapping { +public interface World extends Extent { /** * Get the name of the world. @@ -346,6 +355,13 @@ public interface World extends Extent, Mapping { */ boolean queueBlockBreakEffect(Platform server, Vector position, int blockId, double priority); + /** + * Get the data for blocks and so on for this world. + * + * @return the world data + */ + WorldData getWorldData(); + @Override boolean equals(Object other); diff --git a/src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java b/src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java deleted file mode 100644 index 401ab94a7..000000000 --- a/src/main/java/com/sk89q/worldedit/world/mapping/Mapping.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.mapping; - -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.entity.metadata.Tameable; - -import javax.annotation.Nullable; - -/** - * A mapping can create state objects (such as {@link BaseBlock}) - * from implementation-independent identifiers (such as "minecraft.stone"), - * as well as perform the opposite task of retrieving - * the identifier for a given state object (whenever possible at least, because - * a mapping may not be compatible with a set of state objects that may have - * come from another implementation). In addition, a mapping may be able to - * retrieve a variety of metadata objects (such as {@link Tameable}) to - * describe a given state object. - *

- * However, it may be possible that a mapping be "dumb" and not be able to, - * for example, return a {@link Tameable} for a "Horse" entity, simply because - * it has not be implemented. Any code that queries a mapping must be - * aware of this and act accordingly. - */ -public interface Mapping { - - /** - * Get the mapping for block identifiers. - * - * @return a block mapping - */ - Resolver getBlockMapping(); - - /** - * Get the mapping for entity identifiers. - * - * @return an entity mapping - */ - Resolver getEntityMapping(); - - /** - * Attempt to return an instance of the given class for the given block. - * For example, {@code getMetaData(block, Inventory.class)} might return - * an instance if the block happens to contain an inventory. - *

- * If the given block is not of the given class (i.e. a dirt block does - * not have an inventory) or if the information is simply not available, - * {@code null} will be returned. - *

- * Mutator methods on the returned instance should change the block. - * - * @param block the block - * @param metaDataClass the metadata class for the returned instance - * @param the metadata class - * @return an instance of the given class, otherwise null - */ - @Nullable T getMetaData(BaseBlock block, Class metaDataClass); - - /** - * Attempt to return an instance of the given class for the given entity. - * For example, {@code getMetaData(entity, Creature.class)} might return - * an instance if the entity happens to be a creature. - *

- * If the given entity is not of the given class (i.e. a painting is - * not a creature) or if the information is simply not available, - * {@code null} will be returned. - *

- * Mutator methods on the returned instance should change the entity. - * - * @param entity the entity - * @param metaDataClass the metadata class for the returned instance - * @param the metadata class - * @return an instance of the given class, otherwise null - */ - @Nullable T getMetaData(Entity entity, Class metaDataClass); - - /** - * Attempt to return an instance of the given class for the given entity. - * For example, {@code getMetaData(entity, Creature.class)} might return - * an instance if the entity happens to be a creature. - *

- * If the given entity is not of the given class (i.e. a painting is - * not a creature) or if the information is simply not available, - * {@code null} will be returned. - *

- * Mutator methods on the returned instance should change the entity. - * - * @param entity the entity - * @param metaDataClass the metadata class for the returned instance - * @param the metadata class - * @return an instance of the given class, otherwise null - */ - @Nullable T getMetaData(BaseEntity entity, Class metaDataClass); - -} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java new file mode 100644 index 000000000..7448835cf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -0,0 +1,69 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockMaterial; + +import javax.annotation.Nullable; +import java.util.Map; + +/** + * Provides information on blocks and provides methods to create them. + */ +public interface BlockRegistry { + + /** + * Create a new block using its ID. + * + * @param id the id + * @return the block, which may be null if no block exists + */ + @Nullable + BaseBlock createFromId(String id); + + /** + * Create a new block using its legacy numeric ID. + * + * @param id the id + * @return the block, which may be null if no block exists + */ + @Nullable + BaseBlock createFromId(int id); + + /** + * Get the material for the given block. + * + * @param block the block + * @return the material, or null if the material information is not known + */ + @Nullable + BlockMaterial getMaterial(BaseBlock block); + + /** + * Get an unmodifiable map of states for this block. + * + * @param block the block + * @return a map of states where the key is the state's ID + */ + @Nullable + Map getStates(BaseBlock block); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java new file mode 100644 index 000000000..a111d2592 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -0,0 +1,189 @@ +/* + * 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.registry; + +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BlockMaterial; +import com.sk89q.worldedit.util.gson.VectorAdapter; +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Provides block data based on the built-in block database that is bundled + * with WorldEdit. + * + *

A new instance cannot be created. Use {@link #getInstance()} to get + * an instance.

+ * + *

The data is read from a JSON file that is bundled with WorldEdit. If + * reading fails (which occurs when this class is first instantiated), then + * the methods will return {@code null}s for all blocks.

+ */ +public class BundledBlockData { + + private static final Logger log = Logger.getLogger(BundledBlockData.class.getCanonicalName()); + private static final BundledBlockData INSTANCE = new BundledBlockData(); + + private final Map idMap = new HashMap(); + private final TIntObjectMap legacyMap = new TIntObjectHashMap(); + + /** + * Create a new instance. + */ + private BundledBlockData() { + try { + loadFromResource(); + } catch (IOException e) { + log.log(Level.WARNING, "Failed to load the built-in block registry", e); + } + } + + /** + * Attempt to load the data from file. + * + * @throws IOException thrown on I/O error + */ + private void loadFromResource() throws IOException { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Vector.class, new VectorAdapter()); + Gson gson = gsonBuilder.create(); + URL url = BundledBlockData.class.getResource("blocks.json"); + if (url == null) { + throw new IOException("Could not find blocks.json"); + } + String data = Resources.toString(url, Charset.defaultCharset()); + List entries = gson.fromJson(data, new TypeToken>() {}.getType()); + + for (BlockEntry entry : entries) { + entry.postDeserialization(); + idMap.put(entry.id, entry); + legacyMap.put(entry.legacyId, entry); + } + } + + /** + * Return the entry for the given block ID. + * + * @param id the ID + * @return the entry, or null + */ + @Nullable + private BlockEntry findById(String id) { + return idMap.get(id); + } + + /** + * Return the entry for the given block legacy numeric ID. + * + * @param id the ID + * @return the entry, or null + */ + @Nullable + private BlockEntry findById(int id) { + return legacyMap.get(id); + } + + /** + * Convert the given string ID to a legacy numeric ID. + * + * @param id the ID + * @return the legacy ID, which may be null if the block does not have a legacy ID + */ + @Nullable + public Integer toLegacyId(String id) { + BlockEntry entry = findById(id); + if (entry != null) { + return entry.legacyId; + } else { + return null; + } + } + + /** + * Get the material properties for the given block. + * + * @param id the legacy numeric ID + * @return the material's properties, or null + */ + @Nullable + public BlockMaterial getMaterialById(int id) { + BlockEntry entry = findById(id); + if (entry != null) { + return entry.material; + } else { + return null; + } + } + + /** + * Get the states for the given block. + * + * @param id the legacy numeric ID + * @return the block's states, or null if no information is available + */ + @Nullable + public Map getStatesById(int id) { + BlockEntry entry = findById(id); + if (entry != null) { + return entry.states; + } else { + return null; + } + } + + /** + * Get a singleton instance of this object. + * + * @return the instance + */ + public static BundledBlockData getInstance() { + return INSTANCE; + } + + private static class BlockEntry { + private int legacyId; + private String id; + private String unlocalizedName; + private List aliases; + private Map states = new HashMap(); + private SimpleBlockMaterial material = new SimpleBlockMaterial(); + + void postDeserialization() { + for (SimpleState state : states.values()) { + state.postDeserialization(); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/LegacyBlockRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/LegacyBlockRegistry.java new file mode 100644 index 000000000..e846e7984 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/LegacyBlockRegistry.java @@ -0,0 +1,63 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockMaterial; + +import javax.annotation.Nullable; +import java.util.Map; + +/** + * A block registry that uses {@link BundledBlockData} to serve information + * about blocks. + */ +public class LegacyBlockRegistry implements BlockRegistry { + + @Nullable + @Override + public BaseBlock createFromId(String id) { + Integer legacyId = BundledBlockData.getInstance().toLegacyId(id); + if (legacyId != null) { + return createFromId(legacyId); + } else { + return null; + } + } + + @Nullable + @Override + public BaseBlock createFromId(int id) { + return new BaseBlock(id); + } + + @Nullable + @Override + public BlockMaterial getMaterial(BaseBlock block) { + return BundledBlockData.getInstance().getMaterialById(block.getId()); + } + + @Nullable + @Override + public Map getStates(BaseBlock block) { + return BundledBlockData.getInstance().getStatesById(block.getId()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java b/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java new file mode 100644 index 000000000..21ce1ad0d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java @@ -0,0 +1,51 @@ +/* + * 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.registry; + +/** + * An implementation of {@link WorldData} that uses legacy numeric IDs and + * a built-in block database. + */ +public final class LegacyWorldData implements WorldData { + + private static final LegacyWorldData INSTANCE = new LegacyWorldData(); + private final LegacyBlockRegistry blockRegistry = new LegacyBlockRegistry(); + + /** + * Create a new instance. + */ + private LegacyWorldData() { + } + + @Override + public BlockRegistry getBlockRegistry() { + return blockRegistry; + } + + /** + * Get a singleton instance. + * + * @return an instance + */ + public static LegacyWorldData getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java new file mode 100644 index 000000000..7b190c740 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java @@ -0,0 +1,246 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.blocks.BlockMaterial; + +class SimpleBlockMaterial implements BlockMaterial { + + private boolean renderedAsNormalBlock; + private boolean fullCube; + private boolean opaque; + private boolean powerSource; + private boolean liquid; + private boolean solid; + private float hardness; + private float resistance; + private float slipperiness; + private boolean grassBlocking; + private float ambientOcclusionLightValue; + private int lightOpacity; + private int lightValue; + private boolean fragileWhenPushed; + private boolean unpushable; + private boolean adventureModeExempt; + private boolean ticksRandomly; + private boolean usingNeighborLight; + private boolean movementBlocker; + private boolean burnable; + private boolean toolRequired; + private boolean replacedDuringPlacement; + + @Override + public boolean isRenderedAsNormalBlock() { + return renderedAsNormalBlock; + } + + public void setRenderedAsNormalBlock(boolean renderedAsNormalBlock) { + this.renderedAsNormalBlock = renderedAsNormalBlock; + } + + @Override + public boolean isFullCube() { + return fullCube; + } + + public void setFullCube(boolean fullCube) { + this.fullCube = fullCube; + } + + @Override + public boolean isOpaque() { + return opaque; + } + + public void setOpaque(boolean opaque) { + this.opaque = opaque; + } + + @Override + public boolean isPowerSource() { + return powerSource; + } + + public void setPowerSource(boolean powerSource) { + this.powerSource = powerSource; + } + + @Override + public boolean isLiquid() { + return liquid; + } + + public void setLiquid(boolean liquid) { + this.liquid = liquid; + } + + @Override + public boolean isSolid() { + return solid; + } + + public void setSolid(boolean solid) { + this.solid = solid; + } + + @Override + public float getHardness() { + return hardness; + } + + public void setHardness(float hardness) { + this.hardness = hardness; + } + + @Override + public float getResistance() { + return resistance; + } + + public void setResistance(float resistance) { + this.resistance = resistance; + } + + @Override + public float getSlipperiness() { + return slipperiness; + } + + public void setSlipperiness(float slipperiness) { + this.slipperiness = slipperiness; + } + + @Override + public boolean isGrassBlocking() { + return grassBlocking; + } + + public void setGrassBlocking(boolean grassBlocking) { + this.grassBlocking = grassBlocking; + } + + @Override + public float getAmbientOcclusionLightValue() { + return ambientOcclusionLightValue; + } + + public void setAmbientOcclusionLightValue(float ambientOcclusionLightValue) { + this.ambientOcclusionLightValue = ambientOcclusionLightValue; + } + + @Override + public int getLightOpacity() { + return lightOpacity; + } + + public void setLightOpacity(int lightOpacity) { + this.lightOpacity = lightOpacity; + } + + @Override + public int getLightValue() { + return lightValue; + } + + public void setLightValue(int lightValue) { + this.lightValue = lightValue; + } + + @Override + public boolean isFragileWhenPushed() { + return fragileWhenPushed; + } + + public void setFragileWhenPushed(boolean fragileWhenPushed) { + this.fragileWhenPushed = fragileWhenPushed; + } + + @Override + public boolean isUnpushable() { + return unpushable; + } + + public void setUnpushable(boolean unpushable) { + this.unpushable = unpushable; + } + + @Override + public boolean isAdventureModeExempt() { + return adventureModeExempt; + } + + public void setAdventureModeExempt(boolean adventureModeExempt) { + this.adventureModeExempt = adventureModeExempt; + } + + @Override + public boolean isTicksRandomly() { + return ticksRandomly; + } + + public void setTicksRandomly(boolean ticksRandomly) { + this.ticksRandomly = ticksRandomly; + } + + @Override + public boolean isUsingNeighborLight() { + return usingNeighborLight; + } + + public void setUsingNeighborLight(boolean usingNeighborLight) { + this.usingNeighborLight = usingNeighborLight; + } + + @Override + public boolean isMovementBlocker() { + return movementBlocker; + } + + public void setMovementBlocker(boolean movementBlocker) { + this.movementBlocker = movementBlocker; + } + + @Override + public boolean isBurnable() { + return burnable; + } + + public void setBurnable(boolean burnable) { + this.burnable = burnable; + } + + @Override + public boolean isToolRequired() { + return toolRequired; + } + + public void setToolRequired(boolean toolRequired) { + this.toolRequired = toolRequired; + } + + @Override + public boolean isReplacedDuringPlacement() { + return replacedDuringPlacement; + } + + public void setReplacedDuringPlacement(boolean replacedDuringPlacement) { + this.replacedDuringPlacement = replacedDuringPlacement; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/SimpleState.java b/src/main/java/com/sk89q/worldedit/world/registry/SimpleState.java new file mode 100644 index 000000000..4cc78de9b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/SimpleState.java @@ -0,0 +1,71 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.blocks.BaseBlock; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Map; + +class SimpleState implements State { + + private Byte dataMask; + private Map values; + + @Override + public Map valueMap() { + return Collections.unmodifiableMap(values); + } + + @Nullable + @Override + public StateValue getValue(BaseBlock block) { + for (StateValue value : values.values()) { + if (value.isSet(block)) { + return value; + } + } + + return null; + } + + byte getDataMask() { + return dataMask != null ? dataMask : 0xF; + } + + @Override + public boolean hasDirection() { + for (SimpleStateValue value : values.values()) { + if (value.getDirection() != null) { + return true; + } + } + + return false; + } + + void postDeserialization() { + for (SimpleStateValue v : values.values()) { + v.setState(this); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/SimpleStateValue.java b/src/main/java/com/sk89q/worldedit/world/registry/SimpleStateValue.java new file mode 100644 index 000000000..791bc684a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/SimpleStateValue.java @@ -0,0 +1,55 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +class SimpleStateValue implements StateValue { + + private SimpleState state; + private Byte data; + private Vector direction; + + void setState(SimpleState state) { + this.state = state; + } + + @Override + public boolean isSet(BaseBlock block) { + return data != null && (block.getData() & state.getDataMask()) == data; + } + + @Override + public boolean set(BaseBlock block) { + if (data != null) { + block.setData((block.getData() & ~state.getDataMask()) | data); + return true; + } else { + return false; + } + } + + @Override + public Vector getDirection() { + return direction; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java b/src/main/java/com/sk89q/worldedit/world/registry/State.java similarity index 51% rename from src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java rename to src/main/java/com/sk89q/worldedit/world/registry/State.java index 3acd80ab4..a8cbfde3c 100644 --- a/src/main/java/com/sk89q/worldedit/world/mapping/Resolver.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/State.java @@ -17,40 +17,45 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.world.mapping; +package com.sk89q.worldedit.world.registry; import com.sk89q.worldedit.blocks.BaseBlock; import javax.annotation.Nullable; +import java.util.Map; /** - * A resolver can create state objects (such as {@link BaseBlock}) from - * universal identifiers, but also get the universal identifier for - * a given state object (at least when it is known). - *

- * Identifiers may be case-sensitive. Routines that work with IDs should - * not make changes to the casing of the IDs or perform case-insensitive - * comparisons. Implementations may normalize the casing of IDs if it - * is appropriate. + * Describes a state property of a block. * - * @param the type of state object + *

Example states include "variant" (indicating material or type) and + * "facing" (indicating orientation).

*/ -public interface Resolver { +public interface State { /** - * Create an instance of the state object from the given ID. + * Return a map of available values for this state. * - * @param id the ID - * @return an instance, otherwise null if an instance cannot be created + *

Keys are the value of state and map values describe that + * particular state value.

+ * + * @return the map of state values */ - @Nullable E create(String id); + Map valueMap(); /** - * Get the ID for the given object. + * Get the value that the block is set to. * - * @param object the object - * @return the ID, otherwise null if it is not known + * @param block the block + * @return the state, otherwise null if the block isn't set to any of the values */ - @Nullable String getId(E object); + @Nullable + StateValue getValue(BaseBlock block); + + /** + * Returns whether this state contains directional data. + * + * @return true if directional data is available + */ + boolean hasDirection(); } diff --git a/src/main/java/com/sk89q/worldedit/world/registry/StateValue.java b/src/main/java/com/sk89q/worldedit/world/registry/StateValue.java new file mode 100644 index 000000000..4e565cb19 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/StateValue.java @@ -0,0 +1,56 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import javax.annotation.Nullable; + +/** + * Describes a possible value for a {@code State}. + */ +public interface StateValue { + + /** + * Return whether this state is set on the given block. + * + * @param block the block + * @return true if this value is set + */ + boolean isSet(BaseBlock block); + + /** + * Set the state to this value on the given block. + * + * @param block the block to change + * @return true if the value was set successfully + */ + boolean set(BaseBlock block); + + /** + * Return the direction associated with this value. + * + * @return the direction, otherwise null + */ + @Nullable + Vector getDirection(); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java b/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java similarity index 64% rename from src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java rename to src/main/java/com/sk89q/worldedit/world/registry/WorldData.java index c59beefdb..38bbe2a0e 100644 --- a/src/main/java/com/sk89q/worldedit/world/mapping/NullResolver.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java @@ -17,28 +17,19 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.world.mapping; - -import javax.annotation.Nullable; +package com.sk89q.worldedit.world.registry; /** - * An implementation of a {@link Resolver} that knows nothing and returns - * {@code null} in all cases. - * - * @param the object to resolve + * Describes the necessary data for blocks, entities, and other objects + * on a world. */ -public class NullResolver implements Resolver { +public interface WorldData { - @Nullable - @Override - public E create(String id) { - return null; - } - - @Nullable - @Override - public String getId(E object) { - return null; - } + /** + * Get the block registry. + * + * @return the block registry + */ + BlockRegistry getBlockRegistry(); } diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json new file mode 100644 index 000000000..92410c465 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json @@ -0,0 +1,5968 @@ +[ + { + "legacyId": 0, + "id": "minecraft:air", + "unlocalizedName": "tile.air", + "material": { + "renderedAsNormalBlock": true, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 1, + "id": "minecraft:stone", + "unlocalizedName": "tile.stone", + "states": { + "variant": { + "values": { + "stone": { "data": 0 }, + "granite": { "data": 1 }, + "polished_granite": { "data": 2 }, + "diorite": { "data": 3 }, + "polished_diorite": { "data": 4 }, + "andesite": { "data": 5 }, + "polished_andesite": { "data": 6 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.5, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 2, + "id": "minecraft:grass", + "unlocalizedName": "tile.grass", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.6, + "resistance": 3.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 3, + "id": "minecraft:dirt", + "unlocalizedName": "tile.dirt", + "states": { + "variant": { + "values": { + "dirt": { "data": 0 }, + "coarse_dirt": { "data": 1 }, + "podzol": { "data": 2 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 4, + "id": "minecraft:cobblestone", + "unlocalizedName": "tile.stonebrick", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 5, + "id": "minecraft:planks", + "unlocalizedName": "tile.wood", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 6, + "id": "minecraft:sapling", + "unlocalizedName": "tile.sapling", + "states": { + "variant": { + "values": { + "oak": { "data": 0 }, + "spruce": { "data": 1 }, + "birch": { "data": 2 }, + "jungle": { "data": 3 }, + "acacia": { "data": 4 }, + "darkoak": { "data": 5 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 7, + "id": "minecraft:bedrock", + "unlocalizedName": "tile.bedrock", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": -1.0, + "resistance": 1.8E7, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 8, + "id": "minecraft:flowing_water", + "unlocalizedName": "tile.water", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": true, + "solid": false, + "hardness": 100.0, + "resistance": 500.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 3, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 9, + "id": "minecraft:water", + "unlocalizedName": "tile.water", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": true, + "solid": false, + "hardness": 100.0, + "resistance": 500.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 3, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 10, + "id": "minecraft:flowing_lava", + "unlocalizedName": "tile.lava", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": true, + "solid": false, + "hardness": 100.0, + "resistance": 500.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 15, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 11, + "id": "minecraft:lava", + "unlocalizedName": "tile.lava", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": true, + "solid": false, + "hardness": 100.0, + "resistance": 500.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 15, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 12, + "id": "minecraft:sand", + "unlocalizedName": "tile.sand", + "states": { + "variant": { + "values": { + "sand": { "data": 0 }, + "red_sand": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 13, + "id": "minecraft:gravel", + "unlocalizedName": "tile.gravel", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.6, + "resistance": 3.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 14, + "id": "minecraft:gold_ore", + "unlocalizedName": "tile.oreGold", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 15, + "id": "minecraft:iron_ore", + "unlocalizedName": "tile.oreIron", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 16, + "id": "minecraft:coal_ore", + "unlocalizedName": "tile.oreCoal", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 17, + "id": "minecraft:log", + "unlocalizedName": "tile.log", + "states": { + "variant": { + "dataMask": 3, + "values": { + "oak": { "data": 0 }, + "spruce": { "data": 1 }, + "birch": { "data": 2 }, + "jungle": { "data": 3 } + } + }, + "facing": { + "dataMask": 12, + "values": { + "up": { "data": 0, "direction": [0, 1, 0] }, + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 4, "direction": [1, 0, 0] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "north": { "data": 8, "direction": [0, 0, -1] }, + "south": { "data": 8, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 10.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 18, + "id": "minecraft:leaves", + "unlocalizedName": "tile.leaves", + "states": { + "variant": { + "dataMask": 3, + "values": { + "oak": { "data": 0 }, + "spruce": { "data": 1 }, + "birch": { "data": 2 }, + "jungle": { "data": 3 } + } + }, + "decay": { + "dataMask": 7, + "values": { + "no_decay": { "data": 4 }, + "decay": { "data": 0 } + } + }, + "check_decay": { + "dataMask": 12, + "values": { + "no_decay": { "data": 12 }, + "decay": { "data": 0 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 1, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 19, + "id": "minecraft:sponge", + "unlocalizedName": "tile.sponge", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.6, + "resistance": 3.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 20, + "id": "minecraft:glass", + "unlocalizedName": "tile.glass", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 21, + "id": "minecraft:lapis_ore", + "unlocalizedName": "tile.oreLapis", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 22, + "id": "minecraft:lapis_block", + "unlocalizedName": "tile.blockLapis", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 23, + "id": "minecraft:dispenser", + "unlocalizedName": "tile.dispenser", + "states": { + "facing": { + "dataMask": 7, + "values": { + "down": { "data": 0, "direction": [0, -1, 0] }, + "up": { "data": 1, "direction": [0, 1, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + }, + "powered": { + "dataMask": 8, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.5, + "resistance": 17.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 24, + "id": "minecraft:sandstone", + "unlocalizedName": "tile.sandStone", + "states": { + "variant": { + "values": { + "sandstone": { "data": 0 }, + "chiseled": { "data": 1 }, + "smooth": { "data": 2 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.8, + "resistance": 4.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 25, + "id": "minecraft:noteblock", + "unlocalizedName": "tile.musicBlock", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.8, + "resistance": 4.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 26, + "id": "minecraft:bed", + "unlocalizedName": "tile.bed", + "states": { + "facing": { + "dataMask": 3, + "values": { + "east": { "data": 3, "direction": [1, 0, 0] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 0, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 27, + "id": "minecraft:golden_rail", + "unlocalizedName": "tile.goldenRail", + "states": { + "facing": { + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "south": { "data": 1, "direction": [0, 0, 1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "east_ascending": { "data": 2, "direction": [1, 1, 0] }, + "east_descending": { "data": 2, "direction": [-1, -1, 0] }, + "west_ascending": { "data": 3, "direction": [-1, 1, 0] }, + "west_descending": { "data": 3, "direction": [1, -1, 0] }, + "north_ascending": { "data": 4, "direction": [0, 1, -1] }, + "north_descending": { "data": 4, "direction": [0, -1, 1] }, + "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "southeast": { "data": 6, "direction": [1, 0, 1] }, + "southwest": { "data": 7, "direction": [-1, 0, 1] }, + "northwest": { "data": 8, "direction": [-1, 0, -1] }, + "northeast": { "data": 9, "direction": [1, 0, -1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.7, + "resistance": 3.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 28, + "id": "minecraft:detector_rail", + "unlocalizedName": "tile.detectorRail", + "states": { + "facing": { + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "south": { "data": 1, "direction": [0, 0, 1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "east_ascending": { "data": 2, "direction": [1, 1, 0] }, + "east_descending": { "data": 2, "direction": [-1, -1, 0] }, + "west_ascending": { "data": 3, "direction": [-1, 1, 0] }, + "west_descending": { "data": 3, "direction": [1, -1, 0] }, + "north_ascending": { "data": 4, "direction": [0, 1, -1] }, + "north_descending": { "data": 4, "direction": [0, -1, 1] }, + "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "southeast": { "data": 6, "direction": [1, 0, 1] }, + "southwest": { "data": 7, "direction": [-1, 0, 1] }, + "northwest": { "data": 8, "direction": [-1, 0, -1] }, + "northeast": { "data": 9, "direction": [1, 0, -1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.7, + "resistance": 3.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 29, + "id": "minecraft:sticky_piston", + "unlocalizedName": "tile.pistonStickyBase", + "states": { + "facing": { + "dataMask": 7, + "values": { + "up": { "data": 1, "direction": [0, 1, 0] }, + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 30, + "id": "minecraft:web", + "unlocalizedName": "tile.web", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 4.0, + "resistance": 20.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 1, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": false, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 31, + "id": "minecraft:tallgrass", + "unlocalizedName": "tile.tallgrass", + "states": { + "variant": { + "values": { + "shrub": { "data": 0 }, + "grass": { "data": 1 }, + "fern": { "data": 2 }, + "biome_grass": { "data": 3 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 32, + "id": "minecraft:deadbush", + "unlocalizedName": "tile.deadbush", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 33, + "id": "minecraft:piston", + "unlocalizedName": "tile.pistonBase", + "states": { + "facing": { + "dataMask": 7, + "values": { + "up": { "data": 1, "direction": [0, 1, 0] }, + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 34, + "id": "minecraft:piston_head", + "unlocalizedName": "tile.null", + "states": { + "facing": { + "dataMask": 7, + "values": { + "up": { "data": 1, "direction": [0, 1, 0] }, + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 35, + "id": "minecraft:wool", + "unlocalizedName": "tile.cloth", + "states": { + "color": { + "values": { + "white": { "data": 0 }, + "orange": { "data": 1 }, + "magenta": { "data": 2 }, + "light_blue": { "data": 3 }, + "yellow": { "data": 4 }, + "lime": { "data": 5 }, + "pink": { "data": 6 }, + "gray": { "data": 7 }, + "light_gray": { "data": 8 }, + "cyan": { "data": 9 }, + "purple": { "data": 10 }, + "blue": { "data": 11 }, + "grown": { "data": 12 }, + "green": { "data": 13 }, + "red": { "data": 14 }, + "black": { "data": 15 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.8, + "resistance": 4.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 36, + "id": "minecraft:piston_extension", + "unlocalizedName": "tile.null", + "states": { + "facing": { + "dataMask": 7, + "values": { + "up": { "data": 1, "direction": [0, 1, 0] }, + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": -1.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 37, + "id": "minecraft:yellow_flower", + "unlocalizedName": "tile.flower1", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 38, + "id": "minecraft:red_flower", + "unlocalizedName": "tile.flower2", + "states": { + "variant": { + "values": { + "poppy": { "data": 0 }, + "blue_orchid": { "data": 1 }, + "allium": { "data": 2 }, + "azure_bluet": { "data": 3 }, + "red_tulip": { "data": 4 }, + "orange_tulip": { "data": 5 }, + "white_tulip": { "data": 6 }, + "pink_tulip": { "data": 7 }, + "oxyeye_daisy": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 39, + "id": "minecraft:brown_mushroom", + "unlocalizedName": "tile.mushroom", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 1, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 40, + "id": "minecraft:red_mushroom", + "unlocalizedName": "tile.mushroom", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 41, + "id": "minecraft:gold_block", + "unlocalizedName": "tile.blockGold", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 42, + "id": "minecraft:iron_block", + "unlocalizedName": "tile.blockIron", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 43, + "id": "minecraft:double_stone_slab", + "unlocalizedName": "tile.stoneSlab", + "states": { + "variant": { + "values": { + "stone": { "data": 0 }, + "sandstone": { "data": 1 }, + "wood": { "data": 2 }, + "cobble": { "data": 3 }, + "brick": { "data": 4 }, + "stoneBrick": { "data": 5 }, + "netherBrick": { "data": 6 }, + "quartz": { "data": 7 }, + "smoothStoneBrick": { "data": 8 }, + "smoothSandstone": { "data": 9 }, + "tileQuartz": { "data": 10 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 44, + "id": "minecraft:stone_slab", + "unlocalizedName": "tile.stoneSlab", + "states": { + "variant": { + "dataMask": 12, + "values": { + "stone": { "data": 0 }, + "sandstone": { "data": 1 }, + "wood": { "data": 2 }, + "cobble": { "data": 3 }, + "brick": { "data": 4 }, + "stoneBrick": { "data": 5 }, + "netherBrick": { "data": 6 }, + "quartz": { "data": 7 } + } + }, + "half": { + "dataMask": 8, + "values": { + "top": { "data": 0, "direction": [0, 1, 0] }, + "bottom": { "data": 8, "direction": [0, -1, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 45, + "id": "minecraft:brick_block", + "unlocalizedName": "tile.brick", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 46, + "id": "minecraft:tnt", + "unlocalizedName": "tile.tnt", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 47, + "id": "minecraft:bookshelf", + "unlocalizedName": "tile.bookshelf", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.5, + "resistance": 7.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 48, + "id": "minecraft:mossy_cobblestone", + "unlocalizedName": "tile.stoneMoss", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 49, + "id": "minecraft:obsidian", + "unlocalizedName": "tile.obsidian", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 50.0, + "resistance": 6000.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 50, + "id": "minecraft:torch", + "unlocalizedName": "tile.torch", + "states": { + "facing": { + "values": { + "east": { "data": 1, "direction": [1, 0, 0] }, + "west": { "data": 2, "direction": [-1, 0, 0] }, + "north": { "data": 3, "direction": [0, 0, -1] }, + "south": { "data": 4, "direction": [0, 0, 1] }, + "up": { "data": 5, "direction": [0, 1, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 14, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 51, + "id": "minecraft:fire", + "unlocalizedName": "tile.fire", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 15, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 52, + "id": "minecraft:mob_spawner", + "unlocalizedName": "tile.mobSpawner", + "material": { + "renderedAsNormalBlock": true, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 25.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 53, + "id": "minecraft:oak_stairs", + "unlocalizedName": "tile.stairsWood", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 54, + "id": "minecraft:chest", + "unlocalizedName": "tile.chest", + "states": { + "facing": { + "dataMask": 7, + "values": { + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.5, + "resistance": 12.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 55, + "id": "minecraft:redstone_wire", + "unlocalizedName": "tile.redstoneDust", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 56, + "id": "minecraft:diamond_ore", + "unlocalizedName": "tile.oreDiamond", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 57, + "id": "minecraft:diamond_block", + "unlocalizedName": "tile.blockDiamond", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 58, + "id": "minecraft:crafting_table", + "unlocalizedName": "tile.workbench", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.5, + "resistance": 12.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 59, + "id": "minecraft:wheat", + "unlocalizedName": "tile.crops", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 60, + "id": "minecraft:farmland", + "unlocalizedName": "tile.farmland", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.6, + "resistance": 3.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 61, + "id": "minecraft:furnace", + "unlocalizedName": "tile.furnace", + "states": { + "facing": { + "dataMask": 7, + "values": { + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.5, + "resistance": 17.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 62, + "id": "minecraft:lit_furnace", + "unlocalizedName": "tile.furnace", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.5, + "resistance": 17.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 13, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 63, + "id": "minecraft:standing_sign", + "unlocalizedName": "tile.sign", + "states": { + "facing": { + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "south_southwest": { "data": 1, "direction": [-0.3826, 0, 0.9238] }, + "southwest": { "data": 2, "direction": [-0.7071, 0, 0.7071] }, + "west_southwest": { "data": 3, "direction": [-0.9238, 0, 0.3826] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "west_northwest": { "data": 5, "direction": [-0.9238, 0, -0.3826] }, + "northwest": { "data": 6, "direction": [-0.7071, 0, -0.7071] }, + "north_northwest": { "data": 7, "direction": [-0.3826, 0, -0.9238] }, + "north": { "data": 8, "direction": [0, 0, -1] }, + "north_northeast": { "data": 9, "direction": [0.3826, 0, -0.9238] }, + "northeast": { "data": 10, "direction": [0.7071, 0, -0.7071] }, + "east_northeast": { "data": 11, "direction": [0.9238, 0, -0.3826] }, + "east": { "data": 12, "direction": [1, 0, 0] }, + "east_southeast": { "data": 13, "direction": [0.9238, 0, 0.3826] }, + "southeast": { "data": 14, "direction": [0.7071, 0, 0.7071] }, + "south_southeast": { "data": 15, "direction": [0.3826, 0, 0.9238] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.0, + "resistance": 5.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 64, + "id": "minecraft:wooden_door", + "unlocalizedName": "tile.doorWood", + "states": { + "half": { + "dataMask": 8, + "values": { + "bottom": { "data": 0 }, + "top": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 65, + "id": "minecraft:ladder", + "unlocalizedName": "tile.ladder", + "states": { + "facing": { + "dataMask": 7, + "values": { + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.4, + "resistance": 2.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 66, + "id": "minecraft:rail", + "unlocalizedName": "tile.rail", + "states": { + "facing": { + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "south": { "data": 1, "direction": [0, 0, 1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "east_ascending": { "data": 2, "direction": [1, 1, 0] }, + "east_descending": { "data": 2, "direction": [-1, -1, 0] }, + "west_ascending": { "data": 3, "direction": [-1, 1, 0] }, + "west_descending": { "data": 3, "direction": [1, -1, 0] }, + "north_ascending": { "data": 4, "direction": [0, 1, -1] }, + "north_descending": { "data": 4, "direction": [0, -1, 1] }, + "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "southeast": { "data": 6, "direction": [1, 0, 1] }, + "southwest": { "data": 7, "direction": [-1, 0, 1] }, + "northwest": { "data": 8, "direction": [-1, 0, -1] }, + "northeast": { "data": 9, "direction": [1, 0, -1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.7, + "resistance": 3.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 67, + "id": "minecraft:stone_stairs", + "unlocalizedName": "tile.stairsStone", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 68, + "id": "minecraft:wall_sign", + "unlocalizedName": "tile.sign", + "states": { + "facing": { + "dataMask": 7, + "values": { + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.0, + "resistance": 5.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 69, + "id": "minecraft:lever", + "unlocalizedName": "tile.lever", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 2, "direction": [-1, 0, 0] }, + "north": { "data": 4, "direction": [0, 0, -1] } + } + }, + "powered": { + "dataMask": 8, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 70, + "id": "minecraft:stone_pressure_plate", + "unlocalizedName": "tile.pressurePlate", + "states": { + "powered": { + "dataMask": 1, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 71, + "id": "minecraft:iron_door", + "unlocalizedName": "tile.doorIron", + "states": { + "half": { + "dataMask": 8, + "values": { + "bottom": { "data": 0 }, + "top": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 25.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 72, + "id": "minecraft:wooden_pressure_plate", + "unlocalizedName": "tile.pressurePlate", + "states": { + "powered": { + "dataMask": 1, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 73, + "id": "minecraft:redstone_ore", + "unlocalizedName": "tile.oreRedstone", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 74, + "id": "minecraft:lit_redstone_ore", + "unlocalizedName": "tile.oreRedstone", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 9, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 75, + "id": "minecraft:unlit_redstone_torch", + "unlocalizedName": "tile.notGate", + "states": { + "facing": { + "values": { + "east": { "data": 1, "direction": [1, 0, 0] }, + "west": { "data": 2, "direction": [-1, 0, 0] }, + "north": { "data": 3, "direction": [0, 0, -1] }, + "south": { "data": 4, "direction": [0, 0, 1] }, + "up": { "data": 5, "direction": [0, 1, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 76, + "id": "minecraft:redstone_torch", + "unlocalizedName": "tile.notGate", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 7, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 77, + "id": "minecraft:stone_button", + "unlocalizedName": "tile.button", + "states": { + "facing": { + "dataMask": 7, + "values": { + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] }, + "north": { "data": 4, "direction": [0, 0, -1] }, + "up": { "data": 5, "direction": [0, 1, 0] } + } + }, + "powered": { + "dataMask": 8, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 78, + "id": "minecraft:snow_layer", + "unlocalizedName": "tile.snow", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.1, + "resistance": 0.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 79, + "id": "minecraft:ice", + "unlocalizedName": "tile.ice", + "material": { + "renderedAsNormalBlock": true, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.98, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 3, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 80, + "id": "minecraft:snow", + "unlocalizedName": "tile.snow", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 81, + "id": "minecraft:cactus", + "unlocalizedName": "tile.cactus", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.4, + "resistance": 2.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 82, + "id": "minecraft:clay", + "unlocalizedName": "tile.clay", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.6, + "resistance": 3.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 83, + "id": "minecraft:reeds", + "unlocalizedName": "tile.reeds", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 84, + "id": "minecraft:jukebox", + "unlocalizedName": "tile.jukebox", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 85, + "id": "minecraft:fence", + "unlocalizedName": "tile.fence", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 86, + "id": "minecraft:pumpkin", + "unlocalizedName": "tile.pumpkin", + "states": { + "facing": { + "dataMask": 7, + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "east": { "data": 3, "direction": [1, 0, 0] }, + "none": { "data": 4 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.0, + "resistance": 5.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 87, + "id": "minecraft:netherrack", + "unlocalizedName": "tile.hellrock", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.4, + "resistance": 2.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 88, + "id": "minecraft:soul_sand", + "unlocalizedName": "tile.hellsand", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 89, + "id": "minecraft:glowstone", + "unlocalizedName": "tile.lightgem", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 15, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 90, + "id": "minecraft:portal", + "unlocalizedName": "tile.portal", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": -1.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 11, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 91, + "id": "minecraft:lit_pumpkin", + "unlocalizedName": "tile.litpumpkin", + "states": { + "facing": { + "dataMask": 7, + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "east": { "data": 3, "direction": [1, 0, 0] }, + "none": { "data": 4 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.0, + "resistance": 5.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 15, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 92, + "id": "minecraft:cake", + "unlocalizedName": "tile.cake", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 93, + "id": "minecraft:unpowered_repeater", + "unlocalizedName": "tile.diode", + "states": { + "facing": { + "dataMask": 3, + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 94, + "id": "minecraft:powered_repeater", + "unlocalizedName": "tile.diode", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 9, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 95, + "id": "minecraft:stained_glass", + "unlocalizedName": "tile.stainedGlass", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 96, + "id": "minecraft:trapdoor", + "unlocalizedName": "tile.trapdoor", + "states": { + "facing": { + "dataMask": 11, + "values": { + "south": { "data": 0, "direction": [0, 1, 1] }, + "north": { "data": 1, "direction": [0, 1, -1] }, + "east": { "data": 2, "direction": [1, 1, 0] }, + "west": { "data": 3, "direction": [-1, 1, 0] }, + "south_upper": { "data": 8, "direction": [0, -1, 1] }, + "north_upper": { "data": 9, "direction": [0, -1, -1] }, + "east_upper": { "data": 10, "direction": [1, -1, 0] }, + "west_upper": { "data": 11, "direction": [-1, -1, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 97, + "id": "minecraft:monster_egg", + "unlocalizedName": "tile.monsterStoneEgg", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.75, + "resistance": 3.75, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 98, + "id": "minecraft:stonebrick", + "unlocalizedName": "tile.stonebricksmooth", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.5, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 99, + "id": "minecraft:brown_mushroom_block", + "unlocalizedName": "tile.mushroom", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 100, + "id": "minecraft:red_mushroom_block", + "unlocalizedName": "tile.mushroom", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 101, + "id": "minecraft:iron_bars", + "unlocalizedName": "tile.fenceIron", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 102, + "id": "minecraft:glass_pane", + "unlocalizedName": "tile.thinGlass", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 103, + "id": "minecraft:melon_block", + "unlocalizedName": "tile.melon", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.0, + "resistance": 5.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 104, + "id": "minecraft:pumpkin_stem", + "unlocalizedName": "tile.pumpkinStem", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 105, + "id": "minecraft:melon_stem", + "unlocalizedName": "tile.pumpkinStem", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 106, + "id": "minecraft:vine", + "unlocalizedName": "tile.vine", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": true + } + }, + { + "legacyId": 107, + "id": "minecraft:fence_gate", + "unlocalizedName": "tile.fenceGate", + "states": { + "facing": { + "dataMask": 3, + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "east": { "data": 3, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 108, + "id": "minecraft:brick_stairs", + "unlocalizedName": "tile.stairsBrick", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 109, + "id": "minecraft:stone_brick_stairs", + "unlocalizedName": "tile.stairsStoneBrickSmooth", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.5, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 110, + "id": "minecraft:mycelium", + "unlocalizedName": "tile.mycel", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.6, + "resistance": 3.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 111, + "id": "minecraft:waterlily", + "unlocalizedName": "tile.waterlily", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 112, + "id": "minecraft:nether_brick", + "unlocalizedName": "tile.netherBrick", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 113, + "id": "minecraft:nether_brick_fence", + "unlocalizedName": "tile.netherFence", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 114, + "id": "minecraft:nether_brick_stairs", + "unlocalizedName": "tile.stairsNetherBrick", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 115, + "id": "minecraft:nether_wart", + "unlocalizedName": "tile.netherStalk", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 116, + "id": "minecraft:enchanting_table", + "unlocalizedName": "tile.enchantmentTable", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 6000.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 117, + "id": "minecraft:brewing_stand", + "unlocalizedName": "tile.brewingStand", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 1, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 118, + "id": "minecraft:cauldron", + "unlocalizedName": "tile.cauldron", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 10.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 119, + "id": "minecraft:end_portal", + "unlocalizedName": "tile.null", + "states": { + "facing": { + "dataMask": 3, + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "east": { "data": 3, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": -1.0, + "resistance": 1.8E7, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 15, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 120, + "id": "minecraft:end_portal_frame", + "unlocalizedName": "tile.endPortalFrame", + "material": { + "renderedAsNormalBlock": true, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": -1.0, + "resistance": 1.8E7, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 0, + "lightValue": 1, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 121, + "id": "minecraft:end_stone", + "unlocalizedName": "tile.whiteStone", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 45.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 122, + "id": "minecraft:dragon_egg", + "unlocalizedName": "tile.dragonEgg", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 45.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 1, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 123, + "id": "minecraft:redstone_lamp", + "unlocalizedName": "tile.redstoneLight", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 124, + "id": "minecraft:lit_redstone_lamp", + "unlocalizedName": "tile.redstoneLight", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 15, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 125, + "id": "minecraft:double_wooden_slab", + "unlocalizedName": "tile.woodSlab", + "states": { + "variant": { + "dataMask": 12, + "values": { + "oak": { "data": 0 }, + "spruce": { "data": 1 }, + "birch": { "data": 2 }, + "jungle": { "data": 3 }, + "acacia": { "data": 4 }, + "darkoak": { "data": 5 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 126, + "id": "minecraft:wooden_slab", + "unlocalizedName": "tile.woodSlab", + "states": { + "variant": { + "dataMask": 12, + "values": { + "oak": { "data": 0 }, + "spruce": { "data": 1 }, + "birch": { "data": 2 }, + "jungle": { "data": 3 }, + "acacia": { "data": 4 }, + "darkoak": { "data": 5 } + } + }, + "half": { + "dataMask": 8, + "values": { + "top": { "data": 0, "direction": [0, 1, 0] }, + "bottom": { "data": 8, "direction": [0, -1, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 127, + "id": "minecraft:cocoa", + "unlocalizedName": "tile.cocoa", + "states": { + "facing": { + "dataMask": 3, + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.2, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 128, + "id": "minecraft:sandstone_stairs", + "unlocalizedName": "tile.stairsSandStone", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.8, + "resistance": 4.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 129, + "id": "minecraft:emerald_ore", + "unlocalizedName": "tile.oreEmerald", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 130, + "id": "minecraft:ender_chest", + "unlocalizedName": "tile.enderChest", + "states": { + "facing": { + "dataMask": 7, + "values": { + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 22.5, + "resistance": 3000.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 7, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 131, + "id": "minecraft:tripwire_hook", + "unlocalizedName": "tile.tripWireSource", + "states": { + "facing": { + "dataMask": 3, + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "east": { "data": 3, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 132, + "id": "minecraft:tripwire", + "unlocalizedName": "tile.tripWire", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 133, + "id": "minecraft:emerald_block", + "unlocalizedName": "tile.blockEmerald", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 134, + "id": "minecraft:spruce_stairs", + "unlocalizedName": "tile.stairsWoodSpruce", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 135, + "id": "minecraft:birch_stairs", + "unlocalizedName": "tile.stairsWoodBirch", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 136, + "id": "minecraft:jungle_stairs", + "unlocalizedName": "tile.stairsWoodJungle", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 137, + "id": "minecraft:command_block", + "unlocalizedName": "tile.commandBlock", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": -1.0, + "resistance": 1.8E7, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 138, + "id": "minecraft:beacon", + "unlocalizedName": "tile.beacon", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 15, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 139, + "id": "minecraft:cobblestone_wall", + "unlocalizedName": "tile.cobbleWall", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 140, + "id": "minecraft:flower_pot", + "unlocalizedName": "tile.flowerPot", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 141, + "id": "minecraft:carrots", + "unlocalizedName": "tile.carrots", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 142, + "id": "minecraft:potatoes", + "unlocalizedName": "tile.potatoes", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 143, + "id": "minecraft:wooden_button", + "unlocalizedName": "tile.button", + "states": { + "facing": { + "dataMask": 7, + "values": { + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] }, + "north": { "data": 4, "direction": [0, 0, -1] }, + "up": { "data": 5, "direction": [0, 1, 0] } + } + }, + "powered": { + "dataMask": 8, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 144, + "id": "minecraft:skull", + "unlocalizedName": "tile.skull", + "states": { + "facing": { + "dataMask": 7, + "values": { + "down": { "data": 1, "direction": [0, -1, 0] }, + "up": { "data": 1, "direction": [0, 1, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "east": { "data": 4, "direction": [1, 0, 0] }, + "west": { "data": 5, "direction": [-1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 1.0, + "resistance": 5.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 145, + "id": "minecraft:anvil", + "unlocalizedName": "tile.anvil", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 6000.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": true, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 146, + "id": "minecraft:trapped_chest", + "unlocalizedName": "tile.chestTrap", + "states": { + "facing": { + "dataMask": 7, + "values": { + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 2.5, + "resistance": 12.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 147, + "id": "minecraft:light_weighted_pressure_plate", + "unlocalizedName": "tile.weightedPlate_light", + "states": { + "powered": { + "dataMask": 1, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 148, + "id": "minecraft:heavy_weighted_pressure_plate", + "unlocalizedName": "tile.weightedPlate_heavy", + "states": { + "powered": { + "dataMask": 1, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 1 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 149, + "id": "minecraft:unpowered_comparator", + "unlocalizedName": "tile.comparator", + "states": { + "facing": { + "dataMask": 3, + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 150, + "id": "minecraft:powered_comparator", + "unlocalizedName": "tile.comparator", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": true, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 9, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 151, + "id": "minecraft:daylight_detector", + "unlocalizedName": "tile.daylightDetector", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 152, + "id": "minecraft:redstone_block", + "unlocalizedName": "tile.blockRedstone", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": true, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 153, + "id": "minecraft:quartz_ore", + "unlocalizedName": "tile.netherquartz", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 154, + "id": "minecraft:hopper", + "unlocalizedName": "tile.hopper", + "states": { + "facing": { + "dataMask": 7, + "values": { + "down": { "data": 0, "direction": [0, -1, 0] }, + "up": { "data": 1, "direction": [0, 1, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + }, + "powered": { + "dataMask": 8, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.0, + "resistance": 24.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 155, + "id": "minecraft:quartz_block", + "unlocalizedName": "tile.quartzBlock", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.8, + "resistance": 4.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 156, + "id": "minecraft:quartz_stairs", + "unlocalizedName": "tile.stairsQuartz", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.8, + "resistance": 4.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 157, + "id": "minecraft:activator_rail", + "unlocalizedName": "tile.activatorRail", + "states": { + "facing": { + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "south": { "data": 1, "direction": [0, 0, 1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "east_ascending": { "data": 2, "direction": [1, 1, 0] }, + "east_descending": { "data": 2, "direction": [-1, -1, 0] }, + "west_ascending": { "data": 3, "direction": [-1, 1, 0] }, + "west_descending": { "data": 3, "direction": [1, -1, 0] }, + "north_ascending": { "data": 4, "direction": [0, 1, -1] }, + "north_descending": { "data": 4, "direction": [0, -1, 1] }, + "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "southeast": { "data": 6, "direction": [1, 0, 1] }, + "southwest": { "data": 7, "direction": [-1, 0, 1] }, + "northwest": { "data": 8, "direction": [-1, 0, -1] }, + "northeast": { "data": 9, "direction": [1, 0, -1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.7, + "resistance": 3.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 158, + "id": "minecraft:dropper", + "unlocalizedName": "tile.dropper", + "states": { + "facing": { + "dataMask": 7, + "values": { + "down": { "data": 0, "direction": [0, -1, 0] }, + "up": { "data": 1, "direction": [0, 1, 0] }, + "north": { "data": 2, "direction": [0, 0, -1] }, + "south": { "data": 3, "direction": [0, 0, 1] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "east": { "data": 5, "direction": [1, 0, 0] } + } + }, + "powered": { + "dataMask": 8, + "values": { + "unpowered": { "data": 0 }, + "powered": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 3.5, + "resistance": 17.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 159, + "id": "minecraft:stained_hardened_clay", + "unlocalizedName": "tile.clayHardenedStained", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.25, + "resistance": 21.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 160, + "id": "minecraft:stained_glass_pane", + "unlocalizedName": "tile.thinStainedGlass", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.3, + "resistance": 1.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 161, + "id": "minecraft:leaves2", + "unlocalizedName": "tile.leaves", + "states": { + "variant": { + "dataMask": 3, + "values": { + "acacia": { "data": 0 }, + "darkoak": { "data": 1 } + } + }, + "decay": { + "dataMask": 7, + "values": { + "no_decay": { "data": 4 }, + "decay": { "data": 0 } + } + }, + "check_decay": { + "dataMask": 12, + "values": { + "no_decay": { "data": 12 }, + "decay": { "data": 0 } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.2, + "resistance": 1.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 1, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": true, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 162, + "id": "minecraft:log2", + "unlocalizedName": "tile.log", + "states": { + "variant": { + "dataMask": 3, + "values": { + "acacia": { "data": 0 }, + "darkoak": { "data": 1 } + } + }, + "facing": { + "dataMask": 12, + "values": { + "up": { "data": 0, "direction": [0, 1, 0] }, + "down": { "data": 0, "direction": [0, -1, 0] }, + "east": { "data": 4, "direction": [1, 0, 0] }, + "west": { "data": 4, "direction": [-1, 0, 0] }, + "north": { "data": 8, "direction": [0, 0, -1] }, + "south": { "data": 8, "direction": [0, 0, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 10.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 163, + "id": "minecraft:acacia_stairs", + "unlocalizedName": "tile.stairsWoodAcacia", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 164, + "id": "minecraft:dark_oak_stairs", + "unlocalizedName": "tile.stairsWoodDarkOak", + "states": { + "facing": { + "dataMask": 7, + "values": { + "east": { "data": 4, "direction": [1, 1, 0] }, + "west": { "data": 5, "direction": [-1, 1, 0] }, + "north": { "data": 7, "direction": [0, 1, -1] }, + "south": { "data": 6, "direction": [0, 1, 1] }, + "east_upsidedown": { "data": 0, "direction": [1, -1, 0] }, + "west_upsidedown": { "data": 1, "direction": [-1, -1, 0] }, + "north_upsidedown": { "data": 3, "direction": [0, -1, -1] }, + "south_upsidedown": { "data": 2, "direction": [0, -1, 1] } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 2.0, + "resistance": 15.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": true, + "movementBlocker": true, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 170, + "id": "minecraft:hay_block", + "unlocalizedName": "tile.hayBlock", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 171, + "id": "minecraft:carpet", + "unlocalizedName": "tile.woolCarpet", + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.1, + "resistance": 0.5, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": true, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 172, + "id": "minecraft:hardened_clay", + "unlocalizedName": "tile.clayHardened", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 1.25, + "resistance": 21.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 173, + "id": "minecraft:coal_block", + "unlocalizedName": "tile.blockCoal", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 5.0, + "resistance": 30.0, + "slipperiness": 0.6, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": false, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": true, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 174, + "id": "minecraft:packed_ice", + "unlocalizedName": "tile.icePacked", + "material": { + "renderedAsNormalBlock": true, + "fullCube": true, + "opaque": true, + "powerSource": false, + "liquid": false, + "solid": true, + "hardness": 0.5, + "resistance": 2.5, + "slipperiness": 0.98, + "grassBlocking": false, + "ambientOcclusionLightValue": 0.2, + "lightOpacity": 255, + "lightValue": 0, + "fragileWhenPushed": false, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": false, + "usingNeighborLight": false, + "movementBlocker": true, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + }, + { + "legacyId": 175, + "id": "minecraft:double_plant", + "unlocalizedName": "tile.doublePlant", + "states": { + "variant": { + "dataMask": 7, + "values": { + "sunflower": { "data": 0 }, + "lilac": { "data": 1 }, + "double_tallgrass": { "data": 2 }, + "large_fern": { "data": 3 }, + "rose_bush": { "data": 4 }, + "peony": { "data": 5 } + } + }, + "half": { + "dataMask": 8, + "values": { + "top": { "data": 0 }, + "bottom": { "data": 8 } + } + } + }, + "material": { + "renderedAsNormalBlock": false, + "fullCube": false, + "opaque": false, + "powerSource": false, + "liquid": false, + "solid": false, + "hardness": 0.0, + "resistance": 0.0, + "slipperiness": 0.6, + "grassBlocking": true, + "ambientOcclusionLightValue": 1.0, + "lightOpacity": 0, + "lightValue": 0, + "fragileWhenPushed": true, + "unpushable": false, + "adventureModeExempt": true, + "ticksRandomly": true, + "usingNeighborLight": true, + "movementBlocker": false, + "burnable": false, + "toolRequired": false, + "replacedDuringPlacement": false + } + } +] \ No newline at end of file From 955a52825f405c247090f0c034c968497f0283bd Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 14:34:05 -0700 Subject: [PATCH 17/56] Flip direction of //rotate to have it match previous behavior. --- .../java/com/sk89q/worldedit/command/ClipboardCommands.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index bc6ed59e9..a2330ac06 100644 --- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -190,9 +190,9 @@ public class ClipboardCommands { ClipboardHolder holder = session.getClipboard(); AffineTransform transform = new AffineTransform(); - transform = transform.rotateY(Math.toRadians(yRotate != null ? yRotate : 0)); - transform = transform.rotateX(Math.toRadians(xRotate != null ? xRotate : 0)); - transform = transform.rotateZ(Math.toRadians(zRotate != null ? zRotate : 0)); + transform = transform.rotateY(-Math.toRadians(yRotate != null ? yRotate : 0)); + transform = transform.rotateX(-Math.toRadians(xRotate != null ? xRotate : 0)); + transform = transform.rotateZ(-Math.toRadians(zRotate != null ? zRotate : 0)); holder.setTransform(holder.getTransform().combine(transform)); player.print("The clipboard copy has been rotated."); } From 7b0e5a977fb0b83b0303f2a76d2792a95ac0893b Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 19:06:53 -0700 Subject: [PATCH 18/56] Move GZIPOutputStream out of NBTOutputStream. This is a breaking change with no clear symptoms at first. --- .../java/com/sk89q/jnbt/NBTOutputStream.java | 17 +---------------- .../schematic/MCEditSchematicFormat.java | 3 ++- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/sk89q/jnbt/NBTOutputStream.java b/src/main/java/com/sk89q/jnbt/NBTOutputStream.java index 7c440ef31..d9a56f666 100644 --- a/src/main/java/com/sk89q/jnbt/NBTOutputStream.java +++ b/src/main/java/com/sk89q/jnbt/NBTOutputStream.java @@ -24,21 +24,6 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; -import java.util.zip.GZIPOutputStream; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.EndTag; -import com.sk89q.jnbt.FloatTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; /** *

@@ -72,7 +57,7 @@ public final class NBTOutputStream implements Closeable { * if an I/O error occurs. */ public NBTOutputStream(OutputStream os) throws IOException { - this.os = new DataOutputStream(new GZIPOutputStream(os)); + this.os = new DataOutputStream(os); } /** diff --git a/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java b/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java index 77f0c7036..b3315b865 100644 --- a/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java +++ b/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; /** * @author zml2008 @@ -278,7 +279,7 @@ public class MCEditSchematicFormat extends SchematicFormat { // Build and output CompoundTag schematicTag = new CompoundTag("Schematic", schematic); - NBTOutputStream stream = new NBTOutputStream(new FileOutputStream(file)); + NBTOutputStream stream = new NBTOutputStream(new GZIPOutputStream(new FileOutputStream(file))); stream.writeTag(schematicTag); stream.close(); } From 47ad03a01325a26b2a914746318384ee145c1ff6 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 21:08:34 -0700 Subject: [PATCH 19/56] Add new Clipboard-compatible .schematic reader/writer. --- .../worldedit/command/SchematicCommands.java | 160 +++++++++--- .../extent/clipboard/io/ClipboardFormat.java | 178 +++++++++++++ .../extent/clipboard/io/ClipboardReader.java | 43 ++++ .../extent/clipboard/io/ClipboardWriter.java | 44 ++++ .../extent/clipboard/io/SchematicReader.java | 236 ++++++++++++++++++ .../extent/clipboard/io/SchematicWriter.java | 159 ++++++++++++ 6 files changed, 787 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 0b61d2ff9..24fe89cfe 100644 --- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -19,11 +19,14 @@ package com.sk89q.worldedit.command; +import com.google.common.io.Closer; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EmptyClipboardException; +import com.sk89q.worldedit.FilenameException; import com.sk89q.worldedit.FilenameResolutionException; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -31,12 +34,25 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.schematic.SchematicFormat; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.command.parametric.Optional; +import com.sk89q.worldedit.world.registry.WorldData; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.Arrays; import java.util.Comparator; +import java.util.logging.Level; +import java.util.logging.Logger; import static com.google.common.base.Preconditions.checkNotNull; @@ -45,6 +61,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class SchematicCommands { + private static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName()); private final WorldEdit worldEdit; /** @@ -58,36 +75,114 @@ public class SchematicCommands { } @Command( - aliases = { "load", "l" }, - usage = "[format] ", - desc = "Load a file into your clipboard", - help = "Load a schematic file into your clipboard\n" + - "Format is a format from \"//schematic formats\"\n" + - "If the format is not provided, WorldEdit will\n" + - "attempt to automatically detect the format of the schematic", - flags = "f", - min = 1, - max = 2 + aliases = { "load" }, + usage = "[] ", + desc = "Load a schematic into your clipboard", + min = 0, + max = 1 ) - @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) // TODO: Remove 'clipboard' perm - public void load(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { - // TODO: Update for new clipboard - throw new CommandException("Needs to be re-written again"); + @Deprecated + @CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load" }) + public void load(Player player, LocalSession session, @Optional("schematic") String formatName, String filename) throws FilenameException { + LocalConfiguration config = worldEdit.getConfiguration(); + + File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); + File f = worldEdit.getSafeOpenFile(player, dir, filename, "schematic", "schematic"); + + if (!f.exists()) { + player.printError("Schematic " + filename + " does not exist!"); + return; + } + + ClipboardFormat format = ClipboardFormat.findByAlias(formatName); + if (format == null) { + player.printError("Unknown schematic format: " + formatName); + return; + } + + Closer closer = Closer.create(); + try { + String filePath = f.getCanonicalPath(); + String dirPath = dir.getCanonicalPath(); + + if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { + player.printError("Clipboard file could not read or it does not exist."); + } else { + FileInputStream fis = closer.register(new FileInputStream(f)); + BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); + ClipboardReader reader = format.getReader(bis); + + WorldData worldData = player.getWorld().getWorldData(); + Clipboard clipboard = reader.read(player.getWorld().getWorldData()); + session.setClipboard(new ClipboardHolder(clipboard, worldData)); + + log.info(player.getName() + " loaded " + filePath); + player.print(filename + " loaded. Paste it with //paste"); + } + } catch (IOException e) { + player.printError("Schematic could not read or it does not exist: " + e.getMessage()); + log.log(Level.WARNING, "Failed to load a saved clipboard", e); + } finally { + try { + closer.close(); + } catch (IOException ignored) { + } + } } @Command( - aliases = { "save", "s" }, - usage = "[format] ", - desc = "Save your clipboard to file", - help = "Save your clipboard to file\n" + - "Format is a format from \"//schematic formats\"\n", - min = 1, - max = 2 + aliases = { "save" }, + usage = "[] ", + desc = "Save a schematic into your clipboard", + min = 0, + max = 1 ) - @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"}) // TODO: Remove 'clipboard' perm - public void save(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { - // TODO: Update for new clipboard - throw new CommandException("Needs to be re-written again"); + @Deprecated + @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) + public void save(Player player, LocalSession session, @Optional("schematic") String formatName, String filename) throws FilenameException, CommandException, EmptyClipboardException { + LocalConfiguration config = worldEdit.getConfiguration(); + + File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); + File f = worldEdit.getSafeSaveFile(player, dir, filename, "schematic", "schematic"); + + if (!f.exists()) { + player.printError("Schematic " + filename + " does not exist!"); + return; + } + + ClipboardFormat format = ClipboardFormat.findByAlias(formatName); + if (format == null) { + player.printError("Unknown schematic format: " + formatName); + return; + } + + ClipboardHolder holder = session.getClipboard(); + + Closer closer = Closer.create(); + try { + // Create parent directories + File parent = f.getParentFile(); + if (parent != null && !parent.exists()) { + if (!parent.mkdirs()) { + throw new CommandException("Could not create folder for schematics!"); + } + } + + FileOutputStream fos = closer.register(new FileOutputStream(f)); + BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); + ClipboardWriter writer = closer.register(format.getWriter(bos)); + writer.write(holder.getClipboard(), holder.getWorldData()); + log.info(player.getName() + " saved " + f.getCanonicalPath()); + player.print(filename + " saved."); + } catch (IOException e) { + player.printError("Schematic could not written: " + e.getMessage()); + log.log(Level.WARNING, "Failed to write a saved clipboard", e); + } finally { + try { + closer.close(); + } catch (IOException ignored) { + } + } } @Command( @@ -127,13 +222,13 @@ public class SchematicCommands { ) @CommandPermissions("worldedit.schematic.formats") public void formats(Actor actor) throws WorldEditException { - actor.print("Available schematic formats (Name: Lookup names)"); + actor.print("Available clipboard formats (Name: Lookup names)"); StringBuilder builder; boolean first = true; - for (SchematicFormat format : SchematicFormat.getFormats()) { + for (ClipboardFormat format : ClipboardFormat.values()) { builder = new StringBuilder(); - builder.append(format.getName()).append(": "); - for (String lookupName : format.getLookupNames()) { + builder.append(format.name()).append(": "); + for (String lookupName : format.getAliases()) { if (!first) { builder.append(", "); } @@ -204,9 +299,8 @@ public class SchematicCommands { } build.append("\n\u00a79"); - SchematicFormat format = SchematicFormat.getFormat(file); - build.append(prefix).append(file.getName()) - .append(": ").append(format == null ? "Unknown" : format.getName()); + ClipboardFormat format = ClipboardFormat.findByFile(file); + build.append(prefix).append(file.getName()).append(": ").append(format == null ? "Unknown" : format.name()); } return build.toString(); } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java new file mode 100644 index 000000000..460d23662 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -0,0 +1,178 @@ +/* + * 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.extent.clipboard.io; + +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; + +import javax.annotation.Nullable; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A collection of supported clipboard formats. + */ +public enum ClipboardFormat { + + /** + * The Schematic format used by many software. + */ + SCHEMATIC("mcedit", "mce", "schematic") { + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); + return new SchematicReader(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream)); + return new SchematicWriter(nbtStream); + } + + @Override + public boolean isFormat(File file) { + DataInputStream str = null; + try { + str = new DataInputStream(new GZIPInputStream(new FileInputStream(file))); + if ((str.readByte() & 0xFF) != NBTConstants.TYPE_COMPOUND) { + return false; + } + byte[] nameBytes = new byte[str.readShort() & 0xFFFF]; + str.readFully(nameBytes); + String name = new String(nameBytes, NBTConstants.CHARSET); + return name.equals("Schematic"); + } catch (IOException e) { + return false; + } finally { + if (str != null) { + try { + str.close(); + } catch (IOException ignored) { + } + } + } + } + }; + + private static final Map aliasMap = new HashMap(); + + private final String[] aliases; + + /** + * Create a new instance. + * + * @param aliases an array of aliases by which this format may be referred to + */ + private ClipboardFormat(String ... aliases) { + this.aliases = aliases; + } + + /** + * Get a set of aliases. + * + * @return a set of aliases + */ + public Set getAliases() { + return Collections.unmodifiableSet(new HashSet(Arrays.asList(aliases))); + } + + /** + * Create a reader. + * + * @param inputStream the input stream + * @return a reader + * @throws IOException thrown on I/O error + */ + public abstract ClipboardReader getReader(InputStream inputStream) throws IOException; + + /** + * Create a writer. + * + * @param outputStream the output stream + * @return a writer + * @throws IOException thrown on I/O error + */ + public abstract ClipboardWriter getWriter(OutputStream outputStream) throws IOException; + + /** + * Return whether the given file is of this format. + * + * @param file the file + * @return true if the given file is of this format + */ + public abstract boolean isFormat(File file); + + static { + for (ClipboardFormat format : EnumSet.allOf(ClipboardFormat.class)) { + for (String key : format.aliases) { + aliasMap.put(key, format); + } + } + } + + /** + * Find the clipboard format named by the given alias. + * + * @param alias the alias + * @return the format, otherwise null if none is matched + */ + @Nullable + public static ClipboardFormat findByAlias(String alias) { + checkNotNull(alias); + return aliasMap.get(alias.toLowerCase().trim()); + } + + /** + * Detect the format given a file. + * + * @param file the file + * @return the format, otherwise null if one cannot be detected + */ + @Nullable + public static ClipboardFormat findByFile(File file) { + checkNotNull(file); + + for (ClipboardFormat format : EnumSet.allOf(ClipboardFormat.class)) { + if (format.isFormat(file)) { + return format; + } + } + + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java new file mode 100644 index 000000000..ccb74ee5b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java @@ -0,0 +1,43 @@ +/* + * 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.extent.clipboard.io; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.world.registry.WorldData; + +import java.io.IOException; + +/** + * Reads {@code Clipboard}s. + * + * @see Clipboard + */ +public interface ClipboardReader { + + /** + * Read a {@code Clipboard}. + * + * @param data the world data space to convert the blocks to + * @return the read clipboard + * @throws IOException thrown on I/O error + */ + Clipboard read(WorldData data) throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java new file mode 100644 index 000000000..9f5dc307b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java @@ -0,0 +1,44 @@ +/* + * 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.extent.clipboard.io; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.world.registry.WorldData; + +import java.io.Closeable; +import java.io.IOException; + +/** + * Writes {@code Clipboard}s. + * + * @see Clipboard + */ +public interface ClipboardWriter extends Closeable { + + /** + * Writes a clipboard. + * + * @param clipboard the clipboard + * @param data the world data instance + * @throws IOException thrown on I/O error + */ + void write(Clipboard clipboard, WorldData data) throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java new file mode 100644 index 000000000..2f2e50a6c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java @@ -0,0 +1,236 @@ +/* + * 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.extent.clipboard.io; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.registry.WorldData; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Reads schematic files based that are compatible with MCEdit and other editors. + */ +public class SchematicReader implements ClipboardReader { + + private static final Logger log = Logger.getLogger(SchematicReader.class.getCanonicalName()); + private final NBTInputStream inputStream; + + /** + * Create a new instance. + * + * @param inputStream the input stream to read from + */ + public SchematicReader(NBTInputStream inputStream) { + checkNotNull(inputStream); + this.inputStream = inputStream; + } + + @Override + public Clipboard read(WorldData data) throws IOException { + // Schematic tag + CompoundTag schematicTag = (CompoundTag) inputStream.readTag(); + if (!schematicTag.getName().equals("Schematic")) { + throw new IOException("Tag 'Schematic' does not exist or is not first"); + } + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Blocks")) { + throw new IOException("Schematic file is missing a 'Blocks' tag"); + } + + // Check type of Schematic + String materials = getChildTag(schematic, "Materials", StringTag.class).getValue(); + if (!materials.equals("Alpha")) { + throw new IOException("Schematic file is not an Alpha schematic"); + } + + // Parse origin and region from WEOrigin and WEOffset + Vector origin; + Region region; + + // Get information + short width = getChildTag(schematic, "Width", ShortTag.class).getValue(); + short height = getChildTag(schematic, "Height", ShortTag.class).getValue(); + short length = getChildTag(schematic, "Length", ShortTag.class).getValue(); + + try { + int originX = getChildTag(schematic, "WEOriginX", IntTag.class).getValue(); + int originY = getChildTag(schematic, "WEOriginY", IntTag.class).getValue(); + int originZ = getChildTag(schematic, "WEOriginZ", IntTag.class).getValue(); + Vector min = new Vector(originX, originY, originZ); + + int offsetX = getChildTag(schematic, "WEOffsetX", IntTag.class).getValue(); + int offsetY = getChildTag(schematic, "WEOffsetY", IntTag.class).getValue(); + int offsetZ = getChildTag(schematic, "WEOffsetZ", IntTag.class).getValue(); + Vector offset = new Vector(offsetX, offsetY, offsetZ); + + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(Vector.ONE)); + } catch (IOException ignored) { + origin = new Vector(0, 0, 0); + region = new CuboidRegion(origin, origin.add(width, height, length).subtract(Vector.ONE)); + } + + // Get blocks + byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue(); + byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue(); + byte[] addId = new byte[0]; + short[] blocks = new short[blockId.length]; // Have to later combine IDs + + // We support 4096 block IDs using the same method as vanilla Minecraft, where + // the highest 4 bits are stored in a separate byte array. + if (schematic.containsKey("AddBlocks")) { + addId = getChildTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); + } + + // Combine the AddBlocks data with the first 8-bit block ID + for (int index = 0; index < blockId.length; index++) { + if ((index >> 1) >= addId.length) { // No corresponding AddBlocks index + blocks[index] = (short) (blockId[index] & 0xFF); + } else { + if ((index & 1) == 0) { + blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (blockId[index] & 0xFF)); + } else { + blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF)); + } + } + } + + // Need to pull out tile entities + List tileEntities = getChildTag(schematic, "TileEntities", ListTag.class).getValue(); + Map> tileEntitiesMap = new HashMap>(); + + for (Tag tag : tileEntities) { + if (!(tag instanceof CompoundTag)) continue; + CompoundTag t = (CompoundTag) tag; + + int x = 0; + int y = 0; + int z = 0; + + Map values = new HashMap(); + + for (Map.Entry entry : t.getValue().entrySet()) { + if (entry.getKey().equals("x")) { + if (entry.getValue() instanceof IntTag) { + x = ((IntTag) entry.getValue()).getValue(); + } + } else if (entry.getKey().equals("y")) { + if (entry.getValue() instanceof IntTag) { + y = ((IntTag) entry.getValue()).getValue(); + } + } else if (entry.getKey().equals("z")) { + if (entry.getValue() instanceof IntTag) { + z = ((IntTag) entry.getValue()).getValue(); + } + } + + values.put(entry.getKey(), entry.getValue()); + } + + BlockVector vec = new BlockVector(x, y, z); + tileEntitiesMap.put(vec, values); + } + + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); + + // Don't log a torrent of errors + int failedBlockSets = 0; + + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + for (int z = 0; z < length; ++z) { + int index = y * width * length + z * width + x; + BlockVector pt = new BlockVector(x, y, z); + BaseBlock block = new BaseBlock(blocks[index], blockData[index]); + + if (tileEntitiesMap.containsKey(pt)) { + block.setNbtData(new CompoundTag("", tileEntitiesMap.get(pt))); + } + + try { + clipboard.setBlock(region.getMinimumPoint().add(pt), block); + } catch (WorldEditException e) { + switch (failedBlockSets) { + case 0: + log.log(Level.WARNING, "Failed to set block on a Clipboard", e); + break; + case 1: + log.log(Level.WARNING, "Failed to set block on a Clipboard (again) -- no more messages will be logged", e); + break; + default: + } + + failedBlockSets++; + } + } + } + } + + return clipboard; + } + + /** + * Get child tag of a NBT structure. + * + * @param items The parent tag map + * @param key The name of the tag to get + * @param expected The expected type of the tag + * @return child tag casted to the expected type + * @throws IOException if the tag does not exist or the tag is not of the expected type + */ + private static T getChildTag(Map items, String key, Class expected) throws IOException { + if (!items.containsKey(key)) { + throw new IOException("Schematic file is missing a \"" + key + "\" tag"); + } + + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new IOException(key + " tag is not of tag type " + expected.getName()); + } + + return expected.cast(tag); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java new file mode 100644 index 000000000..b512afb2d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java @@ -0,0 +1,159 @@ +/* + * 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.extent.clipboard.io; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.registry.WorldData; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import static com.google.common.base.Preconditions.checkNotNull; + + /** + * Writes schematic files based that are compatible with MCEdit and other editors. + */ +public class SchematicWriter implements ClipboardWriter { + + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; + private final NBTOutputStream outputStream; + + /** + * Create a new schematic writer. + * + * @param outputStream the output stream to write to + */ + public SchematicWriter(NBTOutputStream outputStream) { + checkNotNull(outputStream); + this.outputStream = outputStream; + } + + @Override + public void write(Clipboard clipboard, WorldData data) throws IOException { + Region region = clipboard.getRegion(); + Vector origin = clipboard.getOrigin(); + Vector min = region.getMinimumPoint(); + Vector offset = min.subtract(origin); + int width = region.getWidth(); + int height = region.getHeight(); + int length = region.getLength(); + + if (width > MAX_SIZE) { + throw new IllegalArgumentException("Width of region too large for a .schematic"); + } + if (height > MAX_SIZE) { + throw new IllegalArgumentException("Height of region too large for a .schematic"); + } + if (length > MAX_SIZE) { + throw new IllegalArgumentException("Length of region too large for a .schematic"); + } + + HashMap schematic = new HashMap(); + schematic.put("Width", new ShortTag("Width", (short) width)); + schematic.put("Length", new ShortTag("Length", (short) length)); + schematic.put("Height", new ShortTag("Height", (short) height)); + schematic.put("Materials", new StringTag("Materials", "Alpha")); + schematic.put("WEOriginX", new IntTag("WEOriginX", min.getBlockX())); + schematic.put("WEOriginY", new IntTag("WEOriginY", min.getBlockY())); + schematic.put("WEOriginZ", new IntTag("WEOriginZ", min.getBlockZ())); + schematic.put("WEOffsetX", new IntTag("WEOffsetX", offset.getBlockX())); + schematic.put("WEOffsetY", new IntTag("WEOffsetY", offset.getBlockY())); + schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", offset.getBlockZ())); + + // Copy + byte[] blocks = new byte[width * height * length]; + byte[] addBlocks = null; + byte[] blockData = new byte[width * height * length]; + ArrayList tileEntities = new ArrayList(); + + for (Vector point : region) { + Vector relative = point.subtract(min); + int x = relative.getBlockX(); + int y = relative.getBlockY(); + int z = relative.getBlockZ(); + + int index = y * width * length + z * width + x; + BaseBlock block = clipboard.getBlock(point); + + // Save 4096 IDs in an AddBlocks section + if (block.getType() > 255) { + if (addBlocks == null) { // Lazily create section + addBlocks = new byte[(blocks.length >> 1) + 1]; + } + + addBlocks[index >> 1] = (byte) (((index & 1) == 0) ? + addBlocks[index >> 1] & 0xF0 | (block.getType() >> 8) & 0xF + : addBlocks[index >> 1] & 0xF | ((block.getType() >> 8) & 0xF) << 4); + } + + blocks[index] = (byte) block.getType(); + blockData[index] = (byte) block.getData(); + + // Store TileEntity data + CompoundTag rawTag = block.getNbtData(); + if (rawTag != null) { + Map values = new HashMap(); + for (Entry entry : rawTag.getValue().entrySet()) { + values.put(entry.getKey(), entry.getValue()); + } + + values.put("id", new StringTag("id", block.getNbtId())); + values.put("x", new IntTag("x", x)); + values.put("y", new IntTag("y", y)); + values.put("z", new IntTag("z", z)); + + CompoundTag tileEntityTag = new CompoundTag("TileEntity", values); + tileEntities.add(tileEntityTag); + } + } + + schematic.put("Blocks", new ByteArrayTag("Blocks", blocks)); + schematic.put("Data", new ByteArrayTag("Data", blockData)); + schematic.put("Entities", new ListTag("Entities", CompoundTag.class, new ArrayList())); + schematic.put("TileEntities", new ListTag("TileEntities", CompoundTag.class, tileEntities)); + + if (addBlocks != null) { + schematic.put("AddBlocks", new ByteArrayTag("AddBlocks", addBlocks)); + } + + // Build and output + CompoundTag schematicTag = new CompoundTag("Schematic", schematic); + outputStream.writeTag(schematicTag); + } + + @Override + public void close() throws IOException { + outputStream.close(); + } + } From 932513d8a1cba7150a8dccf4b19201308432d715 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 21:44:44 -0700 Subject: [PATCH 20/56] Add Transform.isIdentity(). --- .../worldedit/math/transform/AffineTransform.java | 1 + .../worldedit/math/transform/CombinedTransform.java | 11 +++++++++++ .../com/sk89q/worldedit/math/transform/Identity.java | 5 +++++ .../com/sk89q/worldedit/math/transform/Transform.java | 9 +++++++++ 4 files changed, 26 insertions(+) diff --git a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index eecdcc6cc..fe1709fa4 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -109,6 +109,7 @@ public class AffineTransform implements Transform { // =================================================================== // accessors + @Override public boolean isIdentity() { if (m00 != 1) return false; diff --git a/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java index 84b1a474b..eab410b99 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java @@ -54,6 +54,17 @@ public class CombinedTransform implements Transform { this(transforms.toArray(new Transform[checkNotNull(transforms).size()])); } + @Override + public boolean isIdentity() { + for (Transform transform : transforms) { + if (!transform.isIdentity()) { + return false; + } + } + + return true; + } + @Override public Vector apply(Vector vector) { for (Transform transform : transforms) { diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Identity.java b/src/main/java/com/sk89q/worldedit/math/transform/Identity.java index a5f22038d..cac70ba36 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/Identity.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/Identity.java @@ -26,6 +26,11 @@ import com.sk89q.worldedit.Vector; */ public class Identity implements Transform { + @Override + public boolean isIdentity() { + return true; + } + @Override public Vector apply(Vector vector) { return vector; diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Transform.java b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java index cb3109879..b8df8bcbd 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/Transform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java @@ -26,6 +26,15 @@ import com.sk89q.worldedit.Vector; */ public interface Transform { + /** + * Return whether this transform is an identity. + * + *

If it is not known, then {@code false} must be returned.

+ * + * @return true if identity + */ + boolean isIdentity(); + /** * Returns the result of applying the function to the input. * From 2bbf5d2793f10bee98a87b7aa19d3a143a550d51 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 22:04:17 -0700 Subject: [PATCH 21/56] /schematic save should not check if the file exists. --- .../worldedit/command/SchematicCommands.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 24fe89cfe..9987e388f 100644 --- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -25,7 +25,6 @@ import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.FilenameException; import com.sk89q.worldedit.FilenameResolutionException; import com.sk89q.worldedit.LocalConfiguration; @@ -34,10 +33,14 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.CuboidClipboardTransform; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.registry.WorldData; @@ -139,17 +142,12 @@ public class SchematicCommands { ) @Deprecated @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) - public void save(Player player, LocalSession session, @Optional("schematic") String formatName, String filename) throws FilenameException, CommandException, EmptyClipboardException { + public void save(Player player, LocalSession session, @Optional("schematic") String formatName, String filename) throws CommandException, WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); File f = worldEdit.getSafeSaveFile(player, dir, filename, "schematic", "schematic"); - if (!f.exists()) { - player.printError("Schematic " + filename + " does not exist!"); - return; - } - ClipboardFormat format = ClipboardFormat.findByAlias(formatName); if (format == null) { player.printError("Unknown schematic format: " + formatName); @@ -157,6 +155,19 @@ public class SchematicCommands { } ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + Transform transform = holder.getTransform(); + Clipboard target; + + // If we have a transform, we have to make a copy so we can save + // this transformed copy + if (!transform.isIdentity()) { + CuboidClipboardTransform result = CuboidClipboardTransform.transform(clipboard, transform, holder.getWorldData()); + target = new BlockArrayClipboard(result.getTransformedRegion()); + Operations.completeLegacy(result.copyTo(target)); + } else { + target = clipboard; + } Closer closer = Closer.create(); try { @@ -171,7 +182,7 @@ public class SchematicCommands { FileOutputStream fos = closer.register(new FileOutputStream(f)); BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); ClipboardWriter writer = closer.register(format.getWriter(bos)); - writer.write(holder.getClipboard(), holder.getWorldData()); + writer.write(target, holder.getWorldData()); log.info(player.getName() + " saved " + f.getCanonicalPath()); player.print(filename + " saved."); } catch (IOException e) { From 9aec81c8c68f01e389da7e423d35b5bcde26cdbd Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 22:51:17 -0700 Subject: [PATCH 22/56] Change /schematic save to bake in the transform. --- .../command/FlattenedClipboardTransform.java | 143 ++++++++++++++++++ .../worldedit/command/SchematicCommands.java | 7 +- 2 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java diff --git a/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java new file mode 100644 index 000000000..70adc7803 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java @@ -0,0 +1,143 @@ +/* + * 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.command; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.math.transform.CombinedTransform; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.registry.WorldData; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper class to 'bake' a transform into a clipboard. + * + *

This class needs a better name and may need to be made more generic.

+ * + * @see Clipboard + * @see Transform + */ +class FlattenedClipboardTransform { + + private final Clipboard original; + private final Transform transform; + private final WorldData worldData; + + /** + * Create a new instance. + * + * @param original the original clipboard + * @param transform the transform + * @param worldData the world data instance + */ + private FlattenedClipboardTransform(Clipboard original, Transform transform, WorldData worldData) { + checkNotNull(original); + checkNotNull(transform); + checkNotNull(worldData); + this.original = original; + this.transform = transform; + this.worldData = worldData; + } + + /** + * Get the transformed region. + * + * @return the transformed region + */ + public Region getTransformedRegion() { + Region region = original.getRegion(); + Vector minimum = region.getMinimumPoint(); + Vector maximum = region.getMaximumPoint(); + + Transform transformAround = + new CombinedTransform( + new AffineTransform().translate(original.getOrigin().multiply(-1)), + transform, + new AffineTransform().translate(original.getOrigin())); + + Vector[] corners = new Vector[] { + minimum, + maximum, + minimum.setX(maximum.getX()), + minimum.setY(maximum.getY()), + minimum.setZ(maximum.getZ()), + maximum.setX(minimum.getX()), + maximum.setY(minimum.getY()), + maximum.setZ(minimum.getZ()) }; + + for (int i = 0; i < corners.length; i++) { + corners[i] = transformAround.apply(corners[i]); + } + + Vector newMinimum = corners[0]; + Vector newMaximum = corners[0]; + + for (int i = 1; i < corners.length; i++) { + newMinimum = Vector.getMinimum(newMinimum, corners[i]); + newMaximum = Vector.getMaximum(newMaximum, corners[i]); + } + + // After transformation, the points may not really sit on a block, + // so we should expand the region for edge cases + newMinimum = newMinimum.setX(Math.floor(newMinimum.getX())); + newMinimum = newMinimum.setY(Math.floor(newMinimum.getY())); + newMinimum = newMinimum.setZ(Math.floor(newMinimum.getZ())); + + newMaximum = newMaximum.setX(Math.ceil(newMaximum.getX())); + newMaximum = newMaximum.setY(Math.ceil(newMaximum.getY())); + newMaximum = newMaximum.setZ(Math.ceil(newMaximum.getZ())); + + return new CuboidRegion(newMinimum, newMaximum); + } + + /** + * Create an operation to copy from the original clipboard to the given extent. + * + * @param target the target + * @return the operation + */ + public Operation copyTo(Extent target) { + BlockTransformExtent extent = new BlockTransformExtent(original, transform, worldData.getBlockRegistry()); + ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin()); + copy.setTransform(transform); + return copy; + } + + /** + * Create a new instance to bake the transform with. + * + * @param original the original clipboard + * @param transform the transform + * @param worldData the world data instance + * @return a builder + */ + public static FlattenedClipboardTransform transform(Clipboard original, Transform transform, WorldData worldData) { + return new FlattenedClipboardTransform(original, transform, worldData); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 9987e388f..5bc20440c 100644 --- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -35,7 +35,6 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.CuboidClipboardTransform; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; @@ -159,11 +158,11 @@ public class SchematicCommands { Transform transform = holder.getTransform(); Clipboard target; - // If we have a transform, we have to make a copy so we can save - // this transformed copy + // If we have a transform, bake it into the copy if (!transform.isIdentity()) { - CuboidClipboardTransform result = CuboidClipboardTransform.transform(clipboard, transform, holder.getWorldData()); + FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform, holder.getWorldData()); target = new BlockArrayClipboard(result.getTransformedRegion()); + target.setOrigin(clipboard.getOrigin()); Operations.completeLegacy(result.copyTo(target)); } else { target = clipboard; From 708b38312c4b158539aa0400fa1a8699c2ed7d3b Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 9 Jul 2014 22:55:10 -0700 Subject: [PATCH 23/56] Closer isn't available in the Guava version that Bukkit bundles. --- .../worldedit/command/SchematicCommands.java | 2 +- .../com/sk89q/worldedit/util/io/Closer.java | 233 ++++++++++++++++++ 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/sk89q/worldedit/util/io/Closer.java diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 5bc20440c..ae1243ccf 100644 --- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.command; -import com.google.common.io.Closer; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; @@ -41,6 +40,7 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.registry.WorldData; diff --git a/src/main/java/com/sk89q/worldedit/util/io/Closer.java b/src/main/java/com/sk89q/worldedit/util/io/Closer.java new file mode 100644 index 000000000..2e733c6ab --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/Closer.java @@ -0,0 +1,233 @@ +/* + * 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.util.io; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Throwables; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class Closer implements Closeable { + + private static final Logger logger = Logger.getLogger(Closer.class.getCanonicalName()); + + /** + * The suppressor implementation to use for the current Java version. + */ + private static final Suppressor SUPPRESSOR = SuppressingSuppressor.isAvailable() + ? SuppressingSuppressor.INSTANCE + : LoggingSuppressor.INSTANCE; + + /** + * Creates a new {@link Closer}. + */ + public static Closer create() { + return new Closer(SUPPRESSOR); + } + + @VisibleForTesting + final Suppressor suppressor; + + // only need space for 2 elements in most cases, so try to use the smallest array possible + private final Deque stack = new ArrayDeque(4); + private Throwable thrown; + + @VisibleForTesting Closer(Suppressor suppressor) { + this.suppressor = checkNotNull(suppressor); // checkNotNull to satisfy null tests + } + + /** + * Registers the given {@code closeable} to be closed when this {@code Closer} is + * {@linkplain #close closed}. + * + * @return the given {@code closeable} + */ + // close. this word no longer has any meaning to me. + public C register(C closeable) { + stack.push(closeable); + return closeable; + } + + /** + * Stores the given throwable and rethrows it. It will be rethrown as is if it is an + * {@code IOException}, {@code RuntimeException} or {@code Error}. Otherwise, it will be rethrown + * wrapped in a {@code RuntimeException}. Note: Be sure to declare all of the checked + * exception types your try block can throw when calling an overload of this method so as to avoid + * losing the original exception type. + * + *

This method always throws, and as such should be called as + * {@code throw closer.rethrow(e);} to ensure the compiler knows that it will throw. + * + * @return this method does not return; it always throws + * @throws IOException when the given throwable is an IOException + */ + public RuntimeException rethrow(Throwable e) throws IOException { + thrown = e; + Throwables.propagateIfPossible(e, IOException.class); + throw Throwables.propagate(e); + } + + /** + * Stores the given throwable and rethrows it. It will be rethrown as is if it is an + * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of the + * given type. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. Note: + * Be sure to declare all of the checked exception types your try block can throw when calling an + * overload of this method so as to avoid losing the original exception type. + * + *

This method always throws, and as such should be called as + * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw. + * + * @return this method does not return; it always throws + * @throws IOException when the given throwable is an IOException + * @throws X when the given throwable is of the declared type X + */ + public RuntimeException rethrow(Throwable e, + Class declaredType) throws IOException, X { + thrown = e; + Throwables.propagateIfPossible(e, IOException.class); + Throwables.propagateIfPossible(e, declaredType); + throw Throwables.propagate(e); + } + + /** + * Stores the given throwable and rethrows it. It will be rethrown as is if it is an + * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of either + * of the given types. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. + * Note: Be sure to declare all of the checked exception types your try block can throw + * when calling an overload of this method so as to avoid losing the original exception type. + * + *

This method always throws, and as such should be called as + * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw. + * + * @return this method does not return; it always throws + * @throws IOException when the given throwable is an IOException + * @throws X1 when the given throwable is of the declared type X1 + * @throws X2 when the given throwable is of the declared type X2 + */ + public RuntimeException rethrow( + Throwable e, Class declaredType1, Class declaredType2) throws IOException, X1, X2 { + thrown = e; + Throwables.propagateIfPossible(e, IOException.class); + Throwables.propagateIfPossible(e, declaredType1, declaredType2); + throw Throwables.propagate(e); + } + + /** + * Closes all {@code Closeable} instances that have been added to this {@code Closer}. If an + * exception was thrown in the try block and passed to one of the {@code exceptionThrown} methods, + * any exceptions thrown when attempting to close a closeable will be suppressed. Otherwise, the + * first exception to be thrown from an attempt to close a closeable will be thrown and any + * additional exceptions that are thrown after that will be suppressed. + */ + @Override + public void close() throws IOException { + Throwable throwable = thrown; + + // close closeables in LIFO order + while (!stack.isEmpty()) { + Closeable closeable = stack.pop(); + try { + closeable.close(); + } catch (Throwable e) { + if (throwable == null) { + throwable = e; + } else { + suppressor.suppress(closeable, throwable, e); + } + } + } + + if (thrown == null && throwable != null) { + Throwables.propagateIfPossible(throwable, IOException.class); + throw new AssertionError(throwable); // not possible + } + } + + /** + * Suppression strategy interface. + */ + @VisibleForTesting interface Suppressor { + /** + * Suppresses the given exception ({@code suppressed}) which was thrown when attempting to close + * the given closeable. {@code thrown} is the exception that is actually being thrown from the + * method. Implementations of this method should not throw under any circumstances. + */ + void suppress(Closeable closeable, Throwable thrown, Throwable suppressed); + } + + /** + * Suppresses exceptions by logging them. + */ + @VisibleForTesting static final class LoggingSuppressor implements Suppressor { + + static final LoggingSuppressor INSTANCE = new LoggingSuppressor(); + + @Override + public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { + // log to the same place as Closeables + logger.log(Level.WARNING, "Suppressing exception thrown when closing " + closeable, suppressed); + } + } + + /** + * Suppresses exceptions by adding them to the exception that will be thrown using JDK7's + * addSuppressed(Throwable) mechanism. + */ + @VisibleForTesting static final class SuppressingSuppressor implements Suppressor { + + static final SuppressingSuppressor INSTANCE = new SuppressingSuppressor(); + + static boolean isAvailable() { + return addSuppressed != null; + } + + static final Method addSuppressed = getAddSuppressed(); + + private static Method getAddSuppressed() { + try { + return Throwable.class.getMethod("addSuppressed", Throwable.class); + } catch (Throwable e) { + return null; + } + } + + @Override + public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { + // ensure no exceptions from addSuppressed + if (thrown == suppressed) { + return; + } + try { + addSuppressed.invoke(thrown, suppressed); + } catch (Throwable e) { + // if, somehow, IllegalAccessException or another exception is thrown, fall back to logging + LoggingSuppressor.INSTANCE.suppress(closeable, thrown, suppressed); + } + } + } +} From 4f5e130b59347a6be694aac0711cbc4f890e50de Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 01:19:08 -0700 Subject: [PATCH 24/56] Add -p to /br clipboard to paste using origin of clipboard. Closes WORLDEDIT-2825. --- .../com/sk89q/worldedit/command/BrushCommands.java | 13 ++++++------- .../command/tool/brush/ClipboardBrush.java | 6 ++++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 8520cdfdf..6f3d65062 100644 --- a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -46,7 +46,6 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; @@ -132,16 +131,16 @@ public class BrushCommands { @Command( aliases = { "clipboard", "copy" }, usage = "", - flags = "a", desc = "Choose the clipboard brush", help = "Chooses the clipboard brush.\n" + - "The -a flag makes it not paste air.", - min = 0, - max = 0 + "The -a flag makes it not paste air.\n" + + "Without the -p flag, the paste will appear centered at the target location. " + + "With the flag, then the paste will appear relative to where you had " + + "stood relative to the copied area when you copied it." ) @CommandPermissions("worldedit.brush.clipboard") - public void clipboardBrush(Player player, LocalSession session, EditSession editSession, @Switch('a') boolean ignoreAir) throws WorldEditException { + public void clipboardBrush(Player player, LocalSession session, EditSession editSession, @Switch('a') boolean ignoreAir, @Switch('p') boolean usingOrigin) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); @@ -152,7 +151,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(size.getBlockZ()); BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setBrush(new ClipboardBrush(holder, ignoreAir), "worldedit.brush.clipboard"); + tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin), "worldedit.brush.clipboard"); player.print("Clipboard brush shape equipped."); } diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java index a5692265e..7f772239d 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -33,10 +33,12 @@ public class ClipboardBrush implements Brush { private ClipboardHolder holder; private boolean ignoreAirBlocks; + private boolean usingOrigin; - public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks) { + public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin) { this.holder = holder; this.ignoreAirBlocks = ignoreAirBlocks; + this.usingOrigin = usingOrigin; } @Override @@ -47,7 +49,7 @@ public class ClipboardBrush implements Brush { Operation operation = holder .createPaste(editSession, editSession.getWorld().getWorldData()) - .to(pos.subtract(centerOffset)) + .to(usingOrigin ? pos : pos.subtract(centerOffset)) .ignoreAirBlocks(ignoreAirBlocks) .build(); From e5959383c53b48c517cb1bfbeda45ec928315038 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 01:34:05 -0700 Subject: [PATCH 25/56] Fix /schematic load and save not taking 2 arguments. --- .../com/sk89q/worldedit/command/SchematicCommands.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index ae1243ccf..67e8ba20f 100644 --- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -79,9 +79,7 @@ public class SchematicCommands { @Command( aliases = { "load" }, usage = "[] ", - desc = "Load a schematic into your clipboard", - min = 0, - max = 1 + desc = "Load a schematic into your clipboard" ) @Deprecated @CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load" }) @@ -135,9 +133,7 @@ public class SchematicCommands { @Command( aliases = { "save" }, usage = "[] ", - desc = "Save a schematic into your clipboard", - min = 0, - max = 1 + desc = "Save a schematic into your clipboard" ) @Deprecated @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) From bd0e20e8a78154b93dd73d08c4546fe71fc39d0d Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 02:58:04 -0700 Subject: [PATCH 26/56] Have Extent.createEntity() take a Vector rather than a Location. --- .../java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 2 +- .../java/com/sk89q/worldedit/forge/ForgeWorld.java | 3 +-- src/main/java/com/sk89q/worldedit/EditSession.java | 4 ++-- .../worldedit/extent/AbstractDelegateExtent.java | 6 ++---- src/main/java/com/sk89q/worldedit/extent/Extent.java | 5 ++--- .../java/com/sk89q/worldedit/extent/NullExtent.java | 3 +-- .../extent/clipboard/BlockArrayClipboard.java | 4 ++-- .../sk89q/worldedit/internal/LocalWorldAdapter.java | 4 ++-- .../java/com/sk89q/worldedit/world/NullWorld.java | 11 ++++++++--- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 72a774ede..3a02fb266 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -233,7 +233,7 @@ public class BukkitWorld extends LocalWorld { @Nullable @Override - public com.sk89q.worldedit.entity.Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + public com.sk89q.worldedit.entity.Entity createEntity(Vector position, BaseEntity entity) { throw new UnsupportedOperationException("Not implemented yet"); } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 5087799a7..ad826f6c4 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -33,7 +33,6 @@ import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.registry.LegacyWorldData; @@ -510,7 +509,7 @@ public class ForgeWorld extends AbstractWorld { @Nullable @Override - public Entity createEntity(Location location, BaseEntity entity) { + public Entity createEntity(Vector position, BaseEntity entity) { World world = getWorld(); net.minecraft.entity.Entity createdEntity = EntityList.createEntityByName(entity.getTypeId(), world); if (createdEntity != null) { diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 7ad6b867f..1de0cfcd9 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -589,8 +589,8 @@ public class EditSession implements Extent { @Override @Nullable - public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { - return world.createEntity(location, entity); + public Entity createEntity(Vector position, BaseEntity entity) { + return world.createEntity(position, entity); } /** diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 666c33872..445eeeebc 100644 --- a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -26,10 +26,8 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; -import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; - import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -77,8 +75,8 @@ public abstract class AbstractDelegateExtent implements Extent { @Override @Nullable - public Entity createEntity(Location location, BaseEntity entity) { - return extent.createEntity(location, entity); + public Entity createEntity(Vector position, BaseEntity entity) { + return extent.createEntity(position, entity); } @Override diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java index 14bacb425..2048ca007 100644 --- a/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; import java.util.List; @@ -70,10 +69,10 @@ public interface Extent extends InputExtent, OutputExtent { /** * Create an entity at the given location. * + * @param position the position * @param entity the entity - * @param location the location * @return a reference to the created entity, or null if the entity could not be created */ - @Nullable Entity createEntity(Location location, BaseEntity entity); + @Nullable Entity createEntity(Vector position, BaseEntity entity); } diff --git a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index 5f8f84644..a24f4cf48 100644 --- a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -25,7 +25,6 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; import java.util.Collections; @@ -56,7 +55,7 @@ public class NullExtent implements Extent { @Nullable @Override - public Entity createEntity(Location location, BaseEntity entity) { + public Entity createEntity(Vector position, BaseEntity entity) { return null; } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 5c40d42e2..29a66372a 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -99,8 +99,8 @@ public class BlockArrayClipboard implements Clipboard { @Nullable @Override - public Entity createEntity(Location location, BaseEntity entity) { - ClipboardEntity ret = new ClipboardEntity(location, entity); + public Entity createEntity(Vector position, BaseEntity entity) { + ClipboardEntity ret = new ClipboardEntity(new Location(this, position), entity); entities.add(ret); return ret; } diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index dd04767b5..30e7e00db 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -330,8 +330,8 @@ public class LocalWorldAdapter extends LocalWorld { @Override @Nullable - public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { - return world.createEntity(location, entity); + public Entity createEntity(Vector position, BaseEntity entity) { + return world.createEntity(position, entity); } @Override diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 937ba9c3b..b65aecd98 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -19,14 +19,19 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EntityType; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.WorldData; @@ -116,7 +121,7 @@ public class NullWorld extends AbstractWorld { @Nullable @Override - public Entity createEntity(Location location, BaseEntity entity) { + public Entity createEntity(Vector position, BaseEntity entity) { return null; } } From d50cd89005477f5508bc747d04a57304ff2fc1c4 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 02:59:09 -0700 Subject: [PATCH 27/56] Add Entity visitor and function interfaces. --- .../worldedit/function/EntityFunction.java | 39 ++++++++++ .../function/visitor/EntityVisitor.java | 78 +++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/main/java/com/sk89q/worldedit/function/EntityFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java diff --git a/src/main/java/com/sk89q/worldedit/function/EntityFunction.java b/src/main/java/com/sk89q/worldedit/function/EntityFunction.java new file mode 100644 index 000000000..f7048cd1a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/EntityFunction.java @@ -0,0 +1,39 @@ +/* + * 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.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; + +/** + * Applies a function to entities. + */ +public interface EntityFunction { + + /** + * Apply the function to the entity. + * + * @param entity the entity + * @return true if something was changed + * @throws WorldEditException thrown on an error + */ + public boolean apply(Entity entity) throws WorldEditException; + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java new file mode 100644 index 000000000..14509bd8c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java @@ -0,0 +1,78 @@ +/* + * 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.function.visitor; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; + +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits entities as provided by an {@code Iterator}. + */ +public class EntityVisitor implements Operation { + + private final Iterator iterator; + private final EntityFunction function; + private int affected = 0; + + /** + * Create a new instance. + * + * @param iterator the iterator + * @param function the function + */ + public EntityVisitor(Iterator iterator, EntityFunction function) { + checkNotNull(iterator); + checkNotNull(function); + this.iterator = iterator; + this.function = function; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + while (iterator.hasNext()) { + if (function.apply(iterator.next())) { + affected++; + } + } + + return null; + } + + @Override + public void cancel() { + } + +} From c564278dd6a0ae59434361361527d6299b898945 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 14:50:40 -0700 Subject: [PATCH 28/56] Revert Extent.createEntity() taking a Vector. --- .../java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 2 +- .../java/com/sk89q/worldedit/forge/ForgeWorld.java | 3 ++- src/main/java/com/sk89q/worldedit/EditSession.java | 4 ++-- .../worldedit/extent/AbstractDelegateExtent.java | 6 ++++-- src/main/java/com/sk89q/worldedit/extent/Extent.java | 5 +++-- .../java/com/sk89q/worldedit/extent/NullExtent.java | 3 ++- .../extent/clipboard/BlockArrayClipboard.java | 4 ++-- .../sk89q/worldedit/internal/LocalWorldAdapter.java | 4 ++-- .../java/com/sk89q/worldedit/world/NullWorld.java | 11 +++-------- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 3a02fb266..72a774ede 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -233,7 +233,7 @@ public class BukkitWorld extends LocalWorld { @Nullable @Override - public com.sk89q.worldedit.entity.Entity createEntity(Vector position, BaseEntity entity) { + public com.sk89q.worldedit.entity.Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { throw new UnsupportedOperationException("Not implemented yet"); } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index ad826f6c4..5087799a7 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.registry.LegacyWorldData; @@ -509,7 +510,7 @@ public class ForgeWorld extends AbstractWorld { @Nullable @Override - public Entity createEntity(Vector position, BaseEntity entity) { + public Entity createEntity(Location location, BaseEntity entity) { World world = getWorld(); net.minecraft.entity.Entity createdEntity = EntityList.createEntityByName(entity.getTypeId(), world); if (createdEntity != null) { diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 1de0cfcd9..7ad6b867f 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -589,8 +589,8 @@ public class EditSession implements Extent { @Override @Nullable - public Entity createEntity(Vector position, BaseEntity entity) { - return world.createEntity(position, entity); + public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + return world.createEntity(location, entity); } /** diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 445eeeebc..666c33872 100644 --- a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -26,8 +26,10 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; + import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -75,8 +77,8 @@ public abstract class AbstractDelegateExtent implements Extent { @Override @Nullable - public Entity createEntity(Vector position, BaseEntity entity) { - return extent.createEntity(position, entity); + public Entity createEntity(Location location, BaseEntity entity) { + return extent.createEntity(location, entity); } @Override diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java index 2048ca007..14bacb425 100644 --- a/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; import java.util.List; @@ -69,10 +70,10 @@ public interface Extent extends InputExtent, OutputExtent { /** * Create an entity at the given location. * - * @param position the position * @param entity the entity + * @param location the location * @return a reference to the created entity, or null if the entity could not be created */ - @Nullable Entity createEntity(Vector position, BaseEntity entity); + @Nullable Entity createEntity(Location location, BaseEntity entity); } diff --git a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index a24f4cf48..5f8f84644 100644 --- a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; import java.util.Collections; @@ -55,7 +56,7 @@ public class NullExtent implements Extent { @Nullable @Override - public Entity createEntity(Vector position, BaseEntity entity) { + public Entity createEntity(Location location, BaseEntity entity) { return null; } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 29a66372a..5c40d42e2 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -99,8 +99,8 @@ public class BlockArrayClipboard implements Clipboard { @Nullable @Override - public Entity createEntity(Vector position, BaseEntity entity) { - ClipboardEntity ret = new ClipboardEntity(new Location(this, position), entity); + public Entity createEntity(Location location, BaseEntity entity) { + ClipboardEntity ret = new ClipboardEntity(location, entity); entities.add(ret); return ret; } diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index 30e7e00db..dd04767b5 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -330,8 +330,8 @@ public class LocalWorldAdapter extends LocalWorld { @Override @Nullable - public Entity createEntity(Vector position, BaseEntity entity) { - return world.createEntity(position, entity); + public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + return world.createEntity(location, entity); } @Override diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index b65aecd98..937ba9c3b 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -19,19 +19,14 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.WorldData; @@ -121,7 +116,7 @@ public class NullWorld extends AbstractWorld { @Nullable @Override - public Entity createEntity(Vector position, BaseEntity entity) { + public Entity createEntity(Location location, BaseEntity entity) { return null; } } From ceec170be9dcb47f36ba30a335704e8b5cd77e33 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 15:49:34 -0700 Subject: [PATCH 29/56] Change Location to store pitch/yaw rather than a directional vector. --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 8 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 23 ++-- .../sk89q/worldedit/forge/ForgePlayer.java | 9 +- .../com/sk89q/worldedit/util/Location.java | 106 +++++++++++++++--- .../com/sk89q/worldedit/util/Vectors.java | 65 ----------- 5 files changed, 110 insertions(+), 101 deletions(-) delete mode 100644 src/main/java/com/sk89q/worldedit/util/Vectors.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 3fba70a8e..f949510f1 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.Vectors; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; @@ -76,8 +75,11 @@ final class BukkitAdapter { public static Location adapt(org.bukkit.Location location) { checkNotNull(location); Vector position = BukkitUtil.toVector(location); - Vector direction = Vectors.fromEulerDeg(location.getYaw(), location.getPitch()); - return new com.sk89q.worldedit.util.Location(adapt(location.getWorld()), position, direction); + return new com.sk89q.worldedit.util.Location( + adapt(location.getWorld()), + position, + (float) Math.toRadians(location.getYaw()), + (float) Math.toRadians(location.getPitch())); } /** diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 1fcaf1c1d..22a659abf 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -19,23 +19,21 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.util.Vectors; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - import com.sk89q.util.StringUtil; import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.cui.CUIEvent; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; public class BukkitPlayer extends LocalPlayer { private Player player; @@ -180,7 +178,10 @@ public class BukkitPlayer extends LocalPlayer { public com.sk89q.worldedit.util.Location getLocation() { Location nativeLocation = player.getLocation(); Vector position = BukkitUtil.toVector(nativeLocation); - Vector direction = Vectors.fromEulerDeg(nativeLocation.getYaw(), nativeLocation.getPitch()); - return new com.sk89q.worldedit.util.Location(getWorld(), position, direction); + return new com.sk89q.worldedit.util.Location( + getWorld(), + position, + (float) Math.toRadians(nativeLocation.getYaw()), + (float) Math.toRadians(nativeLocation.getPitch())); } } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java index 6a07c1ff8..d1ce05924 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.forge; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVector; import com.sk89q.worldedit.entity.BaseEntity; @@ -29,7 +28,6 @@ import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.LocalWorldAdapter; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.Vectors; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.Packet250CustomPayload; @@ -59,8 +57,11 @@ public class ForgePlayer extends LocalPlayer { @Override public Location getLocation() { Vector position = new Vector(this.player.posX, this.player.posY, this.player.posZ); - Vector direction = Vectors.fromEulerDeg(this.player.cameraYaw, this.player.cameraPitch); - return new Location(ForgeWorldEdit.inst.getWorld(this.player.worldObj), position, direction); + return new Location( + ForgeWorldEdit.inst.getWorld(this.player.worldObj), + position, + (float) Math.toRadians(this.player.cameraYaw), + (float) Math.toRadians(this.player.cameraPitch)); } public WorldVector getPosition() { diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java index d6ee8c468..0bc45e592 100644 --- a/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/src/main/java/com/sk89q/worldedit/util/Location.java @@ -38,7 +38,8 @@ public class Location { private final Extent extent; private final Vector position; - private final Vector direction; + private final float pitch; + private final float yaw; /** * Create a new instance in the given extent at 0, 0, 0 with a @@ -88,6 +89,21 @@ public class Location { this(extent, new Vector(x, y, z), direction); } + /** + * Create a new instance in the given extent with the given coordinates + * and the given direction vector. + * + * @param extent the extent + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @param yaw the yaw, in radians + * @param pitch the pitch, in radians + */ + public Location(Extent extent, double x, double y, double z, float yaw, float pitch) { + this(extent, new Vector(x, y, z), yaw, pitch); + } + /** * Create a new instance in the given extent with the given position vector * and the given direction vector. @@ -97,12 +113,26 @@ public class Location { * @param direction the direction vector */ public Location(Extent extent, Vector position, Vector direction) { + this(extent, position, 0, 0); + this.setDirection(direction); + } + + /** + * Create a new instance in the given extent with the given position vector + * and the given direction vector. + * + * @param extent the extent + * @param position the position vector + * @param yaw the yaw, in radians + * @param pitch the pitch, in radians + */ + public Location(Extent extent, Vector position, float yaw, float pitch) { checkNotNull(extent); checkNotNull(position); - checkNotNull(direction); this.extent = extent; this.position = position; - this.direction = direction; + this.pitch = pitch; + this.yaw = yaw; } /** @@ -125,15 +155,36 @@ public class Location { } /** - * Get the direction. - *

- * The direction vector may be a null vector. It may or may not - * be a unit vector. + * Get the yaw in radians. * - * @return the direction + * @return the yaw in radians + */ + public float getYaw() { + return yaw; + } + + /** + * Get the pitch in radians. + * + * @return the pitch in radians + */ + public float getPitch() { + return pitch; + } + + /** + * Get the direction vector. + * + * @return the direction vector */ public Vector getDirection() { - return direction; + double yaw = this.getYaw(); + double pitch = this.getPitch(); + double xz = Math.cos(pitch); + return new Vector( + -xz * Math.sin(yaw), + -Math.sin(pitch), + xz * Math.cos(yaw)); } /** @@ -143,7 +194,24 @@ public class Location { * @return the new instance */ public Location setDirection(Vector direction) { - return new Location(extent, position, direction); + double x = direction.getX(); + double z = direction.getZ(); + + if (x == 0 && z == 0) { + float pitch = direction.getY() > 0 ? -90 : 90; + return new Location(extent, position, 0, pitch); + } else { + double t = Math.atan2(-x, z); + double x2 = x * x; + double z2 = z * z; + double xz = Math.sqrt(x2 + z2); + double _2pi = 2 * Math.PI; + + float pitch = (float) Math.atan(-direction.getY() / xz); + float yaw = (float) ((t + _2pi) % _2pi); + + return new Location(extent, position, yaw, pitch); + } } /** @@ -181,7 +249,7 @@ public class Location { * @return a new immutable instance */ public Location setX(double x) { - return new Location(extent, position.setX(x), direction); + return new Location(extent, position.setX(x), yaw, pitch); } /** @@ -192,7 +260,7 @@ public class Location { * @return a new immutable instance */ public Location setX(int x) { - return new Location(extent, position.setX(x), direction); + return new Location(extent, position.setX(x), yaw, pitch); } /** @@ -221,7 +289,7 @@ public class Location { * @return a new immutable instance */ public Location setY(double y) { - return new Location(extent, position.setY(y), direction); + return new Location(extent, position.setY(y), yaw, pitch); } /** @@ -232,7 +300,7 @@ public class Location { * @return a new immutable instance */ public Location setY(int y) { - return new Location(extent, position.setY(y), direction); + return new Location(extent, position.setY(y), yaw, pitch); } /** @@ -261,7 +329,7 @@ public class Location { * @return a new immutable instance */ public Location setZ(double z) { - return new Location(extent, position.setZ(z), direction); + return new Location(extent, position.setZ(z), yaw, pitch); } /** @@ -272,7 +340,7 @@ public class Location { * @return a new immutable instance */ public Location setZ(int z) { - return new Location(extent, position.setZ(z), direction); + return new Location(extent, position.setZ(z), yaw, pitch); } @Override @@ -282,7 +350,8 @@ public class Location { Location location = (Location) o; - if (!direction.equals(location.direction)) return false; + if (Double.doubleToLongBits(pitch) != Double.doubleToLongBits(location.pitch)) return false; + if (Double.doubleToLongBits(yaw) != Double.doubleToLongBits(location.yaw)) return false; if (!position.equals(location.position)) return false; if (!extent.equals(location.extent)) return false; @@ -293,7 +362,8 @@ public class Location { public int hashCode() { int result = extent.hashCode(); result = 31 * result + position.hashCode(); - result = 31 * result + direction.hashCode(); + result = 31 * result + Float.floatToIntBits(this.pitch); + result = 31 * result + Float.floatToIntBits(this.yaw); return result; } diff --git a/src/main/java/com/sk89q/worldedit/util/Vectors.java b/src/main/java/com/sk89q/worldedit/util/Vectors.java deleted file mode 100644 index 277bf9c3d..000000000 --- a/src/main/java/com/sk89q/worldedit/util/Vectors.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.util; - -import com.sk89q.worldedit.Vector; - -/** - * Utility methods for {@link Vector}s. - */ -public final class Vectors { - - private Vectors() { - } - - /** - * Create a new {@link Vector} using Euler angles specified in degrees, - * but with no roll. - * - * @param yaw the yaw - * @param pitch the pitch - * @return a new {@link Vector} - */ - public static Vector fromEulerDeg(double yaw, double pitch) { - final double yawRadians = Math.toRadians(yaw); - final double pitchRadians = Math.toRadians(pitch); - return fromEulerRad(yawRadians, pitchRadians); - } - - /** - * Create a new {@link Vector} using Euler angles specified in radians, - * but with no roll. - * - * @param yaw the yaw - * @param pitch the pitch - * @return a new {@link Vector} - */ - public static Vector fromEulerRad(double yaw, double pitch) { - final double y = -Math.sin(pitch); - - final double h = Math.cos(pitch); - - final double x = -h * Math.sin(yaw); - final double z = h * Math.cos(yaw); - - return new Vector(x, y, z); - } - -} From 52f1a7d2d453dd5846e567d2e8f4302f65f23234 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 21:05:16 -0700 Subject: [PATCH 30/56] Fix issue with scaling transforms on blocks. --- .../sk89q/worldedit/extent/transform/BlockTransformExtent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index cf9e9d85e..a0d5ad090 100644 --- a/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -155,7 +155,7 @@ public class BlockTransformExtent extends AbstractDelegateExtent { */ @Nullable private static StateValue getNewStateValue(State state, Transform transform, Vector oldDirection) { - Vector newDirection = transform.apply(oldDirection).normalize(); + Vector newDirection = transform.apply(oldDirection).subtract(transform.apply(Vector.ZERO)).normalize(); StateValue newValue = null; double closest = -2; boolean found = false; From 0ce7954dc9512c69a6e7621425eeb7438e15e1f3 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 10 Jul 2014 22:22:35 -0700 Subject: [PATCH 31/56] Add support for copying entities between Extents. --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 43 +++-- .../sk89q/worldedit/forge/ForgeEntity.java | 42 ++++- .../com/sk89q/worldedit/forge/ForgeWorld.java | 40 ++++- .../java/com/sk89q/worldedit/EditSession.java | 18 +- src/main/java/com/sk89q/worldedit/Vector.java | 35 ++++ .../extent/AbstractDelegateExtent.java | 8 +- .../worldedit/extent/ChangeSetExtent.java | 72 ++++++++ .../com/sk89q/worldedit/extent/Extent.java | 14 +- .../sk89q/worldedit/extent/NullExtent.java | 6 + .../extent/clipboard/BlockArrayClipboard.java | 16 +- .../function/entity/ExtentEntityCopy.java | 103 ++++++++++++ .../function/operation/ForwardExtentCopy.java | 42 ++++- .../function/visitor/EntityVisitor.java | 4 +- .../history/change/EntityCreate.java | 68 ++++++++ .../history/change/EntityRemove.java | 65 +++++++ .../worldedit/internal/LocalWorldAdapter.java | 12 +- .../internal/helper/MCDirections.java | 62 +++++++ .../com/sk89q/worldedit/util/Direction.java | 159 ++++++++++++++++++ .../com/sk89q/worldedit/util/Location.java | 22 +-- .../sk89q/worldedit/world/AbstractWorld.java | 13 +- .../com/sk89q/worldedit/world/NullWorld.java | 5 + .../java/com/sk89q/worldedit/world/World.java | 8 - .../sk89q/worldedit/util/LocationTest.java | 19 --- 23 files changed, 768 insertions(+), 108 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Direction.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 72a774ede..e693f18ea 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -39,7 +39,6 @@ import com.sk89q.worldedit.blocks.MobSpawnerBlock; import com.sk89q.worldedit.blocks.NoteBlock; import com.sk89q.worldedit.blocks.SignBlock; import com.sk89q.worldedit.blocks.SkullBlock; -import com.sk89q.worldedit.bukkit.entity.BukkitEntity; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; @@ -222,6 +221,26 @@ public class BukkitWorld extends LocalWorld { } } + @Override + public List getEntities(Region region) { + World world = getWorld(); + + List entities = new ArrayList(); + for (Vector2D pt : region.getChunks()) { + if (!world.isChunkLoaded(pt.getBlockX(), pt.getBlockZ())) { + continue; + } + + final Entity[] ents = world.getChunkAt(pt.getBlockX(), pt.getBlockZ()).getEntities(); + for (Entity ent : ents) { + if (region.contains(BukkitUtil.toVector(ent.getLocation()))) { + entities.add(BukkitAdapter.adapt(ent)); + } + } + } + return entities; + } + @Override public List getEntities() { List list = new ArrayList(); @@ -1240,26 +1259,6 @@ public class BukkitWorld extends LocalWorld { getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); } - @Override - public LocalEntity[] getEntities(Region region) { - World world = getWorld(); - - List entities = new ArrayList(); - for (Vector2D pt : region.getChunks()) { - if (!world.isChunkLoaded(pt.getBlockX(), pt.getBlockZ())) { - continue; - } - - final Entity[] ents = world.getChunkAt(pt.getBlockX(), pt.getBlockZ()).getEntities(); - for (Entity ent : ents) { - if (region.contains(BukkitUtil.toVector(ent.getLocation()))) { - entities.add(BukkitUtil.toLocalEntity(ent)); - } - } - } - return entities.toArray(new BukkitEntity[entities.size()]); - } - @Override public int killEntities(LocalEntity... entities) { World world = getWorld(); @@ -1267,7 +1266,7 @@ public class BukkitWorld extends LocalWorld { int amount = 0; Set toKill = new HashSet(); for (LocalEntity entity : entities) { - toKill.add(((BukkitEntity) entity).getEntityId()); + toKill.add(((com.sk89q.worldedit.bukkit.entity.BukkitEntity) entity).getEntityId()); } for (Entity entity : world.getEntities()) { if (toKill.contains(entity.getUniqueId())) { diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java index 75f1d9b09..4a55e41bd 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -23,7 +23,10 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.helper.MCDirections; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; +import net.minecraft.entity.EntityHanging; import net.minecraft.entity.EntityList; import net.minecraft.nbt.NBTTagCompound; @@ -40,17 +43,42 @@ class ForgeEntity implements Entity { @Override public BaseEntity getState() { - NBTTagCompound tag = new NBTTagCompound(); - entity.writeToNBT(tag); - return new BaseEntity(EntityList.getEntityString(entity), NBTConverter.fromNative(tag)); + String id = EntityList.getEntityString(entity); + if (id != null) { + NBTTagCompound tag = new NBTTagCompound(); + entity.writeToNBT(tag); + return new BaseEntity(id, NBTConverter.fromNative(tag)); + } else { + return null; + } } @Override public Location getLocation() { - return new Location( - ForgeAdapter.adapt(entity.worldObj), - new Vector(entity.posX, entity.posY, entity.posZ), - ForgeAdapter.adapt(entity.getLookVec())); + Vector position; + float pitch; + float yaw; + + if (entity instanceof EntityHanging) { + EntityHanging hanging = (EntityHanging) entity; + + position = new Vector(hanging.xPosition, hanging.yPosition, hanging.zPosition); + + Direction direction = MCDirections.fromHanging(hanging.hangingDirection); + if (direction != null) { + yaw = direction.toVector().toYaw(); + pitch = direction.toVector().toPitch(); + } else { + yaw = (float) Math.toRadians(entity.rotationYaw); + pitch = (float) Math.toRadians(entity.rotationPitch); + } + } else { + position = new Vector(entity.posX, entity.posY, entity.posZ); + yaw = (float) Math.toRadians(entity.rotationYaw); + pitch = (float) Math.toRadians(entity.rotationPitch); + } + + return new Location(ForgeAdapter.adapt(entity.worldObj), position, yaw, pitch); } @Override diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 5087799a7..7c68e6cdf 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -32,7 +32,10 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; @@ -500,7 +503,29 @@ public class ForgeWorld extends AbstractWorld { } @Override - public List getEntities() { + @SuppressWarnings("unchecked") + public List getEntities(Region region) { + List entities = new ArrayList(); + World world = getWorld(); + for (Vector2D pt : region.getChunks()) { + if (!world.getChunkProvider().chunkExists(pt.getBlockX(), pt.getBlockZ())) { + continue; + } + + Chunk chunk = world.getChunkProvider().provideChunk(pt.getBlockX(), pt.getBlockZ()); + for (List entitySubList : chunk.entityLists) { + for (net.minecraft.entity.Entity entity : entitySubList) { + if (region.contains(new Vector(entity.posX, entity.posY, entity.posZ))) { + entities.add(new ForgeEntity(entity)); + } + } + } + } + return entities; + } + + @Override + public List getEntities() { List entities = new ArrayList(); for (Object entity : getWorld().getLoadedEntityList()) { entities.add(new ForgeEntity((net.minecraft.entity.Entity) entity)); @@ -518,6 +543,19 @@ public class ForgeWorld extends AbstractWorld { if (tag != null) { createdEntity.readFromNBT(NBTConverter.toNative(entity.getNbtData())); } + + createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), (float) Math.toDegrees(location.getYaw()), (float) Math.toDegrees(location.getPitch())); + + // Special handling for hanging entities + if (createdEntity instanceof EntityHanging) { + EntityHanging hanging = (EntityHanging) createdEntity; + hanging.xPosition = location.getBlockX(); + hanging.yPosition = location.getBlockY(); + hanging.zPosition = location.getBlockZ(); + Direction direction = Direction.findClosest(location.getDirection(), Flag.CARDINAL); + hanging.setDirection(MCDirections.toHanging(direction)); + } + world.spawnEntityInWorld(createdEntity); return new ForgeEntity(createdEntity); } else { diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 7ad6b867f..10a849a17 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -582,15 +582,10 @@ public class EditSession implements Extent { return getBlock(position).isAir() && setBlock(position, block); } - @Override - public List getEntities() { - return world.getEntities(); - } - @Override @Nullable public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { - return world.createEntity(location, entity); + return bypassNone.createEntity(location, entity); } /** @@ -649,6 +644,16 @@ public class EditSession implements Extent { return getWorld().getMaximumPoint(); } + @Override + public List getEntities(Region region) { + return bypassNone.getEntities(region); + } + + @Override + public List getEntities() { + return bypassNone.getEntities(); + } + /** * Finish off the queue. */ @@ -1160,6 +1165,7 @@ public class EditSession implements Extent { ForwardExtentCopy copy = new ForwardExtentCopy(this, region, buffer, to); copy.setTransform(new AffineTransform().translate(dir.multiply(distance))); copy.setSourceFunction(remove); // Remove + copy.setRemovingEntities(true); if (!copyAir) { copy.setSourceMask(new ExistingBlockMask(this)); } diff --git a/src/main/java/com/sk89q/worldedit/Vector.java b/src/main/java/com/sk89q/worldedit/Vector.java index c028c5797..5585e9961 100644 --- a/src/main/java/com/sk89q/worldedit/Vector.java +++ b/src/main/java/com/sk89q/worldedit/Vector.java @@ -652,6 +652,40 @@ public class Vector implements Comparable { throw new RuntimeException("This should not happen"); } + /** + * Get this vector's pitch as used within the game. + * + * @return pitch in radians + */ + public float toPitch() { + double x = getX(); + double z = getZ(); + + if (x == 0 && z == 0) { + return getY() > 0 ? -90 : 90; + } else { + double x2 = x * x; + double z2 = z * z; + double xz = Math.sqrt(x2 + z2); + return (float) Math.atan(-getY() / xz); + } + } + + /** + * Get this vector's yaw as used within the game. + * + * @return yaw in radians + */ + public float toYaw() { + double x = getX(); + double z = getZ(); + + double t = Math.atan2(-x, z); + double _2pi = 2 * Math.PI; + + return (float) ((t + _2pi) % _2pi); + } + /** * Get a block point from a point. * @@ -792,4 +826,5 @@ public class Vector implements Comparable { (v1.z + v2.z) / 2 ); } + } diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 666c33872..65399bbf4 100644 --- a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.regions.Region; import javax.annotation.Nullable; @@ -82,10 +83,15 @@ public abstract class AbstractDelegateExtent implements Extent { } @Override - public List getEntities() { + public List getEntities() { return extent.getEntities(); } + @Override + public List getEntities(Region region) { + return extent.getEntities(region); + } + @Override public Vector getMinimumPoint() { return extent.getMinimumPoint(); diff --git a/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java index 87dfeac3d..772d8ca57 100644 --- a/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java @@ -22,8 +22,19 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.history.change.BlockChange; +import com.sk89q.worldedit.history.change.EntityCreate; +import com.sk89q.worldedit.history.change.EntityRemove; import com.sk89q.worldedit.history.changeset.ChangeSet; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -53,4 +64,65 @@ public class ChangeSetExtent extends AbstractDelegateExtent { return super.setBlock(location, block); } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity state) { + Entity entity = super.createEntity(location, state); + if (state != null) { + changeSet.add(new EntityCreate(location, state, entity)); + } + return entity; + } + + @Override + public List getEntities() { + return wrapEntities(super.getEntities()); + } + + @Override + public List getEntities(Region region) { + return wrapEntities(super.getEntities(region)); + } + + private List wrapEntities(List entities) { + List newList = new ArrayList(entities.size()); + for (Entity entity : entities) { + newList.add(new TrackedEntity(entity)); + } + return newList; + } + + private class TrackedEntity implements Entity { + private final Entity entity; + + private TrackedEntity(Entity entity) { + this.entity = entity; + } + + @Override + public BaseEntity getState() { + return entity.getState(); + } + + @Override + public Location getLocation() { + return entity.getLocation(); + } + + @Override + public Extent getExtent() { + return entity.getExtent(); + } + + @Override + public boolean remove() { + Location location = entity.getLocation(); + BaseEntity state = entity.getState(); + boolean success = entity.remove(); + if (state != null && success) { + changeSet.add(new EntityRemove(location, state)); + } + return success; + } + } } diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java index 14bacb425..51ae4fc84 100644 --- a/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.regions.Region; import javax.annotation.Nullable; import java.util.List; @@ -56,6 +57,17 @@ public interface Extent extends InputExtent, OutputExtent { */ Vector getMaximumPoint(); + /** + * Get a list of all entities within the given region. + *

+ * If the extent is not wholly loaded (i.e. a world being simulated in the + * game will not have every chunk loaded), then this list may not be + * incomplete. + * + * @return a list of entities + */ + List getEntities(Region region); + /** * Get a list of all entities. *

@@ -65,7 +77,7 @@ public interface Extent extends InputExtent, OutputExtent { * * @return a list of entities */ - List getEntities(); + List getEntities(); /** * Create an entity at the given location. diff --git a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index 5f8f84644..3df4879de 100644 --- a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.regions.Region; import javax.annotation.Nullable; import java.util.Collections; @@ -49,6 +50,11 @@ public class NullExtent implements Extent { return nullPoint; } + @Override + public List getEntities(Region region) { + return Collections.emptyList(); + } + @Override public List getEntities() { return Collections.emptyList(); diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 5c40d42e2..33be36453 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -93,8 +94,19 @@ public class BlockArrayClipboard implements Clipboard { } @Override - public List getEntities() { - return new ArrayList(entities); + public List getEntities(Region region) { + List filtered = new ArrayList(); + for (Entity entity : entities) { + if (region.contains(entity.getLocation().toVector())) { + filtered.add(entity); + } + } + return Collections.unmodifiableList(filtered); + } + + @Override + public List getEntities() { + return Collections.unmodifiableList(entities); } @Nullable diff --git a/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java new file mode 100644 index 000000000..2728285fe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -0,0 +1,103 @@ +/* + * 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.function.entity; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies entities provided to the function to the provided destination + * {@code Extent}. + */ +public class ExtentEntityCopy implements EntityFunction { + + private final Extent destination; + private final Vector from; + private final Vector to; + private final Transform transform; + private boolean removing; + + /** + * Create a new instance. + * + * @param from the from position + * @param destination the destination {@code Extent} + * @param to the destination position + * @param transform the transformation to apply to both position and orientation + */ + public ExtentEntityCopy(Vector from, Extent destination, Vector to, Transform transform) { + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.destination = destination; + this.from = from; + this.to = to; + this.transform = transform; + } + + /** + * Return whether entities that are copied should be removed. + * + * @return true if removing + */ + public boolean isRemoving() { + return removing; + } + + /** + * Set whether entities that are copied should be removed. + * + * @param removing true if removing + */ + public void setRemoving(boolean removing) { + this.removing = removing; + } + + @Override + public boolean apply(Entity entity) throws WorldEditException { + BaseEntity state = entity.getState(); + if (state != null) { + Location location = entity.getLocation(); + Vector newPosition = transform.apply(location.toVector().subtract(from)); + Vector newDirection = transform.apply(location.getDirection()).subtract(transform.apply(Vector.ZERO)).normalize(); + Location newLocation = new Location(destination, newPosition.add(to), newDirection); + boolean success = destination.createEntity(newLocation, state) != null; + + // Remove + if (isRemoving() && success) { + entity.remove(); + } + + return success; + } else { + return false; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java index ce0f80248..3f9887b28 100644 --- a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java +++ b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -19,20 +19,25 @@ package com.sk89q.worldedit.function.operation; -import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.CombinedRegionFunction; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; import com.sk89q.worldedit.function.block.ExtentBlockCopy; +import com.sk89q.worldedit.function.entity.ExtentEntityCopy; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; +import java.util.List; + import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -52,6 +57,7 @@ public class ForwardExtentCopy implements Operation { private final Vector to; private int repetitions = 1; private Mask sourceMask = Masks.alwaysTrue(); + private boolean removingEntities; private RegionFunction sourceFunction = null; private Transform transform = new Identity(); private Transform currentTransform = null; @@ -177,6 +183,24 @@ public class ForwardExtentCopy implements Operation { this.repetitions = repetitions; } + /** + * Return whether entities that are copied should be removed. + * + * @return true if removing + */ + public boolean isRemovingEntities() { + return removingEntities; + } + + /** + * Set whether entities that are copied should be removed. + * + * @param removing true if removing + */ + public void setRemovingEntities(boolean removingEntities) { + this.removingEntities = removingEntities; + } + /** * Get the number of affected objects. * @@ -200,13 +224,19 @@ public class ForwardExtentCopy implements Operation { currentTransform = transform; } - ExtentBlockCopy copy = new ExtentBlockCopy(source, from, destination, to, currentTransform); - RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, copy); + ExtentBlockCopy blockCopy = new ExtentBlockCopy(source, from, destination, to, currentTransform); + RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, blockCopy); RegionFunction function = sourceFunction != null ? new CombinedRegionFunction(filter, sourceFunction) : filter; - RegionVisitor visitor = new RegionVisitor(region, function); - lastVisitor = visitor; + RegionVisitor blockVisitor = new RegionVisitor(region, function); + + ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform); + entityCopy.setRemoving(removingEntities); + List entities = source.getEntities(region); + EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); + + lastVisitor = blockVisitor; currentTransform = currentTransform.combine(transform); - return new DelegateOperation(this, visitor); + return new DelegateOperation(this, new OperationQueue(blockVisitor, entityVisitor)); } else { return null; } diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java index 14509bd8c..d412103e9 100644 --- a/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java +++ b/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java @@ -34,7 +34,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class EntityVisitor implements Operation { - private final Iterator iterator; + private final Iterator iterator; private final EntityFunction function; private int affected = 0; @@ -44,7 +44,7 @@ public class EntityVisitor implements Operation { * @param iterator the iterator * @param function the function */ - public EntityVisitor(Iterator iterator, EntityFunction function) { + public EntityVisitor(Iterator iterator, EntityFunction function) { checkNotNull(iterator); checkNotNull(function); this.iterator = iterator; diff --git a/src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java b/src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java new file mode 100644 index 000000000..80d0bbcaa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java @@ -0,0 +1,68 @@ +/* + * 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.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Logs the creation of an entity and removes the entity upon undo. + */ +public class EntityCreate implements Change { + + private final Location location; + private final BaseEntity state; + private Entity entity; + + /** + * Create a new instance. + * + * @param location the location + * @param state the state of the created entity + * @param entity the entity that was created + */ + public EntityCreate(Location location, BaseEntity state, Entity entity) { + checkNotNull(location); + checkNotNull(state); + checkNotNull(entity); + this.location = location; + this.state = state; + this.entity = entity; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + if (entity != null) { + entity.remove(); + entity = null; + } + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + entity = checkNotNull(context.getExtent()).createEntity(location, state); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java b/src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java new file mode 100644 index 000000000..eef480a91 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java @@ -0,0 +1,65 @@ +/* + * 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.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tracks the removal of an entity. + */ +public class EntityRemove implements Change { + + private final Location location; + private final BaseEntity state; + private Entity entity; + + /** + * Create a new instance. + * + * @param location the location + * @param state the state of the created entity + */ + public EntityRemove(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + this.location = location; + this.state = state; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + entity = checkNotNull(context.getExtent()).createEntity(location, state); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + if (entity != null) { + entity.remove(); + entity = null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index dd04767b5..2166b506d 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -171,11 +171,6 @@ public class LocalWorldAdapter extends LocalWorld { world.simulateBlockMine(position); } - @Override - public LocalEntity[] getEntities(Region region) { - return world.getEntities(region); - } - @Override public int killEntities(LocalEntity... entity) { return world.killEntities(entity); @@ -293,6 +288,11 @@ public class LocalWorldAdapter extends LocalWorld { return world.getMaximumPoint(); } + @Override + public List getEntities(Region region) { + return world.getEntities(region); + } + @Override public BaseBlock getBlock(Vector position) { return world.getBlock(position); @@ -335,7 +335,7 @@ public class LocalWorldAdapter extends LocalWorld { } @Override - public List getEntities() { + public List getEntities() { return world.getEntities(); } diff --git a/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java new file mode 100644 index 000000000..6805196de --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -0,0 +1,62 @@ +/* + * 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.internal.helper; + +import com.sk89q.worldedit.util.Direction; + +/** + * Utility methods for working with directions in Minecraft. + */ +public final class MCDirections { + + private MCDirections() { + } + + public static Direction fromHanging(int i) { + switch (i) { + case 0: + return Direction.SOUTH; + case 1: + return Direction.WEST; + case 2: + return Direction.NORTH; + case 3: + return Direction.EAST; + default: + return Direction.NORTH; + } + } + + public static int toHanging(Direction direction) { + switch (direction) { + case SOUTH: + return 0; + case WEST: + return 1; + case NORTH: + return 2; + case EAST: + return 3; + default: + return 0; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/Direction.java b/src/main/java/com/sk89q/worldedit/util/Direction.java new file mode 100644 index 000000000..bf1997f19 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Direction.java @@ -0,0 +1,159 @@ +/* + * 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.util; + +import com.sk89q.worldedit.Vector; + +import javax.annotation.Nullable; + +/** + * A collection of cardinal, ordinal, and secondary-ordinal directions. + */ +public enum Direction { + + NORTH(new Vector(0, 0, -1), Flag.CARDINAL), + EAST(new Vector(1, 0, 0), Flag.CARDINAL), + SOUTH(new Vector(0, 0, 1), Flag.CARDINAL), + WEST(new Vector(-1, 0, 0), Flag.CARDINAL), + + UP(new Vector(0, 1, 0), Flag.UPRIGHT), + DOWN(new Vector(0, -1, 0), Flag.UPRIGHT), + + NORTHEAST(new Vector(1, 0, -1), Flag.ORDINAL), + NORTHWEST(new Vector(-1, 0, -1), Flag.ORDINAL), + SOUTHEAST(new Vector(1, 0, 1), Flag.ORDINAL), + SOUTHWEST(new Vector(-1, 0, 1), Flag.ORDINAL), + + WEST_NORTHWEST(new Vector(-Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + WEST_SOUTHWEST(new Vector(-Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + NORTH_NORTHWEST(new Vector(Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + NORTH_NORTHEAST(new Vector(Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + EAST_NORTHEAST(new Vector(Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + EAST_SOUTHEAST(new Vector(Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + SOUTH_SOUTHEAST(new Vector(Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + SOUTH_SOUTHWEST(new Vector(Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL); + + private final Vector direction; + private final int flags; + + private Direction(Vector vector, int flags) { + this.direction = vector.normalize(); + this.flags = flags; + } + + /** + * Return true if the direction is of a cardinal direction (north, west + * east, and south). + * + *

This evaluates as false for directions that have a non-zero + * Y-component.

+ * + * @return true if cardinal + */ + public boolean isCardinal() { + return (flags & Flag.CARDINAL) > 0; + } + + /** + * Return true if the direction is of an ordinal direction (northwest, + * southwest, southeast, northeaast). + * + * @return true if ordinal + */ + public boolean isOrdinal() { + return (flags & Flag.ORDINAL) > 0; + } + + /** + * Return true if the direction is of a secondary ordinal direction + * (north-northwest, north-northeast, south-southwest, etc.). + * + * @return true if secondary ordinal + */ + public boolean isSecondaryOrdinal() { + return (flags & Flag.SECONDARY_ORDINAL) > 0; + } + + /** + * Return whether Y component is non-zero. + * + * @return true if the Y component is non-zero + */ + public boolean isUpright() { + return (flags & Flag.UPRIGHT) > 0; + } + + /** + * Get the vector. + * + * @return the vector + */ + public Vector toVector() { + return direction; + } + + /** + * Find the closest direction to the given direction vector. + * + * @param vector the vector + * @param flags the only flags that are permitted (use bitwise math) + * @return the closest direction, or null if no direction can be returned + */ + @Nullable + public static Direction findClosest(Vector vector, int flags) { + if ((flags & Flag.UPRIGHT) == 0) { + vector = vector.setY(0); + } + vector = vector.normalize(); + + Direction closest = null; + double closestDot = -2; + for (Direction direction : values()) { + if ((~flags & direction.flags) > 0) { + continue; + } + + double dot = direction.toVector().dot(vector); + if (dot >= closestDot) { + closest = direction; + closestDot = dot; + } + } + + return closest; + } + + /** + * Flags to use with {@link #findClosest(Vector, int)}. + */ + public static final class Flag { + public static int CARDINAL = 0x1; + public static int ORDINAL = 0x2; + public static int SECONDARY_ORDINAL = 0x4; + public static int UPRIGHT = 0x8; + + public static int ALL = CARDINAL | ORDINAL | SECONDARY_ORDINAL | UPRIGHT; + + private Flag() { + } + } + +} + diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java index 0bc45e592..e1b6ee487 100644 --- a/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/src/main/java/com/sk89q/worldedit/util/Location.java @@ -113,8 +113,7 @@ public class Location { * @param direction the direction vector */ public Location(Extent extent, Vector position, Vector direction) { - this(extent, position, 0, 0); - this.setDirection(direction); + this(extent, position, direction.toYaw(), direction.toPitch()); } /** @@ -194,24 +193,7 @@ public class Location { * @return the new instance */ public Location setDirection(Vector direction) { - double x = direction.getX(); - double z = direction.getZ(); - - if (x == 0 && z == 0) { - float pitch = direction.getY() > 0 ? -90 : 90; - return new Location(extent, position, 0, pitch); - } else { - double t = Math.atan2(-x, z); - double x2 = x * x; - double z2 = z * z; - double xz = Math.sqrt(x2 + z2); - double _2pi = 2 * Math.PI; - - float pitch = (float) Math.atan(-direction.getY() / xz); - float yaw = (float) ((t + _2pi) % _2pi); - - return new Location(extent, position, yaw, pitch); - } + return new Location(extent, position, direction.toYaw(), direction.toPitch()); } /** diff --git a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index e5876107c..6c982cf6a 100644 --- a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -19,8 +19,13 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalEntity; import com.sk89q.worldedit.LocalWorld.KillFlags; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; @@ -29,7 +34,6 @@ import com.sk89q.worldedit.extension.platform.Platform; 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; @@ -156,11 +160,6 @@ public abstract class AbstractWorld implements World { } } - @Override - public LocalEntity[] getEntities(Region region) { - return new LocalEntity[0]; - } - @Override public int killEntities(LocalEntity... entities) { return 0; diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 937ba9c3b..a4f7a5eed 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -109,6 +109,11 @@ public class NullWorld extends AbstractWorld { return new BaseBlock(BlockID.AIR); } + @Override + public List getEntities(Region region) { + return Collections.emptyList(); + } + @Override public List getEntities() { return Collections.emptyList(); diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index eb12f7f71..1c077d3d2 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -209,14 +209,6 @@ public interface World extends Extent { */ 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. * diff --git a/src/test/java/com/sk89q/worldedit/util/LocationTest.java b/src/test/java/com/sk89q/worldedit/util/LocationTest.java index 06d546e32..1acdbc892 100644 --- a/src/test/java/com/sk89q/worldedit/util/LocationTest.java +++ b/src/test/java/com/sk89q/worldedit/util/LocationTest.java @@ -51,25 +51,6 @@ public class LocationTest { assertEquals(world2, location2.getExtent()); } - @Test - public void testGetDirection() throws Exception { - World world = mock(World.class); - Vector direction = new Vector(1, 1, 1); - Location location = new Location(world, new Vector(), direction); - assertEquals(direction, location.getDirection()); - } - - @Test - public void testSetDirection() throws Exception { - World world = mock(World.class); - Vector direction1 = new Vector(1, 1, 1); - Vector direction2 = new Vector(2, 2, 2); - Location location1 = new Location(world, new Vector(), direction1); - Location location2 = location1.setDirection(direction2); - assertEquals(direction1, location1.getDirection()); - assertEquals(direction2, location2.getDirection()); - } - @Test public void testToVector() throws Exception { World world = mock(World.class); From 9e105336d569094287597fbfbc0a9637b233c8f8 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 12 Jul 2014 18:38:30 -0700 Subject: [PATCH 32/56] Add missing dependencies (Trove, GSON) to build.gradle. --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 118600546..b22524f26 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,8 @@ dependencies { compile group: 'com.sk89q', name: 'jchronic', version:'0.2.4a' compile group: 'com.google.code.findbugs', name: 'jsr305', version: '1.3.9' compile group: 'com.thoughtworks.paranamer', name: 'paranamer', version: '2.6' + compile group: 'com.google.code.gson', name: 'gson', version: '2.2.4' + compile group: 'net.sf.trove4j', name: 'trove4j', version: '3.0.3' testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' } From a95ebde6204789cc067fdf586be804acc80ac8ac Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 13 Jul 2014 00:53:57 -0700 Subject: [PATCH 33/56] Add setYaw, setYaw, and setDirection(yaw, pitch) to Location. --- .../com/sk89q/worldedit/util/Location.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java index e1b6ee487..90ec405be 100644 --- a/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/src/main/java/com/sk89q/worldedit/util/Location.java @@ -162,6 +162,16 @@ public class Location { return yaw; } + /** + * Create a clone of this object with the given yaw. + * + * @param yaw the new yaw + * @return the new instance + */ + public Location setYaw(float yaw) { + return new Location(extent, position, yaw, pitch); + } + /** * Get the pitch in radians. * @@ -171,6 +181,27 @@ public class Location { return pitch; } + /** + * Create a clone of this object with the given pitch. + * + * @param pitch the new yaw + * @return the new instance + */ + public Location setPitch(float pitch) { + return new Location(extent, position, yaw, pitch); + } + + /** + * Create a clone of this object with the given yaw and pitch. + * + * @param yaw the new yaw + * @param pitch the new pitch + * @return the new instance + */ + public Location setDirection(float yaw, float pitch) { + return new Location(extent, position, yaw, pitch); + } + /** * Get the direction vector. * From b751cbe1eed06d61f480274f125bf26aa35c5e65 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 13 Jul 2014 01:14:46 -0700 Subject: [PATCH 34/56] Add support for entities with .schematic files. --- .../extent/clipboard/io/SchematicReader.java | 123 ++++++++++++++---- .../extent/clipboard/io/SchematicWriter.java | 79 +++++++++-- 2 files changed, 167 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java index 2f2e50a6c..ad0e9bbf8 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.DoubleTag; +import com.sk89q.jnbt.FloatTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTInputStream; @@ -31,12 +33,15 @@ import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.registry.WorldData; +import javax.annotation.Nullable; import java.io.IOException; import java.util.HashMap; import java.util.List; @@ -79,29 +84,32 @@ public class SchematicReader implements ClipboardReader { } // Check type of Schematic - String materials = getChildTag(schematic, "Materials", StringTag.class).getValue(); + String materials = requireTag(schematic, "Materials", StringTag.class).getValue(); if (!materials.equals("Alpha")) { throw new IOException("Schematic file is not an Alpha schematic"); } - // Parse origin and region from WEOrigin and WEOffset + // ==================================================================== + // Metadata + // ==================================================================== + Vector origin; Region region; // Get information - short width = getChildTag(schematic, "Width", ShortTag.class).getValue(); - short height = getChildTag(schematic, "Height", ShortTag.class).getValue(); - short length = getChildTag(schematic, "Length", ShortTag.class).getValue(); + short width = requireTag(schematic, "Width", ShortTag.class).getValue(); + short height = requireTag(schematic, "Height", ShortTag.class).getValue(); + short length = requireTag(schematic, "Length", ShortTag.class).getValue(); try { - int originX = getChildTag(schematic, "WEOriginX", IntTag.class).getValue(); - int originY = getChildTag(schematic, "WEOriginY", IntTag.class).getValue(); - int originZ = getChildTag(schematic, "WEOriginZ", IntTag.class).getValue(); + int originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue(); + int originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue(); + int originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue(); Vector min = new Vector(originX, originY, originZ); - int offsetX = getChildTag(schematic, "WEOffsetX", IntTag.class).getValue(); - int offsetY = getChildTag(schematic, "WEOffsetY", IntTag.class).getValue(); - int offsetZ = getChildTag(schematic, "WEOffsetZ", IntTag.class).getValue(); + int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue(); + int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue(); + int offsetZ = requireTag(schematic, "WEOffsetZ", IntTag.class).getValue(); Vector offset = new Vector(offsetX, offsetY, offsetZ); origin = min.subtract(offset); @@ -111,16 +119,20 @@ public class SchematicReader implements ClipboardReader { region = new CuboidRegion(origin, origin.add(width, height, length).subtract(Vector.ONE)); } + // ==================================================================== + // Blocks + // ==================================================================== + // Get blocks - byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue(); - byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue(); + byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue(); + byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue(); byte[] addId = new byte[0]; short[] blocks = new short[blockId.length]; // Have to later combine IDs // We support 4096 block IDs using the same method as vanilla Minecraft, where // the highest 4 bits are stored in a separate byte array. if (schematic.containsKey("AddBlocks")) { - addId = getChildTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); + addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); } // Combine the AddBlocks data with the first 8-bit block ID @@ -137,7 +149,7 @@ public class SchematicReader implements ClipboardReader { } // Need to pull out tile entities - List tileEntities = getChildTag(schematic, "TileEntities", ListTag.class).getValue(); + List tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue(); Map> tileEntitiesMap = new HashMap>(); for (Tag tag : tileEntities) { @@ -208,19 +220,64 @@ public class SchematicReader implements ClipboardReader { } } + // ==================================================================== + // Entities + // ==================================================================== + + try { + List entityTags = requireTag(schematic, "Entities", ListTag.class).getValue(); + + for (Tag tag : entityTags) { + if (tag instanceof CompoundTag) { + CompoundTag compound = (CompoundTag) tag; + StringTag idTag = getTag(compound, StringTag.class, "id"); + Vector position = getVector(getTag(compound, ListTag.class, "Pos")); + + if (idTag != null & position != null) { + Location location = readRotation(getTag(compound, ListTag.class, "Rotation"), new Location(clipboard, position)); + BaseEntity state = new BaseEntity(idTag.getValue(), compound); + clipboard.createEntity(location, state); + } + } + } + } catch (IOException ignored) { // No entities? No problem + } + return clipboard; } - /** - * Get child tag of a NBT structure. - * - * @param items The parent tag map - * @param key The name of the tag to get - * @param expected The expected type of the tag - * @return child tag casted to the expected type - * @throws IOException if the tag does not exist or the tag is not of the expected type - */ - private static T getChildTag(Map items, String key, Class expected) throws IOException { + @Nullable + private static Vector getVector(@Nullable ListTag tag) { + if (tag != null) { + List tags = tag.getValue(); + + if (tags.size() == 3 && tags.get(0) instanceof DoubleTag) { + double x = ((DoubleTag) tags.get(0)).getValue(); + double y = ((DoubleTag) tags.get(1)).getValue(); + double z = ((DoubleTag) tags.get(2)).getValue(); + return new Vector(x, y, z); + } + } + + return null; + } + + @Nullable + private static Location readRotation(@Nullable ListTag tag, Location location) { + if (tag != null) { + List tags = tag.getValue(); + + if (tags.size() == 2 && tags.get(0) instanceof FloatTag) { + float yaw = ((FloatTag) tags.get(0)).getValue(); + float pitch = ((FloatTag) tags.get(1)).getValue(); + location = location.setDirection(yaw, pitch); + } + } + + return location; + } + + private static T requireTag(Map items, String key, Class expected) throws IOException { if (!items.containsKey(key)) { throw new IOException("Schematic file is missing a \"" + key + "\" tag"); } @@ -233,4 +290,20 @@ public class SchematicReader implements ClipboardReader { return expected.cast(tag); } + @Nullable + private static T getTag(CompoundTag tag, Class expected, String key) { + Map items = tag.getValue(); + + if (!items.containsKey(key)) { + return null; + } + + Tag test = items.get(key); + if (!expected.isInstance(test)) { + return null; + } + + return expected.cast(test); + } + } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java index b512afb2d..6e907cb0e 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.DoubleTag; +import com.sk89q.jnbt.FloatTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTOutputStream; @@ -29,19 +31,23 @@ import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.registry.WorldData; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import static com.google.common.base.Preconditions.checkNotNull; - /** +/** * Writes schematic files based that are compatible with MCEdit and other editors. */ public class SchematicWriter implements ClipboardWriter { @@ -79,6 +85,10 @@ public class SchematicWriter implements ClipboardWriter { throw new IllegalArgumentException("Length of region too large for a .schematic"); } + // ==================================================================== + // Metadata + // ==================================================================== + HashMap schematic = new HashMap(); schematic.put("Width", new ShortTag("Width", (short) width)); schematic.put("Length", new ShortTag("Length", (short) length)); @@ -91,11 +101,14 @@ public class SchematicWriter implements ClipboardWriter { schematic.put("WEOffsetY", new IntTag("WEOffsetY", offset.getBlockY())); schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", offset.getBlockZ())); - // Copy + // ==================================================================== + // Block handling + // ==================================================================== + byte[] blocks = new byte[width * height * length]; byte[] addBlocks = null; byte[] blockData = new byte[width * height * length]; - ArrayList tileEntities = new ArrayList(); + List tileEntities = new ArrayList(); for (Vector point : region) { Vector relative = point.subtract(min); @@ -140,20 +153,66 @@ public class SchematicWriter implements ClipboardWriter { schematic.put("Blocks", new ByteArrayTag("Blocks", blocks)); schematic.put("Data", new ByteArrayTag("Data", blockData)); - schematic.put("Entities", new ListTag("Entities", CompoundTag.class, new ArrayList())); schematic.put("TileEntities", new ListTag("TileEntities", CompoundTag.class, tileEntities)); if (addBlocks != null) { schematic.put("AddBlocks", new ByteArrayTag("AddBlocks", addBlocks)); } - // Build and output + // ==================================================================== + // Entities + // ==================================================================== + + List entities = new ArrayList(); + for (Entity entity : clipboard.getEntities()) { + BaseEntity state = entity.getState(); + + if (state != null) { + Map values = new HashMap(); + + // Put NBT provided data + CompoundTag rawTag = state.getNbtData(); + if (rawTag != null) { + values.putAll(rawTag.getValue()); + } + + // Store our location data, overwriting any + values.put("id", new StringTag("id", state.getTypeId())); + values.put("Pos", writeVector(entity.getLocation().toVector(), "Pos")); + values.put("Rotation", writeRotation(entity.getLocation(), "Rotation")); + + CompoundTag entityTag = new CompoundTag("Entity", values); + entities.add(entityTag); + } + } + + schematic.put("Entities", new ListTag("Entities", CompoundTag.class, entities)); + + // ==================================================================== + // Output + // ==================================================================== + CompoundTag schematicTag = new CompoundTag("Schematic", schematic); outputStream.writeTag(schematicTag); } - @Override - public void close() throws IOException { - outputStream.close(); - } - } + private Tag writeVector(Vector vector, String name) { + List list = new ArrayList(); + list.add(new DoubleTag("", vector.getX())); + list.add(new DoubleTag("", vector.getY())); + list.add(new DoubleTag("", vector.getZ())); + return new ListTag(name, DoubleTag.class, list); + } + + private Tag writeRotation(Location location, String name) { + List list = new ArrayList(); + list.add(new FloatTag("", location.getYaw())); + list.add(new FloatTag("", location.getPitch())); + return new ListTag(name, FloatTag.class, list); + } + + @Override + public void close() throws IOException { + outputStream.close(); + } +} From 759c6ba50de0e6a489a48997c2472fcb06ae7a0e Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 13 Jul 2014 18:15:16 -0700 Subject: [PATCH 35/56] Add @Nullable to NbtValued methods. --- src/main/java/com/sk89q/worldedit/world/NbtValued.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/world/NbtValued.java b/src/main/java/com/sk89q/worldedit/world/NbtValued.java index 525744b78..c15c16cf9 100644 --- a/src/main/java/com/sk89q/worldedit/world/NbtValued.java +++ b/src/main/java/com/sk89q/worldedit/world/NbtValued.java @@ -20,7 +20,8 @@ package com.sk89q.worldedit.world; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.DataException; + +import javax.annotation.Nullable; /** * Indicates an object that contains extra data identified as an NBT structure. This @@ -47,6 +48,7 @@ public interface NbtValued { * * @return compound tag, or null */ + @Nullable CompoundTag getNbtData(); /** @@ -55,6 +57,6 @@ public interface NbtValued { * @param nbtData NBT data, or null if no data * @throws DataException if possibly the data is invalid */ - void setNbtData(CompoundTag nbtData) throws DataException; + void setNbtData(@Nullable CompoundTag nbtData) throws DataException; } From bdd6d20013c251f1f31d3e13fda53297e4f751cc Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 13 Jul 2014 18:15:44 -0700 Subject: [PATCH 36/56] Remove DataException from NbtValued's setNbtData(). --- .../sk89q/worldedit/schematic/MCEditSchematicFormat.java | 8 ++------ src/main/java/com/sk89q/worldedit/world/NbtValued.java | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java b/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java index b3315b865..3491b8f55 100644 --- a/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java +++ b/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java @@ -170,12 +170,8 @@ public class MCEditSchematicFormat extends SchematicFormat { BlockVector pt = new BlockVector(x, y, z); BaseBlock block = getBlockForId(blocks[index], blockData[index]); - if (block instanceof TileEntityBlock && tileEntitiesMap.containsKey(pt)) { - try { - ((TileEntityBlock) block).setNbtData(new CompoundTag("", tileEntitiesMap.get(pt))); - } catch (com.sk89q.worldedit.world.DataException e) { - throw new DataException(e.getMessage()); - } + if (tileEntitiesMap.containsKey(pt)) { + block.setNbtData(new CompoundTag("", tileEntitiesMap.get(pt))); } clipboard.setBlock(pt, block); } diff --git a/src/main/java/com/sk89q/worldedit/world/NbtValued.java b/src/main/java/com/sk89q/worldedit/world/NbtValued.java index c15c16cf9..dc312a447 100644 --- a/src/main/java/com/sk89q/worldedit/world/NbtValued.java +++ b/src/main/java/com/sk89q/worldedit/world/NbtValued.java @@ -57,6 +57,6 @@ public interface NbtValued { * @param nbtData NBT data, or null if no data * @throws DataException if possibly the data is invalid */ - void setNbtData(@Nullable CompoundTag nbtData) throws DataException; + void setNbtData(@Nullable CompoundTag nbtData); } From f50c69ee8f604fcf5e971fe346fc9860b297969a Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 13 Jul 2014 21:25:28 -0700 Subject: [PATCH 37/56] Use Location.getYaw() and getPitch() for converting to Bukkit Locations. --- .../java/com/sk89q/worldedit/bukkit/BukkitAdapter.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index f949510f1..579ea88ae 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -91,16 +91,11 @@ final class BukkitAdapter { public static org.bukkit.Location adapt(Location location) { checkNotNull(location); Vector position = location.toVector(); - Vector direction = location.getDirection(); - final double eyeX = direction.getX(); - final double eyeZ = direction.getZ(); - final float yaw = (float) Math.toDegrees(Math.atan2(-eyeX, eyeZ)); - final double length = Math.sqrt(eyeX * eyeX + eyeZ * eyeZ); - final float pitch = (float) Math.toDegrees(Math.atan2(-direction.getY(), length)); return new org.bukkit.Location( adapt((World) location.getExtent()), position.getX(), position.getY(), position.getZ(), - yaw, pitch); + (float) Math.toDegrees(location.getYaw()), + (float) Math.toDegrees(location.getPitch())); } /** From c535ad8682d32f1d1d76b1ab57cbdadecf3e852b Mon Sep 17 00:00:00 2001 From: sk89q Date: Mon, 14 Jul 2014 02:15:21 -0700 Subject: [PATCH 38/56] Have BukkitEntity.getState() return null for now. --- src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java | 2 +- src/main/java/com/sk89q/worldedit/entity/Entity.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index 1625c572a..262a450f1 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -74,7 +74,7 @@ class BukkitEntity implements Entity { @Override public BaseEntity getState() { - throw new UnsupportedOperationException("Not implemented yet"); + return null; } @Override diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java index 800f61c72..7c6d68e7c 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; +import javax.annotation.Nullable; + /** * A reference to an instance of an entity that exists in an {@link Extent} * and thus would have position and similar details. @@ -37,8 +39,9 @@ public interface Entity { /** * Get a copy of the entity's state. * - * @return the entity's state + * @return the entity's state or null if one cannot be gotten */ + @Nullable BaseEntity getState(); /** From f033d87098efb5ed717d7a456db003f03a1bd5fb Mon Sep 17 00:00:00 2001 From: sk89q Date: Mon, 14 Jul 2014 12:10:38 -0700 Subject: [PATCH 39/56] Add new Bukkit implementation adapter system to access MC internals. Replaces the old NMSBlocks. --- pom.xml | 16 +- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 15 + .../sk89q/worldedit/bukkit/BukkitWorld.java | 749 +----------------- .../worldedit/bukkit/DefaultNmsBlock.java | 472 ----------- .../com/sk89q/worldedit/bukkit/NmsBlock.java | 61 -- .../worldedit/bukkit/WorldEditPlugin.java | 194 +++-- .../bukkit/adapter/AdapterLoadException.java | 41 + .../bukkit/adapter/BukkitImplAdapter.java | 49 ++ .../bukkit/adapter/BukkitImplLoader.java | 197 +++++ .../adapter/impl/CraftBukkit_v1_7_R2.class | Bin 0 -> 12200 bytes .../adapter/impl/CraftBukkit_v1_7_R3.class | Bin 0 -> 12200 bytes .../adapter/impl/CraftBukkit_v1_7_R4.class | Bin 0 -> 12210 bytes .../resources/nmsblocks/CBXNmsBlock_145.class | Bin 12701 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_146.class | Bin 12456 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_147.class | Bin 12528 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_15.class | Bin 12533 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_152.class | Bin 12540 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_161.class | Bin 12540 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_162.class | Bin 12540 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_164.class | Bin 12590 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_172.class | Bin 13807 -> 0 bytes .../resources/nmsblocks/CBXNmsBlock_175.class | Bin 13808 -> 0 bytes .../nmsblocks/CBXNmsBlock_prePackage.class | Bin 12484 -> 0 bytes .../nmsblocks/CBXNmsBlock_v152_2.class | Bin 12552 -> 0 bytes .../nmsblocks/MCPCPlusXNmsBlock_147.class | Bin 9277 -> 0 bytes .../nmsblocks/MCPCPlusXNmsBlock_151dv.class | Bin 10513 -> 0 bytes .../nmsblocks/MCPCPlusXNmsBlock_162.class | Bin 9348 -> 0 bytes .../nmsblocks/MCPCPlusXNmsBlock_164.class | Bin 9348 -> 0 bytes .../java/com/sk89q/worldedit/LocalWorld.java | 104 --- .../worldedit/internal/LocalWorldAdapter.java | 55 -- .../command/WorldEditExceptionConverter.java | 2 +- .../java/com/sk89q/worldedit/util/Enums.java | 54 ++ .../sk89q/worldedit/world/AbstractWorld.java | 81 +- .../java/com/sk89q/worldedit/world/World.java | 18 - 34 files changed, 528 insertions(+), 1580 deletions(-) delete mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java delete mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/AdapterLoadException.java create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java create mode 100644 src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class create mode 100644 src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R3.class create mode 100644 src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R4.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_152.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_162.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_164.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_172.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_prePackage.class delete mode 100644 src/bukkit/resources/nmsblocks/CBXNmsBlock_v152_2.class delete mode 100644 src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class delete mode 100644 src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class delete mode 100644 src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class delete mode 100644 src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_164.class create mode 100644 src/main/java/com/sk89q/worldedit/util/Enums.java diff --git a/pom.xml b/pom.xml index f0a66b601..d4ea069f1 100644 --- a/pom.xml +++ b/pom.xml @@ -542,16 +542,6 @@ jar true
- - - - org.bukkit - craftbukkit - 1.7.9-R0.1-SNAPSHOT - compile - jar - true - @@ -578,11 +568,11 @@ - nmsblocks/ + . false - ${basedir}/src/bukkit/resources/nmsblocks/ + ${basedir}/src/bukkit/resources/ - *.class + **/*.class diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 579ea88ae..7de20172b 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -98,6 +98,21 @@ final class BukkitAdapter { (float) Math.toDegrees(location.getPitch())); } + /** + * Create a Bukkit location from a WorldEdit position with a Bukkit world. + * + * @param world the Bukkit world + * @param position the WorldEdit position + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(org.bukkit.World world, Vector position) { + checkNotNull(world); + checkNotNull(position); + return new org.bukkit.Location( + world, + position.getX(), position.getY(), position.getZ()); + } + /** * Create a WorldEdit entity from a Bukkit entity. * diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index e693f18ea..29648289d 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -31,36 +31,23 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.blocks.ContainerBlock; -import com.sk89q.worldedit.blocks.FurnaceBlock; import com.sk89q.worldedit.blocks.LazyBlock; -import com.sk89q.worldedit.blocks.MobSpawnerBlock; -import com.sk89q.worldedit.blocks.NoteBlock; -import com.sk89q.worldedit.blocks.SignBlock; -import com.sk89q.worldedit.blocks.SkullBlock; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Enums; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.WorldData; -import org.bukkit.Bukkit; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.SkullType; import org.bukkit.TreeType; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Chest; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.block.Furnace; -import org.bukkit.block.Sign; -import org.bukkit.block.Skull; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Ambient; import org.bukkit.entity.Animals; import org.bukkit.entity.Boat; @@ -82,15 +69,9 @@ import org.bukkit.entity.Villager; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; import javax.annotation.Nullable; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.InputStream; import java.lang.ref.WeakReference; -import java.lang.reflect.Method; -import java.net.URL; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; @@ -107,118 +88,26 @@ import static com.google.common.base.Preconditions.checkNotNull; public class BukkitWorld extends LocalWorld { private static final Logger logger = WorldEdit.logger; - private final WeakReference worldRef; - private static boolean skipNmsAccess = false; - private static boolean skipNmsSafeSet = false; - private static boolean skipNmsValidBlockCheck = false; + private static final org.bukkit.entity.EntityType tntMinecartType = + Enums.findByValue(org.bukkit.entity.EntityType.class, "MINECART_TNT"); - /* - * holder for the nmsblock class that we should use - */ - private static Class nmsBlockType; - private static Method nmsSetMethod; - private static Method nmsValidBlockMethod; - private static Method nmsGetMethod; - private static Method nmsSetSafeMethod; - - // copied from WG - private static > T tryEnum(Class enumType, String ... values) { - for (String val : values) { - try { - return Enum.valueOf(enumType, val); - } catch (IllegalArgumentException e) {} + private static final Map effects = new HashMap(); + static { + for (Effect effect : Effect.values()) { + effects.put(effect.getId(), effect); } - return null; } - private static org.bukkit.entity.EntityType tntMinecartType; - private static boolean checkMinecartType = true; + + private final WeakReference worldRef; /** * Construct the object. - * @param world + * + * @param world the world */ @SuppressWarnings("unchecked") public BukkitWorld(World world) { this.worldRef = new WeakReference(world); - - if (checkMinecartType) { - tntMinecartType = tryEnum(org.bukkit.entity.EntityType.class, "MINECART_TNT"); - checkMinecartType = false; - } - // check if we have a class we can use for nms access - - // only run once per server startup - if (nmsBlockType != null || skipNmsAccess || skipNmsSafeSet || skipNmsValidBlockCheck) return; - Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit"); - if (!(plugin instanceof WorldEditPlugin)) return; // hopefully never happens - WorldEditPlugin wePlugin = ((WorldEditPlugin) plugin); - File nmsBlocksDir = new File(wePlugin.getDataFolder() + File.separator + "nmsblocks" + File.separator); - if (nmsBlocksDir.listFiles() == null) { // no files to use - skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; - return; - } - try { - // make a classloader that can handle our blocks - NmsBlockClassLoader loader = new NmsBlockClassLoader(BukkitWorld.class.getClassLoader(), nmsBlocksDir); - String filename; - for (File f : nmsBlocksDir.listFiles()) { - if (!f.isFile()) continue; - filename = f.getName(); - // load class using magic keyword - Class testBlock = null; - try { - testBlock = loader.loadClass("CL-NMS" + filename); - } catch (Throwable e) { - // someone is putting things where they don't belong - continue; - } - filename = filename.replaceFirst(".class$", ""); // get rid of extension - if (NmsBlock.class.isAssignableFrom(testBlock)) { - // got a NmsBlock, test it now - Class nmsClass = (Class) testBlock; - boolean canUse = false; - try { - canUse = (Boolean) nmsClass.getMethod("verify").invoke(null); - } catch (Throwable e) { - continue; - } - if (!canUse) continue; // not for this server - nmsBlockType = nmsClass; - nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class); - nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class); - nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class); - nmsSetSafeMethod = nmsBlockType.getMethod("setSafely", - BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class); - // phew - break; - } - } - if (nmsBlockType != null) { - logger.info("[WorldEdit] Using external NmsBlock for this version: " + nmsBlockType.getName()); - } else { - // try our default - try { - nmsBlockType = (Class) Class.forName("com.sk89q.worldedit.bukkit.DefaultNmsBlock"); - boolean canUse = (Boolean) nmsBlockType.getMethod("verify").invoke(null); - if (canUse) { - nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class); - nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class); - nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class); - nmsSetSafeMethod = nmsBlockType.getMethod("setSafely", - BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class); - logger.info("[WorldEdit] Using inbuilt NmsBlock for this version."); - } - } catch (Throwable e) { - // OMG DEVS WAI U NO SUPPORT SERVER - skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; - logger.warning("[WorldEdit] No compatible nms block class found."); - } - } - } catch (Throwable e) { - logger.warning("[WorldEdit] Unable to load NmsBlock classes, make sure they are installed correctly."); - e.printStackTrace(); - skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; - } } @Override @@ -256,41 +145,6 @@ public class BukkitWorld extends LocalWorld { throw new UnsupportedOperationException("Not implemented yet"); } - private class NmsBlockClassLoader extends ClassLoader { - public File searchDir; - public NmsBlockClassLoader(ClassLoader parent, File searchDir) { - super(parent); - this.searchDir = searchDir; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - if (!name.startsWith("CL-NMS")) { - return super.loadClass(name); - } else { - name = name.replace("CL-NMS", ""); // hacky lol - } - try { - URL url = new File(searchDir, name).toURI().toURL(); - InputStream input = url.openConnection().getInputStream(); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - int data = input.read(); - while (data != -1) { - buffer.write(data); - data = input.read(); - } - input.close(); - - byte[] classData = buffer.toByteArray(); - - return defineClass(name.replaceFirst(".class$", ""), classData, 0, classData.length); - } catch (Throwable e) { - throw new ClassNotFoundException(); - } - } - } - /** * Get the world handle. * @@ -318,66 +172,6 @@ public class BukkitWorld extends LocalWorld { return getWorld().getName(); } - /** - * Set block type. - * - * @param pt - * @param type - * @return - */ - @Override - public boolean setBlockType(Vector pt, int type) { - return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type); - } - - /** - * Set block type. - * - * @param pt - * @param type - * @return - */ - @Override - public boolean setBlockTypeFast(Vector pt, int type) { - return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type, false); - } - - @Override - public boolean setTypeIdAndData(Vector pt, int type, int data) { - return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, true); - } - - @Override - public boolean setTypeIdAndDataFast(Vector pt, int type, int data) { - return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, false); - } - - /** - * Get block type. - * - * @param pt - * @return - */ - @Override - public int getBlockType(Vector pt) { - return getWorld().getBlockTypeIdAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - } - - @Override - public void setBlockData(Vector pt, int data) { - getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data); - } - - @Override - public void setBlockDataFast(Vector pt, int data) { - getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data, false); - } - - @Override - public int getBlockData(Vector pt) { - return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getData(); - } - @Override public int getBlockLightLevel(Vector pt) { return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); @@ -423,7 +217,7 @@ public class BukkitWorld extends LocalWorld { try { getWorld().regenerateChunk(chunk.getBlockX(), chunk.getBlockZ()); } catch (Throwable t) { - t.printStackTrace(); + logger.log(Level.WARNING, "Chunk generation via Bukkit raised an error", t); } // Then restore @@ -448,303 +242,6 @@ public class BukkitWorld extends LocalWorld { return true; } - @Override - public boolean copyToWorld(Vector pt, BaseBlock block) { - World world = getWorld(); - - if (block instanceof SignBlock) { - // Signs - setSignText(pt, ((SignBlock) block).getText()); - return true; - } - - if (block instanceof FurnaceBlock) { - // Furnaces - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof Furnace)) return false; - Furnace bukkit = (Furnace) state; - FurnaceBlock we = (FurnaceBlock) block; - bukkit.setBurnTime(we.getBurnTime()); - bukkit.setCookTime(we.getCookTime()); - return setContainerBlockContents(pt, ((ContainerBlock) block).getItems()); - } - - if (block instanceof ContainerBlock) { - // Chests/dispenser - return setContainerBlockContents(pt, ((ContainerBlock) block).getItems()); - } - - if (block instanceof MobSpawnerBlock) { - // Mob spawners - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof CreatureSpawner)) return false; - CreatureSpawner bukkit = (CreatureSpawner) state; - MobSpawnerBlock we = (MobSpawnerBlock) block; - bukkit.setCreatureTypeByName(we.getMobType()); - bukkit.setDelay(we.getDelay()); - return true; - } - - if (block instanceof NoteBlock) { - // Note block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.NoteBlock)) return false; - org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state; - NoteBlock we = (NoteBlock) block; - bukkit.setRawNote(we.getNote()); - return true; - } - - if (block instanceof SkullBlock) { - // Skull block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.Skull)) return false; - Skull bukkit = (Skull) state; - SkullBlock we = (SkullBlock) block; - // this is dumb - SkullType skullType = SkullType.SKELETON; - switch (we.getSkullType()) { - case 0: - skullType = SkullType.SKELETON; - break; - case 1: - skullType = SkullType.WITHER; - break; - case 2: - skullType = SkullType.ZOMBIE; - break; - case 3: - skullType = SkullType.PLAYER; - break; - case 4: - skullType = SkullType.CREEPER; - break; - } - bukkit.setSkullType(skullType); - BlockFace rotation; - switch (we.getRot()) { - // soooo dumb - case 0: - rotation = BlockFace.NORTH; - break; - case 1: - rotation = BlockFace.NORTH_NORTH_EAST; - break; - case 2: - rotation = BlockFace.NORTH_EAST; - break; - case 3: - rotation = BlockFace.EAST_NORTH_EAST; - break; - case 4: - rotation = BlockFace.EAST; - break; - case 5: - rotation = BlockFace.EAST_SOUTH_EAST; - break; - case 6: - rotation = BlockFace.SOUTH_EAST; - break; - case 7: - rotation = BlockFace.SOUTH_SOUTH_EAST; - break; - case 8: - rotation = BlockFace.SOUTH; - break; - case 9: - rotation = BlockFace.SOUTH_SOUTH_WEST; - break; - case 10: - rotation = BlockFace.SOUTH_WEST; - break; - case 11: - rotation = BlockFace.WEST_SOUTH_WEST; - break; - case 12: - rotation = BlockFace.WEST; - break; - case 13: - rotation = BlockFace.WEST_NORTH_WEST; - break; - case 14: - rotation = BlockFace.NORTH_WEST; - break; - case 15: - rotation = BlockFace.NORTH_NORTH_WEST; - break; - default: - rotation = BlockFace.NORTH; - break; - } - bukkit.setRotation(rotation); - if (we.getOwner() != null && !we.getOwner().isEmpty()) bukkit.setOwner(we.getOwner()); - bukkit.update(true); - return true; - } - - if (!skipNmsAccess) { - try { - return (Boolean) nmsSetMethod.invoke(null, world, pt, block); - } catch (Throwable t) { - logger.log(Level.WARNING, "WorldEdit: Failed to do NMS access for direct NBT data copy", t); - skipNmsAccess = true; - } - } - - return false; - } - - @Override - public boolean copyFromWorld(Vector pt, BaseBlock block) { - World world = getWorld(); - - if (block instanceof SignBlock) { - // Signs - ((SignBlock) block).setText(getSignText(pt)); - return true; - } - - if (block instanceof FurnaceBlock) { - // Furnaces - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof Furnace)) return false; - Furnace bukkit = (Furnace) state; - FurnaceBlock we = (FurnaceBlock) block; - we.setBurnTime(bukkit.getBurnTime()); - we.setCookTime(bukkit.getCookTime()); - ((ContainerBlock) block).setItems(getContainerBlockContents(pt)); - return true; - } - - if (block instanceof ContainerBlock) { - // Chests/dispenser - ((ContainerBlock) block).setItems(getContainerBlockContents(pt)); - return true; - } - - if (block instanceof MobSpawnerBlock) { - // Mob spawners - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof CreatureSpawner)) return false; - CreatureSpawner bukkit = (CreatureSpawner) state; - MobSpawnerBlock we = (MobSpawnerBlock) block; - we.setMobType(bukkit.getCreatureTypeName()); - we.setDelay((short) bukkit.getDelay()); - return true; - } - - if (block instanceof NoteBlock) { - // Note block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.NoteBlock)) return false; - org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state; - NoteBlock we = (NoteBlock) block; - we.setNote(bukkit.getRawNote()); - return true; - } - - if (block instanceof SkullBlock) { - // Skull block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.Skull)) return false; - Skull bukkit = (Skull) state; - SkullBlock we = (SkullBlock) block; - byte skullType = 0; - switch (bukkit.getSkullType()) { - // this is dumb but whoever wrote the class is stupid - case SKELETON: - skullType = 0; - break; - case WITHER: - skullType = 1; - break; - case ZOMBIE: - skullType = 2; - break; - case PLAYER: - skullType = 3; - break; - case CREEPER: - skullType = 4; - break; - } - we.setSkullType(skullType); - byte rot = 0; - switch (bukkit.getRotation()) { - // this is even more dumb, hurray for copy/paste - case NORTH: - rot = (byte) 0; - break; - case NORTH_NORTH_EAST: - rot = (byte) 1; - break; - case NORTH_EAST: - rot = (byte) 2; - break; - case EAST_NORTH_EAST: - rot = (byte) 3; - break; - case EAST: - rot = (byte) 4; - break; - case EAST_SOUTH_EAST: - rot = (byte) 5; - break; - case SOUTH_EAST: - rot = (byte) 6; - break; - case SOUTH_SOUTH_EAST: - rot = (byte) 7; - break; - case SOUTH: - rot = (byte) 8; - break; - case SOUTH_SOUTH_WEST: - rot = (byte) 9; - break; - case SOUTH_WEST: - rot = (byte) 10; - break; - case WEST_SOUTH_WEST: - rot = (byte) 11; - break; - case WEST: - rot = (byte) 12; - break; - case WEST_NORTH_WEST: - rot = (byte) 13; - break; - case NORTH_WEST: - rot = (byte) 14; - break; - case NORTH_NORTH_WEST: - rot = (byte) 15; - break; - } - we.setRot(rot); - we.setOwner(bukkit.hasOwner() ? bukkit.getOwner() : ""); - return true; - } - - return false; - } - /** * Gets the single block inventory for a potentially double chest. * Handles people who have an old version of Bukkit. @@ -1032,159 +529,9 @@ public class BukkitWorld extends LocalWorld { return num; } - /** - * Set a sign's text. - * - * @param pt - * @param text - * @return - */ - private boolean setSignText(Vector pt, String[] text) { - World world = getWorld(); - - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) return false; - BlockState state = block.getState(); - if (state == null || !(state instanceof Sign)) return false; - Sign sign = (Sign) state; - sign.setLine(0, text[0]); - sign.setLine(1, text[1]); - sign.setLine(2, text[2]); - sign.setLine(3, text[3]); - sign.update(); - return true; - } - - /** - * Get a sign's text. - * - * @param pt - * @return - */ - private String[] getSignText(Vector pt) { - World world = getWorld(); - - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) return new String[] { "", "", "", "" }; - BlockState state = block.getState(); - if (state == null || !(state instanceof Sign)) return new String[] { "", "", "", "" }; - Sign sign = (Sign) state; - String line0 = sign.getLine(0); - String line1 = sign.getLine(1); - String line2 = sign.getLine(2); - String line3 = sign.getLine(3); - return new String[] { - line0 != null ? line0 : "", - line1 != null ? line1 : "", - line2 != null ? line2 : "", - line3 != null ? line3 : "", - }; - } - - /** - * Get a container block's contents. - * - * @param pt - * @return - */ - private BaseItemStack[] getContainerBlockContents(Vector pt) { - Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) { - return new BaseItemStack[0]; - } - BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { - return new BaseItemStack[0]; - } - - org.bukkit.inventory.InventoryHolder container = (org.bukkit.inventory.InventoryHolder) state; - Inventory inven = container.getInventory(); - if (container instanceof Chest) { - inven = getBlockInventory((Chest) container); - } - int size = inven.getSize(); - BaseItemStack[] contents = new BaseItemStack[size]; - - for (int i = 0; i < size; ++i) { - ItemStack bukkitStack = inven.getItem(i); - if (bukkitStack != null && bukkitStack.getTypeId() > 0) { - contents[i] = new BaseItemStack( - bukkitStack.getTypeId(), - bukkitStack.getAmount(), - bukkitStack.getDurability()); - try { - for (Map.Entry entry : bukkitStack.getEnchantments().entrySet()) { - contents[i].getEnchantments().put(entry.getKey().getId(), entry.getValue()); - } - } catch (Throwable ignore) {} - } - } - - return contents; - } - - /** - * Set a container block's contents. - * - * @param pt - * @param contents - * @return - */ - private boolean setContainerBlockContents(Vector pt, BaseItemStack[] contents) { - Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) { - return false; - } - BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { - return false; - } - - org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; - Inventory inven = chest.getInventory(); - if (chest instanceof Chest) { - inven = getBlockInventory((Chest) chest); - } - int size = inven.getSize(); - - for (int i = 0; i < size; ++i) { - if (i >= contents.length) { - break; - } - - if (contents[i] != null) { - ItemStack toAdd = new ItemStack(contents[i].getType(), - contents[i].getAmount(), - contents[i].getData()); - try { - for (Map.Entry entry : contents[i].getEnchantments().entrySet()) { - toAdd.addEnchantment(Enchantment.getById(entry.getKey()), entry.getValue()); - } - } catch (Throwable ignore) {} - inven.setItem(i, toAdd); - } else { - inven.setItem(i, null); - } - } - - return true; - } - - /** - * Returns whether a block has a valid ID. - * - * @param type - * @return - */ + @SuppressWarnings("deprecation") @Override public boolean isValidBlockType(int type) { - if (!skipNmsValidBlockCheck) { - try { - return (Boolean) nmsValidBlockMethod.invoke(null, type); - } catch (Throwable e) { - skipNmsValidBlockCheck = true; - } - } return Material.getMaterial(type) != null && Material.getMaterial(type).isBlock(); } @@ -1228,13 +575,6 @@ public class BukkitWorld extends LocalWorld { } } - private static final Map effects = new HashMap(); - static { - for (Effect effect : Effect.values()) { - effects.put(effect.getId(), effect); - } - } - @Override public boolean playEffect(Vector position, int type, int data) { World world = getWorld(); @@ -1278,38 +618,25 @@ public class BukkitWorld extends LocalWorld { } @Override - public BaseBlock getBlock(Vector pt) { - int type = getBlockType(pt); - int data = getBlockData(pt); - - switch (type) { - case BlockID.WALL_SIGN: - case BlockID.SIGN_POST: - //case BlockID.CHEST: // Prevent data loss for now - //case BlockID.FURNACE: - //case BlockID.BURNING_FURNACE: - //case BlockID.DISPENSER: - //case BlockID.MOB_SPAWNER: - case BlockID.NOTE_BLOCK: - case BlockID.HEAD: - return super.getBlock(pt); - default: - if (!skipNmsAccess) { - try { - NmsBlock block = null; - block = (NmsBlock) nmsGetMethod.invoke(null, getWorld(), pt, type, data); - if (block != null) { - return block; - } - } catch (Throwable t) { - logger.log(Level.WARNING, - "WorldEdit: Failed to do NMS access for direct NBT data copy", t); - skipNmsAccess = true; - } - } + public BaseBlock getBlock(Vector position) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + return adapter.getBlock(BukkitAdapter.adapt(getWorld(), position)); + } else { + Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return new BaseBlock(bukkitBlock.getTypeId(), bukkitBlock.getData()); } + } - return super.getBlock(pt); + @Override + public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + return adapter.setBlock(BukkitAdapter.adapt(getWorld(), position), block, notifyAndLight); + } else { + Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return bukkitBlock.setTypeIdAndData(block.getType(), (byte) block.getData(), notifyAndLight); + } } @SuppressWarnings("deprecation") @@ -1320,20 +647,6 @@ public class BukkitWorld extends LocalWorld { return new LazyBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), this, position); } - @Override - public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) throws WorldEditException { - if (!skipNmsSafeSet) { - try { - return (Boolean) nmsSetSafeMethod.invoke(null, this, pt, block, notifyAdjacent); - } catch (Throwable t) { - logger.log(Level.WARNING, "WorldEdit: Failed to do NMS safe block set", t); - skipNmsSafeSet = true; - } - } - - return super.setBlock(pt, block, notifyAdjacent); - } - /** * @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)} */ diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java deleted file mode 100644 index 8b738923b..000000000 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java +++ /dev/null @@ -1,472 +0,0 @@ -/* - * 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.bukkit; -import com.sk89q.jnbt.*; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.world.DataException; -import com.sk89q.worldedit.foundation.Block; -import net.minecraft.server.v1_7_R3.*; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_7_R3.CraftWorld; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.*; -import java.util.logging.Logger; - -/** - * A blind handler of blocks with TileEntity data that directly access Minecraft's - * classes through CraftBukkit. - *

- * Usage of this class may break terribly in the future, and therefore usage should - * be trapped in a handler for {@link Throwable}. - */ -public class DefaultNmsBlock extends NmsBlock { - - private static final Logger logger = WorldEdit.logger; - private static Field compoundMapField; - private static final Field nmsBlock_isTileEntityField; // The field is deobfuscated but the method isn't. No idea why. - private NBTTagCompound nbtData = null; - - static { - Field field; - try { - field = net.minecraft.server.v1_7_R3.Block.class.getDeclaredField("isTileEntity"); - field.setAccessible(true); - } catch (NoSuchFieldException e) { - // logger.severe("Could not find NMS block tile entity field!"); - field = null; - } - nmsBlock_isTileEntityField = field; - } - - public static boolean verify() { - return nmsBlock_isTileEntityField != null; - } - - /** - * Create a new instance with a given type ID, data value, and previous - * {@link TileEntityBlock}-implementing object. - * - * @param type block type ID - * @param data data value - * @param tileEntityBlock tile entity block - */ - public DefaultNmsBlock(int type, int data, TileEntityBlock tileEntityBlock) { - super(type, data); - - nbtData = (NBTTagCompound) fromNative(tileEntityBlock.getNbtData()); - } - - /** - * Create a new instance with a given type ID, data value, and raw - * {@link NBTTagCompound} copy. - * - * @param type block type ID - * @param data data value - * @param nbtData raw NBT data - */ - public DefaultNmsBlock(int type, int data, NBTTagCompound nbtData) { - super(type, data); - - this.nbtData = nbtData; - } - - /** - * Build a {@link NBTTagCompound} that has valid coordinates. - * - * @param pt coordinates to set - * @return the tag compound - */ - private NBTTagCompound getNmsData(Vector pt) { - if (nbtData == null) { - return null; - } - - nbtData.set("x", new NBTTagInt(pt.getBlockX())); - nbtData.set("y", new NBTTagInt(pt.getBlockY())); - nbtData.set("z", new NBTTagInt(pt.getBlockZ())); - - return nbtData; - } - - @Override - public boolean hasNbtData() { - return nbtData != null; - } - - @Override - public String getNbtId() { - if (nbtData == null) { - return ""; - } - - return nbtData.getString("id"); - } - - @Override - public CompoundTag getNbtData() { - if (nbtData == null) { - return new CompoundTag(getNbtId(), - new HashMap()); - } - return (CompoundTag) toNative(nbtData); - } - - @Override - public void setNbtData(CompoundTag tag) { - if (tag == null) { - this.nbtData = null; - } - this.nbtData = (NBTTagCompound) fromNative(tag); - } - - /** - * Build an instance from the given information. - * - * @param world world to get the block from - * @param position position to get the block at - * @param type type ID of block - * @param data data value of block - * @return the block, or null - */ - public static DefaultNmsBlock get(World world, Vector position, int type, int data) { - if (!hasTileEntity(type)) { - return null; - } - - TileEntity te = ((CraftWorld) world).getHandle().getTileEntity( - position.getBlockX(), position.getBlockY(), position.getBlockZ()); - - if (te != null) { - NBTTagCompound tag = new NBTTagCompound(); - te.b(tag); // Load data - return new DefaultNmsBlock(type, data, tag); - } - - return null; - } - - /** - * Set an instance or a {@link TileEntityBlock} to the given position. - * - * @param world world to set the block in - * @param position position to set the block at - * @param block the block to set - * @return true if tile entity data was copied to the world - */ - public static boolean set(World world, Vector position, BaseBlock block) { - NBTTagCompound data = null; - if (!hasTileEntity(world.getBlockTypeIdAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()))) { - return false; - } - - if (block instanceof DefaultNmsBlock) { - DefaultNmsBlock nmsProxyBlock = (DefaultNmsBlock) block; - data = nmsProxyBlock.getNmsData(position); - } else if (block instanceof TileEntityBlock) { - DefaultNmsBlock nmsProxyBlock = new DefaultNmsBlock( - block.getId(), block.getData(), block); - data = nmsProxyBlock.getNmsData(position); - } - - if (data != null) { - TileEntity te = ((CraftWorld) world).getHandle().getTileEntity( - position.getBlockX(), position.getBlockY(), position.getBlockZ()); - if (te != null) { - te.a(data); // Load data - return true; - } - } - - return false; - } - - /** - * Tries to set a block 'safely', as in setting the block data to the location, and - * then triggering physics only at the end. - * - * @param world world to set the block in - * @param position position to set the block at - * @param block the block to set - * @param notifyAdjacent true to notify physics and what not - * @return true if block id or data was changed - */ - public static boolean setSafely(BukkitWorld world, Vector position, - Block block, boolean notifyAdjacent) { - - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); - - CraftWorld craftWorld = ((CraftWorld) world.getWorld()); -// TileEntity te = craftWorld.getHandle().getTileEntity(x, y, z); -// craftWorld.getHandle().tileEntityList.remove(te); - - boolean changed = craftWorld.getHandle().setTypeAndData(x, y, z, getNmsBlock(block.getId()), block.getData(), 0); - - if (block instanceof BaseBlock) { - world.copyToWorld(position, (BaseBlock) block); - } - - changed = craftWorld.getHandle().setData(x, y, z, block.getData(), 0) || changed; - if (changed && notifyAdjacent) { - craftWorld.getHandle().notify(x, y, z); - craftWorld.getHandle().update(x, y, z, getNmsBlock(block.getId())); - } - - return changed; - } - - public static boolean hasTileEntity(int type) { - net.minecraft.server.v1_7_R3.Block nmsBlock = getNmsBlock(type); - if (nmsBlock == null) { - return false; - } - - try { - return nmsBlock_isTileEntityField.getBoolean(nmsBlock); // Once we have the field stord, gets are fast - } catch (IllegalAccessException e) { - return false; - } - } - - public static net.minecraft.server.v1_7_R3.Block getNmsBlock(int type) { - return net.minecraft.server.v1_7_R3.Block.e(type); - } - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - private static Tag toNative(NBTBase foreign) { - // temporary fix since mojang removed names from tags - // our nbt spec will need to be updated to theirs - return toNative(getTagName(foreign.getTypeId()), foreign); - } - - // seriously these two methods are hacky - our jnbt spec needs updating - // copied from NMS 1.7.5- code, since it was removed in 1.7.8 - private static String getTagName(int i) { - switch (i) { - case 0: - return "TAG_End"; - case 1: - return "TAG_Byte"; - case 2: - return "TAG_Short"; - case 3: - return "TAG_Int"; - case 4: - return "TAG_Long"; - case 5: - return "TAG_Float"; - case 6: - return "TAG_Double"; - case 7: - return "TAG_Byte_Array"; - case 8: - return "TAG_String"; - case 9: - return "TAG_List"; - case 10: - return "TAG_Compound"; - case 11: - return "TAG_Int_Array"; - case 99: - return "Any Numeric Tag"; - default: - return "UNKNOWN"; - } - } - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @param name name for the tag, if it has one - * @return native WorldEdit NBT structure - */ - @SuppressWarnings("unchecked") - private static Tag toNative(String name, NBTBase foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof NBTTagCompound) { - Map values = new HashMap(); - Collection foreignKeys = null; - - if (compoundMapField == null) { - try { - // Method name may change! - foreignKeys = ((NBTTagCompound) foreign).c(); - } catch (Throwable t) { - try { - logger.warning("WorldEdit: Couldn't get NBTTagCompound.c(), " + - "so we're going to try to get at the 'map' field directly from now on"); - - if (compoundMapField == null) { - compoundMapField = NBTTagCompound.class.getDeclaredField("map"); - compoundMapField.setAccessible(true); - } - } catch (Throwable e) { - // Can't do much beyond this - throw new RuntimeException(e); - } - } - } - - if (compoundMapField != null) { - try { - foreignKeys = ((HashMap) compoundMapField.get(foreign)).keySet(); - } catch (Throwable e) { - // Can't do much beyond this - throw new RuntimeException(e); - } - } - - for (Object obj : foreignKeys) { - String key = (String) obj; - NBTBase base = (NBTBase) ((NBTTagCompound) foreign).get(key); - values.put(key, toNative(key, base)); - } - return new CompoundTag(name, values); - } else if (foreign instanceof NBTTagByte) { - return new ByteTag(name, ((NBTTagByte) foreign).f()); // getByte - } else if (foreign instanceof NBTTagByteArray) { - return new ByteArrayTag(name, - ((NBTTagByteArray) foreign).c()); // data - } else if (foreign instanceof NBTTagDouble) { - return new DoubleTag(name, - ((NBTTagDouble) foreign).g()); // getDouble - } else if (foreign instanceof NBTTagFloat) { - return new FloatTag(name, ((NBTTagFloat) foreign).h()); // getFloat - } else if (foreign instanceof NBTTagInt) { - return new IntTag(name, ((NBTTagInt) foreign).d()); // getInt - } else if (foreign instanceof NBTTagIntArray) { - return new IntArrayTag(name, - ((NBTTagIntArray) foreign).c()); // data - } else if (foreign instanceof NBTTagList) { - try { - return transmorgifyList(name, (NBTTagList) foreign); - } catch (NoSuchFieldException e) { - } catch (SecurityException e) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) {} - return new ListTag(name, ByteTag.class, new ArrayList()); - } else if (foreign instanceof NBTTagLong) { - return new LongTag(name, ((NBTTagLong) foreign).c()); // getLong - } else if (foreign instanceof NBTTagShort) { - return new ShortTag(name, ((NBTTagShort) foreign).e()); // getShort - } else if (foreign instanceof NBTTagString) { - return new StringTag(name, - ((NBTTagString) foreign).a_()); // data - } else if (foreign instanceof NBTTagEnd) { - return new EndTag(); - } else { - throw new IllegalArgumentException("Don't know how to make native " - + foreign.getClass().getCanonicalName()); - } - } - - private static ListTag transmorgifyList(String name, NBTTagList foreign) - throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { - List values = new ArrayList(); - int type = foreign.d(); - Field listField = NBTTagList.class.getDeclaredField("list"); - listField.setAccessible(true); - List foreignList; - foreignList = (List) listField.get(foreign); - for (int i = 0; i < foreign.size(); i++) { - NBTBase element = (NBTBase) foreignList.get(i); - values.add(toNative(null, element)); // list elements shouldn't have names - } - Class cls = NBTConstants.getClassFromType(type); - return new ListTag(name, cls, values); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - private static NBTBase fromNative(Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof CompoundTag) { - NBTTagCompound tag = new NBTTagCompound(); - for (Map.Entry entry : ((CompoundTag) foreign) - .getValue().entrySet()) { - tag.set(entry.getKey(), fromNative(entry.getValue())); - } - return tag; - } else if (foreign instanceof ByteTag) { - return new NBTTagByte(((ByteTag) foreign).getValue()); - } else if (foreign instanceof ByteArrayTag) { - return new NBTTagByteArray(((ByteArrayTag) foreign).getValue()); - } else if (foreign instanceof DoubleTag) { - return new NBTTagDouble(((DoubleTag) foreign).getValue()); - } else if (foreign instanceof FloatTag) { - return new NBTTagFloat(((FloatTag) foreign).getValue()); - } else if (foreign instanceof IntTag) { - return new NBTTagInt(((IntTag) foreign).getValue()); - } else if (foreign instanceof IntArrayTag) { - return new NBTTagIntArray(((IntArrayTag) foreign).getValue()); - } else if (foreign instanceof ListTag) { - NBTTagList tag = new NBTTagList(); - ListTag foreignList = (ListTag) foreign; - for (Tag t : foreignList.getValue()) { - tag.add(fromNative(t)); - } - return tag; - } else if (foreign instanceof LongTag) { - return new NBTTagLong(((LongTag) foreign).getValue()); - } else if (foreign instanceof ShortTag) { - return new NBTTagShort(((ShortTag) foreign).getValue()); - } else if (foreign instanceof StringTag) { - return new NBTTagString(((StringTag) foreign).getValue()); - } else if (foreign instanceof EndTag) { - try { - Method tagMaker = NBTBase.class.getDeclaredMethod("createTag", byte.class); - tagMaker.setAccessible(true); - return (NBTBase) tagMaker.invoke(null, (byte) 0); - } catch (Exception e) { - return null; - } - } else { - throw new IllegalArgumentException("Don't know how to make NMS " - + foreign.getClass().getCanonicalName()); - } - } - - public static boolean isValidBlockType(int type) throws NoClassDefFoundError { - return type == 0 || (type >= 1 && net.minecraft.server.v1_7_R3.Block.e(type) != null); - } - -} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java deleted file mode 100644 index 088de8547..000000000 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.bukkit; - -import org.bukkit.World; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.foundation.Block; - -public abstract class NmsBlock extends BaseBlock { - - protected NmsBlock(int type) { - super(type); - } - - protected NmsBlock(int type, int data) { - super(type, data); - } - - public static boolean verify() { - return false; - } - - public static NmsBlock get(World world, Vector vector, int type, int data) { - return null; - } - - public static boolean set(World world, Vector vector, Block block) { - return false; - } - - public static boolean setSafely(World world, Vector vector, Block block, boolean notify) { - return false; - } - - public static boolean hasTileEntity(int type) { - return false; - } - - public static boolean isValidBlockType(int type) { - return false; - } -} \ No newline at end of file diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 0cdaf470d..eac26306b 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -22,7 +22,16 @@ package com.sk89q.worldedit.bukkit; import com.google.common.base.Joiner; import com.sk89q.util.yaml.YAMLProcessor; import com.sk89q.wepif.PermissionsResolverManager; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.ServerInterface; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditOperation; +import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader; import com.sk89q.worldedit.bukkit.selections.CuboidSelection; import com.sk89q.worldedit.bukkit.selections.CylinderSelection; import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; @@ -32,7 +41,11 @@ import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.event.platform.PlatformReadyEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; -import com.sk89q.worldedit.regions.*; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -40,13 +53,20 @@ import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; -import java.io.*; -import java.util.Enumeration; +import javax.annotation.Nullable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.List; -import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.ZipEntry; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Plugin for Bukkit. * @@ -54,27 +74,13 @@ import java.util.zip.ZipEntry; */ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { - /** - * The name of the CUI's plugin channel registration - */ + private static final Logger log = Logger.getLogger(WorldEditPlugin.class.getCanonicalName()); public static final String CUI_PLUGIN_CHANNEL = "WECUI"; + private static WorldEditPlugin INSTANCE; - /** - * The server interface that all server-related API goes through. - */ + private BukkitImplAdapter bukkitAdapter; private BukkitServerInterface server; - /** - * Main WorldEdit instance. - */ - private WorldEdit controller; - /** - * Deprecated API. - */ - private WorldEditAPI api; - - /** - * Holds the configuration for WorldEdit. - */ + private final WorldEditAPI api = new WorldEditAPI(this); private BukkitConfiguration config; /** @@ -82,41 +88,27 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { */ @Override public void onEnable() { - final String pluginYmlVersion = getDescription().getVersion(); - final String manifestVersion = WorldEdit.getVersion(); + this.INSTANCE = this; - if (!manifestVersion.equalsIgnoreCase(pluginYmlVersion)) { - WorldEdit.setVersion(manifestVersion + " (" + pluginYmlVersion + ")"); - } + WorldEdit worldEdit = WorldEdit.getInstance(); - // Make the data folders that WorldEdit uses - getDataFolder().mkdirs(); - File targetDir = new File(getDataFolder() + File.separator + "nmsblocks"); - targetDir.mkdir(); - copyNmsBlockClasses(targetDir); + loadAdapter(); // Need an adapter to work with special blocks with NBT data + loadConfig(); // Load configuration + PermissionsResolverManager.initialize(this); // Setup permission resolver - // Create the default configuration file - createDefaultConfiguration("config.yml"); - - // Set up configuration and such, including the permissions - // resolver - config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this); - PermissionsResolverManager.initialize(this); - - // Load the configuration - config.load(); - - // Setup interfaces + // Setup platform server = new BukkitServerInterface(this, getServer()); - controller = WorldEdit.getInstance(); - controller.getPlatformManager().register(server); - api = new WorldEditAPI(this); + worldEdit.getPlatformManager().register(server); + + // Register CUI getServer().getMessenger().registerIncomingPluginChannel(this, CUI_PLUGIN_CHANNEL, new CUIChannelListener(this)); getServer().getMessenger().registerOutgoingPluginChannel(this, CUI_PLUGIN_CHANNEL); - // Now we can register events! + + // Now we can register events getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); - getServer().getScheduler().runTaskTimerAsynchronously(this, new SessionTimer(controller, getServer()), 120, 120); + // Register session timer + getServer().getScheduler().runTaskTimerAsynchronously(this, new SessionTimer(worldEdit, getServer()), 120, 120); // If we are on MCPC+/Cauldron, then Forge will have already loaded // Forge WorldEdit and there's (probably) not going to be any other @@ -124,31 +116,34 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } - private void copyNmsBlockClasses(File target) { + private void loadConfig() { + createDefaultConfiguration("config.yml"); // Create the default configuration file + + config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this); + config.load(); + } + + private void loadAdapter() { + // Attempt to load a Bukkit adapter + BukkitImplLoader adapterLoader = new BukkitImplLoader(); + try { - JarFile jar = new JarFile(getFile()); - @SuppressWarnings("rawtypes") - Enumeration entries = jar.entries(); - while (entries.hasMoreElements()) { - JarEntry jarEntry = (JarEntry) entries.nextElement(); - if (!jarEntry.getName().startsWith("nmsblocks") || jarEntry.isDirectory()) continue; + adapterLoader.addFromPath(getClass().getClassLoader()); + } catch (IOException e) { + log.log(Level.WARNING, "Failed to search path for Bukkit adapters"); + } - File file = new File(target + File.separator + jarEntry.getName().replace("nmsblocks", "")); - if (file.exists()) continue; - - InputStream is = jar.getInputStream(jarEntry); - FileOutputStream fos = new FileOutputStream(file); - - fos = new FileOutputStream(file); - byte[] buf = new byte[8192]; - int length = 0; - while ((length = is.read(buf)) > 0) { - fos.write(buf, 0, length); - } - fos.close(); - is.close(); - } - } catch (Throwable e) {} + try { + adapterLoader.addFromJar(getFile()); + } catch (IOException e) { + log.log(Level.WARNING, "Failed to search " + getFile() + " for Bukkit adapters", e); + } + try { + bukkitAdapter = adapterLoader.loadAdapter(); + log.log(Level.INFO, "Using " + bukkitAdapter.getClass().getCanonicalName() + " as the Bukkit adapter"); + } catch (AdapterLoadException e) { + log.log(Level.WARNING, e.getMessage()); + } } /** @@ -156,10 +151,13 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { */ @Override public void onDisable() { - if (controller != null) { - controller.clearSessions(); - controller.getPlatformManager().unregister(server); + WorldEdit worldEdit = WorldEdit.getInstance(); + worldEdit.clearSessions(); + worldEdit.getPlatformManager().unregister(server); + if (config != null) { config.unload(); + } + if (server != null) { server.unregisterCommands(); } this.getServer().getScheduler().cancelTasks(this); @@ -177,7 +175,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { /** * Create a default configuration file from the .jar. * - * @param name + * @param name the filename */ protected void createDefaultConfiguration(String name) { File actual = new File(getDataFolder(), name); @@ -257,7 +255,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { * @return */ public LocalSession getSession(Player player) { - return controller.getSession(wrapPlayer(player)); + return WorldEdit.getInstance().getSession(wrapPlayer(player)); } /** @@ -268,10 +266,10 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { */ public EditSession createEditSession(Player player) { LocalPlayer wePlayer = wrapPlayer(player); - LocalSession session = controller.getSession(wePlayer); + LocalSession session = WorldEdit.getInstance().getSession(wePlayer); BlockBag blockBag = session.getBlockBag(wePlayer); - EditSession editSession = controller.getEditSessionFactory() + EditSession editSession = WorldEdit.getInstance().getEditSessionFactory() .getEditSession(wePlayer.getWorld(), session.getBlockChangeLimit(), blockBag, wePlayer); editSession.enableQueue(); @@ -286,12 +284,12 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { */ public void remember(Player player, EditSession editSession) { LocalPlayer wePlayer = wrapPlayer(player); - LocalSession session = controller.getSession(wePlayer); + LocalSession session = WorldEdit.getInstance().getSession(wePlayer); session.remember(editSession); editSession.flushQueue(); - controller.flushBlockBag(wePlayer, editSession); + WorldEdit.getInstance().flushBlockBag(wePlayer, editSession); } /** @@ -301,10 +299,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { * @param op * @throws Throwable */ - public void perform(Player player, WorldEditOperation op) - throws Throwable { + public void perform(Player player, WorldEditOperation op) throws Throwable { LocalPlayer wePlayer = wrapPlayer(player); - LocalSession session = controller.getSession(wePlayer); + LocalSession session = WorldEdit.getInstance().getSession(wePlayer); EditSession editSession = createEditSession(player); try { @@ -379,7 +376,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { * @return */ public WorldEdit getWorldEdit() { - return controller; + return WorldEdit.getInstance(); } /** @@ -396,7 +393,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { throw new IllegalArgumentException("Offline player not allowed"); } - LocalSession session = controller.getSession(wrapPlayer(player)); + LocalSession session = WorldEdit.getInstance().getSession(wrapPlayer(player)); RegionSelector selector = session.getRegionSelector(BukkitUtil.getLocalWorld(player.getWorld())); try { @@ -434,9 +431,30 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { throw new IllegalArgumentException("Null selection not allowed"); } - LocalSession session = controller.getSession(wrapPlayer(player)); + LocalSession session = WorldEdit.getInstance().getSession(wrapPlayer(player)); RegionSelector sel = selection.getRegionSelector(); session.setRegionSelector(BukkitUtil.getLocalWorld(player.getWorld()), sel); session.dispatchCUISelection(wrapPlayer(player)); } + + /** + * Gets the instance of this plugin. + * + * @return an instance of the plugin + * @throws NullPointerException if the plugin hasn't been enabled + */ + static WorldEditPlugin getInstance() { + return checkNotNull(INSTANCE); + } + + /** + * Get the Bukkit implementation adapter. + * + * @return the adapter + */ + @Nullable + BukkitImplAdapter getBukkitImplAdapter() { + return bukkitAdapter; + } + } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/AdapterLoadException.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/AdapterLoadException.java new file mode 100644 index 000000000..d8459d691 --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/AdapterLoadException.java @@ -0,0 +1,41 @@ +/* + * 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.bukkit.adapter; + +/** + * Thrown when no adapter can be found. + */ +public class AdapterLoadException extends Exception { + + public AdapterLoadException() { + } + + public AdapterLoadException(String message) { + super(message); + } + + public AdapterLoadException(String message, Throwable cause) { + super(message, cause); + } + + public AdapterLoadException(Throwable cause) { + super(cause); + } +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java new file mode 100644 index 000000000..8de74ce80 --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -0,0 +1,49 @@ +/* + * 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.bukkit.adapter; + +import com.sk89q.worldedit.blocks.BaseBlock; +import org.bukkit.Location; + +/** + * An interface for adapters of various Bukkit implementations. + */ +public interface BukkitImplAdapter { + + /** + * Get the block at the given location. + * + * @param location the location + * @return the block + */ + BaseBlock getBlock(Location location); + + /** + * Set the block at the given location. + * + * @param location the location + * @param state the block + * @param notifyAndLight notify and light if set + * @return true if a block was likely changed + */ + boolean setBlock(Location location, BaseBlock state, boolean notifyAndLight); + + +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java new file mode 100644 index 000000000..28704a8ca --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -0,0 +1,197 @@ +/* + * 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.bukkit.adapter; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.io.Closer; +import org.bukkit.Bukkit; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Loads Bukkit implementation adapters. + */ +public class BukkitImplLoader { + + private static final Logger log = Logger.getLogger(BukkitImplLoader.class.getCanonicalName()); + private final List adapterCandidates = new ArrayList(); + private String customCandidate; + + private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl"; + private static final String SEARCH_PACKAGE_DOT = SEARCH_PACKAGE + "."; + private static final String SEARCH_PATH = SEARCH_PACKAGE.replace(".", "/"); + private static final String CLASS_SUFFIX = ".class"; + + private static final String LOAD_ERROR_MESSAGE = + "Failed to find an adapter for Bukkit!\n\n" + + "This version of WorldEdit (%s) does not fully support your version of Bukkit (%s).\n\n" + + "What this means:\n" + + "1) Block operations will work, but chests will be empty, signs will be blank, and so on.\n" + + "2) You won't be able to save and load chests, signs, etc. with .schematic files.\n" + + "3) You won't be able to work with entities properly.\n" + + "4) Undo will will not be able to restore chests, signs, and etc.\n\n" + + "Possible solutions:\n" + + "1) If this is a new version of Minecraft, please wait for us to update. " + + "You can also put in a ticket at http://youtrack.sk89q.com (check for an existing ticket first).\n" + + "2) If you are using an older version of Minecraft, you may need to downgrade WorldEdit.\n" + + "3) If you are using an older version of WorldEdit, you may need to update your WorldEdit.\n" + + "4) If you are not using CraftBukkit, then report this issue to http://youtrack.sk89q.com " + + "(check for an existing ticket first).\n" + + "5) If you are developing WorldEdit, you can force an adapter with " + + "-Dworldedit.bukkit.adapter=the_class_name.\n\n" + + "Can I ignore this error? Yes! Just be aware of the undo issue.\n" + + "Am I using CraftBukkit? %s.\n"; + + /** + * Create a new instance. + */ + public BukkitImplLoader() { + addDefaults(); + } + + /** + * Add default candidates, such as any defined with + * {@code -Dworldedit.bukkit.adapter}. + */ + private void addDefaults() { + String className = System.getProperty("worldedit.bukkit.adapter"); + if (className != null) { + customCandidate = className; + adapterCandidates.add(className); + log.log(Level.INFO, "-Dworldedit.bukkit.adapter used to add " + className + " to the list of available Bukkit adapters"); + } + } + + /** + * Search the given JAR for candidate implementations. + * + * @param file the file + * @throws IOException thrown on I/O error + */ + public void addFromJar(File file) throws IOException { + Closer closer = Closer.create(); + JarFile jar = closer.register(new JarFile(file)); + try { + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry = (JarEntry) entries.nextElement(); + + String className = jarEntry.getName().replaceAll("[/\\\\]+", "."); + + if (!className.startsWith(SEARCH_PACKAGE_DOT) || jarEntry.isDirectory()) continue; + + int beginIndex = 0; + int endIndex = className.length() - CLASS_SUFFIX.length(); + className = className.substring(beginIndex, endIndex); + adapterCandidates.add(className); + } + } finally { + closer.close(); + } + } + + /** + * Search for classes stored as separate files available via the given + * class loader. + * + * @param classLoader the class loader + * @throws IOException thrown on error + */ + public void addFromPath(ClassLoader classLoader) throws IOException { + Enumeration resources = classLoader.getResources(SEARCH_PATH); + while (resources.hasMoreElements()) { + File file = new File(resources.nextElement().getFile()); + addFromPath(file); + } + } + + /** + * Search for classes stored as separate files available via the given + * path. + * + * @param file the path + */ + private void addFromPath(File file) { + String resource = SEARCH_PACKAGE_DOT + file.getName(); + if (file.isDirectory()) { + File[] files = file.listFiles(); + if (files != null) { + for (File child : files) { + addFromPath(child); + } + } + } else if (resource.endsWith(CLASS_SUFFIX)) { + int beginIndex = 0; + int endIndex = resource.length() - CLASS_SUFFIX.length(); + String className = resource.substring(beginIndex, endIndex); + adapterCandidates.add(className); + } + } + + /** + * Iterate through the list of candidates and load an adapter. + * + * @return an adapter + * @throws AdapterLoadException thrown if no adapter could be found + */ + public BukkitImplAdapter loadAdapter() throws AdapterLoadException { + for (String className : adapterCandidates) { + try { + Class cls = Class.forName(className); + if (BukkitImplAdapter.class.isAssignableFrom(cls)) { + return (BukkitImplAdapter) cls.newInstance(); + } else { + log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className + + "' because it does not implement " + BukkitImplAdapter.class.getCanonicalName()); + } + } catch (ClassNotFoundException e) { + log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className + + "' that is not supposed to be missing", e); + } catch (IllegalAccessException e) { + log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className + + "' that is not supposed to be raising this error", e); + } catch (Throwable e) { + if (className.equals(customCandidate)) { + log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className + "'", e); + } + } + } + + String weVersion = WorldEdit.getVersion(); + String bukkitVersion = Bukkit.getBukkitVersion() + " implemented by " + Bukkit.getName() + " " + Bukkit.getVersion(); + String usingCraftBukkit = + Bukkit.getName().equals("CraftBukkit") + ? "Probably (if you got it from dl.bukkit.org, then yes)" + : "No! You are using " + Bukkit.getName(); + + throw new AdapterLoadException( + String.format(LOAD_ERROR_MESSAGE, weVersion, bukkitVersion, usingCraftBukkit)); + } + +} diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class new file mode 100644 index 0000000000000000000000000000000000000000..1fbcb3cbadd0257911c24a08588d809e4f04727b GIT binary patch literal 12200 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 H+mriWi@@;e literal 0 HcmV?d00001 diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class deleted file mode 100644 index b8d6c51f3037bfb3a6a765a11a4a42497d76aeed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12701 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 diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class deleted file mode 100644 index e89c4a70b1919457de1d633c0f7abae9d555f14b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12456 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 diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class deleted file mode 100644 index e3c8c20fdcbbb180f17431028df0388f2b36481e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12528 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 K_&WA`eE$a}@DC~g diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class deleted file mode 100644 index 68781e1986ca2916ed225b82d2009601278f46b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12533 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 Ro`Soa`)%|`5{{gmI5wZXP diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class deleted file mode 100644 index 336c611cb014b8976d3e4c882f94027740d09383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12540 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 diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class deleted file mode 100644 index 6afbcdcc592164ebf507fe5ad50442b4af8fa7e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13808 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

5C)F{$sC|A1Hf?>UyZ4k5)B-TU~-~ zPS7pAbgOi%>7l$nS}h%G5_DTH-7eI%dU&Hy*CyzW1l`$7cS*+v-LYOeHYBJgL3j7k zJ<_pBcle}ZQ-bbI(0w=yNyiqwz-H;#lA!y0>C-}O@1gm9)C>rFKs0QxM|tw#A$kZu zQ-lV3vnWDCt9MhCr@YXk^?7*zv0rO_LVCGv!ZnnjM-udCFFhuVyL3lHI=T|HKS7`A zrN^ZsuH}eHM?68F?WNBNb!QLF%BQ_~Pk6papKr=~nx4dN@rAl_#Pxx42Jxw;tgM6d zG^o!Yjt|sv2Kqh+%*8I<4}F<;@I(ACJ?ljCLx?Ei%Ymj>Ad;>^j9v{i-3v6n2LA+c zEv@70@P823BPRFJMSKJPOXEiT^U6)|=*{#1-$MKORv_hVbeM0)uX667*ZEF*oA08( zaS#2Q??!2K4;S&hJc;k)sld7t{xnze1H70Yq>dxX3AQAoC*ujSA1jr=&M zp9S@E{1`u}GpG$AT1ACi%?p4q(}0A6YYMnlt4|mV9LoVZE`%mtD%QPODBfn$8#=3w zQU&s65peBVa9Ip|XMO~q2q=#{;3LSsg?LIXNugq|wZuWQS(NAfFBPMn)<8Am1L83S zW5$dr_#cheDYaD7C%g~(n1ZOm%M_$J8#SPP{;R`N%BE38Jv6My^B@hC;_D;M$o#CU zfJ#<(lE+@k8lJU?b;9Db2MF}xzZO=4GXRmU!5UHzPI#IU&ro$f_2wM}60Rz<3nXtH zuPS?n_$dtcqJSKYe76fu`#^UZsB^L1%tPN<=&hnLG#{s#1#}86)B?$6z!+^ZIouAT nVZ2IT@`z|CH`fERkCFnkU`!oo3LE5Ec*? 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 diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_v152_2.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_v152_2.class deleted file mode 100644 index 2a4acd48efdd53cec99a68557329fac3f8f4671c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12552 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 TU3@-I!ClUMH{<*DVvq0tC*u|U diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class deleted file mode 100644 index 86da91a7fac994cdc736fb67e1ecdefb9ede319b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9277 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 Aq5uE@ diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class deleted file mode 100644 index b68088e83e2f248e34b1cacd4c9123d5c1c6f4ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10513 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 diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class deleted file mode 100644 index 7f13268657fe362b6efafb9f3825b37749c4bce3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9348 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 diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java index 9dd3498cb..037e92810 100644 --- a/src/main/java/com/sk89q/worldedit/LocalWorld.java +++ b/src/main/java/com/sk89q/worldedit/LocalWorld.java @@ -60,115 +60,11 @@ public abstract class LocalWorld extends AbstractWorld { @Deprecated protected Random random = new Random(); - @Override - public BaseBlock getBlock(Vector pt) { - checkLoadedChunk(pt); - - @SuppressWarnings("deprecation") int type = getBlockType(pt); - @SuppressWarnings("deprecation") 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); - } - } - - /** - * 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 position the position - * @param block the block - * @return true if the copy operation succeeded, false otherwise - */ - public abstract boolean copyFromWorld(Vector position, BaseBlock block); - @Override public BaseBlock getLazyBlock(Vector position) { return getBlock(position); } - @Override - public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) throws WorldEditException { - 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()); - } - - copyToWorld(pt, block); - - return successful; - } - - /** - * 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 - */ - public abstract boolean copyToWorld(Vector position, BaseBlock block); - - @Override - public boolean setBlock(Vector pt, BaseBlock block) throws WorldEditException { - return setBlock(pt, block, true); - } - @Override public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector pt) throws MaxChangedBlocksException { switch (type) { diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index 2166b506d..eba0423bc 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -100,42 +100,6 @@ public class LocalWorldAdapter extends LocalWorld { return world.setBlock(position, block, notifyAndLight); } - @Override - @Deprecated - public boolean setBlockType(Vector position, int type) { - return world.setBlockType(position, type); - } - - @Override - @Deprecated - public boolean setBlockTypeFast(Vector position, int type) { - return world.setBlockTypeFast(position, type); - } - - @Override - @Deprecated - public void setBlockData(Vector position, int data) { - world.setBlockData(position, data); - } - - @Override - @Deprecated - public void setBlockDataFast(Vector position, int data) { - world.setBlockDataFast(position, data); - } - - @Override - @Deprecated - public boolean setTypeIdAndData(Vector position, int type, int data) { - return world.setTypeIdAndData(position, type, data); - } - - @Override - @Deprecated - public boolean setTypeIdAndDataFast(Vector position, int type, int data) { - return world.setTypeIdAndDataFast(position, type, data); - } - @Override public int getBlockLightLevel(Vector position) { return world.getBlockLightLevel(position); @@ -298,30 +262,11 @@ public class LocalWorldAdapter extends LocalWorld { return world.getBlock(position); } - @Override - public boolean copyFromWorld(Vector position, BaseBlock block) { - return false; - } - - @Override - public boolean copyToWorld(Vector position, BaseBlock block) { - return false; - } - @Override public BaseBlock getLazyBlock(Vector position) { return world.getLazyBlock(position); } - @Override - public boolean setBlock(Vector position, BaseBlock block) { - try { - return world.setBlock(position, block); - } catch (WorldEditException e) { - throw new RuntimeException(e); - } - } - @Override @Nullable public Operation commit() { diff --git a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java index 6b8831d13..393e8c134 100644 --- a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java +++ b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java @@ -150,7 +150,7 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { @ExceptionMatch public void convert(WorldEditException e) throws CommandException { - throw new CommandException(e.getMessage()); + throw new CommandException(e.getMessage(), e); } } diff --git a/src/main/java/com/sk89q/worldedit/util/Enums.java b/src/main/java/com/sk89q/worldedit/util/Enums.java new file mode 100644 index 000000000..9f397c127 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Enums.java @@ -0,0 +1,54 @@ +/* + * 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.util; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper methods for enums. + */ +public final class Enums { + + private Enums() { + } + + /** + * Search the given enum for a value that is equal to the one of the + * given values, searching in an ascending manner. + * + * @param enumType the enum type + * @param values the list of values + * @param the type of enum + * @return the found value or null + */ + @Nullable + public static > T findByValue(Class enumType, String... values) { + checkNotNull(enumType); + checkNotNull(values); + for (String val : values) { + try { + return Enum.valueOf(enumType, val); + } catch (IllegalArgumentException ignored) {} + } + return null; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 6c982cf6a..95917043e 100644 --- a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -47,6 +47,37 @@ public abstract class AbstractWorld implements World { private final PriorityQueue effectQueue = new PriorityQueue(); private int taskId = -1; + @Override + public final boolean setBlockType(Vector position, int type) { + try { + return setBlock(position, new BaseBlock(type)); + } catch (WorldEditException ignored) { + return false; + } + } + + @Override + public final void setBlockData(Vector position, int data) { + try { + setBlock(position, new BaseBlock(getLazyBlock(position).getType(), data)); + } catch (WorldEditException ignored) { + } + } + + @Override + public final boolean setTypeIdAndData(Vector position, int type, int data) { + try { + return setBlock(position, new BaseBlock(type, data)); + } catch (WorldEditException ignored) { + return false; + } + } + + @Override + public final boolean setBlock(Vector pt, BaseBlock block) throws WorldEditException { + return setBlock(pt, block, true); + } + @Override public int getMaxY() { return getMaximumPoint().getBlockY(); @@ -82,56 +113,6 @@ public abstract class AbstractWorld implements World { return getLazyBlock(pt).getData(); } - @Override - public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { - return setBlock(position, block, true); - } - - @Override - public boolean setBlockType(Vector position, int type) { - try { - return setBlock(position, new BaseBlock(type)); - } catch (WorldEditException e) { - throw new RuntimeException(e); - } - } - - @Override - public void setBlockData(Vector position, int data) { - try { - setBlock(position, new BaseBlock(getLazyBlock(position).getId(), data)); - } catch (WorldEditException e) { - throw new RuntimeException(e); - } - } - - @Override - public void setBlockDataFast(Vector position, int data) { - setBlockData(position, data); - } - - @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) { diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index 1c077d3d2..c11b1bf2d 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -122,36 +122,18 @@ public interface World extends Extent { @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. * From 9c72a3c43973fda8c577a1b259831568c664c000 Mon Sep 17 00:00:00 2001 From: sk89q Date: Mon, 14 Jul 2014 13:48:30 -0700 Subject: [PATCH 40/56] Fix blocks.json not being placed in the distribution. --- pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pom.xml b/pom.xml index d4ea069f1..ea47ad019 100644 --- a/pom.xml +++ b/pom.xml @@ -203,6 +203,18 @@ install ${basedir}/src/main/java/ + + + + . + false + ${basedir}/src/main/resources/ + + **/*.json + + + + From 505d45237db662ddfdbd1d3d3e76281f6f1ee87e Mon Sep 17 00:00:00 2001 From: sk89q Date: Mon, 14 Jul 2014 15:58:43 -0700 Subject: [PATCH 41/56] Remove UUID fields in ForgeWorld when creating entities. --- .../com/sk89q/worldedit/forge/ForgeWorld.java | 19 +++++--- .../sk89q/worldedit/internal/Constants.java | 45 +++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/internal/Constants.java diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 7c68e6cdf..b7f15e27f 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Direction; @@ -491,10 +492,10 @@ public class ForgeWorld extends AbstractWorld { if (o == null) { return false; } else if ((o instanceof ForgeWorld)) { - ForgeWorld other = ((ForgeWorld) o); - World otherWorld = other.worldRef.get(); - World thisWorld = other.worldRef.get(); - return otherWorld != null && thisWorld != null && otherWorld.equals(thisWorld); + ForgeWorld other = ((ForgeWorld) o); + World otherWorld = other.worldRef.get(); + World thisWorld = other.worldRef.get(); + return otherWorld != null && thisWorld != null && otherWorld.equals(thisWorld); } else if (o instanceof com.sk89q.worldedit.world.World) { return ((com.sk89q.worldedit.world.World) o).getName().equals(getName()); } else { @@ -539,9 +540,13 @@ public class ForgeWorld extends AbstractWorld { World world = getWorld(); net.minecraft.entity.Entity createdEntity = EntityList.createEntityByName(entity.getTypeId(), world); if (createdEntity != null) { - CompoundTag tag = entity.getNbtData(); - if (tag != null) { - createdEntity.readFromNBT(NBTConverter.toNative(entity.getNbtData())); + CompoundTag nativeTag = entity.getNbtData(); + if (nativeTag != null) { + NBTTagCompound tag = NBTConverter.toNative(entity.getNbtData()); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.removeTag(name); + } + createdEntity.readFromNBT(tag); } createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), (float) Math.toDegrees(location.getYaw()), (float) Math.toDegrees(location.getPitch())); diff --git a/src/main/java/com/sk89q/worldedit/internal/Constants.java b/src/main/java/com/sk89q/worldedit/internal/Constants.java new file mode 100644 index 000000000..9194866b4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/Constants.java @@ -0,0 +1,45 @@ +/* + * 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.internal; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public final class Constants { + + private Constants() { + } + + /** + * List of top level NBT fields that should not be copied to a world, + * such as UUIDLeast and UUIDMost. + */ + public static final List NO_COPY_ENTITY_NBT_FIELDS; + + static { + NO_COPY_ENTITY_NBT_FIELDS = Collections.unmodifiableList(Arrays.asList( + "UUIDLeast", "UUIDMost", // Bukkit and Vanilla + "WorldUUIDLeast", "WorldUUIDMost", // Bukkit and Vanilla + "PersistentIDMSB", "PersistentIDLSB" // Forge + )); + } + +} From e2082ee8a485b10070f21cd1e5beb024d563ca5b Mon Sep 17 00:00:00 2001 From: sk89q Date: Mon, 14 Jul 2014 18:11:38 -0700 Subject: [PATCH 42/56] [Bukkit] Implement the new entity API. --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 17 +++++++++++++ .../sk89q/worldedit/bukkit/BukkitEntity.java | 16 ++++++++++-- .../sk89q/worldedit/bukkit/BukkitWorld.java | 12 ++++++++- .../bukkit/adapter/BukkitImplAdapter.java | 23 ++++++++++++++++++ .../adapter/impl/CraftBukkit_v1_7_R2.class | Bin 12200 -> 15315 bytes .../adapter/impl/CraftBukkit_v1_7_R3.class | Bin 12200 -> 15315 bytes .../adapter/impl/CraftBukkit_v1_7_R4.class | Bin 12210 -> 15325 bytes 7 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 7de20172b..970136368 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -113,6 +113,23 @@ final class BukkitAdapter { position.getX(), position.getY(), position.getZ()); } + /** + * Create a Bukkit location from a WorldEdit location with a Bukkit world. + * + * @param world the Bukkit world + * @param location the WorldEdit location + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(org.bukkit.World world, Location location) { + checkNotNull(world); + checkNotNull(location); + return new org.bukkit.Location( + world, + location.getX(), location.getY(), location.getZ(), + (float) Math.toDegrees(location.getYaw()), + (float) Math.toDegrees(location.getPitch())); + } + /** * Create a WorldEdit entity from a Bukkit entity. * diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index 262a450f1..002890778 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -19,8 +19,10 @@ package com.sk89q.worldedit.bukkit; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.metadata.Tameable; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; @@ -74,12 +76,22 @@ class BukkitEntity implements Entity { @Override public BaseEntity getState() { - return null; + if (entity instanceof Player) { + return null; + } + + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + return adapter.getEntity(entity); + } else { + return null; + } } @Override public boolean remove() { - return false; + entity.remove(); + return entity.isDead(); } } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 29648289d..2debe4ebd 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -142,7 +142,17 @@ public class BukkitWorld extends LocalWorld { @Nullable @Override public com.sk89q.worldedit.entity.Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { - throw new UnsupportedOperationException("Not implemented yet"); + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + Entity createdEntity = adapter.createEntity(BukkitAdapter.adapt(getWorld(), location), entity); + if (createdEntity != null) { + return new BukkitEntity(createdEntity); + } else { + return null; + } + } else { + return null; + } } /** diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index 8de74ce80..a5e293593 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -20,7 +20,11 @@ package com.sk89q.worldedit.bukkit.adapter; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.BaseEntity; import org.bukkit.Location; +import org.bukkit.entity.Entity; + +import javax.annotation.Nullable; /** * An interface for adapters of various Bukkit implementations. @@ -45,5 +49,24 @@ public interface BukkitImplAdapter { */ boolean setBlock(Location location, BaseBlock state, boolean notifyAndLight); + /** + * Get the state for the given entity. + * + * @param entity the entity + * @return the state, or null + */ + @Nullable + BaseEntity getEntity(Entity entity); + + /** + * Create the given entity. + * + * @param location the location + * @param state the state + * @return the created entity or null + */ + @Nullable + Entity createEntity(Location location, BaseEntity state); + } diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class index 1fbcb3cbadd0257911c24a08588d809e4f04727b..bc003177317356af89ab80535a66992f4449ec02 100644 GIT binary patch literal 15315 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 D?eNIC diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R3.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R3.class index 7aa94f9a2c1cf756e38d992bfa10e198b6a53610..188b0becc9399d43d50f461512c57693698d3b84 100644 GIT binary patch literal 15315 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 D?eNIC diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R4.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R4.class index 15c6cc9a338b5b66034228222abc7cfeee27b555..b60c4898d0f356b5297f750d0f52ead7a38c93e3 100644 GIT binary patch literal 15325 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 Date: Mon, 14 Jul 2014 20:35:29 -0700 Subject: [PATCH 43/56] Write yaw/pitch in degrees rather than in radians with schematic files. --- .../extent/clipboard/io/SchematicReader.java | 41 +++---------------- .../extent/clipboard/io/SchematicWriter.java | 4 +- 2 files changed, 7 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java index ad0e9bbf8..bae3ae753 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java @@ -40,6 +40,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.registry.WorldData; +import com.sk89q.worldedit.world.storage.NBTConversions; import javax.annotation.Nullable; import java.io.IOException; @@ -230,12 +231,11 @@ public class SchematicReader implements ClipboardReader { for (Tag tag : entityTags) { if (tag instanceof CompoundTag) { CompoundTag compound = (CompoundTag) tag; - StringTag idTag = getTag(compound, StringTag.class, "id"); - Vector position = getVector(getTag(compound, ListTag.class, "Pos")); + String id = compound.getString("id"); + Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation")); - if (idTag != null & position != null) { - Location location = readRotation(getTag(compound, ListTag.class, "Rotation"), new Location(clipboard, position)); - BaseEntity state = new BaseEntity(idTag.getValue(), compound); + if (!id.isEmpty()) { + BaseEntity state = new BaseEntity(id, compound); clipboard.createEntity(location, state); } } @@ -246,37 +246,6 @@ public class SchematicReader implements ClipboardReader { return clipboard; } - @Nullable - private static Vector getVector(@Nullable ListTag tag) { - if (tag != null) { - List tags = tag.getValue(); - - if (tags.size() == 3 && tags.get(0) instanceof DoubleTag) { - double x = ((DoubleTag) tags.get(0)).getValue(); - double y = ((DoubleTag) tags.get(1)).getValue(); - double z = ((DoubleTag) tags.get(2)).getValue(); - return new Vector(x, y, z); - } - } - - return null; - } - - @Nullable - private static Location readRotation(@Nullable ListTag tag, Location location) { - if (tag != null) { - List tags = tag.getValue(); - - if (tags.size() == 2 && tags.get(0) instanceof FloatTag) { - float yaw = ((FloatTag) tags.get(0)).getValue(); - float pitch = ((FloatTag) tags.get(1)).getValue(); - location = location.setDirection(yaw, pitch); - } - } - - return location; - } - private static T requireTag(Map items, String key, Class expected) throws IOException { if (!items.containsKey(key)) { throw new IOException("Schematic file is missing a \"" + key + "\" tag"); diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java index 6e907cb0e..d5bf31e4f 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java @@ -206,8 +206,8 @@ public class SchematicWriter implements ClipboardWriter { private Tag writeRotation(Location location, String name) { List list = new ArrayList(); - list.add(new FloatTag("", location.getYaw())); - list.add(new FloatTag("", location.getPitch())); + list.add(new FloatTag("", (float) Math.toDegrees(location.getYaw()))); + list.add(new FloatTag("", (float) Math.toDegrees(location.getPitch()))); return new ListTag(name, FloatTag.class, list); } From b5aaef25051f73b18f39789328db8b4e3385dabb Mon Sep 17 00:00:00 2001 From: sk89q Date: Mon, 14 Jul 2014 20:36:27 -0700 Subject: [PATCH 44/56] Cleaned up and added many methods to the NBT classes. --- .../java/com/sk89q/jnbt/ByteArrayTag.java | 30 +- src/main/java/com/sk89q/jnbt/ByteTag.java | 28 +- src/main/java/com/sk89q/jnbt/CompoundTag.java | 394 +++++++++++++++++- .../com/sk89q/jnbt/CompoundTagBuilder.java | 107 +++++ src/main/java/com/sk89q/jnbt/DoubleTag.java | 27 +- src/main/java/com/sk89q/jnbt/EndTag.java | 4 +- src/main/java/com/sk89q/jnbt/FloatTag.java | 28 +- src/main/java/com/sk89q/jnbt/IntArrayTag.java | 30 +- src/main/java/com/sk89q/jnbt/IntTag.java | 28 +- src/main/java/com/sk89q/jnbt/ListTag.java | 391 ++++++++++++++++- .../java/com/sk89q/jnbt/ListTagBuilder.java | 129 ++++++ src/main/java/com/sk89q/jnbt/LongTag.java | 27 +- .../java/com/sk89q/jnbt/NBTConstants.java | 6 - .../java/com/sk89q/jnbt/NBTInputStream.java | 52 +-- src/main/java/com/sk89q/jnbt/NBTUtils.java | 41 +- src/main/java/com/sk89q/jnbt/ShortTag.java | 28 +- src/main/java/com/sk89q/jnbt/StringTag.java | 30 +- src/main/java/com/sk89q/jnbt/Tag.java | 27 +- .../world/storage/NBTConversions.java | 58 +++ 19 files changed, 1232 insertions(+), 233 deletions(-) create mode 100644 src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java create mode 100644 src/main/java/com/sk89q/jnbt/ListTagBuilder.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java diff --git a/src/main/java/com/sk89q/jnbt/ByteArrayTag.java b/src/main/java/com/sk89q/jnbt/ByteArrayTag.java index 1d58427be..59e7568e4 100644 --- a/src/main/java/com/sk89q/jnbt/ByteArrayTag.java +++ b/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -19,28 +19,28 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Byte_Array tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Byte_Array} tag. */ public final class ByteArrayTag extends Tag { - /** - * The value. - */ private final byte[] value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public ByteArrayTag(byte[] value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public ByteArrayTag(String name, byte[] value) { super(name); @@ -67,7 +67,7 @@ public final class ByteArrayTag extends Tag { if (name != null && !name.equals("")) { append = "(\"" + this.getName() + "\")"; } - return "TAG_Byte_Array" + append + ": " + hex.toString(); + return "TAG_Byte_Array" + append + ": " + hex; } } diff --git a/src/main/java/com/sk89q/jnbt/ByteTag.java b/src/main/java/com/sk89q/jnbt/ByteTag.java index 3adf3ec8c..56b6d4857 100644 --- a/src/main/java/com/sk89q/jnbt/ByteTag.java +++ b/src/main/java/com/sk89q/jnbt/ByteTag.java @@ -19,28 +19,28 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Byte tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Byte} tag. */ public final class ByteTag extends Tag { - /** - * The value. - */ private final byte value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public ByteTag(byte value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public ByteTag(String name, byte value) { super(name); diff --git a/src/main/java/com/sk89q/jnbt/CompoundTag.java b/src/main/java/com/sk89q/jnbt/CompoundTag.java index 28b3d8da5..7550dd159 100644 --- a/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -20,40 +20,401 @@ package com.sk89q.jnbt; import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Map; -import com.sk89q.jnbt.Tag; /** - * The TAG_Compound tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Compound} tag. */ public final class CompoundTag extends Tag { - /** - * The value. - */ private final Map value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public CompoundTag(Map value) { + super(); + this.value = Collections.unmodifiableMap(value); + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public CompoundTag(String name, Map value) { super(name); this.value = Collections.unmodifiableMap(value); } + /** + * Returns whether this compound tag contains the given key. + * + * @param key the given key + * @return true if the tag contains the given key + */ + public boolean containsKey(String key) { + return value.containsKey(key); + } + @Override public Map getValue() { return value; } + /** + * Return a new compound tag with the given values. + * + * @param value the value + * @return the new compound tag + */ + public CompoundTag setValue(Map value) { + return new CompoundTag(getName(), value); + } + + /** + * Create a compound tag builder. + * + * @return the builder + */ + public CompoundTagBuilder createBuilder() { + return new CompoundTagBuilder(new HashMap(value)); + } + + /** + * Get a byte array named with the given key. + * + *

If the key does not exist or its value is not a byte array tag, + * then an empty byte array will be returned.

+ * + * @param key the key + * @return a byte array + */ + public byte[] getByteArray(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteArrayTag) { + return ((ByteArrayTag) tag).getValue(); + } else { + return new byte[0]; + } + } + + /** + * Get a byte named with the given key. + * + *

If the key does not exist or its value is not a byte tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a byte + */ + public byte getByte(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + } else { + return (byte) 0; + } + } + + /** + * Get a double named with the given key. + * + *

If the key does not exist or its value is not a double tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a double + */ + public double getDouble(String key) { + Tag tag = value.get(key); + if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a double named with the given key, even if it's another + * type of number. + * + *

If the key does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a double + */ + public double asDouble(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + + } else { + return 0; + } + } + + /** + * Get a float named with the given key. + * + *

If the key does not exist or its value is not a float tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a float + */ + public float getFloat(String key) { + Tag tag = value.get(key); + if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a {@code int[]} named with the given key. + * + *

If the key does not exist or its value is not an integer array tag, + * then an empty array will be returned.

+ * + * @param key the key + * @return an integer array + */ + public int[] getIntegerArray(String key) { + Tag tag = value.get(key); + if (tag instanceof IntArrayTag) { + return ((IntArrayTag) tag).getValue(); + } else { + return new int[0]; + } + } + + /** + * Get an integer named with the given key. + * + *

If the key does not exist or its value is not an integer tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return an integer + */ + public int getInteger(String key) { + Tag tag = value.get(key); + if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get an integer named with the given key, even if it's another + * type of number. + * + *

If the key does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return an integer + */ + public int asInteger(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue().intValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().intValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().intValue(); + + } else { + return 0; + } + } + + /** + * Get a list of tags named with the given key. + * + *

If the key does not exist or its value is not a list tag, + * then an empty list will be returned.

+ * + * @param key the key + * @return a list of tags + */ + public List getList(String key) { + Tag tag = value.get(key); + if (tag instanceof ListTag) { + return ((ListTag) tag).getValue(); + } else { + return Collections.emptyList(); + } + } + + /** + * Get a {@code TagList} named with the given key. + * + *

If the key does not exist or its value is not a list tag, + * then an empty tag list will be returned.

+ * + * @param key the key + * @return a tag list instance + */ + public ListTag getListTag(String key) { + Tag tag = value.get(key); + if (tag instanceof ListTag) { + return (ListTag) tag; + } else { + return new ListTag(key, StringTag.class, Collections.emptyList()); + } + } + + /** + * Get a list of tags named with the given key. + * + *

If the key does not exist or its value is not a list tag, + * then an empty list will be returned. If the given key references + * a list but the list of of a different type, then an empty + * list will also be returned.

+ * + * @param key the key + * @return a list of tags + */ + @SuppressWarnings("unchecked") + public List getList(String key, Class listType) { + Tag tag = value.get(key); + if (tag instanceof ListTag) { + ListTag listTag = (ListTag) tag; + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + } + + /** + * Get a long named with the given key. + * + *

If the key does not exist or its value is not a long tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a long + */ + public long getLong(String key) { + Tag tag = value.get(key); + if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + } else { + return 0L; + } + } + + /** + * Get a long named with the given key, even if it's another + * type of number. + * + *

If the key does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a long + */ + public long asLong(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().longValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().longValue(); + + } else { + return 0L; + } + } + + /** + * Get a short named with the given key. + * + *

If the key does not exist or its value is not a short tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a short + */ + public short getShort(String key) { + Tag tag = value.get(key); + if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a string named with the given key. + * + *

If the key does not exist or its value is not a string tag, + * then {@code ""} will be returned.

+ * + * @param key the key + * @return a string + */ + public String getString(String key) { + Tag tag = value.get(key); + if (tag instanceof StringTag) { + return ((StringTag) tag).getValue(); + } else { + return ""; + } + } + @Override public String toString() { String name = getName(); @@ -62,12 +423,9 @@ public final class CompoundTag extends Tag { append = "(\"" + this.getName() + "\")"; } StringBuilder bldr = new StringBuilder(); - bldr.append("TAG_Compound" + append + ": " + value.size() - + " entries\r\n{\r\n"); + bldr.append("TAG_Compound").append(append).append(": ").append(value.size()).append(" entries\r\n{\r\n"); for (Map.Entry entry : value.entrySet()) { - bldr.append(" " - + entry.getValue().toString().replaceAll("\r\n", "\r\n ") - + "\r\n"); + bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); } bldr.append("}"); return bldr.toString(); diff --git a/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java new file mode 100644 index 000000000..58a3320a2 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -0,0 +1,107 @@ +/* + * 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.jnbt; + +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helps create compound tags. + */ +public class CompoundTagBuilder { + + private final Map entries; + + /** + * Create a new instance. + */ + CompoundTagBuilder() { + this.entries = new HashMap(); + } + + /** + * Create a new instance and use the given map (which will be modified). + * + * @param value the value + */ + CompoundTagBuilder(Map value) { + checkNotNull(value); + this.entries = value; + } + + /** + * Put the given key and tag into the compound tag. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder put(String key, Tag value) { + checkNotNull(key); + checkNotNull(value); + entries.put(key, value); + return this; + } + + /** + * Put all the entries from the given map into this map. + * + * @param value the map of tags + * @return this object + */ + public CompoundTagBuilder putAll(Map value) { + checkNotNull(value); + for (Map.Entry entry : value.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * Build an unnamed compound tag with this builder's entries. + * + * @return the new compound tag + */ + public CompoundTag build() { + return new CompoundTag(new HashMap(entries)); + } + + /** + * Build a new compound tag with this builder's entries. + * + * @param name the name of the tag + * @return the created compound tag + */ + public CompoundTag build(String name) { + return new CompoundTag(name, new HashMap(entries)); + } + + /** + * Create a new builder instance. + * + * @return a new builder + */ + public static CompoundTagBuilder create() { + return new CompoundTagBuilder(); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/DoubleTag.java b/src/main/java/com/sk89q/jnbt/DoubleTag.java index f3f69ea05..1ebcdf794 100644 --- a/src/main/java/com/sk89q/jnbt/DoubleTag.java +++ b/src/main/java/com/sk89q/jnbt/DoubleTag.java @@ -19,28 +19,29 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Double tag. - * - * @author Graham Edgecombe + * The {@code TAG_Double} tag. * */ public final class DoubleTag extends Tag { - /** - * The value. - */ private final double value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public DoubleTag(double value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public DoubleTag(String name, double value) { super(name); diff --git a/src/main/java/com/sk89q/jnbt/EndTag.java b/src/main/java/com/sk89q/jnbt/EndTag.java index ec5e167f1..5051cc939 100644 --- a/src/main/java/com/sk89q/jnbt/EndTag.java +++ b/src/main/java/com/sk89q/jnbt/EndTag.java @@ -19,8 +19,6 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** * The TAG_End tag. * @@ -33,7 +31,7 @@ public final class EndTag extends Tag { * Creates the tag. */ public EndTag() { - super(""); + super(); } @Override diff --git a/src/main/java/com/sk89q/jnbt/FloatTag.java b/src/main/java/com/sk89q/jnbt/FloatTag.java index bb005face..21b921b69 100644 --- a/src/main/java/com/sk89q/jnbt/FloatTag.java +++ b/src/main/java/com/sk89q/jnbt/FloatTag.java @@ -19,28 +19,28 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Float tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Float} tag. */ public final class FloatTag extends Tag { - /** - * The value. - */ private final float value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public FloatTag(float value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public FloatTag(String name, float value) { super(name); diff --git a/src/main/java/com/sk89q/jnbt/IntArrayTag.java b/src/main/java/com/sk89q/jnbt/IntArrayTag.java index 1765e50cf..b8dced001 100644 --- a/src/main/java/com/sk89q/jnbt/IntArrayTag.java +++ b/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -19,31 +19,35 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; +import static com.google.common.base.Preconditions.checkNotNull; /** - * The TAG_Int_Array tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Int_Array} tag. */ public final class IntArrayTag extends Tag { - /** - * The value. - */ private final int[] value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public IntArrayTag(int[] value) { + super(); + checkNotNull(value); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public IntArrayTag(String name, int[] value) { super(name); + checkNotNull(value); this.value = value; } diff --git a/src/main/java/com/sk89q/jnbt/IntTag.java b/src/main/java/com/sk89q/jnbt/IntTag.java index 480b54ee9..5591408f6 100644 --- a/src/main/java/com/sk89q/jnbt/IntTag.java +++ b/src/main/java/com/sk89q/jnbt/IntTag.java @@ -19,28 +19,28 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Int tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Int} tag. */ public final class IntTag extends Tag { - /** - * The value. - */ private final int value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public IntTag(int value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public IntTag(String name, int value) { super(name); diff --git a/src/main/java/com/sk89q/jnbt/ListTag.java b/src/main/java/com/sk89q/jnbt/ListTag.java index 282791179..681340620 100644 --- a/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/src/main/java/com/sk89q/jnbt/ListTag.java @@ -19,41 +19,44 @@ package com.sk89q.jnbt; +import javax.annotation.Nullable; import java.util.Collections; import java.util.List; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.Tag; +import java.util.NoSuchElementException; + +import static com.google.common.base.Preconditions.checkNotNull; /** - * The TAG_List tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_List} tag. */ public final class ListTag extends Tag { - /** - * The type. - */ private final Class type; + private final List value; /** - * The value. + * Creates the tag with an empty name. + * + * @param type the type of tag + * @param value the value of the tag */ - private final List value; + public ListTag(Class type, List value) { + super(); + checkNotNull(value); + this.type = type; + this.value = Collections.unmodifiableList(value); + } /** * Creates the tag. * - * @param name - * The name. - * @param type - * The type of item in the list. - * @param value - * The value. + * @param name the name of the tag + * @param type the type of tag + * @param value the value of the tag */ public ListTag(String name, Class type, List value) { super(name); + checkNotNull(value); this.type = type; this.value = Collections.unmodifiableList(value); } @@ -72,6 +75,360 @@ public final class ListTag extends Tag { return value; } + /** + * Create a new list tag with this tag's name and type. + * + * @param list the new list + * @return a new list tag + */ + public ListTag setValue(List list) { + return new ListTag(getName(), getType(), list); + } + + /** + * Get the tag if it exists at the given index. + * + * @param index the index + * @return the tag or null + */ + @Nullable + public Tag getIfExists(int index) { + try { + return value.get(index); + } catch (NoSuchElementException e) { + return null; + } + } + + /** + * Get a byte array named with the given index. + * + *

If the index does not exist or its value is not a byte array tag, + * then an empty byte array will be returned.

+ * + * @param index the index + * @return a byte array + */ + public byte[] getByteArray(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteArrayTag) { + return ((ByteArrayTag) tag).getValue(); + } else { + return new byte[0]; + } + } + + /** + * Get a byte named with the given index. + * + *

If the index does not exist or its value is not a byte tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a byte + */ + public byte getByte(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + } else { + return (byte) 0; + } + } + + /** + * Get a double named with the given index. + * + *

If the index does not exist or its value is not a double tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a double + */ + public double getDouble(int index) { + Tag tag = getIfExists(index); + if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a double named with the given index, even if it's another + * type of number. + * + *

If the index does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a double + */ + public double asDouble(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + + } else { + return 0; + } + } + + /** + * Get a float named with the given index. + * + *

If the index does not exist or its value is not a float tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a float + */ + public float getFloat(int index) { + Tag tag = getIfExists(index); + if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a {@code int[]} named with the given index. + * + *

If the index does not exist or its value is not an integer array tag, + * then an empty array will be returned.

+ * + * @param index the index + * @return an integer array + */ + public int[] getIntegerArray(int index) { + Tag tag = getIfExists(index); + if (tag instanceof IntArrayTag) { + return ((IntArrayTag) tag).getValue(); + } else { + return new int[0]; + } + } + + /** + * Get an integer named with the given index. + * + *

If the index does not exist or its value is not an integer tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return an integer + */ + public int getInteger(int index) { + Tag tag = getIfExists(index); + if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get an integer named with the given index, even if it's another + * type of number. + * + *

If the index does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return an integer + */ + public int asInteger(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue().intValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().intValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().intValue(); + + } else { + return 0; + } + } + + /** + * Get a list of tags named with the given index. + * + *

If the index does not exist or its value is not a list tag, + * then an empty list will be returned.

+ * + * @param index the index + * @return a list of tags + */ + public List getList(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ListTag) { + return ((ListTag) tag).getValue(); + } else { + return Collections.emptyList(); + } + } + + /** + * Get a {@code TagList} named with the given index. + * + *

If the index does not exist or its value is not a list tag, + * then an empty tag list will be returned.

+ * + * @param index the index + * @return a tag list instance + */ + public ListTag getListTag(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ListTag) { + return (ListTag) tag; + } else { + return new ListTag(StringTag.class, Collections.emptyList()); + } + } + + /** + * Get a list of tags named with the given index. + * + *

If the index does not exist or its value is not a list tag, + * then an empty list will be returned. If the given index references + * a list but the list of of a different type, then an empty + * list will also be returned.

+ * + * @param index the index + * @return a list of tags + */ + @SuppressWarnings("unchecked") + public List getList(int index, Class listType) { + Tag tag = getIfExists(index); + if (tag instanceof ListTag) { + ListTag listTag = (ListTag) tag; + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + } + + /** + * Get a long named with the given index. + * + *

If the index does not exist or its value is not a long tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a long + */ + public long getLong(int index) { + Tag tag = getIfExists(index); + if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + } else { + return 0L; + } + } + + /** + * Get a long named with the given index, even if it's another + * type of number. + * + *

If the index does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a long + */ + public long asLong(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().longValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().longValue(); + + } else { + return 0; + } + } + + /** + * Get a short named with the given index. + * + *

If the index does not exist or its value is not a short tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a short + */ + public short getShort(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a string named with the given index. + * + *

If the index does not exist or its value is not a string tag, + * then {@code ""} will be returned.

+ * + * @param index the index + * @return a string + */ + public String getString(int index) { + Tag tag = getIfExists(index); + if (tag instanceof StringTag) { + return ((StringTag) tag).getValue(); + } else { + return ""; + } + } + @Override public String toString() { String name = getName(); diff --git a/src/main/java/com/sk89q/jnbt/ListTagBuilder.java b/src/main/java/com/sk89q/jnbt/ListTagBuilder.java new file mode 100644 index 000000000..2934c2255 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/ListTagBuilder.java @@ -0,0 +1,129 @@ +/* + * 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.jnbt; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helps create list tags. + */ +public class ListTagBuilder { + + private final Class type; + private final List entries; + + /** + * Create a new instance. + * + * @param type of tag contained in this list + */ + ListTagBuilder(Class type) { + checkNotNull(type); + this.type = type; + this.entries = new ArrayList(); + } + + /** + * Add the given tag. + * + * @param value the tag + * @return this object + */ + public ListTagBuilder add(Tag value) { + checkNotNull(value); + if (!type.isInstance(value)) { + throw new IllegalArgumentException(value.getClass().getCanonicalName() + " is not of expected type " + type.getCanonicalName()); + } + entries.add(value); + return this; + } + + /** + * Add all the tags in the given list. + * + * @param value a list of tags + * @return this object + */ + public ListTagBuilder addAll(Collection value) { + checkNotNull(value); + for (Tag v : value) { + add(v); + } + return this; + } + + /** + * Build an unnamed list tag with this builder's entries. + * + * @return the new list tag + */ + public ListTag build() { + return new ListTag(type, new ArrayList(entries)); + } + + /** + * Build a new list tag with this builder's entries. + * + * @param name the name of the tag + * @return the created list tag + */ + public ListTag build(String name) { + return new ListTag(name, type, new ArrayList(entries)); + } + + /** + * Create a new builder instance. + * + * @return a new builder + */ + public static ListTagBuilder create(Class type) { + return new ListTagBuilder(type); + } + + /** + * Create a new builder instance. + * + * @return a new builder + */ + public static ListTagBuilder createWith(T ... entries) { + checkNotNull(entries); + + if (entries.length == 0) { + throw new IllegalArgumentException("This method needs an array of at least one entry"); + } + + Class type = entries[0].getClass(); + for (int i = 1; i < entries.length; i++) { + if (!type.isInstance(entries[i])) { + throw new IllegalArgumentException("An array of different tag types was provided"); + } + } + + ListTagBuilder builder = new ListTagBuilder(type); + builder.addAll(Arrays.asList(entries)); + return builder; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/LongTag.java b/src/main/java/com/sk89q/jnbt/LongTag.java index 121f1365d..26e1902a5 100644 --- a/src/main/java/com/sk89q/jnbt/LongTag.java +++ b/src/main/java/com/sk89q/jnbt/LongTag.java @@ -19,28 +19,29 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Long tag. - * - * @author Graham Edgecombe + * The {@code TAG_Long} tag. * */ public final class LongTag extends Tag { - /** - * The value. - */ private final long value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public LongTag(long value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public LongTag(String name, long value) { super(name); diff --git a/src/main/java/com/sk89q/jnbt/NBTConstants.java b/src/main/java/com/sk89q/jnbt/NBTConstants.java index f214f7dec..7c8001b43 100644 --- a/src/main/java/com/sk89q/jnbt/NBTConstants.java +++ b/src/main/java/com/sk89q/jnbt/NBTConstants.java @@ -29,14 +29,8 @@ import java.nio.charset.Charset; */ public final class NBTConstants { - /** - * The character set used by NBT (UTF-8). - */ public static final Charset CHARSET = Charset.forName("UTF-8"); - /** - * Tag type constants. - */ public static final int TYPE_END = 0, TYPE_BYTE = 1, TYPE_SHORT = 2, TYPE_INT = 3, TYPE_LONG = 4, TYPE_FLOAT = 5, TYPE_DOUBLE = 6, TYPE_BYTE_ARRAY = 7, TYPE_STRING = 8, TYPE_LIST = 9, diff --git a/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/src/main/java/com/sk89q/jnbt/NBTInputStream.java index d50873d12..1d1c5215b 100644 --- a/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -27,20 +27,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.EndTag; -import com.sk89q.jnbt.FloatTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; /** *

@@ -60,19 +46,14 @@ import com.sk89q.jnbt.Tag; */ public final class NBTInputStream implements Closeable { - /** - * The data input stream. - */ private final DataInputStream is; /** - * Creates a new NBTInputStream, which will source its data + * Creates a new {@code NBTInputStream}, which will source its data * from the specified input stream. * - * @param is - * The input stream. - * @throws IOException - * if an I/O error occurs. + * @param is the input stream + * @throws IOException if an I/O error occurs */ public NBTInputStream(InputStream is) throws IOException { this.is = new DataInputStream(is); @@ -82,8 +63,7 @@ public final class NBTInputStream implements Closeable { * Reads an NBT tag from the stream. * * @return The tag that was read. - * @throws IOException - * if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public Tag readTag() throws IOException { return readTag(0); @@ -92,11 +72,9 @@ public final class NBTInputStream implements Closeable { /** * Reads an NBT from the stream. * - * @param depth - * The depth of this tag. + * @param depth the depth of this tag * @return The tag that was read. - * @throws IOException - * if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ private Tag readTag(int depth) throws IOException { int type = is.readByte() & 0xFF; @@ -117,18 +95,13 @@ public final class NBTInputStream implements Closeable { /** * Reads the payload of a tag, given the name and type. * - * @param type - * The type. - * @param name - * The name. - * @param depth - * The depth. - * @return The tag. - * @throws IOException - * if an I/O error occurs. + * @param type the type + * @param name the name + * @param depth the depth + * @return the tag + * @throws IOException if an I/O error occurs. */ - private Tag readTagPayload(int type, String name, int depth) - throws IOException { + private Tag readTagPayload(int type, String name, int depth) throws IOException { switch (type) { case NBTConstants.TYPE_END: if (depth == 0) { @@ -197,6 +170,7 @@ public final class NBTInputStream implements Closeable { } } + @Override public void close() throws IOException { is.close(); } diff --git a/src/main/java/com/sk89q/jnbt/NBTUtils.java b/src/main/java/com/sk89q/jnbt/NBTUtils.java index 53983022c..20b3e5542 100644 --- a/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -19,23 +19,31 @@ package com.sk89q.jnbt; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.storage.InvalidFormatException; import java.util.Map; +import static com.google.common.base.Preconditions.checkNotNull; + /** * A class which contains NBT-related utility methods. * - * @author Graham Edgecombe - * */ public final class NBTUtils { + /** + * Default private constructor. + */ + private NBTUtils() { + } + /** * Gets the type name of a tag. * - * @param clazz - * The tag class. + * @param clazz the tag class * @return The type name. */ public static String getTypeName(Class clazz) { @@ -72,11 +80,9 @@ public final class NBTUtils { /** * Gets the type code of a tag class. * - * @param clazz - * The tag class. + * @param clazz the tag class * @return The type code. - * @throws IllegalArgumentException - * if the tag class is invalid. + * @throws IllegalArgumentException if the tag class is invalid. */ public static int getTypeCode(Class clazz) { if (clazz.equals(ByteArrayTag.class)) { @@ -112,11 +118,9 @@ public final class NBTUtils { /** * Gets the class of a type of tag. * - * @param type - * The type. + * @param type the type * @return The class. - * @throws IllegalArgumentException - * if the tag type is invalid. + * @throws IllegalArgumentException if the tag type is invalid. */ public static Class getTypeClass(int type) { switch (type) { @@ -151,10 +155,17 @@ public final class NBTUtils { } /** - * Default private constructor. + * Read a vector from a list tag containing ideally three values: the + * X, Y, and Z components. + * + *

For values that are unavailable, their values will be 0.

+ * + * @param listTag the list tag + * @return a vector */ - private NBTUtils() { - + public static Vector toVector(ListTag listTag) { + checkNotNull(listTag); + return new Vector(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2)); } /** diff --git a/src/main/java/com/sk89q/jnbt/ShortTag.java b/src/main/java/com/sk89q/jnbt/ShortTag.java index 0a658fa07..fd3ee3a4e 100644 --- a/src/main/java/com/sk89q/jnbt/ShortTag.java +++ b/src/main/java/com/sk89q/jnbt/ShortTag.java @@ -19,28 +19,28 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; - /** - * The TAG_Short tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_Short} tag. */ public final class ShortTag extends Tag { - /** - * The value. - */ private final short value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public ShortTag(short value) { + super(); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public ShortTag(String name, short value) { super(name); diff --git a/src/main/java/com/sk89q/jnbt/StringTag.java b/src/main/java/com/sk89q/jnbt/StringTag.java index b6687c6fd..409511ab5 100644 --- a/src/main/java/com/sk89q/jnbt/StringTag.java +++ b/src/main/java/com/sk89q/jnbt/StringTag.java @@ -19,31 +19,35 @@ package com.sk89q.jnbt; -import com.sk89q.jnbt.Tag; +import static com.google.common.base.Preconditions.checkNotNull; /** - * The TAG_String tag. - * - * @author Graham Edgecombe - * + * The {@code TAG_String} tag. */ public final class StringTag extends Tag { - /** - * The value. - */ private final String value; + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public StringTag(String value) { + super(); + checkNotNull(value); + this.value = value; + } + /** * Creates the tag. - * - * @param name - * The name. - * @param value - * The value. + * + * @param name the name of the tag + * @param value the value of the tag */ public StringTag(String name, String value) { super(name); + checkNotNull(value); this.value = value; } diff --git a/src/main/java/com/sk89q/jnbt/Tag.java b/src/main/java/com/sk89q/jnbt/Tag.java index 18a0a0420..2ab0861ea 100644 --- a/src/main/java/com/sk89q/jnbt/Tag.java +++ b/src/main/java/com/sk89q/jnbt/Tag.java @@ -19,33 +19,36 @@ package com.sk89q.jnbt; +import static com.google.common.base.Preconditions.checkNotNull; + /** - * Represents a single NBT tag. - * - * @author Graham Edgecombe - * + * Represents a NBT tag. */ public abstract class Tag { - /** - * The name of this tag. - */ private final String name; + /** + * Create a new tag with an empty name. + */ + Tag() { + this(""); + } + /** * Creates the tag with the specified name. * - * @param name - * The name. + * @param name the name */ - public Tag(String name) { + Tag(String name) { + checkNotNull(name); this.name = name; } /** * Gets the name of this tag. * - * @return The name of this tag. + * @return the name of this tag */ public final String getName() { return name; @@ -54,7 +57,7 @@ public abstract class Tag { /** * Gets the value of this tag. * - * @return The value of this tag. + * @return the value */ public abstract Object getValue(); diff --git a/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java b/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java new file mode 100644 index 000000000..43b24c39a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java @@ -0,0 +1,58 @@ +/* + * 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.storage; + +import com.sk89q.jnbt.ListTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utility methods for working with NBT data used in Minecraft. + */ +public final class NBTConversions { + + private NBTConversions() { + } + + /** + * Read a {@code Location} from two list tags, the first of which contains + * three numbers for the X, Y, and Z components, and the second of + * which contains two numbers, the yaw and pitch in degrees. + * + *

For values that are unavailable, their values will be 0.

+ * + * @param extent the extent + * @param positionTag the position tag + * @param directionTag the direction tag + * @return a location + */ + public static Location toLocation(Extent extent, ListTag positionTag, ListTag directionTag) { + checkNotNull(extent); + checkNotNull(positionTag); + checkNotNull(directionTag); + return new Location( + extent, + positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), + ((float) Math.toRadians(directionTag.asDouble(0))), ((float) Math.toRadians(directionTag.asDouble(1)))); + } + +} From cf6fa985258bb81c0bbd3cd33b8ed0618fb174e0 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 15 Jul 2014 11:55:28 -0700 Subject: [PATCH 45/56] Rename getInteger -> getInt in NBT library and add putType(...) methods. --- src/main/java/com/sk89q/jnbt/CompoundTag.java | 20 ++-- .../com/sk89q/jnbt/CompoundTagBuilder.java | 107 ++++++++++++++++++ src/main/java/com/sk89q/jnbt/ListTag.java | 20 ++-- 3 files changed, 127 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/sk89q/jnbt/CompoundTag.java b/src/main/java/com/sk89q/jnbt/CompoundTag.java index 7550dd159..6f959e81a 100644 --- a/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -196,13 +196,13 @@ public final class CompoundTag extends Tag { /** * Get a {@code int[]} named with the given key. * - *

If the key does not exist or its value is not an integer array tag, + *

If the key does not exist or its value is not an int array tag, * then an empty array will be returned.

* * @param key the key - * @return an integer array + * @return an int array */ - public int[] getIntegerArray(String key) { + public int[] getIntArray(String key) { Tag tag = value.get(key); if (tag instanceof IntArrayTag) { return ((IntArrayTag) tag).getValue(); @@ -212,15 +212,15 @@ public final class CompoundTag extends Tag { } /** - * Get an integer named with the given key. + * Get an int named with the given key. * - *

If the key does not exist or its value is not an integer tag, + *

If the key does not exist or its value is not an int tag, * then {@code 0} will be returned.

* * @param key the key - * @return an integer + * @return an int */ - public int getInteger(String key) { + public int getInt(String key) { Tag tag = value.get(key); if (tag instanceof IntTag) { return ((IntTag) tag).getValue(); @@ -230,16 +230,16 @@ public final class CompoundTag extends Tag { } /** - * Get an integer named with the given key, even if it's another + * Get an int named with the given key, even if it's another * type of number. * *

If the key does not exist or its value is not a number, * then {@code 0} will be returned.

* * @param key the key - * @return an integer + * @return an int */ - public int asInteger(String key) { + public int asInt(String key) { Tag tag = value.get(key); if (tag instanceof ByteTag) { return ((ByteTag) tag).getValue(); diff --git a/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java index 58a3320a2..187995a6b 100644 --- a/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java +++ b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -62,6 +62,113 @@ public class CompoundTagBuilder { return this; } + /** + * Put the given key and value into the compound tag as a + * {@code ByteArrayTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putByteArray(String key, byte[] value) { + return put(key, new ByteArrayTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code ByteTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putByte(String key, byte value) { + return put(key, new ByteTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code DoubleTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putDouble(String key, double value) { + return put(key, new DoubleTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code FloatTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putFloat(String key, float value) { + return put(key, new FloatTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code IntArrayTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putIntArray(String key, int[] value) { + return put(key, new IntArrayTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as an {@code IntTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putInt(String key, int value) { + return put(key, new IntTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code LongTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putLong(String key, long value) { + return put(key, new LongTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code ShortTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putShort(String key, short value) { + return put(key, new ShortTag(key, value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code StringTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putString(String key, String value) { + return put(key, new StringTag(key, value)); + } + /** * Put all the entries from the given map into this map. * diff --git a/src/main/java/com/sk89q/jnbt/ListTag.java b/src/main/java/com/sk89q/jnbt/ListTag.java index 681340620..4125b43ee 100644 --- a/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/src/main/java/com/sk89q/jnbt/ListTag.java @@ -210,13 +210,13 @@ public final class ListTag extends Tag { /** * Get a {@code int[]} named with the given index. * - *

If the index does not exist or its value is not an integer array tag, + *

If the index does not exist or its value is not an int array tag, * then an empty array will be returned.

* * @param index the index - * @return an integer array + * @return an int array */ - public int[] getIntegerArray(int index) { + public int[] getIntArray(int index) { Tag tag = getIfExists(index); if (tag instanceof IntArrayTag) { return ((IntArrayTag) tag).getValue(); @@ -226,15 +226,15 @@ public final class ListTag extends Tag { } /** - * Get an integer named with the given index. + * Get an int named with the given index. * - *

If the index does not exist or its value is not an integer tag, + *

If the index does not exist or its value is not an int tag, * then {@code 0} will be returned.

* * @param index the index - * @return an integer + * @return an int */ - public int getInteger(int index) { + public int getInt(int index) { Tag tag = getIfExists(index); if (tag instanceof IntTag) { return ((IntTag) tag).getValue(); @@ -244,16 +244,16 @@ public final class ListTag extends Tag { } /** - * Get an integer named with the given index, even if it's another + * Get an int named with the given index, even if it's another * type of number. * *

If the index does not exist or its value is not a number, * then {@code 0} will be returned.

* * @param index the index - * @return an integer + * @return an int */ - public int asInteger(int index) { + public int asInt(int index) { Tag tag = getIfExists(index); if (tag instanceof ByteTag) { return ((ByteTag) tag).getValue(); From 1f709b9cc3466fd67f3fd443555dfff787ee1144 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 15 Jul 2014 12:09:11 -0700 Subject: [PATCH 46/56] Move handling of hanging entities into ExtentEntityCopy. --- .../sk89q/worldedit/forge/ForgeEntity.java | 25 ++------- .../com/sk89q/worldedit/forge/ForgeWorld.java | 10 ---- .../function/entity/ExtentEntityCopy.java | 54 +++++++++++++++++++ .../internal/helper/MCDirections.java | 18 +++++++ 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java index 4a55e41bd..750d1a4b1 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -55,28 +55,9 @@ class ForgeEntity implements Entity { @Override public Location getLocation() { - Vector position; - float pitch; - float yaw; - - if (entity instanceof EntityHanging) { - EntityHanging hanging = (EntityHanging) entity; - - position = new Vector(hanging.xPosition, hanging.yPosition, hanging.zPosition); - - Direction direction = MCDirections.fromHanging(hanging.hangingDirection); - if (direction != null) { - yaw = direction.toVector().toYaw(); - pitch = direction.toVector().toPitch(); - } else { - yaw = (float) Math.toRadians(entity.rotationYaw); - pitch = (float) Math.toRadians(entity.rotationPitch); - } - } else { - position = new Vector(entity.posX, entity.posY, entity.posZ); - yaw = (float) Math.toRadians(entity.rotationYaw); - pitch = (float) Math.toRadians(entity.rotationPitch); - } + Vector position = new Vector(entity.posX, entity.posY, entity.posZ); + float yaw = (float) Math.toRadians(entity.rotationYaw); + float pitch = (float) Math.toRadians(entity.rotationPitch); return new Location(ForgeAdapter.adapt(entity.worldObj), position, yaw, pitch); } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index b7f15e27f..11576145e 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -551,16 +551,6 @@ public class ForgeWorld extends AbstractWorld { createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), (float) Math.toDegrees(location.getYaw()), (float) Math.toDegrees(location.getPitch())); - // Special handling for hanging entities - if (createdEntity instanceof EntityHanging) { - EntityHanging hanging = (EntityHanging) createdEntity; - hanging.xPosition = location.getBlockX(); - hanging.yPosition = location.getBlockY(); - hanging.zPosition = location.getBlockZ(); - Direction direction = Direction.findClosest(location.getDirection(), Flag.CARDINAL); - hanging.setDirection(MCDirections.toHanging(direction)); - } - world.spawnEntityInWorld(createdEntity); return new ForgeEntity(createdEntity); } else { diff --git a/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index 2728285fe..d172d10c6 100644 --- a/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -19,13 +19,18 @@ package com.sk89q.worldedit.function.entity; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; import com.sk89q.worldedit.util.Location; import static com.google.common.base.Preconditions.checkNotNull; @@ -87,6 +92,10 @@ public class ExtentEntityCopy implements EntityFunction { Vector newPosition = transform.apply(location.toVector().subtract(from)); Vector newDirection = transform.apply(location.getDirection()).subtract(transform.apply(Vector.ZERO)).normalize(); Location newLocation = new Location(destination, newPosition.add(to), newDirection); + + // Some entities store their position data in NBT + state = transformNbtData(state); + boolean success = destination.createEntity(newLocation, state) != null; // Remove @@ -100,4 +109,49 @@ public class ExtentEntityCopy implements EntityFunction { } } + /** + * Transform NBT data in the given entity state and return a new instance + * if the NBT data needs to be transformed. + * + * @param state the existing state + * @return a new state or the existing one + */ + private BaseEntity transformNbtData(BaseEntity state) { + CompoundTag tag = state.getNbtData(); + + if (tag != null) { + // Handle hanging entities (paintings, item frames, etc.) + boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ"); + boolean hasDirection = tag.containsKey("Direction"); + boolean hasLegacyDirection = tag.containsKey("Dir"); + + if (hasTilePosition) { + Vector tilePosition = new Vector(tag.asInt("TileX"), tag.asInt("TileY"), tag.asInt("TileZ")); + Vector newTilePosition = transform.apply(tilePosition.subtract(from)).add(to); + + CompoundTagBuilder builder = tag.createBuilder() + .putInt("TileX", newTilePosition.getBlockX()) + .putInt("TileY", newTilePosition.getBlockY()) + .putInt("TileZ", newTilePosition.getBlockZ()); + + if (hasDirection || hasLegacyDirection) { + int d = hasDirection ? tag.asInt("Direction") : MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")); + Direction direction = MCDirections.fromHanging(d); + + if (direction != null) { + Vector vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector.ZERO)).normalize(); + Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL); + + builder.putByte("Direction", (byte) MCDirections.toHanging(newDirection)); + builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection))); + } + } + + return new BaseEntity(state.getTypeId(), builder.build()); + } + } + + return state; + } + } diff --git a/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java index 6805196de..d9e75d62f 100644 --- a/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java +++ b/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -59,4 +59,22 @@ public final class MCDirections { } } + public static int fromLegacyHanging(byte i) { + switch (i) { + case 0: return 2; + case 1: return 1; + case 2: return 0; + default: return 3; + } + } + + public static byte toLegacyHanging(int i) { + switch (i) { + case 0: return (byte) 2; + case 1: return (byte) 1; + case 2: return (byte) 0; + default: return (byte) 3; + } + } + } From 9dbc53476ea943e7844dd189149f20308aaaafc3 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 15 Jul 2014 12:13:57 -0700 Subject: [PATCH 47/56] Delete protected Random instance from LocalWorld. --- src/main/java/com/sk89q/worldedit/LocalWorld.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java index 037e92810..3cf1cf170 100644 --- a/src/main/java/com/sk89q/worldedit/LocalWorld.java +++ b/src/main/java/com/sk89q/worldedit/LocalWorld.java @@ -19,13 +19,11 @@ package com.sk89q.worldedit; -import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.World; -import java.util.Random; - /** * A legacy abstract implementation of {@link World}. New implementations * should use {@link AbstractWorld} when possible. @@ -53,13 +51,6 @@ public abstract class LocalWorld extends AbstractWorld { } } - /** - * @deprecated Don't use this anymore. It will be removed - */ - @SuppressWarnings("ProtectedField") - @Deprecated - protected Random random = new Random(); - @Override public BaseBlock getLazyBlock(Vector position) { return getBlock(position); From 3e34d5ca52db626c4c83cdd7bc98f63e576f37b8 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 15 Jul 2014 19:47:47 -0700 Subject: [PATCH 48/56] Re-implement /remove and /butcher with the new entity API. --- .../sk89q/worldedit/bukkit/BukkitEntity.java | 13 ++ .../worldedit/bukkit/BukkitEntityType.java | 140 ++++++++++++ .../sk89q/worldedit/bukkit/BukkitPlayer.java | 8 + .../sk89q/worldedit/bukkit/BukkitWorld.java | 206 ------------------ .../sk89q/worldedit/forge/ForgeEntity.java | 25 ++- .../worldedit/forge/ForgeEntityType.java | 138 ++++++++++++ .../sk89q/worldedit/forge/ForgePlayer.java | 14 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 137 +----------- .../java/com/sk89q/worldedit/LocalWorld.java | 18 -- .../worldedit/command/BrushCommands.java | 40 ++-- .../worldedit/command/UtilityCommands.java | 150 ++++++------- .../command/tool/brush/ButcherBrush.java | 15 +- .../command/util/CreatureButcher.java | 135 ++++++++++++ .../worldedit/command/util/EntityRemover.java | 160 ++++++++++++++ .../sk89q/worldedit/entity/BaseEntity.java | 9 + .../com/sk89q/worldedit/entity/Entity.java | 3 +- .../worldedit/entity/metadata/EntityType.java | 151 +++++++++++++ .../extension/platform/PlayerProxy.java | 8 + .../worldedit/extent/ChangeSetExtent.java | 6 + .../extent/clipboard/BlockArrayClipboard.java | 6 + .../worldedit/internal/LocalWorldAdapter.java | 29 --- .../worldedit/regions/CylinderRegion.java | 46 +++- .../com/sk89q/worldedit/util/Faceted.java | 52 +++++ .../util/collection/FastListIterator.java | 6 +- .../sk89q/worldedit/world/AbstractWorld.java | 17 -- .../com/sk89q/worldedit/world/NullWorld.java | 10 - .../java/com/sk89q/worldedit/world/World.java | 43 ---- .../world/registry/EntityRegistry.java | 42 ++++ .../world/registry/LegacyWorldData.java | 6 + .../registry/NullEntityRegistry.java} | 74 +++---- .../worldedit/world/registry/WorldData.java | 7 + 31 files changed, 1110 insertions(+), 604 deletions(-) create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntityType.java create mode 100644 src/forge/java/com/sk89q/worldedit/forge/ForgeEntityType.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/metadata/EntityType.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Faceted.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java rename src/main/java/com/sk89q/worldedit/{EntityType.java => world/registry/NullEntityRegistry.java} (70%) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index 002890778..483b740eb 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -23,10 +23,13 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.entity.metadata.EntityType; import com.sk89q.worldedit.entity.metadata.Tameable; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -94,4 +97,14 @@ class BukkitEntity implements Entity { return entity.isDead(); } + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getFacet(Class cls) { + if (EntityType.class.isAssignableFrom(cls)) { + return (T) new BukkitEntityType(entity); + } else { + return null; + } + } } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntityType.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntityType.java new file mode 100644 index 000000000..d80526c83 --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntityType.java @@ -0,0 +1,140 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.entity.metadata.EntityType; +import com.sk89q.worldedit.util.Enums; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Boat; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Golem; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Item; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Painting; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Villager; + +import static com.google.common.base.Preconditions.checkNotNull; + +class BukkitEntityType implements EntityType { + + private static final org.bukkit.entity.EntityType tntMinecartType = + Enums.findByValue(org.bukkit.entity.EntityType.class, "MINECART_TNT"); + + private final Entity entity; + + BukkitEntityType(Entity entity) { + checkNotNull(entity); + this.entity = entity; + } + + @Override + public boolean isPlayerDerived() { + return entity instanceof HumanEntity; + } + + @Override + public boolean isProjectile() { + return entity instanceof Projectile; + } + + @Override + public boolean isItem() { + return entity instanceof Item; + } + + @Override + public boolean isFallingBlock() { + return entity instanceof FallingBlock; + } + + @Override + public boolean isPainting() { + return entity instanceof Painting; + } + + @Override + public boolean isItemFrame() { + return entity instanceof ItemFrame; + } + + @Override + public boolean isBoat() { + return entity instanceof Boat; + } + + @Override + public boolean isMinecart() { + return entity instanceof Minecart; + } + + @Override + public boolean isTNT() { + return entity instanceof TNTPrimed || entity.getType() == tntMinecartType; + } + + @Override + public boolean isExperienceOrb() { + return entity instanceof ExperienceOrb; + } + + @Override + public boolean isLiving() { + return entity instanceof LivingEntity; + } + + @Override + public boolean isAnimal() { + return entity instanceof Animals; + } + + @Override + public boolean isAmbient() { + return entity instanceof Ambient; + } + + @Override + public boolean isNPC() { + return entity instanceof Villager; + } + + @Override + public boolean isGolem() { + return entity instanceof Golem; + } + + @Override + public boolean isTamed() { + return entity instanceof Tameable && ((Tameable) entity).isTamed(); + } + + @Override + public boolean isTagged() { + return entity instanceof LivingEntity && ((LivingEntity) entity).getCustomName() != null; + } +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 22a659abf..8f82aa371 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -35,6 +35,8 @@ import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import javax.annotation.Nullable; + public class BukkitPlayer extends LocalPlayer { private Player player; private WorldEditPlugin plugin; @@ -184,4 +186,10 @@ public class BukkitPlayer extends LocalPlayer { (float) Math.toRadians(nativeLocation.getYaw()), (float) Math.toRadians(nativeLocation.getPitch())); } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 2debe4ebd..170ceacb6 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -22,8 +22,6 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; -import com.sk89q.worldedit.LocalEntity; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -35,12 +33,10 @@ import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Enums; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.WorldData; import org.bukkit.Effect; -import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.TreeType; import org.bukkit.World; @@ -48,24 +44,7 @@ import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Chest; -import org.bukkit.entity.Ambient; -import org.bukkit.entity.Animals; -import org.bukkit.entity.Boat; import org.bukkit.entity.Entity; -import org.bukkit.entity.ExperienceOrb; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Golem; -import org.bukkit.entity.Hanging; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Item; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Minecart; -import org.bukkit.entity.Painting; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.entity.Tameable; -import org.bukkit.entity.Villager; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -75,11 +54,8 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -88,8 +64,6 @@ import static com.google.common.base.Preconditions.checkNotNull; public class BukkitWorld extends LocalWorld { private static final Logger logger = WorldEdit.logger; - private static final org.bukkit.entity.EntityType tntMinecartType = - Enums.findByValue(org.bukkit.entity.EntityType.class, "MINECART_TNT"); private static final Map effects = new HashMap(); static { @@ -377,168 +351,6 @@ public class BukkitWorld extends LocalWorld { world.dropItemNaturally(BukkitUtil.toLocation(world, pt), bukkitItem); } - @Override - public int killMobs(Vector origin, double radius, int flags) { - World world = getWorld(); - - boolean killPets = (flags & KillFlags.PETS) != 0; - boolean killNPCs = (flags & KillFlags.NPCS) != 0; - boolean killAnimals = (flags & KillFlags.ANIMALS) != 0; - boolean withLightning = (flags & KillFlags.WITH_LIGHTNING) != 0; - boolean killGolems = (flags & KillFlags.GOLEMS) != 0; - boolean killAmbient = (flags & KillFlags.AMBIENT) != 0; - boolean killTagged = (flags & KillFlags.TAGGED) != 0; - - int num = 0; - double radiusSq = radius * radius; - - Location bukkitOrigin = BukkitUtil.toLocation(world, origin); - - for (LivingEntity ent : world.getLivingEntities()) { - if (ent instanceof HumanEntity) { - continue; - } - - if (!killAnimals && ent instanceof Animals) { - continue; - } - - if (!killPets && ent instanceof Tameable && ((Tameable) ent).isTamed()) { - continue; // tamed pet - } - - if (!killGolems && ent instanceof Golem) { - continue; - } - - if (!killNPCs && ent instanceof Villager) { - continue; - } - - if (!killAmbient && ent instanceof Ambient) { - continue; - } - - if (!killTagged && isTagged(ent)) { - continue; - } - - if (radius < 0 || bukkitOrigin.distanceSquared(ent.getLocation()) <= radiusSq) { - if (withLightning) { - world.strikeLightningEffect(ent.getLocation()); - } - ent.remove(); - ++num; - } - } - - return num; - } - - private static boolean isTagged(LivingEntity ent) { - return ent.getCustomName() != null; - } - - /** - * Remove entities in an area. - * - * @param origin - * @param radius - * @return - */ - @Override - public int removeEntities(EntityType type, Vector origin, int radius) { - World world = getWorld(); - - int num = 0; - double radiusSq = Math.pow(radius, 2); - - for (Entity ent : world.getEntities()) { - if (radius != -1 - && origin.distanceSq(BukkitUtil.toVector(ent.getLocation())) > radiusSq) { - continue; - } - - switch (type) { - case ALL: - if (ent instanceof Projectile || ent instanceof Boat || ent instanceof Item - || ent instanceof FallingBlock || ent instanceof Minecart || ent instanceof Hanging - || ent instanceof TNTPrimed || ent instanceof ExperienceOrb) { - ent.remove(); - num++; - } - break; - - case PROJECTILES: - case ARROWS: - if (ent instanceof Projectile) { - // covers: arrow, egg, enderpearl, fireball, fish, snowball, throwpotion, thrownexpbottle - ent.remove(); - ++num; - } - break; - - case BOATS: - if (ent instanceof Boat) { - ent.remove(); - ++num; - } - break; - - case ITEMS: - if (ent instanceof Item) { - ent.remove(); - ++num; - } - break; - - case FALLING_BLOCKS: - if (ent instanceof FallingBlock) { - ent.remove(); - ++num; - } - break; - - case MINECARTS: - if (ent instanceof Minecart) { - ent.remove(); - ++num; - } - break; - - case PAINTINGS: - if (ent instanceof Painting) { - ent.remove(); - ++num; - } - break; - - case ITEM_FRAMES: - if (ent instanceof ItemFrame) { - ent.remove(); - ++num; - } - break; - - case TNT: - if (ent instanceof TNTPrimed || ent.getType() == tntMinecartType) { - ent.remove(); - ++num; - } - break; - - case XP_ORBS: - if (ent instanceof ExperienceOrb) { - ent.remove(); - ++num; - } - break; - } - } - - return num; - } - @SuppressWarnings("deprecation") @Override public boolean isValidBlockType(int type) { @@ -609,24 +421,6 @@ public class BukkitWorld extends LocalWorld { getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); } - @Override - public int killEntities(LocalEntity... entities) { - World world = getWorld(); - - int amount = 0; - Set toKill = new HashSet(); - for (LocalEntity entity : entities) { - toKill.add(((com.sk89q.worldedit.bukkit.entity.BukkitEntity) entity).getEntityId()); - } - for (Entity entity : world.getEntities()) { - if (toKill.contains(entity.getUniqueId())) { - entity.remove(); - ++amount; - } - } - return amount; - } - @Override public BaseBlock getBlock(Vector position) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java index 750d1a4b1..cf96d9400 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -22,14 +22,14 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityType; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.helper.MCDirections; -import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; -import net.minecraft.entity.EntityHanging; import net.minecraft.entity.EntityList; import net.minecraft.nbt.NBTTagCompound; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; class ForgeEntity implements Entity { @@ -41,6 +41,15 @@ class ForgeEntity implements Entity { this.entity = entity; } + /** + * Return the underlying entity. + * + * @return the underlying entity + */ + net.minecraft.entity.Entity getEntity() { + return entity; + } + @Override public BaseEntity getState() { String id = EntityList.getEntityString(entity); @@ -73,4 +82,14 @@ class ForgeEntity implements Entity { return true; } + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getFacet(Class cls) { + if (EntityType.class.isAssignableFrom(cls)) { + return (T) new ForgeEntityType(entity); + } else { + return null; + } + } } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntityType.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntityType.java new file mode 100644 index 000000000..a2fc3952e --- /dev/null +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntityType.java @@ -0,0 +1,138 @@ +/* + * 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.forge; + +import com.sk89q.worldedit.entity.metadata.EntityType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.IMerchant; +import net.minecraft.entity.INpc; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.item.EntityBoat; +import net.minecraft.entity.item.EntityEnderEye; +import net.minecraft.entity.item.EntityFallingSand; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.EntityItemFrame; +import net.minecraft.entity.item.EntityMinecart; +import net.minecraft.entity.item.EntityPainting; +import net.minecraft.entity.item.EntityTNTPrimed; +import net.minecraft.entity.item.EntityXPOrb; +import net.minecraft.entity.monster.EntityGolem; +import net.minecraft.entity.passive.EntityAmbientCreature; +import net.minecraft.entity.passive.EntityTameable; +import net.minecraft.entity.passive.IAnimals; +import net.minecraft.entity.player.EntityPlayer; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ForgeEntityType implements EntityType { + + private final Entity entity; + + public ForgeEntityType(Entity entity) { + checkNotNull(entity); + this.entity = entity; + } + + @Override + public boolean isPlayerDerived() { + return entity instanceof EntityPlayer; + } + + @Override + public boolean isProjectile() { + return entity instanceof EntityEnderEye || entity instanceof IProjectile; + } + + @Override + public boolean isItem() { + return entity instanceof EntityItem; + } + + @Override + public boolean isFallingBlock() { + return entity instanceof EntityFallingSand; + } + + @Override + public boolean isPainting() { + return entity instanceof EntityPainting; + } + + @Override + public boolean isItemFrame() { + return entity instanceof EntityItemFrame; + } + + @Override + public boolean isBoat() { + return entity instanceof EntityBoat; + } + + @Override + public boolean isMinecart() { + return entity instanceof EntityMinecart; + } + + @Override + public boolean isTNT() { + return entity instanceof EntityTNTPrimed; + } + + @Override + public boolean isExperienceOrb() { + return entity instanceof EntityXPOrb; + } + + @Override + public boolean isLiving() { + return entity instanceof EntityLiving; + } + + @Override + public boolean isAnimal() { + return entity instanceof IAnimals; + } + + @Override + public boolean isAmbient() { + return entity instanceof EntityAmbientCreature; + } + + @Override + public boolean isNPC() { + return entity instanceof INpc || entity instanceof IMerchant; + } + + @Override + public boolean isGolem() { + return entity instanceof EntityGolem; + } + + @Override + public boolean isTamed() { + return entity instanceof EntityTameable && ((EntityTameable) entity).isTamed(); + } + + @Override + public boolean isTagged() { + return entity instanceof EntityLiving && ((EntityLiving) entity).hasCustomNameTag(); + } +} diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java index d1ce05924..10e4af4a5 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -20,10 +20,10 @@ package com.sk89q.worldedit.forge; import com.sk89q.util.StringUtil; -import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVector; import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.AbstractPlayerActor; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.LocalWorldAdapter; import com.sk89q.worldedit.internal.cui.CUIEvent; @@ -33,7 +33,10 @@ import net.minecraft.item.ItemStack; import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraft.util.ChatMessageComponent; -public class ForgePlayer extends LocalPlayer { +import javax.annotation.Nullable; + +public class ForgePlayer extends AbstractPlayerActor { + private EntityPlayerMP player; protected ForgePlayer(EntityPlayerMP player) { @@ -133,4 +136,11 @@ public class ForgePlayer extends LocalPlayer { public boolean hasPermission(String perm) { return ForgeUtil.hasPermission(this.player, perm); } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } + } \ No newline at end of file diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 11576145e..8b1f2c563 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.forge; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -33,34 +32,15 @@ import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.util.Direction.Flag; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.WorldData; import net.minecraft.block.Block; -import net.minecraft.entity.EntityHanging; import net.minecraft.entity.EntityList; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.IProjectile; -import net.minecraft.entity.item.EntityBoat; -import net.minecraft.entity.item.EntityEnderEye; -import net.minecraft.entity.item.EntityFallingSand; import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.item.EntityItemFrame; -import net.minecraft.entity.item.EntityMinecart; -import net.minecraft.entity.item.EntityPainting; -import net.minecraft.entity.item.EntityTNTPrimed; -import net.minecraft.entity.item.EntityXPOrb; -import net.minecraft.entity.monster.EntityGolem; -import net.minecraft.entity.passive.EntityAmbientCreature; -import net.minecraft.entity.passive.EntityAnimal; -import net.minecraft.entity.passive.EntityTameable; -import net.minecraft.entity.passive.EntityVillager; import net.minecraft.inventory.IInventory; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -224,7 +204,7 @@ public class ForgeWorld extends AbstractWorld { checkNotNull(position); checkNotNull(item); - if ((item == null) || (item.getType() == 0)) { + if (item.getType() == 0) { return; } @@ -233,121 +213,6 @@ public class ForgeWorld extends AbstractWorld { getWorld().spawnEntityInWorld(entity); } - @Override - @SuppressWarnings({"unchecked", "ConstantConditions"}) - public int killMobs(Vector origin, double radius, int flags) { - boolean killPets = (flags & 0x1) != 0; - boolean killNPCs = (flags & 0x2) != 0; - boolean killAnimals = (flags & 0x4) != 0; - - boolean killGolems = (flags & 0x8) != 0; - boolean killAmbient = (flags & 0x10) != 0; - - int num = 0; - double radiusSq = radius * radius; - - for (net.minecraft.entity.Entity obj : (Iterable) getWorld().loadedEntityList) { - if ((obj instanceof EntityLiving)) { - EntityLiving ent = (EntityLiving) obj; - - if (!killAnimals && ent instanceof EntityAnimal) { - continue; - } - - if (!killPets && ent instanceof EntityTameable && ((EntityTameable) ent).isTamed()) { - continue; // tamed pet - } - - if (!killGolems && ent instanceof EntityGolem) { - continue; - } - - if (!killNPCs && ent instanceof EntityVillager) { - continue; - } - - if (!killAmbient && ent instanceof EntityAmbientCreature) { - continue; - } - - if ((radius < 0.0D) || (origin.distanceSq(new Vector(ent.posX, ent.posY, ent.posZ)) <= radiusSq)) { - ent.isDead = true; - num++; - } - } - } - - return num; - } - - @Override - @SuppressWarnings("unchecked") - public int removeEntities(EntityType type, Vector origin, int radius) { - checkNotNull(type); - checkNotNull(origin); - - int num = 0; - double radiusSq = Math.pow(radius, 2.0D); - - for (net.minecraft.entity.Entity ent : (Iterable) getWorld().loadedEntityList) { - if ((radius != -1) && (origin.distanceSq(new Vector(ent.posX, ent.posY, ent.posZ)) > radiusSq)) { - continue; - } - if (type == EntityType.ALL) { - if (((ent instanceof EntityBoat)) || ((ent instanceof EntityItem)) || ((ent instanceof EntityFallingSand)) || ((ent instanceof EntityMinecart)) || ((ent instanceof EntityHanging)) || ((ent instanceof EntityTNTPrimed)) || ((ent instanceof EntityXPOrb)) || ((ent instanceof EntityEnderEye)) || ((ent instanceof IProjectile))) { - ent.isDead = true; - num++; - } - } else if ((type == EntityType.PROJECTILES) || (type == EntityType.ARROWS)) { - if (((ent instanceof EntityEnderEye)) || ((ent instanceof IProjectile))) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.BOATS) { - if ((ent instanceof EntityBoat)) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.ITEMS) { - if ((ent instanceof EntityItem)) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.FALLING_BLOCKS) { - if ((ent instanceof EntityFallingSand)) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.MINECARTS) { - if ((ent instanceof EntityMinecart)) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.PAINTINGS) { - if ((ent instanceof EntityPainting)) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.ITEM_FRAMES) { - if ((ent instanceof EntityItemFrame)) { - ent.isDead = true; - num++; - } - } else if (type == EntityType.TNT) { - if ((ent instanceof EntityTNTPrimed)) { - ent.isDead = true; - num++; - } - } else if ((type == EntityType.XP_ORBS) && ((ent instanceof EntityXPOrb))) { - ent.isDead = true; - num++; - } - - } - - return num; - } - @Override public boolean regenerate(Region region, EditSession editSession) { BaseBlock[] history = new BaseBlock[256 * (getMaxY() + 1)]; diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java index 3cf1cf170..ae1112b95 100644 --- a/src/main/java/com/sk89q/worldedit/LocalWorld.java +++ b/src/main/java/com/sk89q/worldedit/LocalWorld.java @@ -33,24 +33,6 @@ import com.sk89q.worldedit.world.World; @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; - public static final int ANIMALS = 1 << 2; - public static final int GOLEMS = 1 << 3; - public static final int AMBIENT = 1 << 4; - public static final int TAGGED = 1 << 5; - public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED; - public static final int WITH_LIGHTNING = 1 << 20; - - private KillFlags() { - } - } - @Override public BaseBlock getLazyBlock(Vector position) { return getBlock(position); diff --git a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 6f3d65062..1ce10523e 100644 --- a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -25,13 +25,11 @@ import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld.KillFlags; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.command.UtilityCommands.FlagContainer; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.brush.ButcherBrush; import com.sk89q.worldedit.command.tool.brush.ClipboardBrush; @@ -41,6 +39,7 @@ import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; import com.sk89q.worldedit.command.tool.brush.SmoothBrush; import com.sk89q.worldedit.command.tool.brush.SphereBrush; +import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.BlockMask; @@ -229,13 +228,21 @@ public class BrushCommands { @Command( aliases = { "butcher", "kill" }, - usage = "[radius] [command flags]", + usage = "[radius]", + flags = "plangbtf", desc = "Butcher brush", help = "Kills nearby mobs within the specified radius.\n" + - "Any number of 'flags' that the //butcher command uses\n" + - "may be specified as an argument", + "Flags:" + + " -p also kills pets.\n" + + " -n also kills NPCs.\n" + + " -g also kills Golems.\n" + + " -a also kills animals.\n" + + " -b also kills ambient mobs.\n" + + " -t also kills mobs with name tags.\n" + + " -f compounds all previous flags.\n" + + " -l currently does nothing.", min = 0, - max = 2 + max = 1 ) @CommandPermissions("worldedit.brush.butcher") public void butcherBrush(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { @@ -254,24 +261,13 @@ public class BrushCommands { return; } - FlagContainer flags = new FlagContainer(player); - if (args.argsLength() == 2) { - String flagString = args.getString(1); - // straight from the command, using contains instead of hasflag - flags.or(KillFlags.FRIENDLY , flagString.contains("f")); // No permission check here. Flags will instead be filtered by the subsequent calls. - flags.or(KillFlags.PETS , flagString.contains("p"), "worldedit.butcher.pets"); - flags.or(KillFlags.NPCS , flagString.contains("n"), "worldedit.butcher.npcs"); - flags.or(KillFlags.GOLEMS , flagString.contains("g"), "worldedit.butcher.golems"); - flags.or(KillFlags.ANIMALS , flagString.contains("a"), "worldedit.butcher.animals"); - flags.or(KillFlags.AMBIENT , flagString.contains("b"), "worldedit.butcher.ambient"); - flags.or(KillFlags.TAGGED , flagString.contains("t"), "worldedit.butcher.tagged"); - flags.or(KillFlags.WITH_LIGHTNING, flagString.contains("l"), "worldedit.butcher.lightning"); - } + CreatureButcher flags = new CreatureButcher(player); + flags.fromCommand(args); + BrushTool tool = session.getBrushTool(player.getItemInHand()); tool.setSize(radius); - tool.setBrush(new ButcherBrush(flags.flags), "worldedit.brush.butcher"); + tool.setBrush(new ButcherBrush(flags), "worldedit.brush.butcher"); - player.print(String.format("Butcher brush equipped (%.0f).", - radius)); + player.print(String.format("Butcher brush equipped (%.0f).", radius)); } } diff --git a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index d1e0852d8..5dd5cce8d 100644 --- a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -26,30 +26,35 @@ import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld.KillFlags; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.command.util.CreatureButcher; +import com.sk89q.worldedit.command.util.EntityRemover; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.CommandManager; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.patterns.Pattern; import com.sk89q.worldedit.patterns.SingleBlockPattern; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.command.CommandCallable; import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.PrimaryAliasComparator; import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; import com.sk89q.worldedit.util.formatting.Style; import com.sk89q.worldedit.util.formatting.StyledFragment; @@ -374,7 +379,7 @@ public class UtilityCommands { " -b also kills ambient mobs.\n" + " -t also kills mobs with name tags.\n" + " -f compounds all previous flags.\n" + - " -l strikes lightning on each killed mob.", + " -l currently does nothing.", min = 0, max = 1 ) @@ -399,26 +404,37 @@ public class UtilityCommands { } } - FlagContainer flags = new FlagContainer(actor); - flags.or(KillFlags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls. - flags.or(KillFlags.PETS , args.hasFlag('p'), "worldedit.butcher.pets"); - flags.or(KillFlags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs"); - flags.or(KillFlags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems"); - flags.or(KillFlags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals"); - flags.or(KillFlags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient"); - flags.or(KillFlags.TAGGED , args.hasFlag('t'), "worldedit.butcher.tagged"); - flags.or(KillFlags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning"); - // If you add flags here, please add them to com.sk89q.worldedit.commands.BrushCommands.butcherBrush() as well + CreatureButcher flags = new CreatureButcher(actor); + flags.fromCommand(args); + + List visitors = new ArrayList(); + LocalSession session = null; + EditSession editSession = null; - int killed; if (player != null) { - LocalSession session = we.getSessionManager().get(player); - killed = player.getWorld().killMobs(session.getPlacementPosition(player), radius, flags.flags); - } else { - killed = 0; - for (World world : we.getServer().getWorlds()) { - killed += world.killMobs(new Vector(), radius, flags.flags); + session = we.getSessionManager().get(player); + Vector center = session.getPlacementPosition(player); + editSession = session.createEditSession(player); + List entities; + if (radius >= 0) { + CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius); + entities = editSession.getEntities(region); + } else { + entities = editSession.getEntities(); } + visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction(editSession.getWorld().getWorldData().getEntityRegistry()))); + } else { + Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING); + for (World world : platform.getWorlds()) { + List entities = world.getEntities(); + visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction(world.getWorldData().getEntityRegistry()))); + } + } + + int killed = 0; + for (EntityVisitor visitor : visitors) { + Operations.completeLegacy(visitor); + killed += visitor.getAffected(); } if (radius < 0) { @@ -426,25 +442,10 @@ public class UtilityCommands { } else { actor.print("Killed " + killed + " mobs in a radius of " + radius + "."); } - } - public static class FlagContainer { - private final Actor player; - public int flags = 0; - public FlagContainer(Actor player) { - this.player = player; - } - - public void or(int flag, boolean on) { - if (on) flags |= flag; - } - - public void or(int flag, boolean on, String permission) { - or(flag, on); - - if ((flags & flag) != 0 && !player.hasPermission(permission)) { - flags &= ~flag; - } + if (editSession != null) { + session.remember(editSession); + editSession.flushQueue(); } } @@ -457,56 +458,55 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.remove") @Logging(PLACEMENT) - public void remove(Actor actor, @Optional Player player, @Optional LocalSession session, CommandContext args) throws WorldEditException { - + public void remove(Actor actor, CommandContext args) throws WorldEditException, CommandException { String typeStr = args.getString(0); int radius = args.getInteger(1); + Player player = actor instanceof Player ? (Player) actor : null; if (radius < -1) { actor.printError("Use -1 to remove all entities in loaded chunks"); return; } - EntityType type = null; + EntityRemover remover = new EntityRemover(); + remover.fromString(typeStr); - if (typeStr.matches("all")) { - type = EntityType.ALL; - } else if (typeStr.matches("projectiles?|arrows?")) { - type = EntityType.PROJECTILES; - } else if (typeStr.matches("items?") - || typeStr.matches("drops?")) { - type = EntityType.ITEMS; - } else if (typeStr.matches("falling(blocks?|sand|gravel)")) { - type = EntityType.FALLING_BLOCKS; - } else if (typeStr.matches("paintings?") - || typeStr.matches("art")) { - type = EntityType.PAINTINGS; - } else if (typeStr.matches("(item)frames?")) { - type = EntityType.ITEM_FRAMES; - } else if (typeStr.matches("boats?")) { - type = EntityType.BOATS; - } else if (typeStr.matches("minecarts?") - || typeStr.matches("carts?")) { - type = EntityType.MINECARTS; - } else if (typeStr.matches("tnt")) { - type = EntityType.TNT; - } else if (typeStr.matches("xp")) { - type = EntityType.XP_ORBS; + List visitors = new ArrayList(); + LocalSession session = null; + EditSession editSession = null; + + if (player != null) { + session = we.getSessionManager().get(player); + Vector center = session.getPlacementPosition(player); + editSession = session.createEditSession(player); + List entities; + if (radius >= 0) { + CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius); + entities = editSession.getEntities(region); + } else { + entities = editSession.getEntities(); + } + visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction(editSession.getWorld().getWorldData().getEntityRegistry()))); } else { - actor.printError("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); - return; + Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING); + for (World world : platform.getWorlds()) { + List entities = world.getEntities(); + visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction(world.getWorldData().getEntityRegistry()))); + } } int removed = 0; - if (player != null) { - Vector origin = session.getPlacementPosition(player); - removed = player.getWorld().removeEntities(type, origin, radius); - } else { - for (World world : we.getServer().getWorlds()) { - removed += world.removeEntities(type, new Vector(), radius); - } + for (EntityVisitor visitor : visitors) { + Operations.completeLegacy(visitor); + removed += visitor.getAffected(); + } + + actor.print("Marked " + (removed != 1 ? "entities" : "entity") + " for removal."); + + if (editSession != null) { + session.remember(editSession); + editSession.flushQueue(); } - player.print("Marked " + removed + " entit(ies) for removal."); } @Command( diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java index 1a8e4f9cd..637be6d2f 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java @@ -22,19 +22,28 @@ package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.util.CreatureButcher; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.EntityVisitor; +import com.sk89q.worldedit.regions.CylinderRegion; + +import java.util.List; public class ButcherBrush implements Brush { - private int flags; + private CreatureButcher flags; - public ButcherBrush(int flags) { + public ButcherBrush(CreatureButcher flags) { this.flags = flags; } @Override public void build(EditSession editSession, Vector pos, Pattern mat, double size) throws MaxChangedBlocksException { - editSession.getWorld().killMobs(pos, size, flags); + CylinderRegion region = CylinderRegion.createRadius(editSession, pos, size); + List entities = editSession.getEntities(region); + Operations.completeLegacy(new EntityVisitor(entities.iterator(), flags.createFunction(editSession.getWorld().getWorldData().getEntityRegistry()))); } } diff --git a/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java b/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java new file mode 100644 index 000000000..822389bbe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java @@ -0,0 +1,135 @@ +/* + * 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.command.util; + +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityType; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.world.registry.EntityRegistry; + +/** + * The implementation of /butcher. + */ +public class CreatureButcher { + + final class Flags { + @SuppressWarnings("PointlessBitwiseExpression") + public static final int PETS = 1 << 0; + public static final int NPCS = 1 << 1; + public static final int ANIMALS = 1 << 2; + public static final int GOLEMS = 1 << 3; + public static final int AMBIENT = 1 << 4; + public static final int TAGGED = 1 << 5; + public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED; + public static final int WITH_LIGHTNING = 1 << 20; + + private Flags() { + } + } + + private final Actor player; + public int flags = 0; + + public CreatureButcher(Actor player) { + this.player = player; + } + + public void or(int flag, boolean on) { + if (on) flags |= flag; + } + + public void or(int flag, boolean on, String permission) { + or(flag, on); + + if ((flags & flag) != 0 && !player.hasPermission(permission)) { + flags &= ~flag; + } + } + + public void fromCommand(CommandContext args) { + or(Flags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls. + or(Flags.PETS , args.hasFlag('p'), "worldedit.butcher.pets"); + or(Flags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs"); + or(Flags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems"); + or(Flags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals"); + or(Flags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient"); + or(Flags.TAGGED , args.hasFlag('t'), "worldedit.butcher.tagged"); + or(Flags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning"); + } + + public EntityFunction createFunction(final EntityRegistry entityRegistry) { + return new EntityFunction() { + @Override + public boolean apply(Entity entity) throws WorldEditException { + boolean killPets = (flags & Flags.PETS) != 0; + boolean killNPCs = (flags & Flags.NPCS) != 0; + boolean killAnimals = (flags & Flags.ANIMALS) != 0; + boolean killGolems = (flags & Flags.GOLEMS) != 0; + boolean killAmbient = (flags & Flags.AMBIENT) != 0; + boolean killTagged = (flags & Flags.TAGGED) != 0; + + EntityType type = entity.getFacet(EntityType.class); + + if (type == null) { + return false; + } + + if (type.isPlayerDerived()) { + return false; + } + + if (!type.isLiving()) { + return false; + } + + if (!killAnimals && type.isAnimal()) { + return false; + } + + if (!killPets && type.isTamed()) { + return false; + } + + if (!killGolems && type.isGolem()) { + return false; + } + + if (!killNPCs && type.isNPC()) { + return false; + } + + if (!killAmbient && type.isAmbient()) { + return false; + } + + if (!killTagged && type.isTagged()) { + return false; + } + + entity.remove(); + return true; + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java b/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java new file mode 100644 index 000000000..b6459b186 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java @@ -0,0 +1,160 @@ +/* + * 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.command.util; + +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityType; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.world.registry.EntityRegistry; + +import javax.annotation.Nullable; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The implementation of /remove. + */ +public class EntityRemover { + + public enum Type { + ALL("all") { + @Override + boolean matches(EntityType type) { + for (Type value : values()) { + if (value != this && value.matches(type)) { + return true; + } + } + return false; + } + }, + PROJECTILES("projectiles?|arrows?") { + @Override + boolean matches(EntityType type) { + return type.isProjectile(); + } + }, + ITEMS("items?|drops?") { + @Override + boolean matches(EntityType type) { + return type.isItem(); + } + }, + FALLING_BLOCKS("falling(blocks?|sand|gravel)") { + @Override + boolean matches(EntityType type) { + return type.isFallingBlock(); + } + }, + PAINTINGS("paintings?|art") { + @Override + boolean matches(EntityType type) { + return type.isPainting(); + } + }, + ITEM_FRAMES("(item)frames?") { + @Override + boolean matches(EntityType type) { + return type.isItemFrame(); + } + }, + BOATS("boats?") { + @Override + boolean matches(EntityType type) { + return type.isBoat(); + } + }, + MINECARTS("(mine)?carts?") { + @Override + boolean matches(EntityType type) { + return type.isMinecart(); + } + }, + TNT("tnt") { + @Override + boolean matches(EntityType type) { + return type.isTNT(); + } + }, + XP_ORBS("xp") { + @Override + boolean matches(EntityType type) { + return type.isExperienceOrb(); + } + }; + + private final Pattern pattern; + + Type(String pattern) { + this.pattern = Pattern.compile(pattern); + } + + public boolean matches(String str) { + return pattern.matcher(str).matches(); + } + + abstract boolean matches(EntityType type); + + @Nullable + public static Type findByPattern(String str) { + for (Type type : values()) { + if (type.matches(str)) { + return type; + } + } + + return null; + } + } + + private Type type; + + public void fromString(String str) throws CommandException { + Type type = Type.findByPattern(str); + if (type != null) { + this.type = type; + } else { + throw new CommandException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); + } + } + + public EntityFunction createFunction(final EntityRegistry entityRegistry) { + final Type type = this.type; + checkNotNull("type can't be null", type); + return new EntityFunction() { + @Override + public boolean apply(Entity entity) throws WorldEditException { + EntityType registryType = entity.getFacet(EntityType.class); + if (registryType != null) { + if (type.matches(registryType)) { + entity.remove(); + return true; + } + } + + return false; + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java index b1f8b0a91..4f6c40731 100644 --- a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java +++ b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -43,6 +43,15 @@ public class BaseEntity implements NbtValued { setNbtData(nbtData); } + /** + * Create a new base entity with no NBT data. + * + * @param id the entity type ID + */ + public BaseEntity(String id) { + setTypeId(id); + } + /** * Make a clone of a {@link BaseEntity}. * diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java index 7c6d68e7c..4224e5de7 100644 --- a/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Faceted; import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; @@ -34,7 +35,7 @@ import javax.annotation.Nullable; * can then be used to spawn new instances of that particular entity * description. */ -public interface Entity { +public interface Entity extends Faceted { /** * Get a copy of the entity's state. diff --git a/src/main/java/com/sk89q/worldedit/entity/metadata/EntityType.java b/src/main/java/com/sk89q/worldedit/entity/metadata/EntityType.java new file mode 100644 index 000000000..a12225414 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/metadata/EntityType.java @@ -0,0 +1,151 @@ +/* + * 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.entity.metadata; + +/** + * Describes various classes of entities. + */ +public interface EntityType { + + /** + * Test whether the entity is a player-derived entity. + * + * @return true if a player derived entity + */ + boolean isPlayerDerived(); + + /** + * Test whether the entity is a projectile. + * + * @return true if a projectile + */ + boolean isProjectile(); + + /** + * Test whether the entity is an item. + * + * @return true if an item + */ + boolean isItem(); + + /** + * Test whether the entity is a falling block. + * + * @return true if a falling block + */ + boolean isFallingBlock(); + + /** + * Test whether the entity is a painting. + * + * @return true if a painting + */ + boolean isPainting(); + + /** + * Test whether the entity is an item frame. + * + * @return true if an item frame + */ + boolean isItemFrame(); + + /** + * Test whether the entity is a boat. + * + * @return true if a boat + */ + boolean isBoat(); + + /** + * Test whether the entity is a minecart. + * + * @return true if a minecart + */ + boolean isMinecart(); + + /** + * Test whether the entity is a primed TNT block. + * + * @return true if TNT + */ + boolean isTNT(); + + /** + * Test whether the entity is an experience orb. + * + * @return true if an experience orb + */ + boolean isExperienceOrb(); + + /** + * Test whether the entity is a living entity. + * + *

A "living entity" is the superclass of many living entity classes + * in Minecraft.

+ * + * @return true if a living entity + */ + boolean isLiving(); + + /** + * Test whether the entity is an animal. + * + * @return true if an animal + */ + boolean isAnimal(); + + /** + * Test whether the entity is an ambient creature, which includes + * the bat. + * + * @return true if an ambient creature + */ + boolean isAmbient(); + + /** + * Test whether the entity is a non-player controlled character, which + * includes villagers, NPCs from mods, and so on. + * + * @return true if an NPC + */ + boolean isNPC(); + + /** + * Test whether the entity is the iron golem from Minecraft. + * + * @return true if an iron golem + */ + boolean isGolem(); + + /** + * Test whether the entity is tameable and is tamed. + * + * @return true if tamed + */ + boolean isTamed(); + + /** + * Test whether the entity has been named (tagged). + * + * @return true if named + */ + boolean isTagged(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 4aeb23d7a..b1d8979aa 100644 --- a/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; class PlayerProxy extends AbstractPlayerActor { @@ -137,4 +139,10 @@ class PlayerProxy extends AbstractPlayerActor { public void dispatchCUIEvent(CUIEvent event) { cuiActor.dispatchCUIEvent(event); } + + @Nullable + @Override + public T getFacet(Class cls) { + return basePlayer.getFacet(cls); + } } diff --git a/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java index 772d8ca57..84af07ab3 100644 --- a/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java @@ -124,5 +124,11 @@ public class ChangeSetExtent extends AbstractDelegateExtent { } return success; } + + @Nullable + @Override + public T getFacet(Class cls) { + return entity.getFacet(cls); + } } } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 33be36453..43fa5597f 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -164,6 +164,12 @@ public class BlockArrayClipboard implements Clipboard { public boolean remove() { return entities.remove(this); } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } } } diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index eba0423bc..2e5ab5c5d 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -22,8 +22,6 @@ package com.sk89q.worldedit.internal; import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; -import com.sk89q.worldedit.LocalEntity; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; @@ -135,33 +133,6 @@ public class LocalWorldAdapter extends LocalWorld { world.simulateBlockMine(position); } - @Override - public int killEntities(LocalEntity... entity) { - return world.killEntities(entity); - } - - @Override - @Deprecated - public int killMobs(Vector origin, int radius) { - return world.killMobs(origin, radius); - } - - @Override - @Deprecated - public int killMobs(Vector origin, int radius, boolean killPets) { - return world.killMobs(origin, radius, killPets); - } - - @Override - public int killMobs(Vector origin, double radius, int flags) { - return world.killMobs(origin, radius, flags); - } - - @Override - public int removeEntities(EntityType type, Vector origin, int radius) { - return world.removeEntities(type, origin, radius); - } - @Override public boolean regenerate(Region region, EditSession editSession) { return world.regenerate(region, editSession); diff --git a/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index e6eea8cff..2e9a12817 100644 --- a/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -19,7 +19,12 @@ package com.sk89q.worldedit.regions; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.geom.Polygons; import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; @@ -28,6 +33,8 @@ import com.sk89q.worldedit.world.World; import java.util.Iterator; import java.util.List; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Represents a cylindrical region. * @@ -84,6 +91,23 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { hasY = true; } + /** + * Construct the region. + * + * @param center the center position + * @param radius the radius along the X and Z axes + * @param minY the minimum Y, inclusive + * @param maxY the maximum Y, inclusive + */ + public CylinderRegion(Vector center, Vector2D radius, int minY, int maxY) { + super(null); + setCenter(center.toVector2D()); + setRadius(radius); + this.minY = minY; + this.maxY = maxY; + hasY = true; + } + public CylinderRegion(CylinderRegion region) { this(region.world, region.getCenter(), region.getRadius(), region.minY, region.maxY); hasY = region.hasY; @@ -377,4 +401,24 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { public List polygonize(int maxPoints) { return Polygons.polygonizeCylinder(center, radius, maxPoints); } + + /** + * Return a new instance with the given center and radius in the X and Z + * axes with a Y that extends from the bottom of the extent to the top + * of the extent. + * + * @param extent the extent + * @param center the center position + * @param radius the radius in the X and Z axes + * @return a region + */ + public static CylinderRegion createRadius(Extent extent, Vector center, double radius) { + checkNotNull(extent); + checkNotNull(center); + Vector2D radiusVec = new Vector2D(radius, radius); + int minY = extent.getMinimumPoint().getBlockY(); + int maxY = extent.getMaximumPoint().getBlockY(); + return new CylinderRegion(center, radiusVec, minY, maxY); + } + } diff --git a/src/main/java/com/sk89q/worldedit/util/Faceted.java b/src/main/java/com/sk89q/worldedit/util/Faceted.java new file mode 100644 index 000000000..2b54442b3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Faceted.java @@ -0,0 +1,52 @@ +/* + * 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.util; + +import com.sk89q.worldedit.entity.Entity; + +import javax.annotation.Nullable; + +/** + * Indicates that an object can provide various "facets," which are + * specific distinct interfaces that can represent a portion of the object. + * + *

For example, an instance of an {@link Entity} may have a facet + * for accessing its inventory (if it contains an inventory) or a facet + * for accessing its health (if it has health).

+ * + *

Facets are referred to by their interface or abstract class and + * it is dependent on the implementation of the object specifying this + * interface to return the most applicable implementation. However, in + * many cases, such an implementation may not apply or it has not been + * implemented so a request for a facet may return {@code null}.

+ */ +public interface Faceted { + + /** + * Get the facet corresponding to the given class or interface. + * + * @param cls the class or interface + * @param the type + * @return an implementation of the facet or {@code null} if one is unavailable + */ + @Nullable + T getFacet(Class cls); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java b/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java index 1342b91eb..688ce9e55 100644 --- a/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java +++ b/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java @@ -104,7 +104,11 @@ public class FastListIterator implements Iterator { * @return an iterator */ public static Iterator reverseIterator(List list) { - return new FastListIterator(list, list.size() - 1, list.size(), -1); + if (!list.isEmpty()) { + return new FastListIterator(list, list.size() - 1, list.size(), -1); + } else { + return new FastListIterator(list, 0, 0, -1); + } } } diff --git a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 95917043e..b51a1cac8 100644 --- a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -21,8 +21,6 @@ package com.sk89q.worldedit.world; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalEntity; -import com.sk89q.worldedit.LocalWorld.KillFlags; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; @@ -141,21 +139,6 @@ public abstract class AbstractWorld implements World { } } - @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 boolean generateTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException { return generateTree(TreeType.TREE, editSession, pt); diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index a4f7a5eed..3b0854dc6 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -74,16 +74,6 @@ public class NullWorld extends AbstractWorld { public void dropItem(Vector position, BaseItemStack item) { } - @Override - public int killMobs(Vector origin, double radius, int flags) { - return 0; - } - - @Override - public int removeEntities(EntityType type, Vector origin, int radius) { - return 0; - } - @Override public boolean regenerate(Region region, EditSession editSession) { return false; diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index c11b1bf2d..bd2d13d1c 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -22,9 +22,6 @@ package com.sk89q.worldedit.world; import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; -import com.sk89q.worldedit.LocalEntity; -import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -191,46 +188,6 @@ public interface World extends Extent { */ void simulateBlockMine(Vector position); - /** - * 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. * diff --git a/src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java new file mode 100644 index 000000000..787585327 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java @@ -0,0 +1,42 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityType; + +import javax.annotation.Nullable; + +/** + * Provides information on entities. + */ +public interface EntityRegistry { + + /** + * Create a new entity using its ID. + * + * @param id the id + * @return the entity, which may be null if the entity does not exist + */ + @Nullable + BaseEntity createFromId(String id); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java b/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java index 21ce1ad0d..bed5b401f 100644 --- a/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java @@ -27,6 +27,7 @@ public final class LegacyWorldData implements WorldData { private static final LegacyWorldData INSTANCE = new LegacyWorldData(); private final LegacyBlockRegistry blockRegistry = new LegacyBlockRegistry(); + private final NullEntityRegistry entityRegistry = new NullEntityRegistry(); /** * Create a new instance. @@ -39,6 +40,11 @@ public final class LegacyWorldData implements WorldData { return blockRegistry; } + @Override + public EntityRegistry getEntityRegistry() { + return entityRegistry; + } + /** * Get a singleton instance. * diff --git a/src/main/java/com/sk89q/worldedit/EntityType.java b/src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java similarity index 70% rename from src/main/java/com/sk89q/worldedit/EntityType.java rename to src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java index 4b4f83438..b3eadcc10 100644 --- a/src/main/java/com/sk89q/worldedit/EntityType.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java @@ -1,37 +1,37 @@ -/* - * 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; - -/** - * List of removable entity types. - */ -public enum EntityType { - ALL, - @Deprecated ARROWS, - PROJECTILES, - ITEMS, - FALLING_BLOCKS, - PAINTINGS, - ITEM_FRAMES, - BOATS, - MINECARTS, - TNT, - XP_ORBS -} +/* + * 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.registry; + +import com.sk89q.worldedit.entity.BaseEntity; + +import javax.annotation.Nullable; + +/** + * An implementation of an entity registry that knows nothing. + */ +public class NullEntityRegistry implements EntityRegistry { + + @Nullable + @Override + public BaseEntity createFromId(String id) { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java b/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java index 38bbe2a0e..d8bf886e6 100644 --- a/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java @@ -32,4 +32,11 @@ public interface WorldData { */ BlockRegistry getBlockRegistry(); + /** + * Get the entity registry. + * + * @return the entity registry + */ + EntityRegistry getEntityRegistry(); + } From 9b5c112e5cfe10e5964fad04b81dc5c725c91e3d Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 15 Jul 2014 19:53:15 -0700 Subject: [PATCH 49/56] Let NBT Tag(String name) accept a null name. --- src/main/java/com/sk89q/jnbt/Tag.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/sk89q/jnbt/Tag.java b/src/main/java/com/sk89q/jnbt/Tag.java index 2ab0861ea..e0d7d3f4b 100644 --- a/src/main/java/com/sk89q/jnbt/Tag.java +++ b/src/main/java/com/sk89q/jnbt/Tag.java @@ -19,8 +19,6 @@ package com.sk89q.jnbt; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Represents a NBT tag. */ @@ -41,7 +39,9 @@ public abstract class Tag { * @param name the name */ Tag(String name) { - checkNotNull(name); + if (name == null) { + name = ""; + } this.name = name; } From 9feafcfc30c073d43bebb417b8a08528719d8992 Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 15 Jul 2014 20:10:14 -0700 Subject: [PATCH 50/56] Convert newer API from radians to degrees. --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 12 +++++------ .../sk89q/worldedit/bukkit/BukkitPlayer.java | 4 ++-- .../sk89q/worldedit/forge/ForgeEntity.java | 4 ++-- .../sk89q/worldedit/forge/ForgePlayer.java | 4 ++-- .../com/sk89q/worldedit/forge/ForgeWorld.java | 2 +- src/main/java/com/sk89q/worldedit/Vector.java | 7 +++---- .../java/com/sk89q/worldedit/Vector2D.java | 3 +-- .../worldedit/command/ClipboardCommands.java | 6 +++--- .../extent/clipboard/io/SchematicWriter.java | 4 ++-- .../math/transform/AffineTransform.java | 3 +++ .../com/sk89q/worldedit/util/Location.java | 20 +++++++++---------- .../world/storage/NBTConversions.java | 2 +- 12 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 970136368..c9de48b73 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -78,8 +78,8 @@ final class BukkitAdapter { return new com.sk89q.worldedit.util.Location( adapt(location.getWorld()), position, - (float) Math.toRadians(location.getYaw()), - (float) Math.toRadians(location.getPitch())); + location.getYaw(), + location.getPitch()); } /** @@ -94,8 +94,8 @@ final class BukkitAdapter { return new org.bukkit.Location( adapt((World) location.getExtent()), position.getX(), position.getY(), position.getZ(), - (float) Math.toDegrees(location.getYaw()), - (float) Math.toDegrees(location.getPitch())); + location.getYaw(), + location.getPitch()); } /** @@ -126,8 +126,8 @@ final class BukkitAdapter { return new org.bukkit.Location( world, location.getX(), location.getY(), location.getZ(), - (float) Math.toDegrees(location.getYaw()), - (float) Math.toDegrees(location.getPitch())); + location.getYaw(), + location.getPitch()); } /** diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 8f82aa371..519aee885 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -183,8 +183,8 @@ public class BukkitPlayer extends LocalPlayer { return new com.sk89q.worldedit.util.Location( getWorld(), position, - (float) Math.toRadians(nativeLocation.getYaw()), - (float) Math.toRadians(nativeLocation.getPitch())); + nativeLocation.getYaw(), + nativeLocation.getPitch()); } @Nullable diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java index cf96d9400..44ca0a666 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -65,8 +65,8 @@ class ForgeEntity implements Entity { @Override public Location getLocation() { Vector position = new Vector(entity.posX, entity.posY, entity.posZ); - float yaw = (float) Math.toRadians(entity.rotationYaw); - float pitch = (float) Math.toRadians(entity.rotationPitch); + float yaw = entity.rotationYaw; + float pitch = entity.rotationPitch; return new Location(ForgeAdapter.adapt(entity.worldObj), position, yaw, pitch); } diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java index 10e4af4a5..327b03602 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -63,8 +63,8 @@ public class ForgePlayer extends AbstractPlayerActor { return new Location( ForgeWorldEdit.inst.getWorld(this.player.worldObj), position, - (float) Math.toRadians(this.player.cameraYaw), - (float) Math.toRadians(this.player.cameraPitch)); + this.player.cameraYaw, + this.player.cameraPitch); } public WorldVector getPosition() { diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index 8b1f2c563..ac63f7818 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -414,7 +414,7 @@ public class ForgeWorld extends AbstractWorld { createdEntity.readFromNBT(tag); } - createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), (float) Math.toDegrees(location.getYaw()), (float) Math.toDegrees(location.getPitch())); + createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); world.spawnEntityInWorld(createdEntity); return new ForgeEntity(createdEntity); diff --git a/src/main/java/com/sk89q/worldedit/Vector.java b/src/main/java/com/sk89q/worldedit/Vector.java index 5585e9961..c1fd0475e 100644 --- a/src/main/java/com/sk89q/worldedit/Vector.java +++ b/src/main/java/com/sk89q/worldedit/Vector.java @@ -600,8 +600,7 @@ public class Vector implements Comparable { * @param translateZ what to add after rotation * @return */ - public Vector transform2D(double angle, - double aboutX, double aboutZ, double translateX, double translateZ) { + public Vector transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); double x = this.x - aboutX; double z = this.z - aboutZ; @@ -667,7 +666,7 @@ public class Vector implements Comparable { double x2 = x * x; double z2 = z * z; double xz = Math.sqrt(x2 + z2); - return (float) Math.atan(-getY() / xz); + return (float) Math.toDegrees(Math.atan(-getY() / xz)); } } @@ -683,7 +682,7 @@ public class Vector implements Comparable { double t = Math.atan2(-x, z); double _2pi = 2 * Math.PI; - return (float) ((t + _2pi) % _2pi); + return (float) Math.toDegrees(((t + _2pi) % _2pi)); } /** diff --git a/src/main/java/com/sk89q/worldedit/Vector2D.java b/src/main/java/com/sk89q/worldedit/Vector2D.java index 6bb9d7eed..77ba862a1 100644 --- a/src/main/java/com/sk89q/worldedit/Vector2D.java +++ b/src/main/java/com/sk89q/worldedit/Vector2D.java @@ -517,8 +517,7 @@ public class Vector2D { * @param translateZ what to add after rotation * @return */ - public Vector2D transform2D(double angle, - double aboutX, double aboutZ, double translateX, double translateZ) { + public Vector2D transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); double x = this.x - aboutX; double z = this.z - aboutZ; diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index a2330ac06..a5980cdc2 100644 --- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -190,9 +190,9 @@ public class ClipboardCommands { ClipboardHolder holder = session.getClipboard(); AffineTransform transform = new AffineTransform(); - transform = transform.rotateY(-Math.toRadians(yRotate != null ? yRotate : 0)); - transform = transform.rotateX(-Math.toRadians(xRotate != null ? xRotate : 0)); - transform = transform.rotateZ(-Math.toRadians(zRotate != null ? zRotate : 0)); + transform = transform.rotateY(-(yRotate != null ? yRotate : 0)); + transform = transform.rotateX(-(xRotate != null ? xRotate : 0)); + transform = transform.rotateZ(-(zRotate != null ? zRotate : 0)); holder.setTransform(holder.getTransform().combine(transform)); player.print("The clipboard copy has been rotated."); } diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java index d5bf31e4f..6e907cb0e 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java @@ -206,8 +206,8 @@ public class SchematicWriter implements ClipboardWriter { private Tag writeRotation(Location location, String name) { List list = new ArrayList(); - list.add(new FloatTag("", (float) Math.toDegrees(location.getYaw()))); - list.add(new FloatTag("", (float) Math.toDegrees(location.getPitch()))); + list.add(new FloatTag("", location.getYaw())); + list.add(new FloatTag("", location.getPitch())); return new ListTag(name, FloatTag.class, list); } diff --git a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index fe1709fa4..3540daa77 100644 --- a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -244,6 +244,7 @@ public class AffineTransform implements Transform { } public AffineTransform rotateX(double theta) { + theta = Math.toRadians(theta); double cot = Math.cos(theta); double sit = Math.sin(theta); return concatenate( @@ -254,6 +255,7 @@ public class AffineTransform implements Transform { } public AffineTransform rotateY(double theta) { + theta = Math.toRadians(theta); double cot = Math.cos(theta); double sit = Math.sin(theta); return concatenate( @@ -264,6 +266,7 @@ public class AffineTransform implements Transform { } public AffineTransform rotateZ(double theta) { + theta = Math.toRadians(theta); double cot = Math.cos(theta); double sit = Math.sin(theta); return concatenate( diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java index 90ec405be..f1fbcc8ce 100644 --- a/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/src/main/java/com/sk89q/worldedit/util/Location.java @@ -97,8 +97,8 @@ public class Location { * @param x the X coordinate * @param y the Y coordinate * @param z the Z coordinate - * @param yaw the yaw, in radians - * @param pitch the pitch, in radians + * @param yaw the yaw, in degrees + * @param pitch the pitch, in degrees */ public Location(Extent extent, double x, double y, double z, float yaw, float pitch) { this(extent, new Vector(x, y, z), yaw, pitch); @@ -122,8 +122,8 @@ public class Location { * * @param extent the extent * @param position the position vector - * @param yaw the yaw, in radians - * @param pitch the pitch, in radians + * @param yaw the yaw, in degrees + * @param pitch the pitch, in degrees */ public Location(Extent extent, Vector position, float yaw, float pitch) { checkNotNull(extent); @@ -154,9 +154,9 @@ public class Location { } /** - * Get the yaw in radians. + * Get the yaw in degrees. * - * @return the yaw in radians + * @return the yaw in degrees */ public float getYaw() { return yaw; @@ -173,9 +173,9 @@ public class Location { } /** - * Get the pitch in radians. + * Get the pitch in degrees. * - * @return the pitch in radians + * @return the pitch in degrees */ public float getPitch() { return pitch; @@ -208,8 +208,8 @@ public class Location { * @return the direction vector */ public Vector getDirection() { - double yaw = this.getYaw(); - double pitch = this.getPitch(); + double yaw = Math.toRadians(this.getYaw()); + double pitch = Math.toRadians(this.getPitch()); double xz = Math.cos(pitch); return new Vector( -xz * Math.sin(yaw), diff --git a/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java b/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java index 43b24c39a..ad10929ae 100644 --- a/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java @@ -52,7 +52,7 @@ public final class NBTConversions { return new Location( extent, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), - ((float) Math.toRadians(directionTag.asDouble(0))), ((float) Math.toRadians(directionTag.asDouble(1)))); + (float) directionTag.asDouble(0), (float) directionTag.asDouble(1)); } } From d50e05480fe864be5d814e592075f37072b2641f Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 17 Jul 2014 00:08:13 -0700 Subject: [PATCH 51/56] Call setExtent() when setWorld() is caleld on ParserContext. --- .../java/com/sk89q/worldedit/extension/input/ParserContext.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java index 383ee280e..dd3a487af 100644 --- a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java +++ b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java @@ -114,6 +114,7 @@ public class ParserContext { */ public void setWorld(@Nullable World world) { this.world = world; + setExtent(world); } /** From 42be11009782e1d2ff8e311e8d4ce58944e07c07 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 17 Jul 2014 00:21:13 -0700 Subject: [PATCH 52/56] Implemented new biome API. --- .../worldedit/bukkit/BukkitBiomeRegistry.java | 79 +++++++ .../worldedit/bukkit/BukkitBiomeType.java | 106 ---------- .../worldedit/bukkit/BukkitBiomeTypes.java | 59 ------ .../bukkit/BukkitServerInterface.java | 10 +- .../sk89q/worldedit/bukkit/BukkitWorld.java | 48 ++--- .../worldedit/bukkit/BukkitWorldData.java | 53 +++++ .../bukkit/adapter/BukkitImplAdapter.java | 42 ++++ .../adapter/impl/CraftBukkit_v1_7_R2.class | Bin 15315 -> 16351 bytes .../adapter/impl/CraftBukkit_v1_7_R3.class | Bin 15315 -> 16351 bytes .../adapter/impl/CraftBukkit_v1_7_R4.class | Bin 15325 -> 16361 bytes .../worldedit/forge/ForgeBiomeRegistry.java | 107 ++++++++++ .../worldedit/forge/ForgeBiomeTypes.java | 87 -------- .../sk89q/worldedit/forge/ForgePlatform.java | 11 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 22 +- ...orgeBiomeType.java => ForgeWorldData.java} | 89 ++++---- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 2 + .../java/com/sk89q/worldedit/EditSession.java | 15 +- .../worldedit/command/BiomeCommands.java | 144 ++++++------- .../worldedit/command/GenerationCommands.java | 11 +- .../extension/factory/DefaultMaskParser.java | 32 ++- .../extension/platform/Platform.java | 8 - .../extent/AbstractDelegateExtent.java | 12 ++ .../sk89q/worldedit/extent/InputExtent.java | 14 +- .../sk89q/worldedit/extent/NullExtent.java | 13 ++ .../sk89q/worldedit/extent/OutputExtent.java | 11 + .../extent/clipboard/BlockArrayClipboard.java | 12 ++ .../function/biome/BiomeReplace.java | 56 +++++ .../worldedit/function/mask/BiomeMask2D.java | 98 +++++++++ .../worldedit/function/mask/BlockMask.java | 8 + .../function/mask/BoundedHeightMask.java | 8 + .../function/mask/ExistingBlockMask.java | 8 + .../sk89q/worldedit/function/mask/Mask.java | 10 + .../function/mask/MaskIntersection.java | 20 +- .../function/mask/MaskIntersection2D.java | 100 +++++++++ .../worldedit/function/mask/MaskUnion.java | 17 ++ .../worldedit/function/mask/MaskUnion2D.java} | 52 +++-- .../sk89q/worldedit/function/mask/Masks.java | 111 ++++++++-- .../worldedit/function/mask/NoiseFilter.java | 8 + .../worldedit/function/mask/OffsetMask.java | 16 +- .../worldedit/function/mask/OffsetMask2D.java | 91 +++++++++ .../worldedit/function/mask/RegionMask.java | 8 + .../function/mask/SolidBlockMask.java | 8 + .../worldedit/internal/LocalWorldAdapter.java | 8 +- .../internal/ServerInterfaceAdapter.java | 6 - .../internal/command/WorldEditBinding.java | 34 +++- .../regions/shape/ArbitraryBiomeShape.java | 50 +++-- .../sk89q/worldedit/util/WeightedChoice.java | 118 +++++++++++ .../util/function/LevenshteinDistance.java | 192 ++++++++++++++++++ .../com/sk89q/worldedit/world/NullWorld.java | 12 +- .../java/com/sk89q/worldedit/world/World.java | 18 -- .../worldedit/world/biome/BaseBiome.java | 82 ++++++++ .../biome/BiomeData.java} | 21 +- .../worldedit/world/biome/BiomeName.java | 57 ++++++ .../sk89q/worldedit/world/biome/Biomes.java | 70 +++++++ .../registry/BiomeRegistry.java} | 35 ++-- .../world/registry/LegacyWorldData.java | 10 +- .../world/registry/NullBiomeRegistry.java | 57 ++++++ .../worldedit/world/registry/WorldData.java | 7 + 58 files changed, 1830 insertions(+), 553 deletions(-) create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeRegistry.java delete mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java delete mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorldData.java create mode 100644 src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java delete mode 100644 src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeTypes.java rename src/forge/java/com/sk89q/worldedit/forge/{ForgeBiomeType.java => ForgeWorldData.java} (56%) create mode 100644 src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java rename src/{legacy/java/com/sk89q/worldedit/masks/BiomeTypeMask.java => main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java} (54%) create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/util/WeightedChoice.java create mode 100644 src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/BaseBiome.java rename src/main/java/com/sk89q/worldedit/{BiomeType.java => world/biome/BiomeData.java} (74%) create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/Biomes.java rename src/main/java/com/sk89q/worldedit/{BiomeTypes.java => world/registry/BiomeRegistry.java} (56%) create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeRegistry.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeRegistry.java new file mode 100644 index 000000000..72e3379fc --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeRegistry.java @@ -0,0 +1,79 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import org.bukkit.block.Biome; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A biome registry for Bukkit. + */ +class BukkitBiomeRegistry implements BiomeRegistry { + + BukkitBiomeRegistry() { + } + + @Nullable + @Override + public BaseBiome createFromId(int id) { + return new BaseBiome(id); + } + + @Override + public List getBiomes() { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + List biomes = new ArrayList(); + for (Biome biome : Biome.values()) { + int biomeId = adapter.getBiomeId(biome); + biomes.add(new BaseBiome(biomeId)); + } + return biomes; + } else { + return Collections.emptyList(); + } + } + + @Nullable + @Override + public BiomeData getData(BaseBiome biome) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + final Biome bukkitBiome = adapter.getBiome(biome.getId()); + return new BiomeData() { + @Override + public String getName() { + return bukkitBiome.name(); + } + }; + } else { + return null; + } + } + +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java deleted file mode 100644 index 5962d54f8..000000000 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.bukkit; - -import java.util.Locale; - -import org.bukkit.block.Biome; - -import com.sk89q.worldedit.BiomeType; - -public enum BukkitBiomeType implements BiomeType { - - SWAMPLAND(Biome.SWAMPLAND), - FOREST(Biome.FOREST), - TAIGA(Biome.TAIGA), - DESERT(Biome.DESERT), - PLAINS(Biome.PLAINS), - HELL(Biome.HELL), - SKY(Biome.SKY), - RIVER(Biome.RIVER), - EXTREME_HILLS(Biome.EXTREME_HILLS), - OCEAN(Biome.OCEAN), - FROZEN_OCEAN(Biome.FROZEN_OCEAN), - FROZEN_RIVER(Biome.FROZEN_RIVER), - ICE_PLAINS(Biome.ICE_PLAINS), - ICE_MOUNTAINS(Biome.ICE_MOUNTAINS), - MUSHROOM_ISLAND(Biome.MUSHROOM_ISLAND), - MUSHROOM_SHORE(Biome.MUSHROOM_SHORE), - BEACH(Biome.BEACH), - DESERT_HILLS(Biome.DESERT_HILLS), - FOREST_HILLS(Biome.FOREST_HILLS), - TAIGA_HILLS(Biome.TAIGA_HILLS), - SMALL_MOUNTAINS(Biome.SMALL_MOUNTAINS), - JUNGLE(Biome.JUNGLE), - JUNGLE_HILLS(Biome.JUNGLE_HILLS), - JUNGLE_EDGE(Biome.JUNGLE_EDGE), - DEEP_OCEAN(Biome.DEEP_OCEAN), - STONE_BEACH(Biome.STONE_BEACH), - COLD_BEACH(Biome.COLD_BEACH), - BIRCH_FOREST(Biome.BIRCH_FOREST), - BIRCH_FOREST_HILLS(Biome.BIRCH_FOREST_HILLS), - ROOFED_FOREST(Biome.ROOFED_FOREST), - COLD_TAIGA(Biome.COLD_TAIGA), - COLD_TAIGA_HILLS(Biome.COLD_TAIGA_HILLS), - MEGA_TAIGA(Biome.MEGA_TAIGA), - MEGA_TAIGA_HILLS(Biome.MEGA_TAIGA_HILLS), - EXTREME_HILLS_PLUS(Biome.EXTREME_HILLS_PLUS), - SAVANNA(Biome.SAVANNA), - SAVANNA_PLATEAU(Biome.SAVANNA_PLATEAU), - MESA(Biome.MESA), - MESA_PLATEAU_FOREST(Biome.MESA_PLATEAU_FOREST), - MESA_PLATEAU(Biome.MESA_PLATEAU), - SUNFLOWER_PLAINS(Biome.SUNFLOWER_PLAINS), - DESERT_MOUNTAINS(Biome.DESERT_MOUNTAINS), - FLOWER_FOREST(Biome.FLOWER_FOREST), - TAIGA_MOUNTAINS(Biome.TAIGA_MOUNTAINS), - SWAMPLAND_MOUNTAINS(Biome.SWAMPLAND_MOUNTAINS), - ICE_PLAINS_SPIKES(Biome.ICE_PLAINS_SPIKES), - JUNGLE_MOUNTAINS(Biome.JUNGLE_MOUNTAINS), - JUNGLE_EDGE_MOUNTAINS(Biome.JUNGLE_EDGE_MOUNTAINS), - COLD_TAIGA_MOUNTAINS(Biome.COLD_TAIGA_MOUNTAINS), - SAVANNA_MOUNTAINS(Biome.SAVANNA_MOUNTAINS), - SAVANNA_PLATEAU_MOUNTAINS(Biome.SAVANNA_PLATEAU_MOUNTAINS), - MESA_BRYCE(Biome.MESA_BRYCE), - MESA_PLATEAU_FOREST_MOUNTAINS(Biome.MESA_PLATEAU_FOREST_MOUNTAINS), - MESA_PLATEAU_MOUNTAINS(Biome.MESA_PLATEAU_MOUNTAINS), - BIRCH_FOREST_MOUNTAINS(Biome.BIRCH_FOREST_MOUNTAINS), - BIRCH_FOREST_HILLS_MOUNTAINS(Biome.BIRCH_FOREST_HILLS_MOUNTAINS), - ROOFED_FOREST_MOUNTAINS(Biome.ROOFED_FOREST_MOUNTAINS), - MEGA_SPRUCE_TAIGA(Biome.MEGA_SPRUCE_TAIGA), - EXTREME_HILLS_MOUNTAINS(Biome.EXTREME_HILLS_MOUNTAINS), - EXTREME_HILLS_PLUS_MOUNTAINS(Biome.EXTREME_HILLS_PLUS_MOUNTAINS), - MEGA_SPRUCE_TAIGA_HILLS(Biome.MEGA_SPRUCE_TAIGA_HILLS); - - private Biome bukkitBiome; - - private BukkitBiomeType(Biome biome) { - this.bukkitBiome = biome; - } - - @Override - public String getName() { - return name().toLowerCase(Locale.ENGLISH); - } - - public Biome getBukkitBiome() { - return bukkitBiome; - } -} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java deleted file mode 100644 index 8a74fa91b..000000000 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.bukkit; - -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.BiomeTypes; -import com.sk89q.worldedit.UnknownBiomeTypeException; - -public class BukkitBiomeTypes implements BiomeTypes { - - public BukkitBiomeTypes() { - } - - @Override - public boolean has(String name) { - try { - BukkitBiomeType.valueOf(name.toUpperCase(Locale.ENGLISH)); - return true; - } catch (IllegalArgumentException exc) { - return false; - } - } - - @Override - public BiomeType get(String name) throws UnknownBiomeTypeException { - try { - return BukkitBiomeType.valueOf(name.toUpperCase(Locale.ENGLISH)); - } catch (IllegalArgumentException exc) { - throw new UnknownBiomeTypeException(name); - } - } - - @Override - public List all() { - return Arrays.asList(BukkitBiomeType.values()); - } - -} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 1bf4c6a61..adb25c7de 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.bukkit.util.CommandInfo; import com.sk89q.bukkit.util.CommandRegistration; -import com.sk89q.worldedit.BiomeTypes; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.ServerInterface; @@ -50,13 +49,13 @@ public class BukkitServerInterface extends ServerInterface implements MultiUserP public Server server; public WorldEditPlugin plugin; private CommandRegistration dynamicCommands; - private BukkitBiomeTypes biomes; + private BukkitBiomeRegistry biomes; private boolean hookingEvents; public BukkitServerInterface(WorldEditPlugin plugin, Server server) { this.plugin = plugin; this.server = server; - this.biomes = new BukkitBiomeTypes(); + this.biomes = new BukkitBiomeRegistry(); dynamicCommands = new CommandRegistration(plugin); } @@ -81,11 +80,6 @@ public class BukkitServerInterface extends ServerInterface implements MultiUserP plugin.loadConfiguration(); } - @Override - public BiomeTypes getBiomes() { - return biomes; - } - @Override public int schedule(long delay, long period, Runnable task) { return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 170ceacb6..c95e4130d 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalWorld; @@ -34,7 +33,7 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.world.registry.LegacyWorldData; +import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.registry.WorldData; import org.bukkit.Effect; import org.bukkit.Material; @@ -161,25 +160,6 @@ public class BukkitWorld extends LocalWorld { return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); } - @Override - public BiomeType getBiome(Vector2D pt) { - Biome bukkitBiome = getWorld().getBiome(pt.getBlockX(), pt.getBlockZ()); - try { - return BukkitBiomeType.valueOf(bukkitBiome.name()); - } catch (IllegalArgumentException exc) { - return BiomeType.UNKNOWN; - } - } - - @Override - public void setBiome(Vector2D pt, BiomeType biome) { - if (biome instanceof BukkitBiomeType) { - Biome bukkitBiome; - bukkitBiome = ((BukkitBiomeType) biome).getBukkitBiome(); - getWorld().setBiome(pt.getBlockX(), pt.getBlockZ(), bukkitBiome); - } - } - @Override public boolean regenerate(Region region, EditSession editSession) { BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)]; @@ -413,7 +393,7 @@ public class BukkitWorld extends LocalWorld { @Override public WorldData getWorldData() { - return LegacyWorldData.getInstance(); + return BukkitWorldData.getInstance(); } @Override @@ -451,6 +431,29 @@ public class BukkitWorld extends LocalWorld { return new LazyBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), this, position); } + @Override + public BaseBiome getBiome(Vector2D position) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + int id = adapter.getBiomeId(getWorld().getBiome(position.getBlockX(), position.getBlockZ())); + return new BaseBiome(id); + } else { + return new BaseBiome(0); + } + } + + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + Biome bukkitBiome = adapter.getBiome(biome.getId()); + getWorld().setBiome(position.getBlockX(), position.getBlockZ(), bukkitBiome); + return true; + } else { + return false; + } + } + /** * @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)} */ @@ -458,5 +461,4 @@ public class BukkitWorld extends LocalWorld { public boolean setBlock(Vector pt, com.sk89q.worldedit.foundation.Block block, boolean notifyAdjacent) throws WorldEditException { return setBlock(pt, (BaseBlock) block, notifyAdjacent); } - } diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorldData.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorldData.java new file mode 100644 index 000000000..6d747f4aa --- /dev/null +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorldData.java @@ -0,0 +1,53 @@ +/* + * 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.bukkit; + +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.LegacyWorldData; + +/** + * World data for the Bukkit platform. + */ +class BukkitWorldData extends LegacyWorldData { + + private static final BukkitWorldData INSTANCE = new BukkitWorldData(); + private final BiomeRegistry biomeRegistry = new BukkitBiomeRegistry(); + + /** + * Create a new instance. + */ + BukkitWorldData() { + } + + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static BukkitWorldData getInstance() { + return INSTANCE; + } + +} diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index a5e293593..04113a6d5 100644 --- a/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.bukkit.adapter; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Biome; import org.bukkit.entity.Entity; import javax.annotation.Nullable; @@ -31,6 +33,46 @@ import javax.annotation.Nullable; */ public interface BukkitImplAdapter { + /** + * Get the block ID for the given material. + * + *

Returns 0 if it is not known or it doesn't exist.

+ * + * @param material the material + * @return the block ID + */ + int getBlockId(Material material); + + /** + * Get the material for the given block ID. + * + *

Returns {@link Material#AIR} if it is not known or it doesn't exist.

+ * + * @param id the block ID + * @return the material + */ + Material getMaterial(int id); + + /** + * Get the biome ID for the given biome. + * + *

Returns 0 if it is not known or it doesn't exist.

+ * + * @param biome biome + * @return the biome ID + */ + int getBiomeId(Biome biome); + + /** + * Get the biome ID for the given biome ID.. + * + *

Returns {@link Biome#OCEAN} if it is not known or it doesn't exist.

+ * + * @param id the biome ID + * @return the biome + */ + Biome getBiome(int id); + /** * Get the block at the given location. * diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class index bc003177317356af89ab80535a66992f4449ec02..20b3c1930a150e2fcceed10e7434fa6528513eca 100644 GIT binary patch delta 7420 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 PEFb;@OMvJ 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 diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R3.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R3.class index 188b0becc9399d43d50f461512c57693698d3b84..1f8cc436fb9b145c0b8f0c7ef9a2e518ff8e5926 100644 GIT binary patch delta 7420 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 PEFb;@OMvJ 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 diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R4.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R4.class index b60c4898d0f356b5297f750d0f52ead7a38c93e3..f9eb46a5da3e8d2c53e45596647c373e31acf708 100644 GIT binary patch delta 7427 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 delta 6474 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 diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java new file mode 100644 index 000000000..7f0597313 --- /dev/null +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java @@ -0,0 +1,107 @@ +/* + * 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.forge; + +import com.google.common.collect.HashBiMap; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import net.minecraft.world.biome.BiomeGenBase; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Provides access to biome data in Forge. + */ +class ForgeBiomeRegistry implements BiomeRegistry { + + private static Map biomes = Collections.emptyMap(); + private static Map biomeData = Collections.emptyMap(); + + @Nullable + @Override + public BaseBiome createFromId(int id) { + return new BaseBiome(id); + } + + @Override + public List getBiomes() { + List list = new ArrayList(); + for (int biome : biomes.keySet()) { + list.add(new BaseBiome(biome)); + } + return list; + } + + @Nullable + @Override + public BiomeData getData(BaseBiome biome) { + return biomeData.get(biome.getId()); + } + + /** + * Populate the internal static list of biomes. + * + *

If called repeatedly, the last call will overwrite all previous + * calls.

+ */ + static void populate() { + Map biomes = HashBiMap.create(); + Map biomeData = new HashMap(); + + for (BiomeGenBase biome : BiomeGenBase.biomeList) { + if ((biome == null) || (biomes.containsValue(biome))) { + continue; + } + biomes.put(biome.biomeID, biome); + biomeData.put(biome.biomeID, new ForgeBiomeData(biome)); + } + + ForgeBiomeRegistry.biomes = biomes; + ForgeBiomeRegistry.biomeData = biomeData; + } + + /** + * Cached biome data information. + */ + private static class ForgeBiomeData implements BiomeData { + private final BiomeGenBase biome; + + /** + * Create a new instance. + * + * @param biome the base biome + */ + private ForgeBiomeData(BiomeGenBase biome) { + this.biome = biome; + } + + @Override + public String getName() { + return biome.biomeName; + } + } + +} \ No newline at end of file diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeTypes.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeTypes.java deleted file mode 100644 index 68275e49d..000000000 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeTypes.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.forge; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import net.minecraft.world.biome.BiomeGenBase; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.BiomeTypes; -import com.sk89q.worldedit.UnknownBiomeTypeException; - -public class ForgeBiomeTypes implements BiomeTypes { - private static BiMap biomes = HashBiMap.create(); - - public ForgeBiomeTypes() { - all(); - } - - public boolean has(String name) { - for (BiomeGenBase biome : BiomeGenBase.biomeList) { - if ((biome != null) && (biome.biomeName.equalsIgnoreCase(name))) { - return true; - } - } - return false; - } - - public BiomeType get(String name) throws UnknownBiomeTypeException { - if (biomes == null) { - all(); - } - Iterator it = biomes.keySet().iterator(); - while (it.hasNext()) { - BiomeType test = (BiomeType) it.next(); - if (test.getName().equalsIgnoreCase(name)) { - return test; - } - } - throw new UnknownBiomeTypeException(name); - } - - public List all() { - if (biomes.isEmpty()) { - biomes = HashBiMap.create(new HashMap()); - for (BiomeGenBase biome : BiomeGenBase.biomeList) { - if ((biome == null) || (biomes.containsValue(biome))) { - continue; - } - biomes.put(new ForgeBiomeType(biome), biome); - } - } - List retBiomes = new ArrayList(); - retBiomes.addAll(biomes.keySet()); - return retBiomes; - } - - public static BiomeType getFromBaseBiome(BiomeGenBase biome) { - return biomes.containsValue(biome) ? (BiomeType) biomes.inverse().get(biome) : BiomeType.UNKNOWN; - } - - public static BiomeGenBase getFromBiomeType(BiomeType biome) { - return (BiomeGenBase) biomes.get(biome); - } -} \ No newline at end of file diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java index 62c04afb3..3f4f9b19b 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.forge; -import com.sk89q.worldedit.BiomeTypes; +import com.sk89q.worldedit.world.registry.BiomeRegistry; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.entity.Player; @@ -56,13 +56,13 @@ class ForgePlatform extends ServerInterface implements MultiUserPlatform { private final ForgeWorldEdit mod; private final MinecraftServer server; - private final ForgeBiomeTypes biomes; + private final ForgeBiomeRegistry biomes; private boolean hookingEvents = false; ForgePlatform(ForgeWorldEdit mod) { this.mod = mod; this.server = FMLCommonHandler.instance().getMinecraftServerInstance(); - this.biomes = new ForgeBiomeTypes(); + this.biomes = new ForgeBiomeRegistry(); } boolean isHookingEvents() { @@ -95,11 +95,6 @@ class ForgePlatform extends ServerInterface implements MultiUserPlatform { public void reload() { } - @Override - public BiomeTypes getBiomes() { - return this.biomes; - } - @Override public int schedule(long delay, long period, Runnable task) { return -1; diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java index ac63f7818..fdab7bcf1 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.forge; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; @@ -36,7 +35,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; -import com.sk89q.worldedit.world.registry.LegacyWorldData; +import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.registry.WorldData; import net.minecraft.block.Block; import net.minecraft.entity.EntityList; @@ -181,22 +180,23 @@ public class ForgeWorld extends AbstractWorld { } @Override - public BiomeType getBiome(Vector2D position) { + public BaseBiome getBiome(Vector2D position) { checkNotNull(position); - return ForgeBiomeTypes.getFromBaseBiome(getWorld().getBiomeGenForCoords(position.getBlockX(), position.getBlockZ())); + return new BaseBiome(getWorld().getBiomeGenForCoords(position.getBlockX(), position.getBlockZ()).biomeID); } @Override - public void setBiome(Vector2D position, BiomeType biome) { + public boolean setBiome(Vector2D position, BaseBiome biome) { checkNotNull(position); checkNotNull(biome); - if (getWorld().getChunkProvider().chunkExists(position.getBlockX(), position.getBlockZ())) { - Chunk chunk = getWorld().getChunkFromBlockCoords(position.getBlockX(), position.getBlockZ()); - if ((chunk != null) && (chunk.isChunkLoaded)) { - chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = (byte) ForgeBiomeTypes.getFromBiomeType(biome).biomeID; - } + Chunk chunk = getWorld().getChunkFromBlockCoords(position.getBlockX(), position.getBlockZ()); + if ((chunk != null) && (chunk.isChunkLoaded)) { + chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = (byte) biome.getId(); + return true; } + + return false; } @Override @@ -317,7 +317,7 @@ public class ForgeWorld extends AbstractWorld { @Override public WorldData getWorldData() { - return LegacyWorldData.getInstance(); + return ForgeWorldData.getInstance(); } @Override diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeType.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldData.java similarity index 56% rename from src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeType.java rename to src/forge/java/com/sk89q/worldedit/forge/ForgeWorldData.java index 5cd816ad7..c6f3d553c 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeType.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldData.java @@ -1,36 +1,53 @@ -/* - * 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.forge; - -import net.minecraft.world.biome.BiomeGenBase; - -import com.sk89q.worldedit.BiomeType; - -public class ForgeBiomeType implements BiomeType { - private BiomeGenBase biome; - - public ForgeBiomeType(BiomeGenBase biome) { - this.biome = biome; - } - - public String getName() { - return this.biome.biomeName; - } -} \ No newline at end of file +/* + * 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.forge; + +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.LegacyWorldData; + +/** + * World data for the Forge platform. + */ +class ForgeWorldData extends LegacyWorldData { + + private static final ForgeWorldData INSTANCE = new ForgeWorldData(); + private final BiomeRegistry biomeRegistry = new ForgeBiomeRegistry(); + + /** + * Create a new instance. + */ + ForgeWorldData() { + } + + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static ForgeWorldData getInstance() { + return INSTANCE; + } + +} diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index dbc53eb1d..e6e740533 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -103,6 +103,8 @@ public class ForgeWorldEdit { WorldEdit.getInstance().getPlatformManager().unregister(platform); } + ForgeBiomeRegistry.populate(); + this.platform = new ForgePlatform(this); WorldEdit.getInstance().getPlatformManager().register(platform); diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 10a849a17..f97f002ea 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -76,6 +76,7 @@ import com.sk89q.worldedit.util.collection.DoubleArrayList; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import javax.annotation.Nullable; import java.util.*; @@ -377,6 +378,16 @@ public class EditSession implements Extent { return changeSet.size(); } + @Override + public BaseBiome getBiome(Vector2D position) { + return bypassNone.getBiome(position); + } + + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + return bypassNone.setBiome(position, biome); + } + @Override public BaseBlock getLazyBlock(Vector position) { return world.getLazyBlock(position); @@ -2248,7 +2259,7 @@ public class EditSession implements Extent { } // while } - public int makeBiomeShape(final Region region, final Vector zero, final Vector unit, final BiomeType biomeType, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { + public int makeBiomeShape(final Region region, final Vector zero, final Vector unit, final BaseBiome biomeType, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { final Vector2D zero2D = zero.toVector2D(); final Vector2D unit2D = unit.toVector2D(); @@ -2261,7 +2272,7 @@ public class EditSession implements Extent { final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) { @Override - protected BiomeType getBiome(int x, int z, BiomeType defaultBiomeType) { + protected BaseBiome getBiome(int x, int z, BaseBiome defaultBiomeType) { final Vector2D current = new Vector2D(x, z); environment.setCurrentBlock(current.toVector(0)); final Vector2D scaled = current.subtract(zero2D).divide(unit2D); diff --git a/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index a08f70ab3..953168c3b 100644 --- a/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -23,15 +23,29 @@ import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.FlatRegionMaskingFilter; +import com.sk89q.worldedit.function.biome.BiomeReplace; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.masks.BiomeTypeMask; -import com.sk89q.worldedit.masks.InvertedMask; +import com.sk89q.worldedit.function.mask.Mask2D; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.Regions; +import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.HashSet; import java.util.List; @@ -64,7 +78,7 @@ public class BiomeCommands { max = 1 ) @CommandPermissions("worldedit.biome.list") - public void biomeList(Actor actor, CommandContext args) throws WorldEditException { + public void biomeList(Player player, CommandContext args) throws WorldEditException { int page; int offset; int count = 0; @@ -76,16 +90,22 @@ public class BiomeCommands { offset = (page - 1) * 19; } - List biomes = worldEdit.getServer().getBiomes().all(); + BiomeRegistry biomeRegistry = player.getWorld().getWorldData().getBiomeRegistry(); + List biomes = biomeRegistry.getBiomes(); int totalPages = biomes.size() / 19 + 1; - actor.print("Available Biomes (page " + page + "/" + totalPages + ") :"); - for (BiomeType biome : biomes) { + player.print("Available Biomes (page " + page + "/" + totalPages + ") :"); + for (BaseBiome biome : biomes) { if (offset > 0) { offset--; } else { - actor.print(" " + biome.getName()); - if (++count == 19) { - break; + BiomeData data = biomeRegistry.getData(biome); + if (data != null) { + player.print(" " + data.getName()); + if (++count == 19) { + break; + } + } else { + player.print(" "); } } } @@ -103,7 +123,11 @@ public class BiomeCommands { max = 0 ) @CommandPermissions("worldedit.biome.info") - public void biomeInfo(CommandContext args, Player player, LocalSession session) throws WorldEditException { + public void biomeInfo(Player player, LocalSession session, CommandContext args) throws WorldEditException { + BiomeRegistry biomeRegistry = player.getWorld().getWorldData().getBiomeRegistry(); + Set biomes = new HashSet(); + String qualifier; + if (args.hasFlag('t')) { Vector blockPosition = player.getBlockTrace(300); if (blockPosition == null) { @@ -111,15 +135,18 @@ public class BiomeCommands { return; } - BiomeType biome = player.getWorld().getBiome(blockPosition.toVector2D()); - player.print("Biome: " + biome.getName()); + BaseBiome biome = player.getWorld().getBiome(blockPosition.toVector2D()); + biomes.add(biome); + + qualifier = "at line of sight point"; } else if (args.hasFlag('p')) { - BiomeType biome = player.getWorld().getBiome(player.getPosition().toVector2D()); - player.print("Biome: " + biome.getName()); + BaseBiome biome = player.getWorld().getBiome(player.getPosition().toVector2D()); + biomes.add(biome); + + qualifier = "at your position"; } else { World world = player.getWorld(); Region region = session.getSelection(world); - Set biomes = new HashSet(); if (region instanceof FlatRegion) { for (Vector2D pt : ((FlatRegion) region).asFlatRegion()) { @@ -131,9 +158,16 @@ public class BiomeCommands { } } - player.print("Biomes:"); - for (BiomeType biome : biomes) { - player.print(" " + biome.getName()); + qualifier = "in your selection"; + } + + player.print(biomes.size() != 1 ? "Biomes " + qualifier + ":" : "Biome " + qualifier + ":"); + for (BaseBiome biome : biomes) { + BiomeData data = biomeRegistry.getData(biome); + if (data != null) { + player.print(" " + data.getName()); + } else { + player.print(" "); } } } @@ -145,65 +179,31 @@ public class BiomeCommands { desc = "Sets the biome of the player's current block or region.", help = "Set the biome of the region.\n" + - "By default use all the blocks contained in your selection.\n" + - "-p use the block you are currently in", - min = 1, - max = 1 + "By default use all the blocks contained in your selection.\n" + + "-p use the block you are currently in" ) @Logging(REGION) @CommandPermissions("worldedit.biome.set") - public void setBiome(CommandContext args, Player player, LocalSession session, EditSession editSession) throws WorldEditException { - final BiomeType target = worldEdit.getServer().getBiomes().get(args.getString(0)); - if (target == null) { - player.printError("Biome '" + args.getString(0) + "' does not exist!"); - return; - } - + public void setBiome(Player player, LocalSession session, EditSession editSession, BaseBiome target, @Switch('p') boolean atPosition) throws WorldEditException { + World world = player.getWorld(); + Region region; Mask mask = editSession.getMask(); - BiomeTypeMask biomeMask = null; - boolean inverted = false; - if (mask instanceof BiomeTypeMask) { - biomeMask = (BiomeTypeMask) mask; - } else if (mask instanceof InvertedMask && ((InvertedMask) mask).getInvertedMask() instanceof BiomeTypeMask) { - inverted = true; - biomeMask = (BiomeTypeMask) ((InvertedMask) mask).getInvertedMask(); - } + Mask2D mask2d = mask != null ? mask.toMask2D() : null; - if (args.hasFlag('p')) { - Vector2D pos = player.getPosition().toVector2D(); - if (biomeMask == null || (biomeMask.matches2D(editSession, pos) ^ inverted)) { - player.getWorld().setBiome(pos, target); - player.print("Biome changed to " + target.getName() + " at your current location."); - } else { - player.print("Your global mask doesn't match this biome. Type //gmask to disable it."); - } + if (atPosition) { + region = new CuboidRegion(player.getPosition(), player.getPosition()); } else { - int affected = 0; - World world = player.getWorld(); - Region region = session.getSelection(world); - - if (region instanceof FlatRegion) { - for (Vector2D pt : ((FlatRegion) region).asFlatRegion()) { - if (biomeMask == null || (biomeMask.matches2D(editSession, pt) ^ inverted)) { - world.setBiome(pt, target); - ++affected; - } - } - } else { - HashSet alreadyVisited = new HashSet(); - for (Vector pt : region) { - if (!alreadyVisited.contains((long)pt.getBlockX() << 32 | pt.getBlockZ())) { - alreadyVisited.add(((long)pt.getBlockX() << 32 | pt.getBlockZ())); - if (biomeMask == null || (biomeMask.matches(editSession, pt) ^ inverted)) { - world.setBiome(pt.toVector2D(), target); - ++affected; - } - } - } - } - - player.print("Biome changed to " + target.getName() + ". " + affected + " columns affected."); + region = session.getSelection(world); } + + FlatRegionFunction replace = new BiomeReplace(editSession, target); + if (mask2d != null) { + replace = new FlatRegionMaskingFilter(mask2d, replace); + } + FlatRegionVisitor visitor = new FlatRegionVisitor(Regions.asFlatRegion(region), replace); + Operations.completeLegacy(visitor); + + player.print("Biomes were changed in " + visitor.getAffected() + " columns. You may have to rejoin your game (or close and reopen your world) to see a change."); } } diff --git a/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index ffce9f7ec..09abf3b99 100644 --- a/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -22,7 +22,11 @@ package com.sk89q.worldedit.command; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Patterns; @@ -35,6 +39,7 @@ import com.sk89q.worldedit.util.command.binding.Range; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.util.command.parametric.Optional; +import com.sk89q.worldedit.world.biome.BaseBiome; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; @@ -332,7 +337,7 @@ public class GenerationCommands { @Logging(ALL) public void generateBiome(Player player, LocalSession session, EditSession editSession, @Selection Region region, - BiomeType target, + BaseBiome target, @Text String expression, @Switch('h') boolean hollow, @Switch('r') boolean useRawCoords, @@ -368,7 +373,7 @@ public class GenerationCommands { try { final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow); player.findFreePosition(); - player.print("Biome changed to " + target.getName() + ". " + affected + " columns affected."); + player.print("" + affected + " columns affected."); } catch (ExpressionException e) { player.printError(e.getMessage()); } diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java index 9b6dfdf94..2d697fbbb 100644 --- a/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java +++ b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java @@ -19,17 +19,30 @@ package com.sk89q.worldedit.extension.factory; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.mask.*; +import com.sk89q.worldedit.function.mask.BiomeMask2D; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.mask.NoiseFilter; +import com.sk89q.worldedit.function.mask.OffsetMask; +import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.masks.BiomeTypeMask; import com.sk89q.worldedit.math.noise.RandomNoise; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.RequestSelection; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.Biomes; +import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.ArrayList; import java.util.HashSet; @@ -109,18 +122,19 @@ class DefaultMaskParser extends InputParser { return new MaskIntersection(offsetMask, Masks.negate(submask)); case '$': - Set biomes = new HashSet(); + Set biomes = new HashSet(); String[] biomesList = component.substring(1).split(","); + BiomeRegistry biomeRegistry = context.requireWorld().getWorldData().getBiomeRegistry(); + List knownBiomes = biomeRegistry.getBiomes(); for (String biomeName : biomesList) { - try { - BiomeType biome = worldEdit.getServer().getBiomes().get(biomeName); - biomes.add(biome); - } catch (UnknownBiomeTypeException e) { + BaseBiome biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry); + if (biome == null) { throw new InputParseException("Unknown biome '" + biomeName + "'"); } + biomes.add(biome); } - return Masks.wrap(new BiomeTypeMask(biomes)); + return Masks.asMask(new BiomeMask2D(context.requireExtent(), biomes)); case '%': int i = Integer.parseInt(component.substring(1)); diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index bc90eaa5d..412afd9ea 100644 --- a/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.extension.platform; -import com.sk89q.worldedit.BiomeTypes; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.util.command.Dispatcher; @@ -58,13 +57,6 @@ public interface Platform { */ void reload(); - /** - * Returns all available biomes. - * - * @return an object containing all the biomes - */ - BiomeTypes getBiomes(); - /** * Schedules the given task to be invoked once every period ticks * after an initial delay of delay ticks. diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 65399bbf4..7a1bd25f9 100644 --- a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; @@ -28,6 +29,7 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BaseBiome; import javax.annotation.Nullable; @@ -92,6 +94,16 @@ public abstract class AbstractDelegateExtent implements Extent { return extent.getEntities(region); } + @Override + public BaseBiome getBiome(Vector2D position) { + return extent.getBiome(position); + } + + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + return extent.setBiome(position, biome); + } + @Override public Vector getMinimumPoint() { return extent.getMinimumPoint(); diff --git a/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/src/main/java/com/sk89q/worldedit/extent/InputExtent.java index f40750720..81fcce5c9 100644 --- a/src/main/java/com/sk89q/worldedit/extent/InputExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -20,9 +20,10 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.world.biome.BaseBiome; /** * Provides the current state of blocks, entities, and so on. @@ -74,4 +75,15 @@ public interface InputExtent { */ BaseBlock getLazyBlock(Vector position); + /** + * Get the biome at the given location. + * + *

If there is no biome available, then the ocean biome should be + * returned.

+ * + * @param position the (x, z) location to check the biome at + * @return the biome at the location + */ + BaseBiome getBiome(Vector2D position); + } diff --git a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index 3df4879de..1979bdaaf 100644 --- a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; @@ -27,6 +28,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BaseBiome; import javax.annotation.Nullable; import java.util.Collections; @@ -76,11 +78,22 @@ public class NullExtent implements Extent { return new BaseBlock(0); } + @Nullable + @Override + public BaseBiome getBiome(Vector2D position) { + return null; + } + @Override public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { return false; } + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + return false; + } + @Nullable @Override public Operation commit() { diff --git a/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index 1468982f2..e0268495d 100644 --- a/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -20,9 +20,11 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.world.biome.BaseBiome; import javax.annotation.Nullable; @@ -49,6 +51,15 @@ public interface OutputExtent { */ boolean setBlock(Vector position, BaseBlock block) throws WorldEditException; + /** + * Set the biome. + * + * @param position the (x, z) location to set the biome at + * @param biome the biome to set to + * @return true if the biome was successfully set (return value may not be accurate) + */ + boolean setBiome(Vector2D position, BaseBiome biome); + /** * Return an {@link Operation} that should be called to tie up loose ends * (such as to commit changes in a buffer). diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 43fa5597f..1b819e036 100644 --- a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extent.clipboard; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; @@ -28,6 +29,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BaseBiome; import javax.annotation.Nullable; import java.util.ArrayList; @@ -146,6 +148,16 @@ public class BlockArrayClipboard implements Clipboard { } } + @Override + public BaseBiome getBiome(Vector2D position) { + return new BaseBiome(0); + } + + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + return false; + } + @Nullable @Override public Operation commit() { diff --git a/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java b/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java new file mode 100644 index 000000000..f877adce5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java @@ -0,0 +1,56 @@ +/* + * 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.function.biome; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.world.biome.BaseBiome; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Replaces the biome at the locations that this function is applied to. + */ +public class BiomeReplace implements FlatRegionFunction { + + private final Extent extent; + private BaseBiome biome; + + /** + * Create a new instance. + * + * @param extent an extent + * @param biome a biome + */ + public BiomeReplace(Extent extent, BaseBiome biome) { + checkNotNull(extent); + checkNotNull(biome); + this.extent = extent; + this.biome = biome; + } + + @Override + public boolean apply(Vector2D position) throws WorldEditException { + return extent.setBiome(position, biome); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java new file mode 100644 index 000000000..75240db18 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java @@ -0,0 +1,98 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.biome.BaseBiome; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tests true if the biome at applied points is the same as the one given. + */ +public class BiomeMask2D extends AbstractMask2D { + + private final Extent extent; + private final Set biomes = new HashSet(); + + /** + * Create a new biome mask. + * + * @param extent the extent + * @param biomes a list of biomes to match + */ + public BiomeMask2D(Extent extent, Collection biomes) { + checkNotNull(extent); + checkNotNull(biomes); + this.extent = extent; + this.biomes.addAll(biomes); + } + + /** + * Create a new biome mask. + * + * @param extent the extent + * @param biome an array of biomes to match + */ + public BiomeMask2D(Extent extent, BaseBiome... biome) { + this(extent, Arrays.asList(checkNotNull(biome))); + } + + /** + * Add the given biomes to the list of criteria. + * + * @param biomes a list of biomes + */ + public void add(Collection biomes) { + checkNotNull(biomes); + this.biomes.addAll(biomes); + } + + /** + * Add the given biomes to the list of criteria. + * + * @param biome an array of biomes + */ + public void add(BaseBiome... biome) { + add(Arrays.asList(checkNotNull(biome))); + } + + /** + * Get the list of biomes that are tested with. + * + * @return a list of biomes + */ + public Collection getBiomes() { + return biomes; + } + + @Override + public boolean test(Vector2D vector) { + BaseBiome biome = extent.getBiome(vector); + return biomes.contains(biome); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index e05532438..91ac89c14 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -96,4 +97,11 @@ public class BlockMask extends AbstractExtentMask { BaseBlock block = getExtent().getBlock(vector); return blocks.contains(block) || blocks.contains(new BaseBlock(block.getType(), -1)); } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java index 81d143c3d..fe35ff1ef 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkArgument; /** @@ -49,4 +51,10 @@ public class BoundedHeightMask extends AbstractMask { return vector.getY() >= minY && vector.getY() <= maxY; } + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java index 80e9719fc..c3d8f1037 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -23,6 +23,8 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BlockID; +import javax.annotation.Nullable; + /** * A mask that returns true whenever the block at the location is not * an air block (it contains some other block). @@ -43,4 +45,10 @@ public class ExistingBlockMask extends AbstractExtentMask { return getExtent().getLazyBlock(vector).getType() != BlockID.AIR; } + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 611b1b662..96b4af82b 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; +import javax.annotation.Nullable; + /** * Tests whether a given vector meets a criteria. */ @@ -34,4 +36,12 @@ public interface Mask { */ boolean test(Vector vector); + /** + * Get the 2D version of this mask if one exists. + * + * @return a 2D mask version or {@code null} if this mask can't be 2D + */ + @Nullable + Mask2D toMask2D(); + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java index d1a600ef4..d98fdadac 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java @@ -21,9 +21,12 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; +import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -86,7 +89,7 @@ public class MaskIntersection extends AbstractMask { @Override public boolean test(Vector vector) { - if (masks.size() == 0) { + if (masks.isEmpty()) { return false; } @@ -99,4 +102,19 @@ public class MaskIntersection extends AbstractMask { return true; } + @Nullable + @Override + public Mask2D toMask2D() { + List mask2dList = new ArrayList(); + for (Mask mask : masks) { + Mask2D mask2d = mask.toMask2D(); + if (mask2d != null) { + mask2dList.add(mask2d); + } else { + return null; + } + } + return new MaskIntersection2D(mask2dList); + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java new file mode 100644 index 000000000..02e605ff9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java @@ -0,0 +1,100 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.Vector2D; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tests true if all contained masks test true. + */ +public class MaskIntersection2D implements Mask2D { + + private final Set masks = new HashSet(); + + /** + * Create a new intersection. + * + * @param masks a list of masks + */ + public MaskIntersection2D(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Create a new intersection. + * + * @param mask a list of masks + */ + public MaskIntersection2D(Mask2D... mask) { + this(Arrays.asList(checkNotNull(mask))); + } + + /** + * Add some masks to the list. + * + * @param masks the masks + */ + public void add(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Add some masks to the list. + * + * @param mask the masks + */ + public void add(Mask2D... mask) { + add(Arrays.asList(checkNotNull(mask))); + } + + /** + * Get the masks that are tested with. + * + * @return the masks + */ + public Collection getMasks() { + return masks; + } + + @Override + public boolean test(Vector2D vector) { + if (masks.isEmpty()) { + return false; + } + + for (Mask2D mask : masks) { + if (!mask.test(vector)) { + return false; + } + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java index a02983f4a..955ab779e 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -21,7 +21,10 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; +import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * Combines several masks and requires that one or more masks return true @@ -61,4 +64,18 @@ public class MaskUnion extends MaskIntersection { return false; } + @Nullable + @Override + public Mask2D toMask2D() { + List mask2dList = new ArrayList(); + for (Mask mask : getMasks()) { + Mask2D mask2d = mask.toMask2D(); + if (mask2d != null) { + mask2dList.add(mask2d); + } else { + return null; + } + } + return new MaskUnion2D(mask2dList); + } } diff --git a/src/legacy/java/com/sk89q/worldedit/masks/BiomeTypeMask.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java similarity index 54% rename from src/legacy/java/com/sk89q/worldedit/masks/BiomeTypeMask.java rename to src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java index 97ed58e09..099dc9a05 100644 --- a/src/legacy/java/com/sk89q/worldedit/masks/BiomeTypeMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java @@ -17,34 +17,46 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.masks; +package com.sk89q.worldedit.function.mask; -import java.util.HashSet; -import java.util.Set; - -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; -public class BiomeTypeMask extends AbstractMask { - private final Set biomes; +import java.util.Collection; - public BiomeTypeMask() { - this(new HashSet()); +/** + * Tests true if any contained mask is true, even if it just one. + */ +public class MaskUnion2D extends MaskIntersection2D { + + /** + * Create a new union. + * + * @param masks a list of masks + */ + public MaskUnion2D(Collection masks) { + super(masks); } - public BiomeTypeMask(Set biomes) { - this.biomes = biomes; - } - - public boolean matches2D(EditSession editSession, Vector2D pos) { - BiomeType biome = editSession.getWorld().getBiome(pos); - return biomes.contains(biome); + /** + * Create a new union. + * + * @param mask a list of masks + */ + public MaskUnion2D(Mask2D... mask) { + super(mask); } @Override - public boolean matches(EditSession editSession, Vector pos) { - return matches2D(editSession, pos.toVector2D()); + public boolean test(Vector2D vector) { + Collection masks = getMasks(); + + for (Mask2D mask : masks) { + if (mask.test(vector)) { + return true; + } + } + + return false; } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/src/main/java/com/sk89q/worldedit/function/mask/Masks.java index 689b127a7..837bcd2ae 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/Masks.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.*; import com.sk89q.worldedit.session.request.Request; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -29,6 +31,9 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public final class Masks { + private static final AlwaysTrue ALWAYS_TRUE = new AlwaysTrue(); + private static final AlwaysFalse ALWAYS_FALSE = new AlwaysFalse(); + private Masks() { } @@ -38,12 +43,7 @@ public final class Masks { * @return a mask */ public static Mask alwaysTrue() { - return new AbstractMask() { - @Override - public boolean test(Vector vector) { - return true; - } - }; + return ALWAYS_TRUE; } /** @@ -52,12 +52,7 @@ public final class Masks { * @return a mask */ public static Mask2D alwaysTrue2D() { - return new AbstractMask2D() { - @Override - public boolean test(Vector2D vector) { - return true; - } - }; + return ALWAYS_TRUE; } /** @@ -67,12 +62,29 @@ public final class Masks { * @return a new mask */ public static Mask negate(final Mask mask) { + if (mask instanceof AlwaysTrue) { + return ALWAYS_FALSE; + } else if (mask instanceof AlwaysFalse) { + return ALWAYS_TRUE; + } + checkNotNull(mask); return new AbstractMask() { @Override public boolean test(Vector vector) { return !mask.test(vector); } + + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D mask2d = mask.toMask2D(); + if (mask2d != null) { + return negate(mask2d); + } else { + return null; + } + } }; } @@ -83,6 +95,12 @@ public final class Masks { * @return a new mask */ public static Mask2D negate(final Mask2D mask) { + if (mask instanceof AlwaysTrue) { + return ALWAYS_FALSE; + } else if (mask instanceof AlwaysFalse) { + return ALWAYS_TRUE; + } + checkNotNull(mask); return new AbstractMask2D() { @Override @@ -92,6 +110,27 @@ public final class Masks { }; } + /** + * Return a 3-dimensional version of a 2D mask. + * + * @param mask the mask to make 3D + * @return a 3D mask + */ + public static Mask asMask(final Mask2D mask) { + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + return mask.test(vector.toVector2D()); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return mask; + } + }; + } + /** * Wrap an old-style mask and convert it to a new mask. *

@@ -113,6 +152,12 @@ public final class Masks { public boolean test(Vector vector) { return mask.matches(editSession, vector); } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } }; } @@ -135,6 +180,12 @@ public final class Masks { EditSession editSession = Request.request().getEditSession(); return editSession != null && mask.matches(editSession, vector); } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } }; } @@ -156,4 +207,40 @@ public final class Masks { }; } + private static class AlwaysTrue implements Mask, Mask2D { + @Override + public boolean test(Vector vector) { + return true; + } + + @Override + public boolean test(Vector2D vector) { + return true; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return this; + } + } + + private static class AlwaysFalse implements Mask, Mask2D { + @Override + public boolean test(Vector vector) { + return false; + } + + @Override + public boolean test(Vector2D vector) { + return false; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return this; + } + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java index f5aa09807..7c5b658d4 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.math.noise.NoiseGenerator; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -89,4 +91,10 @@ public class NoiseFilter extends AbstractMask { return noiseGenerator.noise(vector) <= density; } + @Nullable + @Override + public Mask2D toMask2D() { + return new NoiseFilter2D(getNoiseGenerator(), getDensity()); + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java index 833a543ef..b5358cb30 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -21,10 +21,13 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; /** - * Checks whether the provided mask tests true for an offset position. + * Checks whether another mask tests true for a position that is offset + * a given vector. */ public class OffsetMask extends AbstractMask { @@ -87,4 +90,15 @@ public class OffsetMask extends AbstractMask { return getMask().test(vector.add(offset)); } + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D childMask = getMask().toMask2D(); + if (childMask != null) { + return new OffsetMask2D(childMask, getOffset().toVector2D()); + } else { + return null; + } + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java new file mode 100644 index 000000000..50d2835ba --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java @@ -0,0 +1,91 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.Vector2D; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether another mask tests true for a position that is offset + * a given vector. + */ +public class OffsetMask2D extends AbstractMask2D { + + private Mask2D mask; + private Vector2D offset; + + /** + * Create a new instance. + * + * @param mask the mask + * @param offset the offset + */ + public OffsetMask2D(Mask2D mask, Vector2D offset) { + checkNotNull(mask); + checkNotNull(offset); + this.mask = mask; + this.offset = offset; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask2D getMask() { + return mask; + } + + /** + * Set the mask. + * + * @param mask the mask + */ + public void setMask(Mask2D mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the offset. + * + * @return the offset + */ + public Vector2D getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(Vector2D offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean test(Vector2D vector) { + return getMask().test(vector.add(offset)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java b/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java index 04e1c4dc3..1ddf891fe 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.regions.Region; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -64,4 +66,10 @@ public class RegionMask extends AbstractMask { return region.contains(vector); } + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java index 2428643c2..b6a10972a 100644 --- a/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java +++ b/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java @@ -24,6 +24,8 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BlockType; +import javax.annotation.Nullable; + public class SolidBlockMask extends AbstractExtentMask { public SolidBlockMask(Extent extent) { @@ -37,4 +39,10 @@ public class SolidBlockMask extends AbstractExtentMask { return !BlockType.canPassThrough(lazyBlock.getType(), lazyBlock.getData()); } + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + } diff --git a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java index 2e5ab5c5d..d800de00a 100644 --- a/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/LocalWorldAdapter.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.internal; -import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalWorld; @@ -37,6 +36,7 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.registry.WorldData; import javax.annotation.Nullable; @@ -109,13 +109,13 @@ public class LocalWorldAdapter extends LocalWorld { } @Override - public BiomeType getBiome(Vector2D position) { + public BaseBiome getBiome(Vector2D position) { return world.getBiome(position); } @Override - public void setBiome(Vector2D position, BiomeType biome) { - world.setBiome(position, biome); + public boolean setBiome(Vector2D position, BaseBiome biome) { + return world.setBiome(position, biome); } @Override diff --git a/src/main/java/com/sk89q/worldedit/internal/ServerInterfaceAdapter.java b/src/main/java/com/sk89q/worldedit/internal/ServerInterfaceAdapter.java index 16d86ee5e..32d0922cc 100644 --- a/src/main/java/com/sk89q/worldedit/internal/ServerInterfaceAdapter.java +++ b/src/main/java/com/sk89q/worldedit/internal/ServerInterfaceAdapter.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.internal; -import com.sk89q.worldedit.BiomeTypes; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.entity.Player; @@ -67,11 +66,6 @@ public class ServerInterfaceAdapter extends ServerInterface { platform.reload(); } - @Override - public BiomeTypes getBiomes() { - return platform.getBiomes(); - } - @Override public int schedule(long delay, long period, Runnable task) { return platform.schedule(delay, period, task); diff --git a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java index 7a6aa4ad3..fbccb8204 100644 --- a/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java +++ b/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.internal.command; -import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; @@ -47,8 +46,12 @@ import com.sk89q.worldedit.util.command.parametric.BindingHelper; import com.sk89q.worldedit.util.command.parametric.BindingMatch; import com.sk89q.worldedit.util.command.parametric.ParameterException; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.Biomes; +import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.Arrays; +import java.util.List; /** * Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}. @@ -288,25 +291,40 @@ public class WorldEditBinding extends BindingHelper { } /** - * Gets an {@link BiomeType} from a {@link ArgumentStack}. + * Gets an {@link BaseBiome} from a {@link ArgumentStack}. * * @param context the context * @return a pattern * @throws ParameterException on error * @throws WorldEditException on error */ - @BindingMatch(type = BiomeType.class, + @BindingMatch(type = BaseBiome.class, behavior = BindingBehavior.CONSUMES, consumedCount = 1) - public BiomeType getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException { + public BaseBiome getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException { String input = context.next(); if (input != null) { - BiomeType type = worldEdit.getServer().getBiomes().get(input); - if (type != null) { - return type; + Actor actor = context.getContext().getLocals().get(Actor.class); + World world; + if (actor instanceof Entity) { + Extent extent = ((Entity) actor).getExtent(); + if (extent instanceof World) { + world = (World) extent; + } else { + throw new ParameterException("A world is required."); + } + } else { + throw new ParameterException("An entity is required."); + } + + BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry(); + List knownBiomes = biomeRegistry.getBiomes(); + BaseBiome biome = Biomes.findBiomeByName(knownBiomes, input, biomeRegistry); + if (biome != null) { + return biome; } else { throw new ParameterException( - String.format("Can't recognize biome type '%s' -- use //biomelist to list available types", input)); + String.format("Can't recognize biome type '%s' -- use /biomelist to list available types", input)); } } else { throw new ParameterException( diff --git a/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java index 2da795df9..bb8edb3b9 100644 --- a/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java +++ b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java @@ -19,12 +19,12 @@ package com.sk89q.worldedit.regions.shape; -import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BaseBiome; /** * Generates solid and hollow shapes according to materials returned by the @@ -58,7 +58,7 @@ public abstract class ArbitraryBiomeShape { cacheSizeX = (int) (max.getX() - cacheOffsetX + 2); cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2); - cache = new BiomeType[cacheSizeX * cacheSizeZ]; + cache = new BaseBiome[cacheSizeX * cacheSizeZ]; } protected Iterable getExtent() { @@ -72,24 +72,24 @@ public abstract class ArbitraryBiomeShape { * OUTSIDE = outside * else = inside */ - private final BiomeType[] cache; + private final BaseBiome[] cache; /** * Override this function to specify the shape to generate. * * @param x X coordinate to be queried * @param z Z coordinate to be queried - * @param defaultBiomeType The default biome for the current column. + * @param defaultBaseBiome The default biome for the current column. * @return material to place or null to not place anything. */ - protected abstract BiomeType getBiome(int x, int z, BiomeType defaultBiomeType); + protected abstract BaseBiome getBiome(int x, int z, BaseBiome defaultBaseBiome); - private BiomeType getBiomeCached(int x, int z, BiomeType biomeType) { + private BaseBiome getBiomeCached(int x, int z, BaseBiome BaseBiome) { final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; - final BiomeType cacheEntry = cache[index]; + final BaseBiome cacheEntry = cache[index]; if (cacheEntry == null) {// unknown, fetch material - final BiomeType material = getBiome(x, z, biomeType); + final BaseBiome material = getBiome(x, z, BaseBiome); if (material == null) { // outside cache[index] = OUTSIDE; @@ -108,13 +108,13 @@ public abstract class ArbitraryBiomeShape { return cacheEntry; } - private boolean isInsideCached(int x, int z, BiomeType biomeType) { + private boolean isInsideCached(int x, int z, BaseBiome BaseBiome) { final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; - final BiomeType cacheEntry = cache[index]; + final BaseBiome cacheEntry = cache[index]; if (cacheEntry == null) { // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape - return getBiomeCached(x, z, biomeType) != null; + return getBiomeCached(x, z, BaseBiome) != null; } return cacheEntry != OUTSIDE; @@ -124,11 +124,11 @@ public abstract class ArbitraryBiomeShape { * Generates the shape. * * @param editSession The EditSession to use. - * @param biomeType The default biome type. + * @param BaseBiome The default biome type. * @param hollow Specifies whether to generate a hollow shape. * @return number of affected blocks. */ - public int generate(EditSession editSession, BiomeType biomeType, boolean hollow) { + public int generate(EditSession editSession, BaseBiome BaseBiome, boolean hollow) { int affected = 0; for (Vector2D position : getExtent()) { @@ -136,7 +136,7 @@ public abstract class ArbitraryBiomeShape { int z = position.getBlockZ(); if (!hollow) { - final BiomeType material = getBiome(x, z, biomeType); + final BaseBiome material = getBiome(x, z, BaseBiome); if (material != OUTSIDE) { editSession.getWorld().setBiome(position, material); ++affected; @@ -145,26 +145,26 @@ public abstract class ArbitraryBiomeShape { continue; } - final BiomeType material = getBiomeCached(x, z, biomeType); + final BaseBiome material = getBiomeCached(x, z, BaseBiome); if (material == null) { continue; } boolean draw = false; do { - if (!isInsideCached(x + 1, z, biomeType)) { + if (!isInsideCached(x + 1, z, BaseBiome)) { draw = true; break; } - if (!isInsideCached(x - 1, z, biomeType)) { + if (!isInsideCached(x - 1, z, BaseBiome)) { draw = true; break; } - if (!isInsideCached(x, z + 1, biomeType)) { + if (!isInsideCached(x, z + 1, BaseBiome)) { draw = true; break; } - if (!isInsideCached(x, z - 1, biomeType)) { + if (!isInsideCached(x, z - 1, BaseBiome)) { draw = true; break; } @@ -181,9 +181,15 @@ public abstract class ArbitraryBiomeShape { return affected; } - private static final BiomeType OUTSIDE = new BiomeType() { - public String getName() { - throw new UnsupportedOperationException(); + private static final BaseBiome OUTSIDE = new BaseBiome(0) { + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object o) { + return this == o; } }; } diff --git a/src/main/java/com/sk89q/worldedit/util/WeightedChoice.java b/src/main/java/com/sk89q/worldedit/util/WeightedChoice.java new file mode 100644 index 000000000..3e5d5d440 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/WeightedChoice.java @@ -0,0 +1,118 @@ +/* + * 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.util; + +import com.google.common.base.Function; +import com.google.common.base.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Returns the best choice given a weighting function and a target weight. + * + *

A function must be supplied that returns a numeric score for each + * choice. The function can return null to mean that the choice should + * not be considered.

+ * + * @param the type of choice + */ +public class WeightedChoice { + + private final Function function; + private double target; + private double best; + private T current; + + /** + * Create a new instance. + * + * @param function a function that assigns a score for each choice + * @param target the target score that the best choice should be closest to + */ + public WeightedChoice(Function function, double target) { + checkNotNull(function); + this.function = function; + this.target = target; + } + + /** + * Consider the given object. + * + * @param object the choice + */ + public void consider(T object) { + checkNotNull(object); + Number value = checkNotNull(function.apply(object)); + if (value != null) { + double distance = Math.abs(target - value.doubleValue()); + if (current == null || distance <= best) { + best = distance; + current = object; + } + } + } + + /** + * Get the best choice. + * + * @return the best choice + */ + public Optional> getChoice() { + if (current != null) { + return Optional.of(new Choice(current, best)); + } else { + return Optional.absent(); + } + } + + /** + * A tuple of choice and score. + * + * @param the choice type + */ + public static class Choice { + private final T object; + private final double value; + + private Choice(T object, double value) { + this.object = object; + this.value = value; + } + + /** + * Get the chosen value. + * + * @return the value + */ + public T getValue() { + return object; + } + + /** + * Get the score. + * + * @return the score + */ + public double getScore() { + return value; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java b/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java new file mode 100644 index 000000000..8767f3a2f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java @@ -0,0 +1,192 @@ +/* + * 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.util.function; + +import com.google.common.base.Function; + +import javax.annotation.Nullable; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Provides a Levenshtein distance between a given string and each string + * that this function is applied to. + */ +public class LevenshteinDistance implements Function { + + public final static Pattern STANDARD_CHARS = Pattern.compile("[ _\\-]"); + + private final String baseString; + private final boolean caseSensitive; + private final Pattern replacePattern; + + /** + * Create a new instance. + * + * @param baseString the string to compare to + * @param caseSensitive true to make case sensitive comparisons + */ + public LevenshteinDistance(String baseString, boolean caseSensitive) { + this(baseString, caseSensitive, null); + } + + /** + * Create a new instance. + * + * @param baseString the string to compare to + * @param caseSensitive true to make case sensitive comparisons + * @param replacePattern pattern to match characters to be removed in both the input and test strings (may be null) + */ + public LevenshteinDistance(String baseString, boolean caseSensitive, @Nullable Pattern replacePattern) { + checkNotNull(baseString); + this.caseSensitive = caseSensitive; + this.replacePattern = replacePattern; + baseString = caseSensitive ? baseString : baseString.toLowerCase(); + baseString = replacePattern != null ? replacePattern.matcher(baseString).replaceAll("") : baseString; + this.baseString = baseString; + } + + @Nullable + @Override + public Integer apply(String input) { + if (input == null) { + return null; + } + + if (replacePattern != null) { + input = replacePattern.matcher(input).replaceAll(""); + } + + if (caseSensitive) { + return distance(baseString, input); + } else { + return distance(baseString, input.toLowerCase()); + } + } + + /** + *

Find the Levenshtein distance between two Strings.

+ * + *

This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).

+ * + *
+ * + *

Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError + * which can occur when my Java implementation is used with very large strings.
+ * This implementation of the Levenshtein distance algorithm + * is from http://www.merriampark.com/ldjava.htm

+ * + *
+     * distance(null, *)             = IllegalArgumentException
+     * distance(*, null)             = IllegalArgumentException
+     * distance("","")               = 0
+     * distance("","a")              = 1
+     * distance("aaapppp", "")       = 7
+     * distance("frog", "fog")       = 1
+     * distance("fly", "ant")        = 3
+     * distance("elephant", "hippo") = 7
+     * distance("hippo", "elephant") = 7
+     * distance("hippo", "zzzzzzzz") = 8
+     * distance("hello", "hallo")    = 1
+     * 
+ * + * @param s the first String, must not be null + * @param t the second String, must not be null + * @return result distance + * @throws IllegalArgumentException if either String input null + */ + public static int distance(String s, String t) { + if (s == null || t == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + + /* + * The difference between this impl. and the previous is that, rather + * than creating and retaining a matrix of size s.length()+1 by + * t.length()+1, we maintain two single-dimensional arrays of length + * s.length()+1. The first, d, is the 'current working' distance array + * that maintains the newest distance cost counts as we iterate through + * the characters of String s. Each time we increment the index of + * String t we are comparing, d is copied to p, the second int[]. Doing + * so allows us to retain the previous cost counts as required by the + * algorithm (taking the minimum of the cost count to the left, up one, + * and diagonally up and to the left of the current cost count being + * calculated). (Note that the arrays aren't really copied anymore, just + * switched...this is clearly much better than cloning an array or doing + * a System.arraycopy() each time through the outer loop.) + * + * Effectively, the difference between the two implementations is this + * one does not cause an out of memory condition when calculating the LD + * over two very large strings. + */ + + int n = s.length(); // length of s + int m = t.length(); // length of t + + if (n == 0) { + return m; + } else if (m == 0) { + return n; + } + + int p[] = new int[n + 1]; // 'previous' cost array, horizontally + int d[] = new int[n + 1]; // cost array, horizontally + int _d[]; // placeholder to assist in swapping p and d + + // indexes into strings s and t + int i; // iterates through s + int j; // iterates through t + + char tj; // jth character of t + + int cost; // cost + + for (i = 0; i <= n; ++i) { + p[i] = i; + } + + for (j = 1; j <= m; ++j) { + tj = t.charAt(j - 1); + d[0] = j; + + for (i = 1; i <= n; ++i) { + cost = s.charAt(i - 1) == tj ? 0 : 1; + // minimum of cell to the left+1, to the top+1, diagonally left + // and up +cost + d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + + cost); + } + + // copy current distance counts to 'previous row' distance counts + _d = p; + p = d; + d = _d; + } + + // our last action in the above loop was to switch d and p, so p now + // actually has the most recent cost counts + return p[n]; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 3b0854dc6..cfb141a42 100644 --- a/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -19,7 +19,11 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; @@ -28,6 +32,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.WorldData; @@ -62,12 +67,13 @@ public class NullWorld extends AbstractWorld { } @Override - public BiomeType getBiome(Vector2D position) { + public BaseBiome getBiome(Vector2D position) { return null; } @Override - public void setBiome(Vector2D position, BiomeType biome) { + public boolean setBiome(Vector2D position, BaseBiome biome) { + return false; } @Override diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java index bd2d13d1c..657f510e3 100644 --- a/src/main/java/com/sk89q/worldedit/world/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -19,12 +19,10 @@ package com.sk89q.worldedit.world; -import com.sk89q.worldedit.BiomeType; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -147,22 +145,6 @@ public interface World extends Extent { */ 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. * diff --git a/src/main/java/com/sk89q/worldedit/world/biome/BaseBiome.java b/src/main/java/com/sk89q/worldedit/world/biome/BaseBiome.java new file mode 100644 index 000000000..f60299f66 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/BaseBiome.java @@ -0,0 +1,82 @@ +/* + * 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.biome; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Basic storage object to represent a given biome. + */ +public class BaseBiome { + + private int id; + + /** + * Create a new biome with the given biome ID. + * + * @param id the biome ID + */ + public BaseBiome(int id) { + this.id = id; + } + + /** + * Create a clone of the given biome. + * + * @param biome the biome to clone + */ + public BaseBiome(BaseBiome biome) { + checkNotNull(biome); + this.id = biome.getId(); + } + + /** + * Get the biome ID. + * + * @return the biome ID + */ + public int getId() { + return id; + } + + /** + * Set the biome id. + * + * @param id the biome ID + */ + public void setId(int id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + BaseBiome baseBiome = (BaseBiome) o; + + return id == baseBiome.id; + } + + @Override + public int hashCode() { + return id; + } +} diff --git a/src/main/java/com/sk89q/worldedit/BiomeType.java b/src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java similarity index 74% rename from src/main/java/com/sk89q/worldedit/BiomeType.java rename to src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java index 93d9efe4a..5f21dd978 100644 --- a/src/main/java/com/sk89q/worldedit/BiomeType.java +++ b/src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java @@ -17,20 +17,19 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit; +package com.sk89q.worldedit.world.biome; -public interface BiomeType { - - public static final BiomeType UNKNOWN = new BiomeType() { - public String getName() { - return "Unknown"; - } - }; +/** + * Provides information about a biome. + */ +public interface BiomeData { /** - * Get the name of this biome type. + * Get the name of the biome, which does not have to follow any + * particular convention. * - * @return String + * @return the biome's name */ - public String getName(); + String getName(); + } diff --git a/src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java b/src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java new file mode 100644 index 000000000..145d891cb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java @@ -0,0 +1,57 @@ +/* + * 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.biome; + +import com.google.common.base.Function; +import com.sk89q.worldedit.world.registry.BiomeRegistry; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Returns the name of a biome using a given {@code BiomeRegistry}. + */ +class BiomeName implements Function { + + private final BiomeRegistry registry; + + /** + * Create a new instance. + * + * @param registry the biome registry + */ + BiomeName(BiomeRegistry registry) { + checkNotNull(registry); + this.registry = registry; + } + + @Nullable + @Override + public String apply(BaseBiome input) { + BiomeData data = registry.getData(input); + if (data != null) { + return data.getName(); + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/biome/Biomes.java b/src/main/java/com/sk89q/worldedit/world/biome/Biomes.java new file mode 100644 index 000000000..c19c2ac93 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/Biomes.java @@ -0,0 +1,70 @@ +/* + * 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.biome; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Optional; +import com.sk89q.worldedit.util.WeightedChoice; +import com.sk89q.worldedit.util.WeightedChoice.Choice; +import com.sk89q.worldedit.util.function.LevenshteinDistance; +import com.sk89q.worldedit.world.registry.BiomeRegistry; + +import javax.annotation.Nullable; +import java.util.Collection; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utility methods related to biomes. + */ +public final class Biomes { + + private Biomes() { + } + + /** + * Find a biome that matches the given input name. + * + * @param biomes a list of biomes + * @param name the name to test + * @param registry a biome registry + * @return a biome or null + */ + @Nullable + public static BaseBiome findBiomeByName(Collection biomes, String name, BiomeRegistry registry) { + checkNotNull(biomes); + checkNotNull(name); + checkNotNull(registry); + + Function compare = new LevenshteinDistance(name, false, LevenshteinDistance.STANDARD_CHARS); + WeightedChoice chooser = new WeightedChoice(Functions.compose(compare, new BiomeName(registry)), 0); + for (BaseBiome biome : biomes) { + chooser.consider(biome); + } + Optional> choice = chooser.getChoice(); + if (choice.isPresent() && choice.get().getScore() <= 1) { + return choice.get().getValue(); + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/BiomeTypes.java b/src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java similarity index 56% rename from src/main/java/com/sk89q/worldedit/BiomeTypes.java rename to src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java index 0d61b4c80..ab3942463 100644 --- a/src/main/java/com/sk89q/worldedit/BiomeTypes.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java @@ -17,31 +17,42 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit; +package com.sk89q.worldedit.world.registry; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.BiomeData; + +import javax.annotation.Nullable; import java.util.List; -public interface BiomeTypes { +/** + * Provides information on biomes. + */ +public interface BiomeRegistry { /** - * Returns if a biome with the given name is available. + * Create a new biome given its biome ID. * - * @param name - * @return + * @param id its biome ID + * @return a new biome or null if it can't be created */ - boolean has(String name); + @Nullable + BaseBiome createFromId(int id); /** - * Returns the biome type for the given name + * Get a list of available biomes. * - * @return + * @return a list of biomes */ - BiomeType get(String name) throws UnknownBiomeTypeException; + List getBiomes(); /** - * Returns a list of all available biome types. + * Get data about a biome. * - * @return + * @param biome the biome + * @return a data object or null if information is not known */ - List all(); + @Nullable + BiomeData getData(BaseBiome biome); + } diff --git a/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java b/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java index bed5b401f..2fabd886d 100644 --- a/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/LegacyWorldData.java @@ -23,16 +23,17 @@ package com.sk89q.worldedit.world.registry; * An implementation of {@link WorldData} that uses legacy numeric IDs and * a built-in block database. */ -public final class LegacyWorldData implements WorldData { +public class LegacyWorldData implements WorldData { private static final LegacyWorldData INSTANCE = new LegacyWorldData(); private final LegacyBlockRegistry blockRegistry = new LegacyBlockRegistry(); private final NullEntityRegistry entityRegistry = new NullEntityRegistry(); + private final NullBiomeRegistry biomeRegistry = new NullBiomeRegistry(); /** * Create a new instance. */ - private LegacyWorldData() { + protected LegacyWorldData() { } @Override @@ -45,6 +46,11 @@ public final class LegacyWorldData implements WorldData { return entityRegistry; } + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + /** * Get a singleton instance. * diff --git a/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java new file mode 100644 index 000000000..8bbf7c1ff --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java @@ -0,0 +1,57 @@ +/* + * 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.registry; + +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.BiomeData; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; + +/** + * A biome registry that knows nothing. + */ +public class NullBiomeRegistry implements BiomeRegistry { + + /** + * Create a new instance. + */ + public NullBiomeRegistry() { + } + + @Nullable + @Override + public BaseBiome createFromId(int id) { + return null; + } + + @Override + public List getBiomes() { + return Collections.emptyList(); + } + + @Nullable + @Override + public BiomeData getData(BaseBiome biome) { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java b/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java index d8bf886e6..d6a4b21f8 100644 --- a/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java +++ b/src/main/java/com/sk89q/worldedit/world/registry/WorldData.java @@ -39,4 +39,11 @@ public interface WorldData { */ EntityRegistry getEntityRegistry(); + /** + * Get the biome registry. + * + * @return the biome registry + */ + BiomeRegistry getBiomeRegistry(); + } From 9c205e0e00c1531e6793e64cde991cc4ec59272e Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 17 Jul 2014 14:50:44 -0700 Subject: [PATCH 53/56] Fix naming errors in ArbitraryBiomeShape caused by biome commit. --- .../regions/shape/ArbitraryBiomeShape.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java index bb8edb3b9..a5a3b883d 100644 --- a/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java +++ b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java @@ -84,12 +84,12 @@ public abstract class ArbitraryBiomeShape { */ protected abstract BaseBiome getBiome(int x, int z, BaseBiome defaultBaseBiome); - private BaseBiome getBiomeCached(int x, int z, BaseBiome BaseBiome) { + private BaseBiome getBiomeCached(int x, int z, BaseBiome baseBiome) { final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; final BaseBiome cacheEntry = cache[index]; if (cacheEntry == null) {// unknown, fetch material - final BaseBiome material = getBiome(x, z, BaseBiome); + final BaseBiome material = getBiome(x, z, baseBiome); if (material == null) { // outside cache[index] = OUTSIDE; @@ -108,13 +108,13 @@ public abstract class ArbitraryBiomeShape { return cacheEntry; } - private boolean isInsideCached(int x, int z, BaseBiome BaseBiome) { + private boolean isInsideCached(int x, int z, BaseBiome baseBiome) { final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; final BaseBiome cacheEntry = cache[index]; if (cacheEntry == null) { // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape - return getBiomeCached(x, z, BaseBiome) != null; + return getBiomeCached(x, z, baseBiome) != null; } return cacheEntry != OUTSIDE; @@ -124,11 +124,11 @@ public abstract class ArbitraryBiomeShape { * Generates the shape. * * @param editSession The EditSession to use. - * @param BaseBiome The default biome type. + * @param baseBiome The default biome type. * @param hollow Specifies whether to generate a hollow shape. * @return number of affected blocks. */ - public int generate(EditSession editSession, BaseBiome BaseBiome, boolean hollow) { + public int generate(EditSession editSession, BaseBiome baseBiome, boolean hollow) { int affected = 0; for (Vector2D position : getExtent()) { @@ -136,7 +136,7 @@ public abstract class ArbitraryBiomeShape { int z = position.getBlockZ(); if (!hollow) { - final BaseBiome material = getBiome(x, z, BaseBiome); + final BaseBiome material = getBiome(x, z, baseBiome); if (material != OUTSIDE) { editSession.getWorld().setBiome(position, material); ++affected; @@ -145,26 +145,26 @@ public abstract class ArbitraryBiomeShape { continue; } - final BaseBiome material = getBiomeCached(x, z, BaseBiome); + final BaseBiome material = getBiomeCached(x, z, baseBiome); if (material == null) { continue; } boolean draw = false; do { - if (!isInsideCached(x + 1, z, BaseBiome)) { + if (!isInsideCached(x + 1, z, baseBiome)) { draw = true; break; } - if (!isInsideCached(x - 1, z, BaseBiome)) { + if (!isInsideCached(x - 1, z, baseBiome)) { draw = true; break; } - if (!isInsideCached(x, z + 1, BaseBiome)) { + if (!isInsideCached(x, z + 1, baseBiome)) { draw = true; break; } - if (!isInsideCached(x, z - 1, BaseBiome)) { + if (!isInsideCached(x, z - 1, baseBiome)) { draw = true; break; } From 8508055ddc04826868728c582230bc647c46d304 Mon Sep 17 00:00:00 2001 From: sk89q Date: Fri, 18 Jul 2014 01:01:47 -0700 Subject: [PATCH 54/56] Add block transform test that tests against older rotation code. Also fixes the rotations for some blocks. --- .../transform/BlockTransformExtent.java | 2 +- .../worldedit/world/registry/blocks.json | 55 +++++++++++-- .../transform/BlockTransformExtentTest.java | 79 +++++++++++++++++++ 3 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java diff --git a/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index a0d5ad090..dc634ed2f 100644 --- a/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -106,7 +106,7 @@ public class BlockTransformExtent extends AbstractDelegateExtent { * @param registry the registry * @return the same block */ - private static BaseBlock transform(BaseBlock block, Transform transform, BlockRegistry registry) { + public static BaseBlock transform(BaseBlock block, Transform transform, BlockRegistry registry) { return transform(block, transform, registry, block); } diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json index 92410c465..f4a08d736 100644 --- a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json @@ -919,7 +919,7 @@ "facing": { "values": { "north": { "data": 0, "direction": [0, 0, -1] }, - "south": { "data": 1, "direction": [0, 0, 1] }, + "south": { "data": 0, "direction": [0, 0, 1] }, "east": { "data": 1, "direction": [1, 0, 0] }, "west": { "data": 1, "direction": [-1, 0, 0] }, "east_ascending": { "data": 2, "direction": [1, 1, 0] }, @@ -929,6 +929,7 @@ "north_ascending": { "data": 4, "direction": [0, 1, -1] }, "north_descending": { "data": 4, "direction": [0, -1, 1] }, "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "south_descending": { "data": 5, "direction": [0, -1, -1] }, "southeast": { "data": 6, "direction": [1, 0, 1] }, "southwest": { "data": 7, "direction": [-1, 0, 1] }, "northwest": { "data": 8, "direction": [-1, 0, -1] }, @@ -969,7 +970,7 @@ "facing": { "values": { "north": { "data": 0, "direction": [0, 0, -1] }, - "south": { "data": 1, "direction": [0, 0, 1] }, + "south": { "data": 0, "direction": [0, 0, 1] }, "east": { "data": 1, "direction": [1, 0, 0] }, "west": { "data": 1, "direction": [-1, 0, 0] }, "east_ascending": { "data": 2, "direction": [1, 1, 0] }, @@ -979,6 +980,7 @@ "north_ascending": { "data": 4, "direction": [0, 1, -1] }, "north_descending": { "data": 4, "direction": [0, -1, 1] }, "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "south_descending": { "data": 5, "direction": [0, -1, -1] }, "southeast": { "data": 6, "direction": [1, 0, 1] }, "southwest": { "data": 7, "direction": [-1, 0, 1] }, "northwest": { "data": 8, "direction": [-1, 0, -1] }, @@ -2320,7 +2322,7 @@ "facing": { "values": { "north": { "data": 0, "direction": [0, 0, -1] }, - "south": { "data": 1, "direction": [0, 0, 1] }, + "south": { "data": 0, "direction": [0, 0, 1] }, "east": { "data": 1, "direction": [1, 0, 0] }, "west": { "data": 1, "direction": [-1, 0, 0] }, "east_ascending": { "data": 2, "direction": [1, 1, 0] }, @@ -2330,6 +2332,7 @@ "north_ascending": { "data": 4, "direction": [0, 1, -1] }, "north_descending": { "data": 4, "direction": [0, -1, 1] }, "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "south_descending": { "data": 5, "direction": [0, -1, -1] }, "southeast": { "data": 6, "direction": [1, 0, 1] }, "southwest": { "data": 7, "direction": [-1, 0, 1] }, "northwest": { "data": 8, "direction": [-1, 0, -1] }, @@ -2457,7 +2460,15 @@ "east": { "data": 1, "direction": [1, 0, 0] }, "south": { "data": 3, "direction": [0, 0, 1] }, "west": { "data": 2, "direction": [-1, 0, 0] }, - "north": { "data": 4, "direction": [0, 0, -1] } + "north": { "data": 4, "direction": [0, 0, -1] }, + "ground_south": { "data": 5, "direction": [0, 1, 1] }, + "ground_north": { "data": 5, "direction": [0, 1, -1] }, + "ground_east": { "data": 6, "direction": [1, 1, 0] }, + "ground_west": { "data": 6, "direction": [-1, 1, 0] }, + "ceiling_south": { "data": 7, "direction": [0, -1, -1] }, + "ceiling_north": { "data": 7, "direction": [0, -1, 1] }, + "ceiling_east": { "data": 0, "direction": [1, -1, 0] }, + "ceiling_west": { "data": 0, "direction": [-1, -1, 0] } } }, "powered": { @@ -3286,6 +3297,17 @@ "legacyId": 94, "id": "minecraft:powered_repeater", "unlocalizedName": "tile.diode", + "states": { + "facing": { + "dataMask": 3, + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] } + } + } + }, "material": { "renderedAsNormalBlock": false, "fullCube": false, @@ -5006,6 +5028,17 @@ "legacyId": 145, "id": "minecraft:anvil", "unlocalizedName": "tile.anvil", + "states": { + "facing": { + "dataMask": 3, + "values": { + "south": { "data": 0, "direction": [0, 0, 1] }, + "north": { "data": 0, "direction": [0, 0, -1] }, + "west": { "data": 1, "direction": [-1, 0, 0] }, + "east": { "data": 1, "direction": [1, 0, 0] } + } + } + }, "material": { "renderedAsNormalBlock": false, "fullCube": false, @@ -5191,6 +5224,17 @@ "legacyId": 150, "id": "minecraft:powered_comparator", "unlocalizedName": "tile.comparator", + "states": { + "facing": { + "dataMask": 3, + "values": { + "north": { "data": 0, "direction": [0, 0, -1] }, + "east": { "data": 1, "direction": [1, 0, 0] }, + "south": { "data": 2, "direction": [0, 0, 1] }, + "west": { "data": 3, "direction": [-1, 0, 0] } + } + } + }, "material": { "renderedAsNormalBlock": false, "fullCube": false, @@ -5433,7 +5477,7 @@ "facing": { "values": { "north": { "data": 0, "direction": [0, 0, -1] }, - "south": { "data": 1, "direction": [0, 0, 1] }, + "south": { "data": 0, "direction": [0, 0, 1] }, "east": { "data": 1, "direction": [1, 0, 0] }, "west": { "data": 1, "direction": [-1, 0, 0] }, "east_ascending": { "data": 2, "direction": [1, 1, 0] }, @@ -5443,6 +5487,7 @@ "north_ascending": { "data": 4, "direction": [0, 1, -1] }, "north_descending": { "data": 4, "direction": [0, -1, 1] }, "south_ascending": { "data": 5, "direction": [0, 1, 1] }, + "south_descending": { "data": 5, "direction": [0, -1, -1] }, "southeast": { "data": 6, "direction": [1, 0, 1] }, "southwest": { "data": 7, "direction": [-1, 0, 1] }, "northwest": { "data": 8, "direction": [-1, 0, -1] }, diff --git a/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java b/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java new file mode 100644 index 000000000..d85f9c2c4 --- /dev/null +++ b/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java @@ -0,0 +1,79 @@ +/* + * 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.extent.transform; + +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockData; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import com.sk89q.worldedit.world.registry.LegacyBlockRegistry; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +public class BlockTransformExtentTest { + + private final Transform ROTATE_90 = new AffineTransform().rotateY(-90); + private final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90); + private final Set ignored = new HashSet(); + + @Before + public void setUp() throws Exception { + ignored.add(BlockType.BED); // Broken in existing rotation code? + ignored.add(BlockType.WOODEN_DOOR); // Complicated + ignored.add(BlockType.IRON_DOOR); // Complicated + ignored.add(BlockType.STONE_BUTTON); // Existing rotation code doesn't handle down/up directions + ignored.add(BlockType.WOODEN_BUTTON); // Existing rotation code doesn't handle down/up directions + ignored.add(BlockType.END_PORTAL); // Not supported in existing rotation code + } + + @Test + public void testTransform() throws Exception { + BlockRegistry blockRegistry = new LegacyBlockRegistry(); + for (BlockType type : BlockType.values()) { + if (ignored.contains(type)) { + continue; + } + + BaseBlock orig = new BaseBlock(type.getID()); + for (int i = 1; i < 4; i++) { + BaseBlock rotated = BlockTransformExtent.transform(new BaseBlock(orig), ROTATE_90, blockRegistry); + BaseBlock reference = new BaseBlock(orig.getType(), BlockData.rotate90(orig.getType(), orig.getData())); + assertThat(type + "#" + type.getID() + " rotated " + (90 * i) + " degrees did not match BlockData.rotate90()'s expected result", rotated, equalTo(reference)); + orig = rotated; + } + + orig = new BaseBlock(type.getID()); + for (int i = 0; i < 4; i++) { + BaseBlock rotated = BlockTransformExtent.transform(new BaseBlock(orig), ROTATE_NEG_90, blockRegistry); + BaseBlock reference = new BaseBlock(orig.getType(), BlockData.rotate90Reverse(orig.getType(), orig.getData())); + assertThat(type + "#" + type.getID() + " rotated " + (-90 * i) + " degrees did not match BlockData.rotate90Reverse()'s expected result", rotated, equalTo(reference)); + orig = rotated; + } + } + } +} \ No newline at end of file From 9dbe87b77b5ae42626249175831f3df5e7824954 Mon Sep 17 00:00:00 2001 From: sk89q Date: Fri, 18 Jul 2014 01:50:07 -0700 Subject: [PATCH 55/56] Add static to some fields on BlockTransformExtentTest. --- .../worldedit/extent/transform/BlockTransformExtentTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java b/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java index d85f9c2c4..b3ae0763f 100644 --- a/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java +++ b/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java @@ -37,8 +37,8 @@ import static org.junit.Assert.assertThat; public class BlockTransformExtentTest { - private final Transform ROTATE_90 = new AffineTransform().rotateY(-90); - private final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90); + private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90); + private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90); private final Set ignored = new HashSet(); @Before From 7d3976049665cd93d6b747f61ed9066980180fc9 Mon Sep 17 00:00:00 2001 From: sk89q Date: Fri, 18 Jul 2014 02:15:42 -0700 Subject: [PATCH 56/56] Add support for Bukkit for MC 1.6.4. --- .../adapter/impl/CraftBukkit_v1_6_R3.class | Bin 0 -> 16313 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_6_R3.class diff --git a/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_6_R3.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_6_R3.class new file mode 100644 index 0000000000000000000000000000000000000000..6d5c96592cf3e7ce8f76633ec7aa1cee485fa7c8 GIT binary patch literal 16313 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 literal 0 HcmV?d00001

The previous implementation of the Levenshtein distance algorithm + * was from http://www.merriampark.com/ld.htm