@Command( aliases = {"/copy"}, flags = "e", desc = "Копирует выделенную территорию в буфер обмена", help = "Копирует выделенную территорию в буфер обмен\n" + "Флаги:\n" + " -e определяет, будут ли объекты копироваться в буфер обмена\n" + "ПРЕДУПРЕЖДЕНИЕ: Вставленные объекты не могут быть отменены!", min = 0, max = 0) @CommandPermissions("worldedit.clipboard.copy") public void copy( CommandContext args, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { Region region = session.getSelection(player.getWorld()); Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); Vector pos = session.getPlacementPosition(player); CuboidClipboard clipboard = new CuboidClipboard(max.subtract(min).add(new Vector(1, 1, 1)), min, min.subtract(pos)); clipboard.copy(editSession); if (args.hasFlag('e')) { for (LocalEntity entity : player.getWorld().getEntities(region)) { clipboard.storeEntity(entity); } } session.setClipboard(clipboard); player.print("Блок(и) скопирован(ы)."); }
@Command( aliases = {"/cut"}, usage = "[leave-id]", desc = "Вырезает выделенную территорию в буфер обмена", help = "Вырезает выделенную территорию в буфер обмена\n" + "Флаги:\n" + " -e controls определяет, будут ли объекты копироваться в буфер обмена\n" + "ПРЕДУПРЕЖДЕНИЕ: Вырезанные и вставленные объекты не могут быть отменены!", flags = "e", min = 0, max = 1) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) public void cut( CommandContext args, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { BaseBlock block = new BaseBlock(BlockID.AIR); LocalWorld world = player.getWorld(); if (args.argsLength() > 0) { block = we.getBlock(player, args.getString(0)); } 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(new Vector(1, 1, 1)), min, min.subtract(pos)); clipboard.copy(editSession); if (args.hasFlag('e')) { LocalEntity[] entities = world.getEntities(region); for (LocalEntity entity : entities) { clipboard.storeEntity(entity); } world.killEntities(entities); } session.setClipboard(clipboard); int affected = editSession.setBlocks(session.getSelection(world), block); player.print( affected + " " + StringUtil.plural(affected, "блок вырезан", "блока вырезано", "блоков вырезано") + "."); }
@Command( aliases = {"/rotate"}, usage = "<angle-in-degrees>", desc = "Поворот содержимого буфера обмена", min = 1, max = 1) @CommandPermissions("worldedit.clipboard.rotate") public void rotate( CommandContext args, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { int angle = args.getInteger(0); if (angle % 90 == 0) { CuboidClipboard clipboard = session.getClipboard(); clipboard.rotate2D(angle); player.print("Содержимое буфера обмена повернуто на " + angle + " градусов."); } else { player.printError("Углы должны делиться на 90 градусов."); } }
@Command( aliases = {"/flip"}, usage = "[dir]", flags = "p", desc = "Переворачивает содержимое буфера обмена.", help = "Переворачивает содержимое буфера обмена.\n" + "Флаг -p переворачивает выделенную территорию вокруг игрока,\n" + "а не центра выделения.", min = 0, max = 1) @CommandPermissions("worldedit.clipboard.flip") public void flip( CommandContext args, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { CuboidClipboard.FlipDirection dir = we.getFlipDirection(player, args.argsLength() > 0 ? args.getString(0).toLowerCase() : "me"); CuboidClipboard clipboard = session.getClipboard(); clipboard.flip(dir, args.hasFlag('p')); player.print("Содержимое буфера обмена перевернуто."); }
public WorldEditSchematic(Object schematic) { weSchematic = (CuboidClipboard) schematic; // Center at the bottom X,Z center // This should be configurable, maybe? try { com.sk89q.worldedit.Vector weSize = weSchematic.getSize(); size = new Vector(weSize.getBlockX(), weSize.getBlockY(), weSize.getBlockZ()); center = new Vector(Math.floor(size.getBlockX() / 2), 0, Math.floor(size.getBlockZ() / 2)); } catch (Exception ex) { ex.printStackTrace(); } if (center == null) { center = new Vector(0, 0, 0); } if (size == null) { size = new Vector(0, 0, 0); } }
@SuppressWarnings({"deprecation"}) @Override public MaterialAndData getBlock(Vector v) { int x = v.getBlockX() + center.getBlockX(); int y = v.getBlockY() + center.getBlockY(); int z = v.getBlockZ() + center.getBlockZ(); try { if (x < 0 || x >= size.getBlockZ() || y < 0 || y >= size.getBlockY() || z < 0 || z >= size.getBlockZ()) { return null; } com.sk89q.worldedit.Vector vector = new com.sk89q.worldedit.Vector(x, y, z); BaseBlock baseBlock = weSchematic.getBlock(vector); Material material = Material.getMaterial(baseBlock.getId()); int materialData = baseBlock.getData(); MaterialAndData blockData = new MaterialAndData(material, (byte) materialData); // Note.. we don't actually get a SignBlock here, for some reason. // May have something to do with loading schematics not actually supporting sign // text, it doesn't work with //schematic and //paste, either. // It looks like //paste works in a dev build of WE, but it still doesn't give me the blocks // Looking at WE's code, it seems like the part that's needed is commented out... ?? if (material == Material.SIGN_POST || material == Material.WALL_SIGN) { try { if (baseBlock.hasNbtData()) { SignBlock signBlock = new SignBlock(material.getId(), materialData); CompoundTag nbtData = baseBlock.getNbtData(); signBlock.setNbtData(nbtData); blockData.setSignLines(signBlock.getText()); } } catch (Throwable ex) { ex.printStackTrace(); } } else if (material == Material.COMMAND) { try { if (baseBlock.hasNbtData()) { CompoundTag nbtRoot = baseBlock.getNbtData(); Map<String, Tag> rootValues = nbtRoot.getValue(); if (rootValues.containsKey("Command")) { Object commandValue = rootValues.get("Command").getValue(); blockData.setCommandLine((String) commandValue); } if (rootValues.containsKey("CustomName")) { Object nameValue = rootValues.get("CustomName").getValue(); blockData.setCustomName((String) nameValue); } } } catch (Throwable ex) { ex.printStackTrace(); } } else if (material == Material.CHEST) { try { if (baseBlock.hasNbtData()) { ChestBlock chestBlock = new ChestBlock(materialData); CompoundTag nbtRoot = baseBlock.getNbtData(); chestBlock.setNbtData(nbtRoot); BaseItemStack[] items = chestBlock.getItems(); if (items != null && items.length > 0) { ItemStack[] contents = new ItemStack[items.length]; for (int i = 0; i < items.length; i++) { if (items[i] != null) { Material itemMaterial = Material.getMaterial(items[i].getType()); // Bukkit.getLogger().info("Item from chest: " + itemMaterial + " at " + i + " / " // + contents.length); short itemData = items[i].getData(); int itemAmount = items[i].getAmount(); ItemStack newStack = new ItemStack(itemMaterial, itemAmount, itemData); Map<Integer, Integer> enchantments = items[i].getEnchantments(); if (enchantments != null && enchantments.size() > 0) { for (Entry<Integer, Integer> enchantment : enchantments.entrySet()) { try { Enchantment enchantmentType = Enchantment.getById(enchantment.getKey()); newStack.addEnchantment(enchantmentType, enchantment.getValue()); } catch (Exception ex) { // This seems to happen a lot .. like on potions especially. ex.printStackTrace(); } } } contents[i] = newStack; } } blockData.setInventoryContents(contents); } } } catch (Throwable ex) { ex.printStackTrace(); } } return blockData; } catch (ArrayIndexOutOfBoundsException ex) { // TODO: Figure out why this still happens, even with the size check } catch (Throwable ex) { ex.printStackTrace(); } return null; }
@SuppressWarnings("deprecation") public Material getMaterialAt(int x, int y, int z) { return Material.getMaterial( clipboard.getBlock(new com.sk89q.worldedit.Vector(x, y, z)).getType()); }
public int getLength() { return clipboard.getLength(); }
public int getHeight() { return clipboard.getHeight(); }
public int getWidth() { return clipboard.getWidth(); }
public CuboidClipboard load(InputStream stream) throws IOException, DataException { NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(stream)); Vector origin = new Vector(); Vector offset = new Vector(); // Schematic tag NamedTag rootTag = nbtStream.readNamedTag(); nbtStream.close(); if (!rootTag.getName().equals("Schematic")) { throw new DataException("Tag \"Schematic\" does not exist or is not first"); } CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); // Check Map<String, Tag> schematic = schematicTag.getValue(); if (!schematic.containsKey("Blocks")) { throw new DataException("Schematic file is missing a \"Blocks\" tag"); } // Get information short width = getChildTag(schematic, "Width", ShortTag.class).getValue(); short length = getChildTag(schematic, "Length", ShortTag.class).getValue(); short height = getChildTag(schematic, "Height", ShortTag.class).getValue(); try { int originX = getChildTag(schematic, "WEOriginX", IntTag.class).getValue(); int originY = getChildTag(schematic, "WEOriginY", IntTag.class).getValue(); int originZ = getChildTag(schematic, "WEOriginZ", IntTag.class).getValue(); origin = new Vector(originX, originY, originZ); } catch (DataException e) { // No origin data } try { int offsetX = getChildTag(schematic, "WEOffsetX", IntTag.class).getValue(); int offsetY = getChildTag(schematic, "WEOffsetY", IntTag.class).getValue(); int offsetZ = getChildTag(schematic, "WEOffsetZ", IntTag.class).getValue(); offset = new Vector(offsetX, offsetY, offsetZ); } catch (DataException e) { // No offset data } // Check type of Schematic String materials = getChildTag(schematic, "Materials", StringTag.class).getValue(); if (!materials.equals("Alpha")) { throw new DataException("Schematic file is not an Alpha schematic"); } // Get blocks byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue(); byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue(); byte[] addId = new byte[0]; short[] blocks = new short[blockId.length]; // Have to later combine IDs // We support 4096 block IDs using the same method as vanilla Minecraft, where // the highest 4 bits are stored in a separate byte array. if (schematic.containsKey("AddBlocks")) { addId = getChildTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); } // Combine the AddBlocks data with the first 8-bit block ID for (int index = 0; index < blockId.length; index++) { if ((index >> 1) >= addId.length) { // No corresponding AddBlocks index blocks[index] = (short) (blockId[index] & 0xFF); } else { if ((index & 1) == 0) { blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (blockId[index] & 0xFF)); } else { blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF)); } } } // Need to pull out tile entities List<Tag> tileEntities = getChildTag(schematic, "TileEntities", ListTag.class).getValue(); Map<BlockVector, Map<String, Tag>> tileEntitiesMap = new HashMap<BlockVector, Map<String, Tag>>(); for (Tag tag : tileEntities) { if (!(tag instanceof CompoundTag)) continue; CompoundTag t = (CompoundTag) tag; int x = 0; int y = 0; int z = 0; Map<String, Tag> values = new HashMap<String, Tag>(); for (Map.Entry<String, Tag> 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); } Vector size = new Vector(width, height, length); CuboidClipboard clipboard = new CuboidClipboard(size); clipboard.setOrigin(origin); clipboard.setOffset(offset); 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 = getBlockForId(blocks[index], blockData[index]); if (tileEntitiesMap.containsKey(pt)) { block.setNbtData(new CompoundTag(tileEntitiesMap.get(pt))); } clipboard.setBlock(pt, block); } } } return clipboard; }
@Override public void save(CuboidClipboard clipboard, File file) throws IOException, DataException { int width = clipboard.getWidth(); int height = clipboard.getHeight(); int length = clipboard.getLength(); if (width > MAX_SIZE) { throw new DataException("Width of region too large for a .schematic"); } if (height > MAX_SIZE) { throw new DataException("Height of region too large for a .schematic"); } if (length > MAX_SIZE) { throw new DataException("Length of region too large for a .schematic"); } HashMap<String, Tag> schematic = new HashMap<String, Tag>(); schematic.put("Width", new ShortTag((short) width)); schematic.put("Length", new ShortTag((short) length)); schematic.put("Height", new ShortTag((short) height)); schematic.put("Materials", new StringTag("Alpha")); schematic.put("WEOriginX", new IntTag(clipboard.getOrigin().getBlockX())); schematic.put("WEOriginY", new IntTag(clipboard.getOrigin().getBlockY())); schematic.put("WEOriginZ", new IntTag(clipboard.getOrigin().getBlockZ())); schematic.put("WEOffsetX", new IntTag(clipboard.getOffset().getBlockX())); schematic.put("WEOffsetY", new IntTag(clipboard.getOffset().getBlockY())); schematic.put("WEOffsetZ", new IntTag(clipboard.getOffset().getBlockZ())); // Copy byte[] blocks = new byte[width * height * length]; byte[] addBlocks = null; byte[] blockData = new byte[width * height * length]; ArrayList<Tag> tileEntities = new ArrayList<Tag>(); 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; BaseBlock block = clipboard.getPoint(new BlockVector(x, y, z)); // Save 4096 IDs in an AddBlocks section if (block.getType() > 255) { if (addBlocks == null) { // Lazily create section addBlocks = new byte[(blocks.length >> 1) + 1]; } addBlocks[index >> 1] = (byte) (((index & 1) == 0) ? addBlocks[index >> 1] & 0xF0 | (block.getType() >> 8) & 0xF : addBlocks[index >> 1] & 0xF | ((block.getType() >> 8) & 0xF) << 4); } blocks[index] = (byte) block.getType(); blockData[index] = (byte) block.getData(); // Get the list of key/values from the block CompoundTag rawTag = block.getNbtData(); if (rawTag != null) { Map<String, Tag> values = new HashMap<String, Tag>(); for (Entry<String, Tag> entry : rawTag.getValue().entrySet()) { values.put(entry.getKey(), entry.getValue()); } values.put("id", new StringTag(block.getNbtId())); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); CompoundTag tileEntityTag = new CompoundTag(values); tileEntities.add(tileEntityTag); } } } } schematic.put("Blocks", new ByteArrayTag(blocks)); schematic.put("Data", new ByteArrayTag(blockData)); schematic.put("Entities", new ListTag(CompoundTag.class, new ArrayList<Tag>())); schematic.put("TileEntities", new ListTag(CompoundTag.class, tileEntities)); if (addBlocks != null) { schematic.put("AddBlocks", new ByteArrayTag(addBlocks)); } // Build and output CompoundTag schematicTag = new CompoundTag(schematic); NBTOutputStream stream = new NBTOutputStream(new GZIPOutputStream(new FileOutputStream(file))); stream.writeNamedTag("Schematic", schematicTag); stream.close(); }