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'
}
diff --git a/pom.xml b/pom.xml
index 6b09a8665..5d33c64b6 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
@@ -187,6 +203,18 @@
install
${basedir}/src/main/java/
+
+
+
+ .
+ false
+ ${basedir}/src/main/resources/
+
+ **/*.json
+
+
+
+
@@ -367,12 +395,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
+
+
@@ -513,16 +554,6 @@
jar
true
-
-
-
- org.bukkit
- craftbukkit
- 1.7.9-R0.1-SNAPSHOT
- compile
- jar
- true
-
@@ -549,11 +580,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
new file mode 100644
index 000000000..c9de48b73
--- /dev/null
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java
@@ -0,0 +1,144 @@
+/*
+ * 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.entity.Entity;
+import com.sk89q.worldedit.util.Location;
+import com.sk89q.worldedit.world.World;
+import org.bukkit.Bukkit;
+
+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 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.
+ *
+ * @param location the Bukkit location
+ * @return a WorldEdit location
+ */
+ public static Location adapt(org.bukkit.Location location) {
+ checkNotNull(location);
+ Vector position = BukkitUtil.toVector(location);
+ return new com.sk89q.worldedit.util.Location(
+ adapt(location.getWorld()),
+ position,
+ location.getYaw(),
+ location.getPitch());
+ }
+
+ /**
+ * 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();
+ return new org.bukkit.Location(
+ adapt((World) location.getExtent()),
+ position.getX(), position.getY(), position.getZ(),
+ location.getYaw(),
+ 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 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(),
+ location.getYaw(),
+ location.getPitch());
+ }
+
+ /**
+ * 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/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/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java
new file mode 100644
index 000000000..483b740eb
--- /dev/null
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitEntity.java
@@ -0,0 +1,110 @@
+/*
+ * 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.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;
+
+/**
+ * An adapter to adapt a Bukkit entity into a WorldEdit one.
+ */
+class BukkitEntity implements Entity {
+
+ private final org.bukkit.entity.Entity entity;
+
+ /**
+ * Create a new instance.
+ *
+ * @param entity the entity
+ */
+ BukkitEntity(org.bukkit.entity.Entity 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 && getEntity() instanceof org.bukkit.entity.Tameable) {
+ return (T) new TameableAdapter((org.bukkit.entity.Tameable) getEntity());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Extent getExtent() {
+ return BukkitAdapter.adapt(getEntity().getWorld());
+ }
+
+ @Override
+ public Location getLocation() {
+ return BukkitAdapter.adapt(getEntity().getLocation());
+ }
+
+ @Override
+ public BaseEntity getState() {
+ 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() {
+ entity.remove();
+ return entity.isDead();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ @Override
+ public T getFacet(Class extends T> 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 637c7c7e8..519aee885 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
@@ -19,22 +19,23 @@
package com.sk89q.worldedit.bukkit;
-import com.sk89q.worldedit.WorldEditException;
-import com.sk89q.worldedit.blocks.BaseBlock;
-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;
+
+import javax.annotation.Nullable;
public class BukkitPlayer extends LocalPlayer {
private Player player;
@@ -170,11 +171,25 @@ 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();
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,
+ nativeLocation.getYaw(),
+ nativeLocation.getPitch());
+ }
+
+ @Nullable
+ @Override
+ public T getFacet(Class extends T> cls) {
+ return null;
}
}
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 4c73526d3..c95e4130d 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
@@ -19,32 +19,42 @@
package com.sk89q.worldedit.bukkit;
-import com.sk89q.worldedit.*;
-import com.sk89q.worldedit.EntityType;
+import com.sk89q.worldedit.BlockVector2D;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
-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.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.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.TreeGenerator;
-import org.bukkit.*;
-import org.bukkit.Location;
-import org.bukkit.block.*;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.*;
+import com.sk89q.worldedit.world.biome.BaseBiome;
+import com.sk89q.worldedit.world.registry.WorldData;
+import org.bukkit.Effect;
+import org.bukkit.Material;
+import org.bukkit.TreeType;
+import org.bukkit.World;
+import org.bukkit.block.Biome;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.Chest;
+import org.bukkit.entity.Entity;
import org.bukkit.inventory.DoubleChestInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.Plugin;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.InputStream;
+import javax.annotation.Nullable;
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.List;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -53,153 +63,69 @@ 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;
- /*
- * holder for the nmsblock class that we should use
- */
- private static Class extends NmsBlock> 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 extends NmsBlock> nmsClass = (Class extends NmsBlock>) 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 extends NmsBlock>) 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;
- }
}
- private class NmsBlockClassLoader extends ClassLoader {
- public File searchDir;
- public NmsBlockClassLoader(ClassLoader parent, File searchDir) {
- super(parent);
- this.searchDir = searchDir;
- }
+ @Override
+ public List getEntities(Region region) {
+ World world = getWorld();
- @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
+ List entities = new ArrayList();
+ for (Vector2D pt : region.getChunks()) {
+ if (!world.isChunkLoaded(pt.getBlockX(), pt.getBlockZ())) {
+ continue;
}
- 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();
+ 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));
}
- input.close();
-
- byte[] classData = buffer.toByteArray();
-
- return defineClass(name.replaceFirst(".class$", ""), classData, 0, classData.length);
- } catch (Throwable e) {
- throw new ClassNotFoundException();
}
}
+ return entities;
+ }
+
+ @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) {
+ 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;
+ }
}
/**
@@ -229,90 +155,11 @@ 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();
}
- @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)];
@@ -334,7 +181,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
@@ -359,303 +206,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.
@@ -781,321 +331,9 @@ 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;
- }
-
- /**
- * 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();
}
@@ -1139,13 +377,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();
@@ -1160,82 +391,36 @@ public class BukkitWorld extends LocalWorld {
return true;
}
+ @Override
+ public WorldData getWorldData() {
+ return BukkitWorldData.getInstance();
+ }
+
@Override
public void simulateBlockMine(Vector pt) {
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));
- }
- }
+ 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 entities.toArray(new BukkitEntity[entities.size()]);
}
@Override
- public int killEntities(LocalEntity... entities) {
- World world = getWorld();
-
- int amount = 0;
- Set toKill = new HashSet();
- for (LocalEntity entity : entities) {
- toKill.add(((BukkitEntity) entity).getEntityId());
+ 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);
}
- for (Entity entity : world.getEntities()) {
- if (toKill.contains(entity.getUniqueId())) {
- entity.remove();
- ++amount;
- }
- }
- return amount;
- }
-
- @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;
- }
- }
- }
-
- return super.getBlock(pt);
}
@SuppressWarnings("deprecation")
@@ -1247,17 +432,26 @@ public class BukkitWorld extends LocalWorld {
}
@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;
- }
+ 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);
}
+ }
- return super.setBlock(pt, block, notifyAdjacent);
+ @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;
+ }
}
/**
@@ -1267,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/DefaultNmsBlock.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java
deleted file mode 100644
index 23d5e64e8..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) throws DataException {
- 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 extends Tag> 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/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/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..04113a6d5
--- /dev/null
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.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.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;
+
+/**
+ * An interface for adapters of various Bukkit implementations.
+ */
+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.
+ *
+ * @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);
+
+ /**
+ * 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/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_6_R3.class b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_6_R3.class
new file mode 100644
index 000000000..6d5c96592
Binary files /dev/null and b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_6_R3.class differ
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 000000000..20b3c1930
Binary files /dev/null and b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R2.class differ
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
new file mode 100644
index 000000000..1f8cc436f
Binary files /dev/null and b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R3.class differ
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
new file mode 100644
index 000000000..f9eb46a5d
Binary files /dev/null and b/src/bukkit/resources/com/sk89q/worldedit/bukkit/adapter/impl/CraftBukkit_v1_7_R4.class differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class
deleted file mode 100644
index b8d6c51f3..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class
deleted file mode 100644
index e89c4a70b..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class
deleted file mode 100644
index e3c8c20fd..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class
deleted file mode 100644
index 68781e198..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_152.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_152.class
deleted file mode 100644
index 8dda57ec9..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_152.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class
deleted file mode 100644
index 336c611cb..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_162.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_162.class
deleted file mode 100644
index 2d70cfbcb..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_162.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_164.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_164.class
deleted file mode 100644
index 7520a85a1..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_164.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_172.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_172.class
deleted file mode 100644
index a7fb7e100..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_172.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class
deleted file mode 100644
index 6afbcdcc5..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/CBXNmsBlock_prePackage.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_prePackage.class
deleted file mode 100644
index 07a94b131..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_prePackage.class and /dev/null differ
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 2a4acd48e..000000000
Binary files a/src/bukkit/resources/nmsblocks/CBXNmsBlock_v152_2.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class
deleted file mode 100644
index 86da91a7f..000000000
Binary files a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class
deleted file mode 100644
index b68088e83..000000000
Binary files a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class
deleted file mode 100644
index 7f1326865..000000000
Binary files a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class and /dev/null differ
diff --git a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_164.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_164.class
deleted file mode 100644
index ac6c27721..000000000
Binary files a/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_164.class and /dev/null differ
diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeType.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java
similarity index 69%
rename from src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeType.java
rename to src/forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java
index 5cd816ad7..5a1d6120f 100644
--- a/src/forge/java/com/sk89q/worldedit/forge/ForgeBiomeType.java
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeAdapter.java
@@ -1,36 +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.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.Vector;
+import com.sk89q.worldedit.world.World;
+import net.minecraft.util.Vec3;
+
+final class ForgeAdapter {
+
+ private ForgeAdapter() {
+ }
+
+ 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/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/ForgeEntity.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java
new file mode 100644
index 000000000..44ca0a666
--- /dev/null
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeEntity.java
@@ -0,0 +1,95 @@
+/*
+ * 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.entity.metadata.EntityType;
+import com.sk89q.worldedit.extent.Extent;
+import com.sk89q.worldedit.util.Location;
+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 {
+
+ private final net.minecraft.entity.Entity entity;
+
+ ForgeEntity(net.minecraft.entity.Entity entity) {
+ checkNotNull(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);
+ if (id != null) {
+ NBTTagCompound tag = new NBTTagCompound();
+ entity.writeToNBT(tag);
+ return new BaseEntity(id, NBTConverter.fromNative(tag));
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Location getLocation() {
+ Vector position = new Vector(entity.posX, entity.posY, entity.posZ);
+ float yaw = entity.rotationYaw;
+ float pitch = entity.rotationPitch;
+
+ return new Location(ForgeAdapter.adapt(entity.worldObj), position, yaw, pitch);
+ }
+
+ @Override
+ public Extent getExtent() {
+ return ForgeAdapter.adapt(entity.worldObj);
+ }
+
+ @Override
+ public boolean remove() {
+ entity.setDead();
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ @Override
+ public T getFacet(Class extends T> 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/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/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java
index 21978c270..327b03602 100644
--- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java
@@ -20,21 +20,23 @@
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;
+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;
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;
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) {
@@ -50,11 +52,19 @@ 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);
- 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,
+ this.player.cameraYaw,
+ this.player.cameraPitch);
}
public WorldVector getPosition() {
@@ -126,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 extends T> 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 9271a1ce2..fdab7bcf1 100644
--- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorld.java
@@ -20,24 +20,26 @@
package com.sk89q.worldedit.forge;
import com.sk89q.jnbt.CompoundTag;
-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.LazyBlock;
+import com.sk89q.worldedit.entity.BaseEntity;
+import com.sk89q.worldedit.entity.Entity;
+import com.sk89q.worldedit.internal.Constants;
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.biome.BaseBiome;
+import com.sk89q.worldedit.world.registry.WorldData;
import net.minecraft.block.Block;
-import net.minecraft.entity.Entity;
-import net.minecraft.entity.EntityHanging;
-import net.minecraft.entity.EntityLiving;
-import net.minecraft.entity.IProjectile;
-import net.minecraft.entity.item.*;
-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.entity.EntityList;
+import net.minecraft.entity.item.EntityItem;
import net.minecraft.inventory.IInventory;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
@@ -48,8 +50,10 @@ 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.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
@@ -176,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
@@ -199,7 +204,7 @@ public class ForgeWorld extends AbstractWorld {
checkNotNull(position);
checkNotNull(item);
- if ((item == null) || (item.getType() == 0)) {
+ if (item.getType() == 0) {
return;
}
@@ -208,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 (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 (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)];
@@ -425,6 +315,11 @@ public class ForgeWorld extends AbstractWorld {
return false;
}
+ @Override
+ public WorldData getWorldData() {
+ return ForgeWorldData.getInstance();
+ }
+
@Override
public boolean isValidBlockType(int id) {
return (id == 0) || (net.minecraft.block.Block.blocksList[id] != null);
@@ -462,10 +357,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 {
@@ -473,6 +368,61 @@ public class ForgeWorld extends AbstractWorld {
}
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public List extends Entity> 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 extends Entity> getEntities() {
+ List entities = new ArrayList();
+ for (Object entity : getWorld().getLoadedEntityList()) {
+ entities.add(new ForgeEntity((net.minecraft.entity.Entity) entity));
+ }
+ return entities;
+ }
+
+ @Nullable
+ @Override
+ public Entity createEntity(Location location, BaseEntity entity) {
+ World world = getWorld();
+ net.minecraft.entity.Entity createdEntity = EntityList.createEntityByName(entity.getTypeId(), world);
+ if (createdEntity != null) {
+ 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(), location.getYaw(), location.getPitch());
+
+ world.spawnEntityInWorld(createdEntity);
+ return new ForgeEntity(createdEntity);
+ } else {
+ return null;
+ }
+ }
+
/**
* Thrown when the reference to the world is lost.
*/
diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldData.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldData.java
new file mode 100644
index 000000000..c6f3d553c
--- /dev/null
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldData.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.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/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/forge/resources/defaults/worldedit.properties b/src/forge/resources/defaults/worldedit.properties
index f7e362f20..9c3f5d327 100644
--- a/src/forge/resources/defaults/worldedit.properties
+++ b/src/forge/resources/defaults/worldedit.properties
@@ -1,32 +1,32 @@
-#Don't put comments; they get removed
-default-max-polygon-points=-1
-schematic-save-dir=schematics
-allow-extra-data-values=false
-super-pickaxe-many-drop-items=true
-register-help=true
-nav-wand-item=345
-profile=false
-super-pickaxe-drop-items=true
-disallowed-blocks=6,26,27,28,31,32,34,36,37,38,39,40,46,50,51,55,59,66,69,75,76,93,94,77,81,83,7,14,15,16,56
-max-super-pickaxe-size=5
-max-brush-radius=10
-craftscript-dir=craftscripts
-no-double-slash=false
-wand-item=271
-shell-save-type=
-scripting-timeout=3000
-snapshots-dir=
-use-inventory-creative-override=false
-log-file=worldedit.log
-max-changed-blocks=-1
-nav-wand-distance=50
-butcher-default-radius=-1
-default-max-changed-blocks=-1
-history-size=15
-use-inventory=false
-allow-symbolic-links=false
-use-inventory-override=false
-log-commands=false
-butcher-max-radius=-1
-max-polygon-points=20
-max-radius=-1
+#Don't put comments; they get removed
+default-max-polygon-points=-1
+schematic-save-dir=schematics
+allow-extra-data-values=false
+super-pickaxe-many-drop-items=true
+register-help=true
+nav-wand-item=345
+profile=false
+super-pickaxe-drop-items=true
+disallowed-blocks=6,26,27,28,31,32,34,36,37,38,39,40,46,50,51,55,59,66,69,75,76,93,94,77,81,83,7,14,15,16,56
+max-super-pickaxe-size=5
+max-brush-radius=10
+craftscript-dir=craftscripts
+no-double-slash=false
+wand-item=271
+shell-save-type=
+scripting-timeout=3000
+snapshots-dir=
+use-inventory-creative-override=false
+log-file=worldedit.log
+max-changed-blocks=-1
+nav-wand-distance=50
+butcher-default-radius=-1
+default-max-changed-blocks=-1
+history-size=15
+use-inventory=false
+allow-symbolic-links=false
+use-inventory-override=false
+log-commands=false
+butcher-max-radius=-1
+max-polygon-points=20
+max-radius=-1
diff --git a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java b/src/legacy/java/com/sk89q/worldedit/blocks/ChestBlock.java
similarity index 78%
rename from src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/ChestBlock.java
index fcc9f0a32..d5547e661 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java
+++ b/src/legacy/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/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 72%
rename from src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/DispenserBlock.java
index 0608e4935..c13c7f163 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java
+++ b/src/legacy/java/com/sk89q/worldedit/blocks/DispenserBlock.java
@@ -1,105 +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 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;
-
-/**
- * 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) 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");
- }
-
- items.add((CompoundTag) tag);
- }
-
- setItems(deserializeInventory(items));
- }
-}
+/*
+ * 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 73%
rename from src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/FurnaceBlock.java
index db4d3e210..07b38c78b 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java
+++ b/src/legacy/java/com/sk89q/worldedit/blocks/FurnaceBlock.java
@@ -1,164 +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 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.ShortTag;
-import com.sk89q.jnbt.StringTag;
-import com.sk89q.jnbt.Tag;
-import com.sk89q.worldedit.world.DataException;
-
-/**
- * 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) throws DataException {
- 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");
- }
-
- 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");
- }
- 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();
- }
- }
-}
+/*
+ * 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 91%
rename from src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java
index 591744fac..bf9ad5d19 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java
+++ b/src/legacy/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/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
similarity index 91%
rename from src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
index 0004f4210..ed38b5bc8 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
+++ b/src/legacy/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/legacy/java/com/sk89q/worldedit/blocks/NoteBlock.java
similarity index 87%
rename from src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/NoteBlock.java
index 19d3dc150..0f5c819e3 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java
+++ b/src/legacy/java/com/sk89q/worldedit/blocks/NoteBlock.java
@@ -1,125 +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 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;
-
-/**
- * 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) throws DataException {
- 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 DataException("'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 92%
rename from src/main/java/com/sk89q/worldedit/blocks/SignBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java
index 8afff7001..e4d36c0d2 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java
+++ b/src/legacy/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/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java
similarity index 91%
rename from src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java
rename to src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java
index 02ab5ac6e..ac62da26c 100644
--- a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java
+++ b/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java
@@ -1,196 +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 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;
-
-/**
- * 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) throws DataException {
- 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 DataException("'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();
+ }
+ }
+}
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 @@
+
+
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..6f959e81a 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 int array tag,
+ * then an empty array will be returned.
+ *
+ * @param key the key
+ * @return an int array
+ */
+ public int[] getIntArray(String key) {
+ Tag tag = value.get(key);
+ if (tag instanceof IntArrayTag) {
+ return ((IntArrayTag) tag).getValue();
+ } else {
+ return new int[0];
+ }
+ }
+
+ /**
+ * Get an int named with the given key.
+ *
+ * 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 int
+ */
+ public int getInt(String key) {
+ Tag tag = value.get(key);
+ if (tag instanceof IntTag) {
+ return ((IntTag) tag).getValue();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * 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 int
+ */
+ public int asInt(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..187995a6b
--- /dev/null
+++ b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java
@@ -0,0 +1,214 @@
+/*
+ * 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 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.
+ *
+ * @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..4125b43ee 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 extends Tag> 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 extends Tag> type, List extends Tag> 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 extends Tag> type, List extends Tag> 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 int array tag,
+ * then an empty array will be returned.
+ *
+ * @param index the index
+ * @return an int array
+ */
+ public int[] getIntArray(int index) {
+ Tag tag = getIfExists(index);
+ if (tag instanceof IntArrayTag) {
+ return ((IntArrayTag) tag).getValue();
+ } else {
+ return new int[0];
+ }
+ }
+
+ /**
+ * Get an int named with the given index.
+ *
+ * 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 int
+ */
+ public int getInt(int index) {
+ Tag tag = getIfExists(index);
+ if (tag instanceof IntTag) {
+ return ((IntTag) tag).getValue();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * 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 int
+ */
+ public int asInt(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 extends Tag> type;
+ private final List entries;
+
+ /**
+ * Create a new instance.
+ *
+ * @param type of tag contained in this list
+ */
+ ListTagBuilder(Class extends Tag> 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 extends Tag> 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 extends Tag> 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 extends Tag> 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/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/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 extends Tag> 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 extends Tag> 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 extends Tag> 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..e0d7d3f4b 100644
--- a/src/main/java/com/sk89q/jnbt/Tag.java
+++ b/src/main/java/com/sk89q/jnbt/Tag.java
@@ -20,32 +20,35 @@
package com.sk89q.jnbt;
/**
- * 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) {
+ if (name == null) {
+ 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/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java
index a641f0089..f97f002ea 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;
@@ -69,12 +71,12 @@ 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;
import com.sk89q.worldedit.world.World;
+import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable;
import java.util.*;
@@ -376,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);
@@ -581,6 +593,12 @@ public class EditSession implements Extent {
return getBlock(position).isAir() && setBlock(position, block);
}
+ @Override
+ @Nullable
+ public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) {
+ return bypassNone.createEntity(location, entity);
+ }
+
/**
* Insert a contrived block change into the history.
*
@@ -637,6 +655,16 @@ public class EditSession implements Extent {
return getWorld().getMaximumPoint();
}
+ @Override
+ public List extends Entity> getEntities(Region region) {
+ return bypassNone.getEntities(region);
+ }
+
+ @Override
+ public List extends Entity> getEntities() {
+ return bypassNone.getEntities();
+ }
+
/**
* Finish off the queue.
*/
@@ -1148,6 +1176,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));
}
@@ -2230,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();
@@ -2243,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/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java
index df38b58a5..0bf0bfeb3 100644
--- a/src/main/java/com/sk89q/worldedit/LocalSession.java
+++ b/src/main/java/com/sk89q/worldedit/LocalSession.java
@@ -38,11 +38,17 @@ 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;
-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
@@ -62,7 +68,7 @@ public class LocalSession {
private boolean placeAtPos1 = false;
private LinkedList history = new LinkedList();
private int historyPointer = 0;
- private CuboidClipboard clipboard;
+ private ClipboardHolder clipboard;
private boolean toolControl = true;
private boolean superPickaxe = false;
private BlockTool pickaxeMode = new SinglePickaxe();
@@ -324,9 +330,9 @@ public class LocalSession {
* Gets the clipboard.
*
* @return clipboard, may be null
- * @throws EmptyClipboardException
+ * @throws EmptyClipboardException thrown if no clipboard is set
*/
- public CuboidClipboard getClipboard() throws EmptyClipboardException {
+ public ClipboardHolder getClipboard() throws EmptyClipboardException {
if (clipboard == null) {
throw new EmptyClipboardException();
}
@@ -336,9 +342,11 @@ 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 void setClipboard(CuboidClipboard clipboard) {
+ public void setClipboard(@Nullable ClipboardHolder clipboard) {
this.clipboard = clipboard;
}
diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java
index 9dd3498cb..ae1112b95 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.
@@ -35,140 +33,11 @@ import java.util.Random;
@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() {
- }
- }
-
- /**
- * @deprecated Don't use this anymore. It will be removed
- */
- @SuppressWarnings("ProtectedField")
- @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/Vector.java b/src/main/java/com/sk89q/worldedit/Vector.java
index c028c5797..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;
@@ -652,6 +651,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.toDegrees(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) Math.toDegrees(((t + _2pi) % _2pi));
+ }
+
/**
* Get a block point from a point.
*
@@ -792,4 +825,5 @@ public class Vector implements Comparable {
(v1.z + v2.z) / 2
);
}
+
}
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/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java
index 1a0d25a5e..2e3a4d2df 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;
@@ -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;
@@ -84,13 +89,14 @@ 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");
getVersion();
+ BundledBlockData.getInstance(); // Load block registry
}
private WorldEdit() {
@@ -132,33 +138,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 +217,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 +226,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 +237,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 +250,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 +264,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 +273,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 +282,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 +296,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 +305,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 +318,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/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/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/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/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/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java
index f954e26d8..1ce10523e 100644
--- a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java
@@ -22,17 +22,30 @@ 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.LocalWorld.KillFlags;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.LocalConfiguration;
+import com.sk89q.worldedit.LocalSession;
+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.command.util.CreatureButcher;
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.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
@@ -117,32 +130,27 @@ 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();
- CuboidClipboard clipboard = session.getClipboard();
-
- if (clipboard == null) {
- player.printError("Copy something first.");
- return;
- }
-
- Vector size = clipboard.getSize();
+ 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, usingOrigin), "worldedit.brush.clipboard");
player.print("Clipboard brush shape equipped.");
}
@@ -220,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 {
@@ -245,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/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java
index ffc765095..a5980cdc2 100644
--- a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java
@@ -20,19 +20,32 @@
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.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.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;
+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;
-import com.sk89q.worldedit.world.World;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
@@ -57,87 +70,63 @@ 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, @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);
+ public void copy(Player player, LocalSession session, EditSession editSession,
+ @Selection Region region, @Switch('e') boolean copyEntities,
+ @Switch('m') Mask mask) throws WorldEditException {
- 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);
+ 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.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
- if (copyEntities) {
- for (LocalEntity entity : player.getWorld().getEntities(region)) {
- clipboard.storeEntity(entity);
- }
- }
-
- session.setClipboard(clipboard);
-
- player.print("Block(s) copied.");
+ player.print(region.getArea() + " block(s) were copied.");
}
@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, @Optional("air") BaseBlock block, @Switch('e') boolean copyEntities) throws WorldEditException {
- World world = player.getWorld();
+ public void cut(Player player, LocalSession session, EditSession editSession,
+ @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities,
+ @Switch('m') Mask mask) throws WorldEditException {
- 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);
+ 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.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
- if (copyEntities) {
- LocalEntity[] entities = world.getEntities(region);
- for (LocalEntity entity : entities) {
- clipboard.storeEntity(entity);
- }
- world.killEntities(entities);
- }
-
- session.setClipboard(clipboard);
-
- editSession.setBlocks(region, block);
- player.print("Block(s) cut.");
+ player.print(region.getArea() + " block(s) were copied.");
}
@Command(
@@ -156,79 +145,76 @@ 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');
+ ClipboardHolder holder = session.getClipboard();
+ Clipboard clipboard = holder.getClipboard();
+ Region region = clipboard.getRegion();
- CuboidClipboard clipboard = session.getClipboard();
+ Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player);
+ Operation operation = holder
+ .createPaste(editSession, editSession.getWorld().getWorldData())
+ .to(to)
+ .ignoreAirBlocks(ignoreAirBlocks)
+ .build();
+ Operations.completeLegacy(operation);
- 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) {
+ 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);
}
@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 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, 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(-(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.");
}
@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 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,
+ @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(
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/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/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java
index 2b0d25526..67e8ba20f 100644
--- a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java
@@ -19,18 +19,42 @@
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.FilenameException;
+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 com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
+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.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;
+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;
@@ -39,6 +63,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;
/**
@@ -52,113 +77,94 @@ 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"
)
- @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) // TODO: Remove 'clipboard' perm
- public void load(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
+ @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();
- 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");
+ File f = worldEdit.getSafeOpenFile(player, dir, filename, "schematic", "schematic");
if (!f.exists()) {
- player.printError("Schematic " + fileName + " does not exist!");
+ player.printError("Schematic " + filename + " does not exist!");
return;
}
- SchematicFormat format = formatName == null ? null : SchematicFormat.getFormat(formatName);
- if (format == null) {
- format = SchematicFormat.getFormat(f);
- }
-
+ ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
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;
- }
-
+ Closer closer = Closer.create();
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.");
+ player.printError("Clipboard file 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");
+ 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 (DataException e) {
- player.printError("Load error: " + e.getMessage());
} 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"
)
- @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 {
-
+ @Deprecated
+ @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" })
+ public void save(Player player, LocalSession session, @Optional("schematic") String formatName, String filename) throws CommandException, WorldEditException {
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;
- }
+ ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
+ if (format == null) {
+ player.printError("Unknown schematic format: " + formatName);
+ return;
}
+ ClipboardHolder holder = session.getClipboard();
+ Clipboard clipboard = holder.getClipboard();
+ Transform transform = holder.getTransform();
+ Clipboard target;
+
+ // If we have a transform, bake it into the copy
+ if (!transform.isIdentity()) {
+ 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;
+ }
+
+ Closer closer = Closer.create();
try {
// Create parent directories
File parent = f.getParentFile();
@@ -168,13 +174,20 @@ public class SchematicCommands {
}
}
- format.save(session.getClipboard(), f);
- WorldEdit.logger.info(player.getName() + " saved " + f.getCanonicalPath());
+ FileOutputStream fos = closer.register(new FileOutputStream(f));
+ BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
+ ClipboardWriter writer = closer.register(format.getWriter(bos));
+ writer.write(target, holder.getWorldData());
+ log.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());
+ log.log(Level.WARNING, "Failed to write a saved clipboard", e);
+ } finally {
+ try {
+ closer.close();
+ } catch (IOException ignored) {
+ }
}
}
@@ -215,13 +228,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(", ");
}
@@ -292,9 +305,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/command/SelectionCommands.java b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
index ba5144f9e..4d8d165dc 100644
--- a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
@@ -21,9 +21,9 @@ 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.CuboidClipboard;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
@@ -33,6 +33,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockType;
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;
@@ -43,6 +44,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;
@@ -582,15 +584,16 @@ 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();
- Vector offset = clipboard.getOffset();
+ ClipboardHolder holder = session.getClipboard();
+ Clipboard clipboard = holder.getClipboard();
+ Region region = clipboard.getRegion();
+ Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint());
+ Vector origin = clipboard.getOrigin();
- player.print("Size: " + size);
- player.print("Offset: " + offset);
+ player.print("Cuboid dimensions (max - min): " + size);
+ player.print("Offset: " + origin);
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;
}
@@ -608,8 +611,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());
}
@@ -653,7 +655,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');
@@ -661,13 +663,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/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 extends Entity> 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 extends Entity> 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 extends Entity> 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 extends Entity> 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/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/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 extends Entity> 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/tool/brush/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java
index ef5fffbcc..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
@@ -19,24 +19,41 @@
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.operation.Operation;
+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 CuboidClipboard clipboard;
- private boolean noAir;
+ private ClipboardHolder holder;
+ private boolean ignoreAirBlocks;
+ private boolean usingOrigin;
- public ClipboardBrush(CuboidClipboard clipboard, boolean noAir) {
- this.clipboard = clipboard;
- this.noAir = noAir;
+ public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin) {
+ this.holder = holder;
+ this.ignoreAirBlocks = ignoreAirBlocks;
+ this.usingOrigin = usingOrigin;
}
+ @Override
public void build(EditSession editSession, Vector pos, Pattern mat, double size) throws MaxChangedBlocksException {
- clipboard.place(editSession, pos.subtract(clipboard.getSize().divide(2)), noAir);
+ Clipboard clipboard = holder.getClipboard();
+ Region region = clipboard.getRegion();
+ Vector centerOffset = region.getCenter().subtract(clipboard.getOrigin());
+
+ Operation operation = holder
+ .createPaste(editSession, editSession.getWorld().getWorldData())
+ .to(usingOrigin ? pos : pos.subtract(centerOffset))
+ .ignoreAirBlocks(ignoreAirBlocks)
+ .build();
+
+ Operations.completeLegacy(operation);
}
}
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 2cb248a69..4f6c40731 100644
--- a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java
+++ b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java
@@ -20,14 +20,8 @@
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;
/**
@@ -35,52 +29,43 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class BaseEntity implements NbtValued {
+ private String id;
private CompoundTag nbtData;
/**
- * Create a new entity with the given entity ID.
+ * Create a new base entity.
*
- * @param id the ID of the entity, which determines its type
+ * @param id the entity type ID
+ * @param nbtData NBT data
+ */
+ public BaseEntity(String id, CompoundTag nbtData) {
+ setTypeId(id);
+ setNbtData(nbtData);
+ }
+
+ /**
+ * Create a new base entity with no NBT data.
+ *
+ * @param id the entity type ID
*/
public BaseEntity(String id) {
- checkNotNull(id);
- Map map = new HashMap();
- map.put("id", new StringTag("id", id));
- this.nbtData = new CompoundTag("", map);
+ setTypeId(id);
}
/**
- * Create a new entity with the given NBT data.
+ * Make a clone of a {@link BaseEntity}.
*
- * @param nbtData the NBT data
+ * @param other the object to clone
*/
- 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 "";
- }
+ public BaseEntity(BaseEntity other) {
+ checkNotNull(other);
+ setTypeId(other.getTypeId());
+ setNbtData(other.getNbtData());
}
@Override
public boolean hasNbtData() {
- return getNbtData() != null;
+ return true;
}
@Override
@@ -89,9 +74,28 @@ public class BaseEntity implements NbtValued {
}
@Override
- public void setNbtData(CompoundTag nbtData) throws DataException {
+ 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 950557bc3..4224e5de7 100644
--- a/src/main/java/com/sk89q/worldedit/entity/Entity.java
+++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java
@@ -19,13 +19,11 @@
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.Faceted;
import com.sk89q.worldedit.util.Location;
-import com.sk89q.worldedit.world.World;
+
+import javax.annotation.Nullable;
/**
* A reference to an instance of an entity that exists in an {@link Extent}
@@ -37,138 +35,15 @@ import com.sk89q.worldedit.world.World;
* can then be used to spawn new instances of that particular entity
* description.
*/
-public interface Entity {
+public interface Entity extends Faceted {
/**
- * 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.
+ * Get a copy of the entity's state.
*
- * @param searchPos search position
+ * @return the entity's state or null if one cannot be gotten
*/
- 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();
+ @Nullable
+ BaseEntity getState();
/**
* Get the location of this entity.
@@ -178,57 +53,17 @@ public interface Entity {
Location getLocation();
/**
- * Get the actor's position.
- *
- * If the actor has no permission, then return a dummy location.
+ * Get the extent that this entity is on.
*
- * @return the actor's position
+ * @return the extent
*/
- WorldVector getPosition();
+ Extent getExtent();
/**
- * Get the player's view pitch.
+ * Remove this entity from it container.
*
- * @return pitch
+ * @return true if removal was successful
*/
- 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.
- *
- * @return the world
- */
- World getWorld();
+ 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 0098dc2f4..c5e2e333e 100644
--- a/src/main/java/com/sk89q/worldedit/entity/Player.java
+++ b/src/main/java/com/sk89q/worldedit/entity/Player.java
@@ -20,16 +20,27 @@
package com.sk89q.worldedit.entity;
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.
*
@@ -81,4 +92,182 @@ public interface Player extends Entity, Actor {
*/
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/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();
+
+}
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/EntityType.java b/src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java
similarity index 74%
rename from src/main/java/com/sk89q/worldedit/EntityType.java
rename to src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java
index 4b4f83438..6f288a00f 100644
--- a/src/main/java/com/sk89q/worldedit/EntityType.java
+++ b/src/main/java/com/sk89q/worldedit/entity/metadata/Tameable.java
@@ -1,37 +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;
-
-/**
- * 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.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/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 77%
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..2d697fbbb 100644
--- a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java
+++ b/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java
@@ -17,19 +17,32 @@
* 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.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));
@@ -135,7 +149,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 86%
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 1d4f66d35..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,16 +17,18 @@
* 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;
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/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..dd3a487af 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.
*/
@@ -114,6 +114,7 @@ public class ParserContext {
*/
public void setWorld(@Nullable World world) {
this.world = world;
+ setExtent(world);
}
/**
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 9e4c9843c..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,26 +19,38 @@
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;
import java.io.File;
-import static com.google.common.base.Preconditions.checkNotNull;
-
/**
* An abstract implementation of both a {@link Actor} and a {@link Player}
* that is intended for implementations of WorldEdit to use to wrap
* players that make use of WorldEdit.
*/
-public abstract class AbstractPlayerActor implements Actor, Player {
+public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
+
+ @Override
+ public final Extent getExtent() {
+ return getWorld();
+ }
/**
* Returns direction according to rotation. May return null.
@@ -468,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/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/extension/platform/PlayerProxy.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java
index b2569490f..b1d8979aa 100644
--- a/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java
@@ -21,12 +21,15 @@ package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldVector;
+import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.inventory.BlockBag;
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 {
@@ -67,6 +70,11 @@ class PlayerProxy extends AbstractPlayerActor {
return basePlayer.getName();
}
+ @Override
+ public BaseEntity getState() {
+ throw new UnsupportedOperationException("Can't getState() on a player");
+ }
+
@Override
public Location getLocation() {
return basePlayer.getLocation();
@@ -131,4 +139,10 @@ class PlayerProxy extends AbstractPlayerActor {
public void dispatchCUIEvent(CUIEvent event) {
cuiActor.dispatchCUIEvent(event);
}
+
+ @Nullable
+ @Override
+ public T getFacet(Class extends T> cls) {
+ return basePlayer.getFacet(cls);
+ }
}
diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java
index b9c4c1158..7a1bd25f9 100644
--- a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java
+++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java
@@ -20,13 +20,21 @@
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;
+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 com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable;
+import java.util.List;
+
import static com.google.common.base.Preconditions.checkNotNull;
/**
@@ -70,6 +78,32 @@ 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 extends Entity> getEntities() {
+ return extent.getEntities();
+ }
+
+ @Override
+ public List extends Entity> getEntities(Region region) {
+ 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/ChangeSetExtent.java b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java
index 87dfeac3d..84af07ab3 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,71 @@ 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 extends Entity> getEntities() {
+ return wrapEntities(super.getEntities());
+ }
+
+ @Override
+ public List extends Entity> getEntities(Region region) {
+ return wrapEntities(super.getEntities(region));
+ }
+
+ private List extends Entity> wrapEntities(List extends Entity> 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;
+ }
+
+ @Nullable
+ @Override
+ public T getFacet(Class extends T> cls) {
+ return entity.getFacet(cls);
+ }
+ }
}
diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java
index 34d86d298..51ae4fc84 100644
--- a/src/main/java/com/sk89q/worldedit/extent/Extent.java
+++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java
@@ -20,6 +20,13 @@
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 com.sk89q.worldedit.regions.Region;
+
+import javax.annotation.Nullable;
+import java.util.List;
/**
* A world, portion of a world, clipboard, or other object that can have blocks
@@ -50,4 +57,35 @@ 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 extends Entity> getEntities(Region region);
+
+ /**
+ * 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 extends Entity> 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/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 f291bc2f2..1979bdaaf 100644
--- a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java
+++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java
@@ -20,11 +20,19 @@
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;
+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;
+import java.util.List;
/**
* An extent that returns air blocks for all blocks and does not
@@ -44,6 +52,22 @@ public class NullExtent implements Extent {
return nullPoint;
}
+ @Override
+ public List getEntities(Region region) {
+ return Collections.emptyList();
+ }
+
+ @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);
@@ -54,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
new file mode 100644
index 000000000..1b819e036
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java
@@ -0,0 +1,187 @@
+/*
+ * 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.Vector2D;
+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 com.sk89q.worldedit.world.biome.BaseBiome;
+
+import javax.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.Collections;
+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 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);
+ this.region = region.clone();
+ this.origin = region.getMinimumPoint();
+
+ Vector dimensions = getDimensions();
+ blocks = new BaseBlock[dimensions.getBlockX()][dimensions.getBlockY()][dimensions.getBlockZ()];
+ }
+
+ @Override
+ public Region getRegion() {
+ return region.clone();
+ }
+
+ @Override
+ public Vector getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public void setOrigin(Vector origin) {
+ this.origin = origin;
+ }
+
+ @Override
+ public 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 extends Entity> 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 extends Entity> getEntities() {
+ return Collections.unmodifiableList(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;
+ }
+ }
+
+ @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() {
+ 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);
+ }
+
+ @Nullable
+ @Override
+ public T getFacet(Class extends T> cls) {
+ return null;
+ }
+ }
+
+}
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..e68d5b2c0
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.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.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 dimensions of the copy, which is at minimum (1, 1, 1).
+ *
+ * @return the dimensions
+ */
+ Vector getDimensions();
+
+ /**
+ * Get the origin point from which the copy was made from.
+ *
+ * @return the origin
+ */
+ 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/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/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..bae3ae753
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java
@@ -0,0 +1,278 @@
+/*
+ * 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.DoubleTag;
+import com.sk89q.jnbt.FloatTag;
+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.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 com.sk89q.worldedit.world.storage.NBTConversions;
+
+import javax.annotation.Nullable;
+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 = requireTag(schematic, "Materials", StringTag.class).getValue();
+ if (!materials.equals("Alpha")) {
+ throw new IOException("Schematic file is not an Alpha schematic");
+ }
+
+ // ====================================================================
+ // Metadata
+ // ====================================================================
+
+ Vector origin;
+ Region region;
+
+ // Get information
+ 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 = 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 = 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);
+ 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));
+ }
+
+ // ====================================================================
+ // Blocks
+ // ====================================================================
+
+ // Get blocks
+ 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 = requireTag(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 = requireTag(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++;
+ }
+ }
+ }
+ }
+
+ // ====================================================================
+ // Entities
+ // ====================================================================
+
+ try {
+ List entityTags = requireTag(schematic, "Entities", ListTag.class).getValue();
+
+ for (Tag tag : entityTags) {
+ if (tag instanceof CompoundTag) {
+ CompoundTag compound = (CompoundTag) tag;
+ String id = compound.getString("id");
+ Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation"));
+
+ if (!id.isEmpty()) {
+ BaseEntity state = new BaseEntity(id, compound);
+ clipboard.createEntity(location, state);
+ }
+ }
+ }
+ } catch (IOException ignored) { // No entities? No problem
+ }
+
+ return clipboard;
+ }
+
+ private static T requireTag(Map items, String key, Class