Add a new block metadata framework and fix //rotate and //flip.

Remove the previous Mapping interfaces.
This commit is contained in:
sk89q 2014-07-09 14:14:17 -07:00
parent 22dceb5614
commit 56b349ead8
29 changed files with 7425 additions and 319 deletions

View File

@ -19,24 +19,67 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EntityType; import com.sk89q.worldedit.EntityType;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.*; import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.blocks.ContainerBlock; import com.sk89q.worldedit.blocks.ContainerBlock;
import com.sk89q.worldedit.blocks.FurnaceBlock;
import com.sk89q.worldedit.blocks.LazyBlock;
import com.sk89q.worldedit.blocks.MobSpawnerBlock;
import com.sk89q.worldedit.blocks.NoteBlock; import com.sk89q.worldedit.blocks.NoteBlock;
import com.sk89q.worldedit.blocks.SignBlock;
import com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.bukkit.entity.BukkitEntity; import com.sk89q.worldedit.bukkit.entity.BukkitEntity;
import com.sk89q.worldedit.entity.*; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.mapping.NullResolver; import com.sk89q.worldedit.world.registry.LegacyWorldData;
import com.sk89q.worldedit.world.mapping.Resolver; import com.sk89q.worldedit.world.registry.WorldData;
import org.bukkit.*; import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.*; import org.bukkit.Material;
import org.bukkit.SkullType;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Furnace;
import org.bukkit.block.Sign;
import org.bukkit.block.Skull;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.*; import org.bukkit.entity.Ambient;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Golem;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Villager;
import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.DoubleChestInventory;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -49,7 +92,14 @@ import java.io.InputStream;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -1180,6 +1230,11 @@ public class BukkitWorld extends LocalWorld {
return true; return true;
} }
@Override
public WorldData getWorldData() {
return LegacyWorldData.getInstance();
}
@Override @Override
public void simulateBlockMine(Vector pt) { public void simulateBlockMine(Vector pt) {
getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally();
@ -1280,38 +1335,6 @@ public class BukkitWorld extends LocalWorld {
return super.setBlock(pt, block, notifyAdjacent); return super.setBlock(pt, block, notifyAdjacent);
} }
@Override
public Resolver<BaseBlock> getBlockMapping() {
return new NullResolver<BaseBlock>();
}
@Override
public Resolver<BaseEntity> getEntityMapping() {
return new NullResolver<BaseEntity>();
}
@Nullable
@Override
public <T> T getMetaData(BaseBlock block, Class<T> metaDataClass) {
return null;
}
@Nullable
@Override
public <T> T getMetaData(com.sk89q.worldedit.entity.Entity entity, Class<T> metaDataClass) {
if (entity instanceof com.sk89q.worldedit.bukkit.BukkitEntity) {
return ((com.sk89q.worldedit.bukkit.BukkitEntity) entity).getMetaData(metaDataClass);
}
return null;
}
@Nullable
@Override
public <T> T getMetaData(BaseEntity entity, Class<T> metaDataClass) {
return null;
}
/** /**
* @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)} * @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)}
*/ */

View File

@ -20,7 +20,13 @@
package com.sk89q.worldedit.forge; package com.sk89q.worldedit.forge;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EntityType;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.blocks.LazyBlock;
@ -30,14 +36,22 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.mapping.NullResolver; import com.sk89q.worldedit.world.registry.LegacyWorldData;
import com.sk89q.worldedit.world.mapping.Resolver; import com.sk89q.worldedit.world.registry.WorldData;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.entity.EntityHanging; import net.minecraft.entity.EntityHanging;
import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.IProjectile; import net.minecraft.entity.IProjectile;
import net.minecraft.entity.item.*; import net.minecraft.entity.item.EntityBoat;
import net.minecraft.entity.item.EntityEnderEye;
import net.minecraft.entity.item.EntityFallingSand;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.item.EntityItemFrame;
import net.minecraft.entity.item.EntityMinecart;
import net.minecraft.entity.item.EntityPainting;
import net.minecraft.entity.item.EntityTNTPrimed;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.monster.EntityGolem; import net.minecraft.entity.monster.EntityGolem;
import net.minecraft.entity.passive.EntityAmbientCreature; import net.minecraft.entity.passive.EntityAmbientCreature;
import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.passive.EntityAnimal;
@ -432,6 +446,11 @@ public class ForgeWorld extends AbstractWorld {
return false; return false;
} }
@Override
public WorldData getWorldData() {
return LegacyWorldData.getInstance();
}
@Override @Override
public boolean isValidBlockType(int id) { public boolean isValidBlockType(int id) {
return (id == 0) || (net.minecraft.block.Block.blocksList[id] != null); return (id == 0) || (net.minecraft.block.Block.blocksList[id] != null);
@ -480,34 +499,6 @@ public class ForgeWorld extends AbstractWorld {
} }
} }
@Override
public Resolver<BaseBlock> getBlockMapping() {
return new NullResolver<BaseBlock>();
}
@Override
public Resolver<BaseEntity> getEntityMapping() {
return new NullResolver<BaseEntity>();
}
@Nullable
@Override
public <T> T getMetaData(BaseBlock block, Class<T> metaDataClass) {
return null;
}
@Nullable
@Override
public <T> T getMetaData(Entity entity, Class<T> metaDataClass) {
return null;
}
@Nullable
@Override
public <T> T getMetaData(BaseEntity entity, Class<T> metaDataClass) {
return null;
}
@Override @Override
public List<Entity> getEntities() { public List<Entity> getEntities() {
List<Entity> entities = new ArrayList<Entity>(); List<Entity> entities = new ArrayList<Entity>();

View File

@ -29,7 +29,6 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe;
import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.Masks;
@ -44,7 +43,12 @@ import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.snapshot.Snapshot; 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 * An instance of this represents the WorldEdit session of a user. A session
@ -326,7 +330,7 @@ public class LocalSession {
* Gets the clipboard. * Gets the clipboard.
* *
* @return clipboard, may be null * @return clipboard, may be null
* @throws EmptyClipboardException * @throws EmptyClipboardException thrown if no clipboard is set
*/ */
public ClipboardHolder getClipboard() throws EmptyClipboardException { public ClipboardHolder getClipboard() throws EmptyClipboardException {
if (clipboard == null) { if (clipboard == null) {
@ -338,10 +342,12 @@ public class LocalSession {
/** /**
* Sets the clipboard. * Sets the clipboard.
* *
* @param clipboard * <p>Pass {@code null} to clear the clipboard.</p>
*
* @param clipboard the clipboard, or null if the clipboard is to be cleared
*/ */
public ClipboardHolder replaceClipboard(Clipboard clipboard) { public void setClipboard(@Nullable ClipboardHolder clipboard) {
return this.clipboard = new ClipboardHolder(clipboard); this.clipboard = clipboard;
} }
/** /**

View File

@ -46,9 +46,14 @@ import com.sk89q.worldedit.session.SessionManager;
import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.logging.WorldEditPrefixHandler; import com.sk89q.worldedit.util.logging.WorldEditPrefixHandler;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import javax.script.ScriptException; 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.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -91,6 +96,7 @@ public class WorldEdit {
static { static {
WorldEditPrefixHandler.register("com.sk89q.worldedit"); WorldEditPrefixHandler.register("com.sk89q.worldedit");
getVersion(); getVersion();
BundledBlockData.getInstance(); // Load block registry
} }
private WorldEdit() { private WorldEdit() {

View File

@ -0,0 +1,71 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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();
}

View File

@ -32,9 +32,9 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy; 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.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
@ -92,7 +92,7 @@ public class ClipboardCommands {
copy.setSourceMask(mask); copy.setSourceMask(mask);
} }
Operations.completeLegacy(copy); Operations.completeLegacy(copy);
session.replaceClipboard(clipboard); session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
player.print(region.getArea() + " block(s) were copied."); player.print(region.getArea() + " block(s) were copied.");
} }
@ -124,7 +124,7 @@ public class ClipboardCommands {
copy.setSourceMask(mask); copy.setSourceMask(mask);
} }
Operations.completeLegacy(copy); Operations.completeLegacy(copy);
session.replaceClipboard(clipboard); session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
player.print(region.getArea() + " block(s) were copied."); player.print(region.getArea() + " block(s) were copied.");
} }
@ -154,12 +154,12 @@ public class ClipboardCommands {
Region region = clipboard.getRegion(); Region region = clipboard.getRegion();
Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player);
ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, region, clipboard.getOrigin(), editSession, to); Operation operation = holder
copy.setTransform(holder.getTransform()); .createPaste(editSession, editSession.getWorld().getWorldData())
if (ignoreAirBlocks) { .to(to)
copy.setSourceMask(new ExistingBlockMask(clipboard)); .ignoreAirBlocks(ignoreAirBlocks)
} .build();
Operations.completeLegacy(copy); Operations.completeLegacy(operation);
if (selectPasted) { if (selectPasted) {
Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint())); Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint()));
@ -169,7 +169,7 @@ public class ClipboardCommands {
selector.explainRegionAdjust(player, session); selector.explainRegionAdjust(player, session);
} }
player.print("The clipboard has been pasted at " + to.add(region.getMinimumPoint())); player.print("The clipboard has been pasted at " + to);
} }
@Command( @Command(
@ -252,7 +252,7 @@ public class ClipboardCommands {
) )
@CommandPermissions("worldedit.clipboard.clear") @CommandPermissions("worldedit.clipboard.clear")
public void clearClipboard(Player player, LocalSession session, EditSession editSession) throws WorldEditException { public void clearClipboard(Player player, LocalSession session, EditSession editSession) throws WorldEditException {
session.replaceClipboard(null); session.setClipboard(null);
player.print("Clipboard cleared."); player.print("Clipboard cleared.");
} }
} }

View File

@ -23,8 +23,7 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
@ -33,11 +32,11 @@ import com.sk89q.worldedit.session.ClipboardHolder;
public class ClipboardBrush implements Brush { public class ClipboardBrush implements Brush {
private ClipboardHolder holder; private ClipboardHolder holder;
private boolean noAir; private boolean ignoreAirBlocks;
public ClipboardBrush(ClipboardHolder holder, boolean noAir) { public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks) {
this.holder = holder; this.holder = holder;
this.noAir = noAir; this.ignoreAirBlocks = ignoreAirBlocks;
} }
@Override @Override
@ -45,12 +44,14 @@ public class ClipboardBrush implements Brush {
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion(); Region region = clipboard.getRegion();
Vector centerOffset = region.getCenter().subtract(clipboard.getOrigin()); Vector centerOffset = region.getCenter().subtract(clipboard.getOrigin());
ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, region, clipboard.getOrigin(), editSession, pos.subtract(centerOffset));
copy.setTransform(holder.getTransform()); Operation operation = holder
if (noAir) { .createPaste(editSession, editSession.getWorld().getWorldData())
copy.setSourceMask(new ExistingBlockMask(clipboard)); .to(pos.subtract(centerOffset))
} .ignoreAirBlocks(ignoreAirBlocks)
Operations.completeLegacy(copy); .build();
Operations.completeLegacy(operation);
} }
} }

View File

@ -0,0 +1,181 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.transform;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import com.sk89q.worldedit.world.registry.State;
import com.sk89q.worldedit.world.registry.StateValue;
import javax.annotation.Nullable;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Transforms blocks themselves (but not their position) according to a
* given transform.
*/
public class BlockTransformExtent extends AbstractDelegateExtent {
private static final double RIGHT_ANGLE = Math.toRadians(90);
private final Transform transform;
private final BlockRegistry blockRegistry;
/**
* Create a new instance.
*
* @param extent the extent
* @param blockRegistry the block registry used for block direction data
*/
public BlockTransformExtent(Extent extent, Transform transform, BlockRegistry blockRegistry) {
super(extent);
checkNotNull(transform);
checkNotNull(blockRegistry);
this.transform = transform;
this.blockRegistry = blockRegistry;
}
/**
* Get the transform.
*
* @return the transform
*/
public Transform getTransform() {
return transform;
}
/**
* Transform a block without making a copy.
*
* @param block the block
* @param reverse true to transform in the opposite direction
* @return the same block
*/
private BaseBlock transformBlock(BaseBlock block, boolean reverse) {
transform(block, reverse ? transform.inverse() : transform, blockRegistry);
return block;
}
@Override
public BaseBlock getBlock(Vector position) {
return transformBlock(super.getBlock(position), false);
}
@Override
public BaseBlock getLazyBlock(Vector position) {
return transformBlock(super.getLazyBlock(position), false);
}
@Override
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
return super.setBlock(location, transformBlock(new BaseBlock(block), true));
}
/**
* Transform the given block using the given transform.
*
* <p>The provided block is modified.</p>
*
* @param block the block
* @param transform the transform
* @param registry the registry
* @return the same block
*/
private static BaseBlock transform(BaseBlock block, Transform transform, BlockRegistry registry) {
return transform(block, transform, registry, block);
}
/**
* Transform the given block using the given transform.
*
* @param block the block
* @param transform the transform
* @param registry the registry
* @param changedBlock the block to change
* @return the changed block
*/
private static BaseBlock transform(BaseBlock block, Transform transform, BlockRegistry registry, BaseBlock changedBlock) {
checkNotNull(block);
checkNotNull(transform);
checkNotNull(registry);
Map<String, ? extends State> states = registry.getStates(block);
if (states == null) {
return changedBlock;
}
for (State state : states.values()) {
if (state.hasDirection()) {
StateValue value = state.getValue(block);
if (value != null && value.getDirection() != null) {
StateValue newValue = getNewStateValue(state, transform, value.getDirection());
if (newValue != null) {
newValue.set(changedBlock);
}
}
}
}
return changedBlock;
}
/**
* Get the new value with the transformed direction.
*
* @param state the state
* @param transform the transform
* @param oldDirection the old direction to transform
* @return a new state or null if none could be found
*/
@Nullable
private static StateValue getNewStateValue(State state, Transform transform, Vector oldDirection) {
Vector newDirection = transform.apply(oldDirection).normalize();
StateValue newValue = null;
double closest = -2;
boolean found = false;
for (StateValue v : state.valueMap().values()) {
if (v.getDirection() != null) {
double dot = v.getDirection().normalize().dot(newDirection);
if (dot >= closest) {
closest = dot;
newValue = v;
found = true;
}
}
}
if (found) {
return newValue;
} else {
return null;
}
}
}

View File

@ -19,7 +19,16 @@
package com.sk89q.worldedit.internal; package com.sk89q.worldedit.internal;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EntityType;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
@ -30,7 +39,7 @@ import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.mapping.Resolver; import com.sk89q.worldedit.world.registry.WorldData;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
@ -259,6 +268,11 @@ public class LocalWorldAdapter extends LocalWorld {
return world.queueBlockBreakEffect(server, position, blockId, priority); return world.queueBlockBreakEffect(server, position, blockId, priority);
} }
@Override
public WorldData getWorldData() {
return world.getWorldData();
}
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return world.equals(other); return world.equals(other);
@ -313,33 +327,6 @@ public class LocalWorldAdapter extends LocalWorld {
public Operation commit() { public Operation commit() {
return world.commit(); return world.commit();
} }
@Override
public Resolver<BaseBlock> getBlockMapping() {
return world.getBlockMapping();
}
@Override
public Resolver<BaseEntity> getEntityMapping() {
return world.getEntityMapping();
}
@Override
@Nullable
public <T> T getMetaData(BaseBlock block, Class<T> metaDataClass) {
return world.getMetaData(block, metaDataClass);
}
@Override
@Nullable
public <T> T getMetaData(Entity entity, Class<T> metaDataClass) {
return world.getMetaData(entity, metaDataClass);
}
@Override
@Nullable
public <T> T getMetaData(BaseEntity entity, Class<T> metaDataClass) {
return world.getMetaData(entity, metaDataClass);
}
@Override @Override
@Nullable @Nullable

View File

@ -24,6 +24,15 @@ package com.sk89q.worldedit.math;
*/ */
public final class MathUtils { public final class MathUtils {
/**
* Safe minimum, such that 1 / SAFE_MIN does not overflow.
* <p>
* In IEEE 754 arithmetic, this is also the smallest normalized number
* 2<sup>-1022</sup>. The value of this constant is from Apache Commons
* Math 2.2.
*/
public static final double SAFE_MIN = 0x1.0p-1022;
private MathUtils() { private MathUtils() {
} }

View File

@ -292,6 +292,10 @@ public class AffineTransform implements Transform {
vector.getX() * m20 + vector.getY() * m21 + vector.getZ() * m22 + m23); vector.getX() * m20 + vector.getY() * m21 + vector.getZ() * m22 + m23);
} }
public AffineTransform combine(AffineTransform other) {
return concatenate(other);
}
@Override @Override
public Transform combine(Transform other) { public Transform combine(Transform other) {
if (other instanceof AffineTransform) { if (other instanceof AffineTransform) {
@ -305,4 +309,6 @@ public class AffineTransform implements Transform {
public String toString() { public String toString() {
return String.format("Affine[%g %g %g %g, %g %g %g %g, %g %g %g %g]}", m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23); return String.format("Affine[%g %g %g %g, %g %g %g %g, %g %g %g %g]}", m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23);
} }
} }

View File

@ -19,13 +19,20 @@
package com.sk89q.worldedit.math.transform; package com.sk89q.worldedit.math.transform;
import com.google.common.base.Function;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
/** /**
* Makes a transformation of {@link Vector}s. * Makes a transformation of {@link Vector}s.
*/ */
public interface Transform extends Function<Vector, Vector> { public interface Transform {
/**
* Returns the result of applying the function to the input.
*
* @param input the input
* @return the result
*/
Vector apply(Vector input);
/** /**
* Create a new inverse transform. * Create a new inverse transform.

View File

@ -19,9 +19,11 @@
package com.sk89q.worldedit.session; package com.sk89q.worldedit.session;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Identity;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.registry.WorldData;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -30,6 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
public class ClipboardHolder { public class ClipboardHolder {
private final WorldData worldData;
private final Clipboard clipboard; private final Clipboard clipboard;
private Transform transform = new Identity(); private Transform transform = new Identity();
@ -37,10 +40,22 @@ public class ClipboardHolder {
* Create a new instance with the given clipboard. * Create a new instance with the given clipboard.
* *
* @param clipboard the clipboard * @param clipboard the clipboard
* @param worldData the mapping of blocks, entities, and so on
*/ */
public ClipboardHolder(Clipboard clipboard) { public ClipboardHolder(Clipboard clipboard, WorldData worldData) {
checkNotNull(clipboard); checkNotNull(clipboard);
checkNotNull(worldData);
this.clipboard = clipboard; this.clipboard = clipboard;
this.worldData = worldData;
}
/**
* Get the mapping used for blocks, entities, and so on.
*
* @return the mapping
*/
public WorldData getWorldData() {
return worldData;
} }
/** /**
@ -74,4 +89,13 @@ public class ClipboardHolder {
return transform; return transform;
} }
/**
* Create a builder for an operation to paste this clipboard.
*
* @return a builder
*/
public PasteBuilder createPaste(Extent targetExtent, WorldData targetWorldData) {
return new PasteBuilder(this, targetExtent, targetWorldData);
}
} }

View File

@ -0,0 +1,102 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.session;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.registry.WorldData;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Builds an operation to paste the contents of a clipboard.
*/
public class PasteBuilder {
private final Clipboard clipboard;
private final WorldData worldData;
private final Transform transform;
private final Extent targetExtent;
private final WorldData targetWorldData;
private Vector to = new Vector();
private boolean ignoreAirBlocks;
/**
* Create a new instance.
*
* @param holder the clipboard holder
* @param targetExtent
* @param targetWorldData
*/
PasteBuilder(ClipboardHolder holder, Extent targetExtent, WorldData targetWorldData) {
checkNotNull(holder);
checkNotNull(targetExtent);
checkNotNull(targetWorldData);
this.clipboard = holder.getClipboard();
this.worldData = holder.getWorldData();
this.transform = holder.getTransform();
this.targetExtent = targetExtent;
this.targetWorldData = targetWorldData;
}
/**
* Set the target location.
*
* @param to the target location
* @return this builder instance
*/
public PasteBuilder to(Vector to) {
this.to = to;
return this;
}
/**
* Set whether air blocks in the source are skipped over when pasting.
*
* @return this builder instance
*/
public PasteBuilder ignoreAirBlocks(boolean ignoreAirBlocks) {
this.ignoreAirBlocks = ignoreAirBlocks;
return this;
}
/**
* Build the operation.
*
* @return the operation
*/
public Operation build() {
BlockTransformExtent extent = new BlockTransformExtent(clipboard, transform, targetWorldData.getBlockRegistry());
ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to);
copy.setTransform(transform);
if (ignoreAirBlocks) {
copy.setSourceMask(new ExistingBlockMask(clipboard));
}
return copy;
}
}

View File

@ -0,0 +1,49 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.sk89q.worldedit.Vector;
import java.lang.reflect.Type;
/**
* Deserializes {@code Vector}s for GSON.
*/
public class VectorAdapter implements JsonDeserializer<Vector> {
@Override
public Vector deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonArray jsonArray = json.getAsJsonArray();
if (jsonArray.size() != 3) {
throw new JsonParseException("Expected array of 3 length for Vector");
}
double x = jsonArray.get(0).getAsDouble();
double y = jsonArray.get(1).getAsDouble();
double z = jsonArray.get(2).getAsDouble();
return new Vector(x, y, z);
}
}

View File

@ -28,8 +28,8 @@ import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.mapping.NullResolver; import com.sk89q.worldedit.world.registry.LegacyWorldData;
import com.sk89q.worldedit.world.mapping.Resolver; import com.sk89q.worldedit.world.registry.WorldData;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
@ -94,6 +94,11 @@ public class NullWorld extends AbstractWorld {
return false; return false;
} }
@Override
public WorldData getWorldData() {
return LegacyWorldData.getInstance();
}
@Override @Override
public BaseBlock getBlock(Vector position) { public BaseBlock getBlock(Vector position) {
return new BaseBlock(BlockID.AIR); return new BaseBlock(BlockID.AIR);
@ -104,34 +109,6 @@ public class NullWorld extends AbstractWorld {
return new BaseBlock(BlockID.AIR); return new BaseBlock(BlockID.AIR);
} }
@Override
public Resolver<BaseBlock> getBlockMapping() {
return new NullResolver<BaseBlock>();
}
@Override
public Resolver<BaseEntity> getEntityMapping() {
return new NullResolver<BaseEntity>();
}
@Nullable
@Override
public <T> T getMetaData(BaseBlock block, Class<T> metaDataClass) {
return null;
}
@Nullable
@Override
public <T> T getMetaData(Entity entity, Class<T> metaDataClass) {
return null;
}
@Nullable
@Override
public <T> T getMetaData(BaseEntity entity, Class<T> metaDataClass) {
return null;
}
@Override @Override
public List<Entity> getEntities() { public List<Entity> getEntities() {
return Collections.emptyList(); return Collections.emptyList();

View File

@ -19,7 +19,16 @@
package com.sk89q.worldedit.world; package com.sk89q.worldedit.world;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EntityType;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
@ -28,12 +37,12 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.mapping.Mapping; import com.sk89q.worldedit.world.registry.WorldData;
/** /**
* Represents a world (dimension). * Represents a world (dimension).
*/ */
public interface World extends Extent, Mapping { public interface World extends Extent {
/** /**
* Get the name of the world. * Get the name of the world.
@ -346,6 +355,13 @@ public interface World extends Extent, Mapping {
*/ */
boolean queueBlockBreakEffect(Platform server, Vector position, int blockId, double priority); boolean queueBlockBreakEffect(Platform server, Vector position, int blockId, double priority);
/**
* Get the data for blocks and so on for this world.
*
* @return the world data
*/
WorldData getWorldData();
@Override @Override
boolean equals(Object other); boolean equals(Object other);

View File

@ -1,114 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.mapping;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.metadata.Tameable;
import javax.annotation.Nullable;
/**
* A mapping can create state objects (such as {@link BaseBlock})
* from implementation-independent identifiers (such as "minecraft.stone"),
* as well as perform the opposite task of retrieving
* the identifier for a given state object (whenever possible at least, because
* a mapping may not be compatible with a set of state objects that may have
* come from another implementation). In addition, a mapping may be able to
* retrieve a variety of metadata objects (such as {@link Tameable}) to
* describe a given state object.
* </p>
* However, it may be possible that a mapping be "dumb" and not be able to,
* for example, return a {@link Tameable} for a "Horse" entity, simply because
* it has not be implemented. Any code that queries a mapping must be
* aware of this and act accordingly.
*/
public interface Mapping {
/**
* Get the mapping for block identifiers.
*
* @return a block mapping
*/
Resolver<BaseBlock> getBlockMapping();
/**
* Get the mapping for entity identifiers.
*
* @return an entity mapping
*/
Resolver<BaseEntity> getEntityMapping();
/**
* Attempt to return an instance of the given class for the given block.
* For example, {@code getMetaData(block, Inventory.class)} might return
* an instance if the block happens to contain an inventory.
* </p>
* If the given block is not of the given class (i.e. a dirt block does
* not have an inventory) or if the information is simply not available,
* {@code null} will be returned.
* </p>
* Mutator methods on the returned instance should change the block.
*
* @param block the block
* @param metaDataClass the metadata class for the returned instance
* @param <T> the metadata class
* @return an instance of the given class, otherwise null
*/
@Nullable <T> T getMetaData(BaseBlock block, Class<T> metaDataClass);
/**
* Attempt to return an instance of the given class for the given entity.
* For example, {@code getMetaData(entity, Creature.class)} might return
* an instance if the entity happens to be a creature.
* </p>
* If the given entity is not of the given class (i.e. a painting is
* not a creature) or if the information is simply not available,
* {@code null} will be returned.
* </p>
* Mutator methods on the returned instance should change the entity.
*
* @param entity the entity
* @param metaDataClass the metadata class for the returned instance
* @param <T> the metadata class
* @return an instance of the given class, otherwise null
*/
@Nullable <T> T getMetaData(Entity entity, Class<T> metaDataClass);
/**
* Attempt to return an instance of the given class for the given entity.
* For example, {@code getMetaData(entity, Creature.class)} might return
* an instance if the entity happens to be a creature.
* </p>
* If the given entity is not of the given class (i.e. a painting is
* not a creature) or if the information is simply not available,
* {@code null} will be returned.
* </p>
* Mutator methods on the returned instance should change the entity.
*
* @param entity the entity
* @param metaDataClass the metadata class for the returned instance
* @param <T> the metadata class
* @return an instance of the given class, otherwise null
*/
@Nullable <T> T getMetaData(BaseEntity entity, Class<T> metaDataClass);
}

View File

@ -0,0 +1,69 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockMaterial;
import javax.annotation.Nullable;
import java.util.Map;
/**
* Provides information on blocks and provides methods to create them.
*/
public interface BlockRegistry {
/**
* Create a new block using its ID.
*
* @param id the id
* @return the block, which may be null if no block exists
*/
@Nullable
BaseBlock createFromId(String id);
/**
* Create a new block using its legacy numeric ID.
*
* @param id the id
* @return the block, which may be null if no block exists
*/
@Nullable
BaseBlock createFromId(int id);
/**
* Get the material for the given block.
*
* @param block the block
* @return the material, or null if the material information is not known
*/
@Nullable
BlockMaterial getMaterial(BaseBlock block);
/**
* Get an unmodifiable map of states for this block.
*
* @param block the block
* @return a map of states where the key is the state's ID
*/
@Nullable
Map<String, ? extends State> getStates(BaseBlock block);
}

View File

@ -0,0 +1,189 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockMaterial;
import com.sk89q.worldedit.util.gson.VectorAdapter;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import javax.annotation.Nullable;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Provides block data based on the built-in block database that is bundled
* with WorldEdit.
*
* <p>A new instance cannot be created. Use {@link #getInstance()} to get
* an instance.</p>
*
* <p>The data is read from a JSON file that is bundled with WorldEdit. If
* reading fails (which occurs when this class is first instantiated), then
* the methods will return {@code null}s for all blocks.</p>
*/
public class BundledBlockData {
private static final Logger log = Logger.getLogger(BundledBlockData.class.getCanonicalName());
private static final BundledBlockData INSTANCE = new BundledBlockData();
private final Map<String, BlockEntry> idMap = new HashMap<String, BlockEntry>();
private final TIntObjectMap<BlockEntry> legacyMap = new TIntObjectHashMap<BlockEntry>();
/**
* Create a new instance.
*/
private BundledBlockData() {
try {
loadFromResource();
} catch (IOException e) {
log.log(Level.WARNING, "Failed to load the built-in block registry", e);
}
}
/**
* Attempt to load the data from file.
*
* @throws IOException thrown on I/O error
*/
private void loadFromResource() throws IOException {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Vector.class, new VectorAdapter());
Gson gson = gsonBuilder.create();
URL url = BundledBlockData.class.getResource("blocks.json");
if (url == null) {
throw new IOException("Could not find blocks.json");
}
String data = Resources.toString(url, Charset.defaultCharset());
List<BlockEntry> entries = gson.fromJson(data, new TypeToken<List<BlockEntry>>() {}.getType());
for (BlockEntry entry : entries) {
entry.postDeserialization();
idMap.put(entry.id, entry);
legacyMap.put(entry.legacyId, entry);
}
}
/**
* Return the entry for the given block ID.
*
* @param id the ID
* @return the entry, or null
*/
@Nullable
private BlockEntry findById(String id) {
return idMap.get(id);
}
/**
* Return the entry for the given block legacy numeric ID.
*
* @param id the ID
* @return the entry, or null
*/
@Nullable
private BlockEntry findById(int id) {
return legacyMap.get(id);
}
/**
* Convert the given string ID to a legacy numeric ID.
*
* @param id the ID
* @return the legacy ID, which may be null if the block does not have a legacy ID
*/
@Nullable
public Integer toLegacyId(String id) {
BlockEntry entry = findById(id);
if (entry != null) {
return entry.legacyId;
} else {
return null;
}
}
/**
* Get the material properties for the given block.
*
* @param id the legacy numeric ID
* @return the material's properties, or null
*/
@Nullable
public BlockMaterial getMaterialById(int id) {
BlockEntry entry = findById(id);
if (entry != null) {
return entry.material;
} else {
return null;
}
}
/**
* Get the states for the given block.
*
* @param id the legacy numeric ID
* @return the block's states, or null if no information is available
*/
@Nullable
public Map<String, ? extends State> getStatesById(int id) {
BlockEntry entry = findById(id);
if (entry != null) {
return entry.states;
} else {
return null;
}
}
/**
* Get a singleton instance of this object.
*
* @return the instance
*/
public static BundledBlockData getInstance() {
return INSTANCE;
}
private static class BlockEntry {
private int legacyId;
private String id;
private String unlocalizedName;
private List<String> aliases;
private Map<String, SimpleState> states = new HashMap<String, SimpleState>();
private SimpleBlockMaterial material = new SimpleBlockMaterial();
void postDeserialization() {
for (SimpleState state : states.values()) {
state.postDeserialization();
}
}
}
}

View File

@ -0,0 +1,63 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockMaterial;
import javax.annotation.Nullable;
import java.util.Map;
/**
* A block registry that uses {@link BundledBlockData} to serve information
* about blocks.
*/
public class LegacyBlockRegistry implements BlockRegistry {
@Nullable
@Override
public BaseBlock createFromId(String id) {
Integer legacyId = BundledBlockData.getInstance().toLegacyId(id);
if (legacyId != null) {
return createFromId(legacyId);
} else {
return null;
}
}
@Nullable
@Override
public BaseBlock createFromId(int id) {
return new BaseBlock(id);
}
@Nullable
@Override
public BlockMaterial getMaterial(BaseBlock block) {
return BundledBlockData.getInstance().getMaterialById(block.getId());
}
@Nullable
@Override
public Map<String, ? extends State> getStates(BaseBlock block) {
return BundledBlockData.getInstance().getStatesById(block.getId());
}
}

View File

@ -0,0 +1,51 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
/**
* An implementation of {@link WorldData} that uses legacy numeric IDs and
* a built-in block database.
*/
public final class LegacyWorldData implements WorldData {
private static final LegacyWorldData INSTANCE = new LegacyWorldData();
private final LegacyBlockRegistry blockRegistry = new LegacyBlockRegistry();
/**
* Create a new instance.
*/
private LegacyWorldData() {
}
@Override
public BlockRegistry getBlockRegistry() {
return blockRegistry;
}
/**
* Get a singleton instance.
*
* @return an instance
*/
public static LegacyWorldData getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,246 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.blocks.BlockMaterial;
class SimpleBlockMaterial implements BlockMaterial {
private boolean renderedAsNormalBlock;
private boolean fullCube;
private boolean opaque;
private boolean powerSource;
private boolean liquid;
private boolean solid;
private float hardness;
private float resistance;
private float slipperiness;
private boolean grassBlocking;
private float ambientOcclusionLightValue;
private int lightOpacity;
private int lightValue;
private boolean fragileWhenPushed;
private boolean unpushable;
private boolean adventureModeExempt;
private boolean ticksRandomly;
private boolean usingNeighborLight;
private boolean movementBlocker;
private boolean burnable;
private boolean toolRequired;
private boolean replacedDuringPlacement;
@Override
public boolean isRenderedAsNormalBlock() {
return renderedAsNormalBlock;
}
public void setRenderedAsNormalBlock(boolean renderedAsNormalBlock) {
this.renderedAsNormalBlock = renderedAsNormalBlock;
}
@Override
public boolean isFullCube() {
return fullCube;
}
public void setFullCube(boolean fullCube) {
this.fullCube = fullCube;
}
@Override
public boolean isOpaque() {
return opaque;
}
public void setOpaque(boolean opaque) {
this.opaque = opaque;
}
@Override
public boolean isPowerSource() {
return powerSource;
}
public void setPowerSource(boolean powerSource) {
this.powerSource = powerSource;
}
@Override
public boolean isLiquid() {
return liquid;
}
public void setLiquid(boolean liquid) {
this.liquid = liquid;
}
@Override
public boolean isSolid() {
return solid;
}
public void setSolid(boolean solid) {
this.solid = solid;
}
@Override
public float getHardness() {
return hardness;
}
public void setHardness(float hardness) {
this.hardness = hardness;
}
@Override
public float getResistance() {
return resistance;
}
public void setResistance(float resistance) {
this.resistance = resistance;
}
@Override
public float getSlipperiness() {
return slipperiness;
}
public void setSlipperiness(float slipperiness) {
this.slipperiness = slipperiness;
}
@Override
public boolean isGrassBlocking() {
return grassBlocking;
}
public void setGrassBlocking(boolean grassBlocking) {
this.grassBlocking = grassBlocking;
}
@Override
public float getAmbientOcclusionLightValue() {
return ambientOcclusionLightValue;
}
public void setAmbientOcclusionLightValue(float ambientOcclusionLightValue) {
this.ambientOcclusionLightValue = ambientOcclusionLightValue;
}
@Override
public int getLightOpacity() {
return lightOpacity;
}
public void setLightOpacity(int lightOpacity) {
this.lightOpacity = lightOpacity;
}
@Override
public int getLightValue() {
return lightValue;
}
public void setLightValue(int lightValue) {
this.lightValue = lightValue;
}
@Override
public boolean isFragileWhenPushed() {
return fragileWhenPushed;
}
public void setFragileWhenPushed(boolean fragileWhenPushed) {
this.fragileWhenPushed = fragileWhenPushed;
}
@Override
public boolean isUnpushable() {
return unpushable;
}
public void setUnpushable(boolean unpushable) {
this.unpushable = unpushable;
}
@Override
public boolean isAdventureModeExempt() {
return adventureModeExempt;
}
public void setAdventureModeExempt(boolean adventureModeExempt) {
this.adventureModeExempt = adventureModeExempt;
}
@Override
public boolean isTicksRandomly() {
return ticksRandomly;
}
public void setTicksRandomly(boolean ticksRandomly) {
this.ticksRandomly = ticksRandomly;
}
@Override
public boolean isUsingNeighborLight() {
return usingNeighborLight;
}
public void setUsingNeighborLight(boolean usingNeighborLight) {
this.usingNeighborLight = usingNeighborLight;
}
@Override
public boolean isMovementBlocker() {
return movementBlocker;
}
public void setMovementBlocker(boolean movementBlocker) {
this.movementBlocker = movementBlocker;
}
@Override
public boolean isBurnable() {
return burnable;
}
public void setBurnable(boolean burnable) {
this.burnable = burnable;
}
@Override
public boolean isToolRequired() {
return toolRequired;
}
public void setToolRequired(boolean toolRequired) {
this.toolRequired = toolRequired;
}
@Override
public boolean isReplacedDuringPlacement() {
return replacedDuringPlacement;
}
public void setReplacedDuringPlacement(boolean replacedDuringPlacement) {
this.replacedDuringPlacement = replacedDuringPlacement;
}
}

View File

@ -0,0 +1,71 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.blocks.BaseBlock;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Map;
class SimpleState implements State {
private Byte dataMask;
private Map<String, SimpleStateValue> values;
@Override
public Map<String, SimpleStateValue> valueMap() {
return Collections.unmodifiableMap(values);
}
@Nullable
@Override
public StateValue getValue(BaseBlock block) {
for (StateValue value : values.values()) {
if (value.isSet(block)) {
return value;
}
}
return null;
}
byte getDataMask() {
return dataMask != null ? dataMask : 0xF;
}
@Override
public boolean hasDirection() {
for (SimpleStateValue value : values.values()) {
if (value.getDirection() != null) {
return true;
}
}
return false;
}
void postDeserialization() {
for (SimpleStateValue v : values.values()) {
v.setState(this);
}
}
}

View File

@ -0,0 +1,55 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
class SimpleStateValue implements StateValue {
private SimpleState state;
private Byte data;
private Vector direction;
void setState(SimpleState state) {
this.state = state;
}
@Override
public boolean isSet(BaseBlock block) {
return data != null && (block.getData() & state.getDataMask()) == data;
}
@Override
public boolean set(BaseBlock block) {
if (data != null) {
block.setData((block.getData() & ~state.getDataMask()) | data);
return true;
} else {
return false;
}
}
@Override
public Vector getDirection() {
return direction;
}
}

View File

@ -17,40 +17,45 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.world.mapping; package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Map;
/** /**
* A resolver can create state objects (such as {@link BaseBlock}) from * Describes a state property of a block.
* universal identifiers, but also get the universal identifier for
* a given state object (at least when it is known).
* </p>
* Identifiers may be case-sensitive. Routines that work with IDs should
* not make changes to the casing of the IDs or perform case-insensitive
* comparisons. Implementations may normalize the casing of IDs if it
* is appropriate.
* *
* @param <E> the type of state object * <p>Example states include "variant" (indicating material or type) and
* "facing" (indicating orientation).</p>
*/ */
public interface Resolver<E> { public interface State {
/** /**
* Create an instance of the state object from the given ID. * Return a map of available values for this state.
* *
* @param id the ID * <p>Keys are the value of state and map values describe that
* @return an instance, otherwise null if an instance cannot be created * particular state value.</p>
*
* @return the map of state values
*/ */
@Nullable E create(String id); Map<String, ? extends StateValue> valueMap();
/** /**
* Get the ID for the given object. * Get the value that the block is set to.
* *
* @param object the object * @param block the block
* @return the ID, otherwise null if it is not known * @return the state, otherwise null if the block isn't set to any of the values
*/ */
@Nullable String getId(E object); @Nullable
StateValue getValue(BaseBlock block);
/**
* Returns whether this state contains directional data.
*
* @return true if directional data is available
*/
boolean hasDirection();
} }

View File

@ -0,0 +1,56 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import javax.annotation.Nullable;
/**
* Describes a possible value for a {@code State}.
*/
public interface StateValue {
/**
* Return whether this state is set on the given block.
*
* @param block the block
* @return true if this value is set
*/
boolean isSet(BaseBlock block);
/**
* Set the state to this value on the given block.
*
* @param block the block to change
* @return true if the value was set successfully
*/
boolean set(BaseBlock block);
/**
* Return the direction associated with this value.
*
* @return the direction, otherwise null
*/
@Nullable
Vector getDirection();
}

View File

@ -17,28 +17,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.world.mapping; package com.sk89q.worldedit.world.registry;
import javax.annotation.Nullable;
/** /**
* An implementation of a {@link Resolver} that knows nothing and returns * Describes the necessary data for blocks, entities, and other objects
* {@code null} in all cases. * on a world.
*
* @param <E> the object to resolve
*/ */
public class NullResolver<E> implements Resolver<E> { public interface WorldData {
@Nullable /**
@Override * Get the block registry.
public E create(String id) { *
return null; * @return the block registry
} */
BlockRegistry getBlockRegistry();
@Nullable
@Override
public String getId(E object) {
return null;
}
} }

File diff suppressed because it is too large Load Diff