diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 00807b4b5..78482c962 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -3,18 +3,18 @@ * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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. + * 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 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 . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package com.sk89q.worldedit.bukkit.adapter; @@ -47,15 +47,14 @@ public class BukkitImplLoader { private static final String CLASS_SUFFIX = ".class"; private static final String LOAD_ERROR_MESSAGE = - "\n**********************************************\n" + - "** This WorldEdit version does not fully support your version of Bukkit.\n" + - "**\n" + - "** When working with blocks or undoing, chests will be empty, signs\n" + - "** will be blank, and so on. There will be no support for entity\n" + - "** and block property-related functions.\n" + - "**\n" + - "** Please see https://worldedit.enginehub.org/en/latest/faq/#bukkit-adapters\n" + - "**********************************************\n"; + "\n**********************************************\n" + + "** This WorldEdit version does not fully support your version of Bukkit.\n" + + "**\n" + "** When working with blocks or undoing, chests will be empty, signs\n" + + "** will be blank, and so on. There will be no support for entity\n" + + "** and block property-related functions.\n" + + "**\n" + + "** Please see https://worldedit.enginehub.org/en/latest/faq/#bukkit-adapters\n" + + "**********************************************\n"; /** * Create a new instance. @@ -97,7 +96,9 @@ public class BukkitImplLoader { String className = jarEntry.getName().replaceAll("[/\\\\]+", "."); - if (!className.startsWith(SEARCH_PACKAGE_DOT) || jarEntry.isDirectory()) continue; + if (!className.startsWith(SEARCH_PACKAGE_DOT) || jarEntry.isDirectory()) { + continue; + } int beginIndex = 0; int endIndex = className.length() - CLASS_SUFFIX.length(); @@ -155,32 +156,23 @@ public class BukkitImplLoader { */ public BukkitImplAdapter loadAdapter() throws AdapterLoadException { for (String className : adapterCandidates) { - System.out.println("Candidate: " + className); try { Class cls = Class.forName(className); - if (cls.isSynthetic()){ - System.out.println(className + " is synthetic, continuing"); + if (cls.isSynthetic()) { continue; - }else{ - System.out.println(className + " is not synthetic"); } if (BukkitImplAdapter.class.isAssignableFrom(cls)) { - System.out.println(className + " is assignable from BukkitImplAdapter, returning"); return (BukkitImplAdapter) cls.newInstance(); - }else{ - System.out.println(className + " is NOT assignable from BukkitImplAdapter, returning"); } } catch (ClassNotFoundException e) { - log.warn("Failed to load the Bukkit adapter class '" + className + - "' that is not supposed to be missing", e); + log.warn("Failed to load the Bukkit adapter class '" + className + + "' that is not supposed to be missing", e); } catch (IllegalAccessException e) { - log.warn("Failed to load the Bukkit adapter class '" + className + - "' that is not supposed to be raising this error", e); + log.warn("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.warn("Failed to load the Bukkit adapter class '" + className + "'", e); - }else{ - log.warn(className + " is not custom candidate.", e); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java index 38298c5a0..07e287753 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -1,64 +1,64 @@ -/* - * 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.Locale; - -/** - * The {@code TAG_Byte_Array} tag. - */ -public final class ByteArrayTag extends Tag { - - @Override - public int getTypeCode() { - return NBTConstants.TYPE_BYTE_ARRAY; - } - - 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; - } - - @Override - public byte[] getValue() { - return value; - } - - @Override - public String toString() { - StringBuilder hex = new StringBuilder(); - for (byte b : value) { - String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT); - if (hexDigits.length() == 1) { - hex.append("0"); - } - hex.append(hexDigits).append(" "); - } - return "TAG_Byte_Array(" + hex + ")"; - } - -} +/* + * 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.Locale; + +/** + * The {@code TAG_Byte_Array} tag. + */ +public final class ByteArrayTag extends Tag { + + @Override + public int getTypeCode() { + return NBTConstants.TYPE_BYTE_ARRAY; + } + + 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; + } + + @Override + public byte[] getValue() { + return value; + } + + @Override + public String toString() { + StringBuilder hex = new StringBuilder(); + for (byte b : value) { + String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT); + if (hexDigits.length() == 1) { + hex.append("0"); + } + hex.append(hexDigits).append(" "); + } + return "TAG_Byte_Array(" + hex + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java index b90b1acfb..027b875f4 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java @@ -1,53 +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.jnbt; - -/** - * The {@code TAG_Byte} tag. - */ -public final class ByteTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_BYTE; - } - - 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; - } - - @Override - public Byte getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_Byte(" + value + ")"; - } - -} +/* + * 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; + +/** + * The {@code TAG_Byte} tag. + */ +public final class ByteTag extends NumberTag { + @Override + public int getTypeCode() { + return NBTConstants.TYPE_BYTE; + } + + 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; + } + + @Override + public Byte getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Byte(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java index 1a4bd9399..fc8336e36 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java @@ -1,53 +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.jnbt; - -/** - * The {@code TAG_Double} tag. - */ -public final class DoubleTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_DOUBLE; - } - - 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; - } - - @Override - public Double getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_Double(" + value + ")"; - } - -} +/* + * 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; + +/** + * The {@code TAG_Double} tag. + */ +public final class DoubleTag extends NumberTag { + @Override + public int getTypeCode() { + return NBTConstants.TYPE_DOUBLE; + } + + 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; + } + + @Override + public Double getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Double(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java index eaf76c620..db5b6a1d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java @@ -1,53 +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.jnbt; - -/** - * The {@code TAG_Float} tag. - */ -public final class FloatTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_FLOAT; - } - - 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; - } - - @Override - public Float getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_Float(" + value + ")"; - } - -} +/* + * 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; + +/** + * The {@code TAG_Float} tag. + */ +public final class FloatTag extends NumberTag { + @Override + public int getTypeCode() { + return NBTConstants.TYPE_FLOAT; + } + + 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; + } + + @Override + public Float getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Float(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java index e1da41b01..45898e131 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java @@ -1,53 +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.jnbt; - -/** - * The {@code TAG_Int} tag. - */ -public final class IntTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_INT; - } - - 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; - } - - @Override - public Integer getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_Int(" + value + ")"; - } - -} +/* + * 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; + +/** + * The {@code TAG_Int} tag. + */ +public final class IntTag extends NumberTag { + @Override + public int getTypeCode() { + return NBTConstants.TYPE_INT; + } + + 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; + } + + @Override + public Integer getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Int(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java index 4525cd719..0d88949b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java @@ -1,53 +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.jnbt; - -/** - * The {@code TAG_Long} tag. - */ -public final class LongTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_LONG; - } - - 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; - } - - @Override - public Long getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_Long(" + value + ")"; - } - -} +/* + * 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; + +/** + * The {@code TAG_Long} tag. + */ +public final class LongTag extends NumberTag { + @Override + public int getTypeCode() { + return NBTConstants.TYPE_LONG; + } + + 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; + } + + @Override + public Long getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Long(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java index 50b4d6263..70f12133f 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java @@ -1,93 +1,93 @@ -/* - * 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.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -/** - * A class which holds constant values. - */ -public final class NBTConstants { - - public static final Charset CHARSET = StandardCharsets.UTF_8; - - public static final int TYPE_END = 0; - public static final int TYPE_BYTE = 1; - public static final int TYPE_SHORT = 2; - public static final int TYPE_INT = 3; - public static final int TYPE_LONG = 4; - public static final int TYPE_FLOAT = 5; - public static final int TYPE_DOUBLE = 6; - public static final int TYPE_BYTE_ARRAY = 7; - public static final int TYPE_STRING = 8; - public static final int TYPE_LIST = 9; - public static final int TYPE_COMPOUND = 10; - public static final int TYPE_INT_ARRAY = 11; - public static final int TYPE_LONG_ARRAY = 12; - - /** - * Default private constructor. - */ - private NBTConstants() { - - } - - /** - * Convert a type ID to its corresponding {@link Tag} class. - * - * @param id type ID - * @return tag class - * @throws IllegalArgumentException thrown if the tag ID is not valid - */ - public static Class getClassFromType(int id) { - switch (id) { - case TYPE_END: - return EndTag.class; - case TYPE_BYTE: - return ByteTag.class; - case TYPE_SHORT: - return ShortTag.class; - case TYPE_INT: - return IntTag.class; - case TYPE_LONG: - return LongTag.class; - case TYPE_FLOAT: - return FloatTag.class; - case TYPE_DOUBLE: - return DoubleTag.class; - case TYPE_BYTE_ARRAY: - return ByteArrayTag.class; - case TYPE_STRING: - return StringTag.class; - case TYPE_LIST: - return ListTag.class; - case TYPE_COMPOUND: - return CompoundTag.class; - case TYPE_INT_ARRAY: - return IntArrayTag.class; - case TYPE_LONG_ARRAY: - return LongArrayTag.class; - default: - throw new IllegalArgumentException("Unknown tag type ID of " + id); - } - } - -} +/* + * 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.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * A class which holds constant values. + */ +public final class NBTConstants { + + public static final Charset CHARSET = StandardCharsets.UTF_8; + + public static final int TYPE_END = 0; + public static final int TYPE_BYTE = 1; + public static final int TYPE_SHORT = 2; + public static final int TYPE_INT = 3; + public static final int TYPE_LONG = 4; + public static final int TYPE_FLOAT = 5; + public static final int TYPE_DOUBLE = 6; + public static final int TYPE_BYTE_ARRAY = 7; + public static final int TYPE_STRING = 8; + public static final int TYPE_LIST = 9; + public static final int TYPE_COMPOUND = 10; + public static final int TYPE_INT_ARRAY = 11; + public static final int TYPE_LONG_ARRAY = 12; + + /** + * Default private constructor. + */ + private NBTConstants() { + + } + + /** + * Convert a type ID to its corresponding {@link Tag} class. + * + * @param id type ID + * @return tag class + * @throws IllegalArgumentException thrown if the tag ID is not valid + */ + public static Class getClassFromType(int id) { + switch (id) { + case TYPE_END: + return EndTag.class; + case TYPE_BYTE: + return ByteTag.class; + case TYPE_SHORT: + return ShortTag.class; + case TYPE_INT: + return IntTag.class; + case TYPE_LONG: + return LongTag.class; + case TYPE_FLOAT: + return FloatTag.class; + case TYPE_DOUBLE: + return DoubleTag.class; + case TYPE_BYTE_ARRAY: + return ByteArrayTag.class; + case TYPE_STRING: + return StringTag.class; + case TYPE_LIST: + return ListTag.class; + case TYPE_COMPOUND: + return CompoundTag.class; + case TYPE_INT_ARRAY: + return IntArrayTag.class; + case TYPE_LONG_ARRAY: + return LongArrayTag.class; + default: + throw new IllegalArgumentException("Unknown tag type ID of " + id); + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java index 9a79de34c..cc8d20277 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java @@ -1,513 +1,513 @@ -/* - * 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 com.boydti.fawe.object.io.LittleEndianOutputStream; - -import java.io.Closeable; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.Flushable; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; -import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * This class writes NBT, or Named Binary Tag - * {@code Tag} objects to an underlying {@code OutputStream}. - * - *

- * The NBT format was created by Markus Persson, and the specification may be - * found at - * https://minecraft.gamepedia.com/NBT_format. - *

- */ -public final class NBTOutputStream extends OutputStream implements Closeable, DataOutput { - - /** - * The output stream. - */ - private final DataOutput os; - - /** - * Creates a new {@code NBTOutputStream}, which will write data to the - * specified underlying output stream. - * - * @param os - * The output stream. - * @throws IOException - * if an I/O error occurs. - */ - public NBTOutputStream(OutputStream os) throws IOException { - this(os instanceof DataOutput ? (DataOutput) os : new DataOutputStream(os)); - } - - // Don't delete - public NBTOutputStream(DataOutput os) { - this.os = os; - } - - public NBTOutputStream(DataOutputStream os) { - this.os = os; - } - - // Don't delete - public NBTOutputStream(OutputStream os, boolean littleEndian) throws IOException { - this(littleEndian ? new LittleEndianOutputStream(os) : os); - } - - public DataOutput getOutputStream() { - return os; - } - - /** - * Writes a tag. - * - * @param tag - * The tag to write. - * @throws IOException - * if an I/O error occurs. - */ - public void writeNamedTag(String name, Tag tag) throws IOException { - checkNotNull(name); - checkNotNull(tag); - - int type = NBTUtils.getTypeCode(tag.getClass()); - writeNamedTagName(name, type); - - if (type == NBTConstants.TYPE_END) { - throw new IOException("Named TAG_End not permitted."); - } - - writeTagPayload(tag); - } - - public void writeNamedTag(String name, String value) throws IOException { - checkNotNull(name); - checkNotNull(value); - int type = NBTConstants.TYPE_STRING; - writeNamedTagName(name, type); - byte[] bytes = value.getBytes(NBTConstants.CHARSET); - os.writeShort(bytes.length); - os.write(bytes); - } - - public void writeNamedTag(String name, int value) throws IOException { - checkNotNull(name); - int type = NBTConstants.TYPE_INT; - writeNamedTagName(name, type); - os.writeInt(value); - } - - public void writeNamedTag(String name, byte value) throws IOException { - checkNotNull(name); - int type = NBTConstants.TYPE_BYTE; - writeNamedTagName(name, type); - os.writeByte(value); - } - - public void writeNamedTag(String name, short value) throws IOException { - checkNotNull(name); - int type = NBTConstants.TYPE_SHORT; - writeNamedTagName(name, type); - os.writeShort(value); - } - - public void writeNamedTag(String name, long value) throws IOException { - checkNotNull(name); - int type = NBTConstants.TYPE_LONG; - writeNamedTagName(name, type); - os.writeLong(value); - } - - public void writeNamedTag(String name, byte[] bytes) throws IOException { - checkNotNull(name); - int type = NBTConstants.TYPE_BYTE_ARRAY; - writeNamedTagName(name, type); - os.writeInt(bytes.length); - os.write(bytes); - } - - public void writeNamedTag(String name, int[] data) throws IOException { - checkNotNull(name); - int type = NBTConstants.TYPE_INT_ARRAY; - writeNamedTagName(name, type); - os.writeInt(data.length); - for (int aData : data) { - os.writeInt(aData); - } - } - - public void writeNamedEmptyList(String name) throws IOException { - writeNamedEmptyList(name, NBTConstants.TYPE_COMPOUND); - } - - private void writeNamedEmptyList(String name, int type) throws IOException { - writeNamedTagName(name, NBTConstants.TYPE_LIST); - os.writeByte(type); - os.writeInt(0); - } - - public void writeNamedTagName(String name, int type) throws IOException { - // byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); - - os.writeByte(type); - os.writeUTF(name); - // os.writeShort(nameBytes.length); - // os.write(nameBytes); - } - - public void writeLazyCompoundTag(String name, LazyWrite next) throws IOException { - byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); - os.writeByte(NBTConstants.TYPE_COMPOUND); - os.writeShort(nameBytes.length); - os.write(nameBytes); - next.write(this); - os.writeByte(NBTConstants.TYPE_END); - } - - public interface LazyWrite { - void write(NBTOutputStream out) throws IOException; - } - - public void writeTag(Tag tag) throws IOException { - int type = NBTUtils.getTypeCode(tag.getClass()); - os.writeByte(type); - writeTagPayload(tag); - } - - public void writeEndTag() throws IOException { - os.writeByte(NBTConstants.TYPE_END); - } - - /** - * Writes tag payload. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - public void writeTagPayload(Tag tag) throws IOException { - int type = NBTUtils.getTypeCode(tag.getClass()); - switch (type) { - case NBTConstants.TYPE_END: - writeEndTagPayload((EndTag) tag); - break; - case NBTConstants.TYPE_BYTE: - writeByteTagPayload((ByteTag) tag); - break; - case NBTConstants.TYPE_SHORT: - writeShortTagPayload((ShortTag) tag); - break; - case NBTConstants.TYPE_INT: - writeIntTagPayload((IntTag) tag); - break; - case NBTConstants.TYPE_LONG: - writeLongTagPayload((LongTag) tag); - break; - case NBTConstants.TYPE_FLOAT: - writeFloatTagPayload((FloatTag) tag); - break; - case NBTConstants.TYPE_DOUBLE: - writeDoubleTagPayload((DoubleTag) tag); - break; - case NBTConstants.TYPE_BYTE_ARRAY: - writeByteArrayTagPayload((ByteArrayTag) tag); - break; - case NBTConstants.TYPE_STRING: - writeStringTagPayload((StringTag) tag); - break; - case NBTConstants.TYPE_LIST: - writeListTagPayload((ListTag) tag); - break; - case NBTConstants.TYPE_COMPOUND: - writeCompoundTagPayload((CompoundTag) tag); - break; - case NBTConstants.TYPE_INT_ARRAY: - writeIntArrayTagPayload((IntArrayTag) tag); - break; - case NBTConstants.TYPE_LONG_ARRAY: - writeLongArrayTagPayload((LongArrayTag) tag); - break; - default: - throw new IOException("Invalid tag type: " + type + "."); - } - } - - /** - * Writes a {@code TAG_Byte} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeByteTagPayload(ByteTag tag) throws IOException { - os.writeByte(tag.getValue()); - } - - /** - * Writes a {@code TAG_Byte_Array} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException { - byte[] bytes = tag.getValue(); - os.writeInt(bytes.length); - os.write(bytes); - } - - /** - * Writes a {@code TAG_Compound} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeCompoundTagPayload(CompoundTag tag) throws IOException { - for (Map.Entry entry : tag.getValue().entrySet()) { - writeNamedTag(entry.getKey(), entry.getValue()); - } - os.writeByte((byte) 0); // end tag - better way? - } - - /** - * Writes a {@code TAG_List} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeListTagPayload(ListTag tag) throws IOException { - Class clazz = tag.getType(); - if (clazz == null) { - clazz = CompoundTag.class; - } - List tags = tag.getValue(); - int size = tags.size(); - if (!tags.isEmpty()) { - Tag tag0 = tags.get(0); - os.writeByte(tag0.getTypeCode()); - } else { - os.writeByte(NBTUtils.getTypeCode(clazz)); - } - os.writeInt(size); - for (Tag tag1 : tags) { - writeTagPayload(tag1); - } - } - - /** - * Writes a {@code TAG_String} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeStringTagPayload(StringTag tag) throws IOException { - byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET); - os.writeShort(bytes.length); - os.write(bytes); - } - - /** - * Writes a {@code TAG_Double} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeDoubleTagPayload(DoubleTag tag) throws IOException { - os.writeDouble(tag.getValue()); - } - - /** - * Writes a {@code TAG_Float} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeFloatTagPayload(FloatTag tag) throws IOException { - os.writeFloat(tag.getValue()); - } - - /** - * Writes a {@code TAG_Long} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeLongTagPayload(LongTag tag) throws IOException { - os.writeLong(tag.getValue()); - } - - /** - * Writes a {@code TAG_Int} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeIntTagPayload(IntTag tag) throws IOException { - os.writeInt(tag.getValue()); - } - - /** - * Writes a {@code TAG_Short} tag. - * - * @param tag - * The tag. - * @throws IOException - * if an I/O error occurs. - */ - private void writeShortTagPayload(ShortTag tag) throws IOException { - os.writeShort(tag.getValue()); - } - - /** - * Writes a {@code TAG_Empty} tag. - * - * @param tag the tag - */ - private void writeEndTagPayload(EndTag tag) { - /* empty */ - } - - private void writeIntArrayTagPayload(IntArrayTag tag) throws IOException { - int[] data = tag.getValue(); - os.writeInt(data.length); - for (int aData : data) { - os.writeInt(aData); - } - } - - private void writeLongArrayTagPayload(LongArrayTag tag) throws IOException { - long[] data = tag.getValue(); - os.writeInt(data.length); - for (long aData : data) { - os.writeLong(aData); - } - } - - @Override - public void close() throws IOException { - if (os instanceof Closeable) { - ((Closeable) os).close(); - } - } - - @Override - public void write(int b) throws IOException { - os.write(b); - } - - @Override - public void write(byte[] b) throws IOException { - os.write(b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - os.write(b, off, len); - } - - @Override - public void writeBoolean(boolean v) throws IOException { - os.writeBoolean(v); - } - - @Override - public void writeByte(int v) throws IOException { - os.writeByte(v); - } - - @Override - public void writeShort(int v) throws IOException { - os.writeShort(v); - } - - @Override - public void writeChar(int v) throws IOException { - os.writeChar(v); - } - - @Override - public void writeInt(int v) throws IOException { - os.writeInt(v); - } - - @Override - public void writeLong(long v) throws IOException { - os.writeLong(v); - } - - @Override - public void writeFloat(float v) throws IOException { - os.writeFloat(v); - } - - @Override - public void writeDouble(double v) throws IOException { - os.writeDouble(v); - } - - @Override - public void writeBytes(String s) throws IOException { - os.writeBytes(s); - } - - @Override - public void writeChars(String s) throws IOException { - os.writeChars(s); - } - - @Override - public void writeUTF(String s) throws IOException { - os.writeUTF(s); - } - - /** - * Flush output. - * - * @throws IOException - */ - @Override - public void flush() throws IOException { - if (os instanceof Flushable) { - ((Flushable) os).flush(); - } - } -} +/* + * 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 com.boydti.fawe.object.io.LittleEndianOutputStream; + +import java.io.Closeable; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.Flushable; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * This class writes NBT, or Named Binary Tag + * {@code Tag} objects to an underlying {@code OutputStream}. + * + *

+ * The NBT format was created by Markus Persson, and the specification may be + * found at + * https://minecraft.gamepedia.com/NBT_format. + *

+ */ +public final class NBTOutputStream extends OutputStream implements Closeable, DataOutput { + + /** + * The output stream. + */ + private final DataOutput os; + + /** + * Creates a new {@code NBTOutputStream}, which will write data to the + * specified underlying output stream. + * + * @param os + * The output stream. + * @throws IOException + * if an I/O error occurs. + */ + public NBTOutputStream(OutputStream os) throws IOException { + this(os instanceof DataOutput ? (DataOutput) os : new DataOutputStream(os)); + } + + // Don't delete + public NBTOutputStream(DataOutput os) { + this.os = os; + } + + public NBTOutputStream(DataOutputStream os) { + this.os = os; + } + + // Don't delete + public NBTOutputStream(OutputStream os, boolean littleEndian) throws IOException { + this(littleEndian ? new LittleEndianOutputStream(os) : os); + } + + public DataOutput getOutputStream() { + return os; + } + + /** + * Writes a tag. + * + * @param tag + * The tag to write. + * @throws IOException + * if an I/O error occurs. + */ + public void writeNamedTag(String name, Tag tag) throws IOException { + checkNotNull(name); + checkNotNull(tag); + + int type = NBTUtils.getTypeCode(tag.getClass()); + writeNamedTagName(name, type); + + if (type == NBTConstants.TYPE_END) { + throw new IOException("Named TAG_End not permitted."); + } + + writeTagPayload(tag); + } + + public void writeNamedTag(String name, String value) throws IOException { + checkNotNull(name); + checkNotNull(value); + int type = NBTConstants.TYPE_STRING; + writeNamedTagName(name, type); + byte[] bytes = value.getBytes(NBTConstants.CHARSET); + os.writeShort(bytes.length); + os.write(bytes); + } + + public void writeNamedTag(String name, int value) throws IOException { + checkNotNull(name); + int type = NBTConstants.TYPE_INT; + writeNamedTagName(name, type); + os.writeInt(value); + } + + public void writeNamedTag(String name, byte value) throws IOException { + checkNotNull(name); + int type = NBTConstants.TYPE_BYTE; + writeNamedTagName(name, type); + os.writeByte(value); + } + + public void writeNamedTag(String name, short value) throws IOException { + checkNotNull(name); + int type = NBTConstants.TYPE_SHORT; + writeNamedTagName(name, type); + os.writeShort(value); + } + + public void writeNamedTag(String name, long value) throws IOException { + checkNotNull(name); + int type = NBTConstants.TYPE_LONG; + writeNamedTagName(name, type); + os.writeLong(value); + } + + public void writeNamedTag(String name, byte[] bytes) throws IOException { + checkNotNull(name); + int type = NBTConstants.TYPE_BYTE_ARRAY; + writeNamedTagName(name, type); + os.writeInt(bytes.length); + os.write(bytes); + } + + public void writeNamedTag(String name, int[] data) throws IOException { + checkNotNull(name); + int type = NBTConstants.TYPE_INT_ARRAY; + writeNamedTagName(name, type); + os.writeInt(data.length); + for (int aData : data) { + os.writeInt(aData); + } + } + + public void writeNamedEmptyList(String name) throws IOException { + writeNamedEmptyList(name, NBTConstants.TYPE_COMPOUND); + } + + private void writeNamedEmptyList(String name, int type) throws IOException { + writeNamedTagName(name, NBTConstants.TYPE_LIST); + os.writeByte(type); + os.writeInt(0); + } + + public void writeNamedTagName(String name, int type) throws IOException { + // byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); + + os.writeByte(type); + os.writeUTF(name); + // os.writeShort(nameBytes.length); + // os.write(nameBytes); + } + + public void writeLazyCompoundTag(String name, LazyWrite next) throws IOException { + byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); + os.writeByte(NBTConstants.TYPE_COMPOUND); + os.writeShort(nameBytes.length); + os.write(nameBytes); + next.write(this); + os.writeByte(NBTConstants.TYPE_END); + } + + public interface LazyWrite { + void write(NBTOutputStream out) throws IOException; + } + + public void writeTag(Tag tag) throws IOException { + int type = NBTUtils.getTypeCode(tag.getClass()); + os.writeByte(type); + writeTagPayload(tag); + } + + public void writeEndTag() throws IOException { + os.writeByte(NBTConstants.TYPE_END); + } + + /** + * Writes tag payload. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + public void writeTagPayload(Tag tag) throws IOException { + int type = NBTUtils.getTypeCode(tag.getClass()); + switch (type) { + case NBTConstants.TYPE_END: + writeEndTagPayload((EndTag) tag); + break; + case NBTConstants.TYPE_BYTE: + writeByteTagPayload((ByteTag) tag); + break; + case NBTConstants.TYPE_SHORT: + writeShortTagPayload((ShortTag) tag); + break; + case NBTConstants.TYPE_INT: + writeIntTagPayload((IntTag) tag); + break; + case NBTConstants.TYPE_LONG: + writeLongTagPayload((LongTag) tag); + break; + case NBTConstants.TYPE_FLOAT: + writeFloatTagPayload((FloatTag) tag); + break; + case NBTConstants.TYPE_DOUBLE: + writeDoubleTagPayload((DoubleTag) tag); + break; + case NBTConstants.TYPE_BYTE_ARRAY: + writeByteArrayTagPayload((ByteArrayTag) tag); + break; + case NBTConstants.TYPE_STRING: + writeStringTagPayload((StringTag) tag); + break; + case NBTConstants.TYPE_LIST: + writeListTagPayload((ListTag) tag); + break; + case NBTConstants.TYPE_COMPOUND: + writeCompoundTagPayload((CompoundTag) tag); + break; + case NBTConstants.TYPE_INT_ARRAY: + writeIntArrayTagPayload((IntArrayTag) tag); + break; + case NBTConstants.TYPE_LONG_ARRAY: + writeLongArrayTagPayload((LongArrayTag) tag); + break; + default: + throw new IOException("Invalid tag type: " + type + "."); + } + } + + /** + * Writes a {@code TAG_Byte} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeByteTagPayload(ByteTag tag) throws IOException { + os.writeByte(tag.getValue()); + } + + /** + * Writes a {@code TAG_Byte_Array} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException { + byte[] bytes = tag.getValue(); + os.writeInt(bytes.length); + os.write(bytes); + } + + /** + * Writes a {@code TAG_Compound} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeCompoundTagPayload(CompoundTag tag) throws IOException { + for (Map.Entry entry : tag.getValue().entrySet()) { + writeNamedTag(entry.getKey(), entry.getValue()); + } + os.writeByte((byte) 0); // end tag - better way? + } + + /** + * Writes a {@code TAG_List} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeListTagPayload(ListTag tag) throws IOException { + Class clazz = tag.getType(); + if (clazz == null) { + clazz = CompoundTag.class; + } + List tags = tag.getValue(); + int size = tags.size(); + if (!tags.isEmpty()) { + Tag tag0 = tags.get(0); + os.writeByte(tag0.getTypeCode()); + } else { + os.writeByte(NBTUtils.getTypeCode(clazz)); + } + os.writeInt(size); + for (Tag tag1 : tags) { + writeTagPayload(tag1); + } + } + + /** + * Writes a {@code TAG_String} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeStringTagPayload(StringTag tag) throws IOException { + byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET); + os.writeShort(bytes.length); + os.write(bytes); + } + + /** + * Writes a {@code TAG_Double} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeDoubleTagPayload(DoubleTag tag) throws IOException { + os.writeDouble(tag.getValue()); + } + + /** + * Writes a {@code TAG_Float} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeFloatTagPayload(FloatTag tag) throws IOException { + os.writeFloat(tag.getValue()); + } + + /** + * Writes a {@code TAG_Long} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeLongTagPayload(LongTag tag) throws IOException { + os.writeLong(tag.getValue()); + } + + /** + * Writes a {@code TAG_Int} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeIntTagPayload(IntTag tag) throws IOException { + os.writeInt(tag.getValue()); + } + + /** + * Writes a {@code TAG_Short} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeShortTagPayload(ShortTag tag) throws IOException { + os.writeShort(tag.getValue()); + } + + /** + * Writes a {@code TAG_Empty} tag. + * + * @param tag the tag + */ + private void writeEndTagPayload(EndTag tag) { + /* empty */ + } + + private void writeIntArrayTagPayload(IntArrayTag tag) throws IOException { + int[] data = tag.getValue(); + os.writeInt(data.length); + for (int aData : data) { + os.writeInt(aData); + } + } + + private void writeLongArrayTagPayload(LongArrayTag tag) throws IOException { + long[] data = tag.getValue(); + os.writeInt(data.length); + for (long aData : data) { + os.writeLong(aData); + } + } + + @Override + public void close() throws IOException { + if (os instanceof Closeable) { + ((Closeable) os).close(); + } + } + + @Override + public void write(int b) throws IOException { + os.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + os.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + os.write(b, off, len); + } + + @Override + public void writeBoolean(boolean v) throws IOException { + os.writeBoolean(v); + } + + @Override + public void writeByte(int v) throws IOException { + os.writeByte(v); + } + + @Override + public void writeShort(int v) throws IOException { + os.writeShort(v); + } + + @Override + public void writeChar(int v) throws IOException { + os.writeChar(v); + } + + @Override + public void writeInt(int v) throws IOException { + os.writeInt(v); + } + + @Override + public void writeLong(long v) throws IOException { + os.writeLong(v); + } + + @Override + public void writeFloat(float v) throws IOException { + os.writeFloat(v); + } + + @Override + public void writeDouble(double v) throws IOException { + os.writeDouble(v); + } + + @Override + public void writeBytes(String s) throws IOException { + os.writeBytes(s); + } + + @Override + public void writeChars(String s) throws IOException { + os.writeChars(s); + } + + @Override + public void writeUTF(String s) throws IOException { + os.writeUTF(s); + } + + /** + * Flush output. + * + * @throws IOException + */ + @Override + public void flush() throws IOException { + if (os instanceof Flushable) { + ((Flushable) os).flush(); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index cb765d2d7..bae194af3 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -1,195 +1,195 @@ -/* - * 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 com.sk89q.worldedit.math.Vector3; -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. - * - */ -public final class NBTUtils { - - /** - * Default private constructor. - */ - private NBTUtils() { - } - - /** - * Gets the type name of a tag. - * - * @param clazz the tag class - * @return The type name. - */ - public static String getTypeName(Class clazz) { - if (clazz.equals(ByteArrayTag.class)) { - return "TAG_Byte_Array"; - } else if (clazz.equals(ByteTag.class)) { - return "TAG_Byte"; - } else if (CompoundTag.class.isAssignableFrom(clazz)) { - return "TAG_Compound"; - } else if (clazz.equals(DoubleTag.class)) { - return "TAG_Double"; - } else if (clazz.equals(EndTag.class)) { - return "TAG_End"; - } else if (clazz.equals(FloatTag.class)) { - return "TAG_Float"; - } else if (clazz.equals(IntTag.class)) { - return "TAG_Int"; - } else if (clazz.equals(ListTag.class)) { - return "TAG_List"; - } else if (clazz.equals(LongTag.class)) { - return "TAG_Long"; - } else if (clazz.equals(ShortTag.class)) { - return "TAG_Short"; - } else if (clazz.equals(StringTag.class)) { - return "TAG_String"; - } else if (clazz.equals(IntArrayTag.class)) { - return "TAG_Int_Array"; - } else if (clazz.equals(LongArrayTag.class)) { - return "TAG_Long_Array"; - } else { - throw new IllegalArgumentException("Invalid tag class (" - + clazz.getName() + ")."); - } - } - - /** - * Gets the type code of a tag class. - * - * @param clazz the tag class - * @return The type code. - * @throws IllegalArgumentException if the tag class is invalid. - */ - public static int getTypeCode(Class clazz) { - if (clazz.equals(ByteArrayTag.class)) { - return NBTConstants.TYPE_BYTE_ARRAY; - } else if (clazz.equals(ByteTag.class)) { - return NBTConstants.TYPE_BYTE; - } else if (CompoundTag.class.isAssignableFrom(clazz)) { - return NBTConstants.TYPE_COMPOUND; - } else if (clazz.equals(DoubleTag.class)) { - return NBTConstants.TYPE_DOUBLE; - } else if (clazz.equals(EndTag.class)) { - return NBTConstants.TYPE_END; - } else if (clazz.equals(FloatTag.class)) { - return NBTConstants.TYPE_FLOAT; - } else if (clazz.equals(IntTag.class)) { - return NBTConstants.TYPE_INT; - } else if (clazz.equals(ListTag.class)) { - return NBTConstants.TYPE_LIST; - } else if (clazz.equals(LongTag.class)) { - return NBTConstants.TYPE_LONG; - } else if (clazz.equals(ShortTag.class)) { - return NBTConstants.TYPE_SHORT; - } else if (clazz.equals(StringTag.class)) { - return NBTConstants.TYPE_STRING; - } else if (clazz.equals(IntArrayTag.class)) { - return NBTConstants.TYPE_INT_ARRAY; - } else if (clazz.equals(LongArrayTag.class)) { - return NBTConstants.TYPE_LONG_ARRAY; - } else { - throw new IllegalArgumentException("Invalid tag class (" - + clazz.getName() + ")."); - } - } - - /** - * Gets the class of a type of tag. - * - * @param type the type - * @return The class. - * @throws IllegalArgumentException if the tag type is invalid. - */ - public static Class getTypeClass(int type) { - switch (type) { - case NBTConstants.TYPE_END: - return EndTag.class; - case NBTConstants.TYPE_BYTE: - return ByteTag.class; - case NBTConstants.TYPE_SHORT: - return ShortTag.class; - case NBTConstants.TYPE_INT: - return IntTag.class; - case NBTConstants.TYPE_LONG: - return LongTag.class; - case NBTConstants.TYPE_FLOAT: - return FloatTag.class; - case NBTConstants.TYPE_DOUBLE: - return DoubleTag.class; - case NBTConstants.TYPE_BYTE_ARRAY: - return ByteArrayTag.class; - case NBTConstants.TYPE_STRING: - return StringTag.class; - case NBTConstants.TYPE_LIST: - return ListTag.class; - case NBTConstants.TYPE_COMPOUND: - return CompoundTag.class; - case NBTConstants.TYPE_INT_ARRAY: - return IntArrayTag.class; - case NBTConstants.TYPE_LONG_ARRAY: - return LongArrayTag.class; - default: - throw new IllegalArgumentException("Invalid tag type : " + type - + "."); - } - } - - /** - * 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 - */ - public static Vector3 toVector(ListTag listTag) { - checkNotNull(listTag); - return Vector3.at(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2)); - } - - /** - * Get child tag of a NBT structure. - * - * @param items the map to read from - * @param key the key to look for - * @param expected the expected NBT class type - * @return child tag - * @throws InvalidFormatException if the format of the items is invalid - */ - public static T getChildTag(Map items, String key, Class expected) throws InvalidFormatException { - if (!items.containsKey(key)) { - throw new InvalidFormatException("Missing a \"" + key + "\" tag"); - } - Tag tag = items.get(key); - if (!expected.isInstance(tag)) { - throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName()); - } - return expected.cast(tag); - } - -} +/* + * 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 com.sk89q.worldedit.math.Vector3; +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. + * + */ +public final class NBTUtils { + + /** + * Default private constructor. + */ + private NBTUtils() { + } + + /** + * Gets the type name of a tag. + * + * @param clazz the tag class + * @return The type name. + */ + public static String getTypeName(Class clazz) { + if (clazz.equals(ByteArrayTag.class)) { + return "TAG_Byte_Array"; + } else if (clazz.equals(ByteTag.class)) { + return "TAG_Byte"; + } else if (CompoundTag.class.isAssignableFrom(clazz)) { + return "TAG_Compound"; + } else if (clazz.equals(DoubleTag.class)) { + return "TAG_Double"; + } else if (clazz.equals(EndTag.class)) { + return "TAG_End"; + } else if (clazz.equals(FloatTag.class)) { + return "TAG_Float"; + } else if (clazz.equals(IntTag.class)) { + return "TAG_Int"; + } else if (clazz.equals(ListTag.class)) { + return "TAG_List"; + } else if (clazz.equals(LongTag.class)) { + return "TAG_Long"; + } else if (clazz.equals(ShortTag.class)) { + return "TAG_Short"; + } else if (clazz.equals(StringTag.class)) { + return "TAG_String"; + } else if (clazz.equals(IntArrayTag.class)) { + return "TAG_Int_Array"; + } else if (clazz.equals(LongArrayTag.class)) { + return "TAG_Long_Array"; + } else { + throw new IllegalArgumentException("Invalid tag class (" + + clazz.getName() + ")."); + } + } + + /** + * Gets the type code of a tag class. + * + * @param clazz the tag class + * @return The type code. + * @throws IllegalArgumentException if the tag class is invalid. + */ + public static int getTypeCode(Class clazz) { + if (clazz.equals(ByteArrayTag.class)) { + return NBTConstants.TYPE_BYTE_ARRAY; + } else if (clazz.equals(ByteTag.class)) { + return NBTConstants.TYPE_BYTE; + } else if (CompoundTag.class.isAssignableFrom(clazz)) { + return NBTConstants.TYPE_COMPOUND; + } else if (clazz.equals(DoubleTag.class)) { + return NBTConstants.TYPE_DOUBLE; + } else if (clazz.equals(EndTag.class)) { + return NBTConstants.TYPE_END; + } else if (clazz.equals(FloatTag.class)) { + return NBTConstants.TYPE_FLOAT; + } else if (clazz.equals(IntTag.class)) { + return NBTConstants.TYPE_INT; + } else if (clazz.equals(ListTag.class)) { + return NBTConstants.TYPE_LIST; + } else if (clazz.equals(LongTag.class)) { + return NBTConstants.TYPE_LONG; + } else if (clazz.equals(ShortTag.class)) { + return NBTConstants.TYPE_SHORT; + } else if (clazz.equals(StringTag.class)) { + return NBTConstants.TYPE_STRING; + } else if (clazz.equals(IntArrayTag.class)) { + return NBTConstants.TYPE_INT_ARRAY; + } else if (clazz.equals(LongArrayTag.class)) { + return NBTConstants.TYPE_LONG_ARRAY; + } else { + throw new IllegalArgumentException("Invalid tag class (" + + clazz.getName() + ")."); + } + } + + /** + * Gets the class of a type of tag. + * + * @param type the type + * @return The class. + * @throws IllegalArgumentException if the tag type is invalid. + */ + public static Class getTypeClass(int type) { + switch (type) { + case NBTConstants.TYPE_END: + return EndTag.class; + case NBTConstants.TYPE_BYTE: + return ByteTag.class; + case NBTConstants.TYPE_SHORT: + return ShortTag.class; + case NBTConstants.TYPE_INT: + return IntTag.class; + case NBTConstants.TYPE_LONG: + return LongTag.class; + case NBTConstants.TYPE_FLOAT: + return FloatTag.class; + case NBTConstants.TYPE_DOUBLE: + return DoubleTag.class; + case NBTConstants.TYPE_BYTE_ARRAY: + return ByteArrayTag.class; + case NBTConstants.TYPE_STRING: + return StringTag.class; + case NBTConstants.TYPE_LIST: + return ListTag.class; + case NBTConstants.TYPE_COMPOUND: + return CompoundTag.class; + case NBTConstants.TYPE_INT_ARRAY: + return IntArrayTag.class; + case NBTConstants.TYPE_LONG_ARRAY: + return LongArrayTag.class; + default: + throw new IllegalArgumentException("Invalid tag type : " + type + + "."); + } + } + + /** + * 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 + */ + public static Vector3 toVector(ListTag listTag) { + checkNotNull(listTag); + return Vector3.at(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2)); + } + + /** + * Get child tag of a NBT structure. + * + * @param items the map to read from + * @param key the key to look for + * @param expected the expected NBT class type + * @return child tag + * @throws InvalidFormatException if the format of the items is invalid + */ + public static T getChildTag(Map items, String key, Class expected) throws InvalidFormatException { + if (!items.containsKey(key)) { + throw new InvalidFormatException("Missing a \"" + key + "\" tag"); + } + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName()); + } + return expected.cast(tag); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java index 3464254bf..30f47246a 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java @@ -1,53 +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.jnbt; - -/** - * The {@code TAG_Short} tag. - */ -public final class ShortTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_SHORT; - } - - 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; - } - - @Override - public Short getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_Short(" + value + ")"; - } - -} +/* + * 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; + +/** + * The {@code TAG_Short} tag. + */ +public final class ShortTag extends NumberTag { + @Override + public int getTypeCode() { + return NBTConstants.TYPE_SHORT; + } + + 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; + } + + @Override + public Short getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Short(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java index 057ac8c64..5920c6f68 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java @@ -1,57 +1,57 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.jnbt; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * The {@code TAG_String} tag. - */ -public final class StringTag extends Tag { - - @Override - public int getTypeCode() { - return NBTConstants.TYPE_STRING; - } - - 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; - } - - @Override - public String getValue() { - return value; - } - - @Override - public String toString() { - return "TAG_String(" + value + ")"; - } - -} +/* + * 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 static com.google.common.base.Preconditions.checkNotNull; + +/** + * The {@code TAG_String} tag. + */ +public final class StringTag extends Tag { + + @Override + public int getTypeCode() { + return NBTConstants.TYPE_STRING; + } + + 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; + } + + @Override + public String getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_String(" + value + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java index adfc5147a..387dc62c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java @@ -1,40 +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.jnbt; - -/** - * Represents a NBT tag. - */ -public abstract class Tag { - - /** - * Gets the value of this tag. - * - * @return the value - */ - public abstract Object getValue(); - - public Object toRaw() { - return getValue(); - } - - public abstract int getTypeCode(); - -} +/* + * 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; + +/** + * Represents a NBT tag. + */ +public abstract class Tag { + + /** + * Gets the value of this tag. + * + * @return the value + */ + public abstract Object getValue(); + + public Object toRaw() { + return getValue(); + } + + public abstract int getTypeCode(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Command.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Command.java index 5bee25f32..3e14f1b94 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Command.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Command.java @@ -1,99 +1,99 @@ -/* - * 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.minecraft.util.commands; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This annotation indicates a command. Methods should be marked with this - * annotation to tell {@link CommandsManager} that the method is a command. - * Note that the method name can actually be anything. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface Command { - - /** - * A list of aliases for the command. The first alias is the most - * important -- it is the main name of the command. (The method name - * is never used for anything). - * - * @return Aliases for a command - */ - String[] aliases(); - - /** - * Usage instruction. Example text for usage could be - * {@code [-h harps] [name] [message]}. - * - * @return Usage instructions for a command - */ - String usage() default ""; - - /** - * @return A short description for the command. - */ - String desc(); - - /** - * The minimum number of arguments. This should be 0 or above. - * - * @return the minimum number of arguments - */ - int min() default 0; - - /** - * The maximum number of arguments. Use -1 for an unlimited number - * of arguments. - * - * @return the maximum number of arguments - */ - int max() default -1; - - /** - * Flags allow special processing for flags such as -h in the command, - * allowing users to easily turn on a flag. This is a string with - * each character being a flag. Use A-Z and a-z as possible flags. - * Appending a flag with a : makes the flag character before a value flag, - * meaning that if it is given it must have a value - * - * @return Flags matching a-zA-Z - */ - String flags() default ""; - - /** - * @return A long description for the command. - */ - String help() default ""; - - /** - * Get whether any flag can be used. - * - * @return true if so - */ - boolean anyFlags() default false; - - /** - * Should the command be queued - * @return true if so - */ - boolean queued() default true; - -} +/* + * 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.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This annotation indicates a command. Methods should be marked with this + * annotation to tell {@link CommandsManager} that the method is a command. + * Note that the method name can actually be anything. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Command { + + /** + * A list of aliases for the command. The first alias is the most + * important -- it is the main name of the command. (The method name + * is never used for anything). + * + * @return Aliases for a command + */ + String[] aliases(); + + /** + * Usage instruction. Example text for usage could be + * {@code [-h harps] [name] [message]}. + * + * @return Usage instructions for a command + */ + String usage() default ""; + + /** + * @return A short description for the command. + */ + String desc(); + + /** + * The minimum number of arguments. This should be 0 or above. + * + * @return the minimum number of arguments + */ + int min() default 0; + + /** + * The maximum number of arguments. Use -1 for an unlimited number + * of arguments. + * + * @return the maximum number of arguments + */ + int max() default -1; + + /** + * Flags allow special processing for flags such as -h in the command, + * allowing users to easily turn on a flag. This is a string with + * each character being a flag. Use A-Z and a-z as possible flags. + * Appending a flag with a : makes the flag character before a value flag, + * meaning that if it is given it must have a value + * + * @return Flags matching a-zA-Z + */ + String flags() default ""; + + /** + * @return A long description for the command. + */ + String help() default ""; + + /** + * Get whether any flag can be used. + * + * @return true if so + */ + boolean anyFlags() default false; + + /** + * Should the command be queued + * @return true if so + */ + boolean queued() default true; + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java index 9dfc58d6f..b7620a1ee 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java @@ -1,362 +1,362 @@ -/* - * 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.minecraft.util.commands; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class CommandContext { - - protected final String command; - protected final List parsedArgs; - - protected final List originalArgIndices; - protected final String[] originalArgs; - protected final Set booleanFlags = new HashSet<>(); - protected final Map valueFlags = new HashMap<>(); - protected final SuggestionContext suggestionContext; - protected final CommandLocals locals; - - public static String[] split(String args) { - return args.split(" ", -1); - } - - public CommandContext(String args) throws CommandException { - this(args.split(" ", -1), null); - } - - public CommandContext(String[] args) throws CommandException { - this(args, null); - } - - public CommandContext(String args, Set valueFlags) throws CommandException { - this(args.split(" ", -1), valueFlags); - } - - public CommandContext(String args, Set valueFlags, boolean allowHangingFlag) - throws CommandException { - this(args.split(" ", -1), valueFlags, allowHangingFlag, new CommandLocals()); - } - - public CommandContext(String[] args, Set valueFlags) throws CommandException { - this(args, valueFlags, false, null); - } - - /** - * Parse the given array of arguments. - * - *

Empty arguments are removed from the list of arguments.

- * - * @param args an array with arguments - * @param valueFlags a set containing all value flags (pass null to disable value flag parsing) - * @param allowHangingFlag true if hanging flags are allowed - * @param locals the locals, null to create empty one - * @throws CommandException thrown on a parsing error - */ - public CommandContext(String[] args, Set valueFlags, boolean allowHangingFlag, CommandLocals locals) throws CommandException { - this(args, valueFlags, allowHangingFlag, locals, true); - } - - /** - * Parse the given array of arguments. - * - *

Empty arguments are removed from the list of arguments.

- * - * @param args an array with arguments - * @param valueFlags a set containing all value flags (pass null to disable value flag parsing) - * @param allowHangingFlag true if hanging flags are allowed - * @param locals the locals, null to create empty one - * @param parseFlags where to parse flags - * @throws CommandException thrown on a parsing error - */ - public CommandContext(String[] args, Set valueFlags, boolean allowHangingFlag, CommandLocals locals, boolean parseFlags) throws CommandException { - if (valueFlags == null) { - valueFlags = Collections.emptySet(); - } - - originalArgs = args; - command = args[0]; - this.locals = locals != null ? locals : new CommandLocals(); - boolean isHanging = false; - SuggestionContext suggestionContext = SuggestionContext.hangingValue(); - - // Eliminate empty args and combine multiword args first - List argIndexList = new ArrayList<>(args.length); - List argList = new ArrayList<>(args.length); - for (int i = 1; i < args.length; ++i) { - isHanging = false; - - String arg = args[i]; - if (arg.isEmpty()) { - isHanging = true; - continue; - } - - argIndexList.add(i); - - switch (arg.charAt(0)) { - case '\'': - case '"': - final StringBuilder build = new StringBuilder(); - final char quotedChar = arg.charAt(0); - - int endIndex; - for (endIndex = i; endIndex < args.length; ++endIndex) { - final String arg2 = args[endIndex]; - if (arg2.charAt(arg2.length() - 1) == quotedChar && arg2.length() > 1) { - if (endIndex != i) build.append(' '); - build.append(arg2.substring(endIndex == i ? 1 : 0, arg2.length() - 1)); - break; - } else if (endIndex == i) { - build.append(arg2.substring(1)); - } else { - build.append(' ').append(arg2); - } - } - - if (endIndex < args.length) { - arg = build.toString(); - i = endIndex; - } - - // In case there is an empty quoted string - if (arg.isEmpty()) { - continue; - } - // else raise exception about hanging quotes? - } - argList.add(arg); - } - - // Then flags - - this.originalArgIndices = new ArrayList<>(argIndexList.size()); - this.parsedArgs = new ArrayList<>(argList.size()); - - if (parseFlags) { - for (int nextArg = 0; nextArg < argList.size(); ) { - // Fetch argument - String arg = argList.get(nextArg++); - suggestionContext = SuggestionContext.hangingValue(); - - // Not a flag? - if (arg.charAt(0) != '-' || arg.length() == 1 || !arg.matches("^-[a-zA-Z\\?]+$")) { - if (!isHanging) { - suggestionContext = SuggestionContext.lastValue(); - } - - originalArgIndices.add(argIndexList.get(nextArg - 1)); - parsedArgs.add(arg); - continue; - } - - // Handle flag parsing terminator -- - if (arg.equals("--")) { - while (nextArg < argList.size()) { - originalArgIndices.add(argIndexList.get(nextArg)); - parsedArgs.add(argList.get(nextArg++)); - } - break; - } - - // Go through the flag characters - for (int i = 1; i < arg.length(); ++i) { - char flagName = arg.charAt(i); - - if (valueFlags.contains(flagName)) { - if (this.valueFlags.containsKey(flagName)) { - throw new CommandException("Value flag '" + flagName + "' already given"); - } - - if (nextArg >= argList.size()) { - if (allowHangingFlag) { - suggestionContext = SuggestionContext.flag(flagName); - break; - } else { - throw new CommandException("No value specified for the '-" + flagName + "' flag."); - } - } - - // If it is a value flag, read another argument and add it - this.valueFlags.put(flagName, argList.get(nextArg++)); - if (!isHanging) { - suggestionContext = SuggestionContext.flag(flagName); - } - } else { - booleanFlags.add(flagName); - } - } - } - } else { - for (int i = 0; i < argList.size(); i++) { - String arg = argList.get(i); - originalArgIndices.add(argIndexList.get(i)); - parsedArgs.add(arg); - } - } - - this.suggestionContext = suggestionContext; - } - - public SuggestionContext getSuggestionContext() { - return suggestionContext; - } - - public String getCommand() { - return command; - } - - public boolean matches(String command) { - return this.command.equalsIgnoreCase(command); - } - - public String getString(int index) { - return parsedArgs.get(index); - } - - public String getString(int index, String def) { - return index < parsedArgs.size() ? parsedArgs.get(index) : def; - } - - public String getJoinedStrings(int initialIndex) { - initialIndex = originalArgIndices.get(initialIndex); - StringBuilder buffer = new StringBuilder(originalArgs[initialIndex]); - for (int i = initialIndex + 1; i < originalArgs.length; ++i) { - buffer.append(" ").append(originalArgs[i]); - } - return buffer.toString(); - } - - public String getRemainingString(int start) { - return getString(start, parsedArgs.size() - 1); - } - - public String getString(int start, int end) { - StringBuilder buffer = new StringBuilder(parsedArgs.get(start)); - for (int i = start + 1; i < end + 1; ++i) { - buffer.append(" ").append(parsedArgs.get(i)); - } - return buffer.toString(); - } - - public int getInteger(int index) throws NumberFormatException { - return Integer.parseInt(parsedArgs.get(index)); - } - - public int getInteger(int index, int def) throws NumberFormatException { - return index < parsedArgs.size() ? Integer.parseInt(parsedArgs.get(index)) : def; - } - - public double getDouble(int index) throws NumberFormatException { - return Double.parseDouble(parsedArgs.get(index)); - } - - public double getDouble(int index, double def) throws NumberFormatException { - return index < parsedArgs.size() ? Double.parseDouble(parsedArgs.get(index)) : def; - } - - public String[] getSlice(int index) { - String[] slice = new String[originalArgs.length - index]; - System.arraycopy(originalArgs, index, slice, 0, originalArgs.length - index); - return slice; - } - - public String[] getPaddedSlice(int index, int padding) { - String[] slice = new String[originalArgs.length - index + padding]; - System.arraycopy(originalArgs, index, slice, padding, originalArgs.length - index); - return slice; - } - - public String[] getParsedSlice(int index) { - String[] slice = new String[parsedArgs.size() - index]; - System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, 0, parsedArgs.size() - index); - return slice; - } - - public String[] getParsedPaddedSlice(int index, int padding) { - String[] slice = new String[parsedArgs.size() - index + padding]; - System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, padding, parsedArgs.size() - index); - return slice; - } - - public boolean hasFlag(char ch) { - return booleanFlags.contains(ch) || valueFlags.containsKey(ch); - } - - public Set getFlags() { - return booleanFlags; - } - - public Map getValueFlags() { - return valueFlags; - } - - public String getFlag(char ch) { - return valueFlags.get(ch); - } - - public String getFlag(char ch, String def) { - final String value = valueFlags.get(ch); - if (value == null) { - return def; - } - - return value; - } - - public int getFlagInteger(char ch) throws NumberFormatException { - return Integer.parseInt(valueFlags.get(ch)); - } - - public int getFlagInteger(char ch, int def) throws NumberFormatException { - final String value = valueFlags.get(ch); - if (value == null) { - return def; - } - - return Integer.parseInt(value); - } - - public double getFlagDouble(char ch) throws NumberFormatException { - return Double.parseDouble(valueFlags.get(ch)); - } - - public double getFlagDouble(char ch, double def) throws NumberFormatException { - final String value = valueFlags.get(ch); - if (value == null) { - return def; - } - - return Double.parseDouble(value); - } - - public int argsLength() { - return parsedArgs.size(); - } - - public CommandLocals getLocals() { - return locals; - } -} +/* + * 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.minecraft.util.commands; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class CommandContext { + + protected final String command; + protected final List parsedArgs; + + protected final List originalArgIndices; + protected final String[] originalArgs; + protected final Set booleanFlags = new HashSet<>(); + protected final Map valueFlags = new HashMap<>(); + protected final SuggestionContext suggestionContext; + protected final CommandLocals locals; + + public static String[] split(String args) { + return args.split(" ", -1); + } + + public CommandContext(String args) throws CommandException { + this(args.split(" ", -1), null); + } + + public CommandContext(String[] args) throws CommandException { + this(args, null); + } + + public CommandContext(String args, Set valueFlags) throws CommandException { + this(args.split(" ", -1), valueFlags); + } + + public CommandContext(String args, Set valueFlags, boolean allowHangingFlag) + throws CommandException { + this(args.split(" ", -1), valueFlags, allowHangingFlag, new CommandLocals()); + } + + public CommandContext(String[] args, Set valueFlags) throws CommandException { + this(args, valueFlags, false, null); + } + + /** + * Parse the given array of arguments. + * + *

Empty arguments are removed from the list of arguments.

+ * + * @param args an array with arguments + * @param valueFlags a set containing all value flags (pass null to disable value flag parsing) + * @param allowHangingFlag true if hanging flags are allowed + * @param locals the locals, null to create empty one + * @throws CommandException thrown on a parsing error + */ + public CommandContext(String[] args, Set valueFlags, boolean allowHangingFlag, CommandLocals locals) throws CommandException { + this(args, valueFlags, allowHangingFlag, locals, true); + } + + /** + * Parse the given array of arguments. + * + *

Empty arguments are removed from the list of arguments.

+ * + * @param args an array with arguments + * @param valueFlags a set containing all value flags (pass null to disable value flag parsing) + * @param allowHangingFlag true if hanging flags are allowed + * @param locals the locals, null to create empty one + * @param parseFlags where to parse flags + * @throws CommandException thrown on a parsing error + */ + public CommandContext(String[] args, Set valueFlags, boolean allowHangingFlag, CommandLocals locals, boolean parseFlags) throws CommandException { + if (valueFlags == null) { + valueFlags = Collections.emptySet(); + } + + originalArgs = args; + command = args[0]; + this.locals = locals != null ? locals : new CommandLocals(); + boolean isHanging = false; + SuggestionContext suggestionContext = SuggestionContext.hangingValue(); + + // Eliminate empty args and combine multiword args first + List argIndexList = new ArrayList<>(args.length); + List argList = new ArrayList<>(args.length); + for (int i = 1; i < args.length; ++i) { + isHanging = false; + + String arg = args[i]; + if (arg.isEmpty()) { + isHanging = true; + continue; + } + + argIndexList.add(i); + + switch (arg.charAt(0)) { + case '\'': + case '"': + final StringBuilder build = new StringBuilder(); + final char quotedChar = arg.charAt(0); + + int endIndex; + for (endIndex = i; endIndex < args.length; ++endIndex) { + final String arg2 = args[endIndex]; + if (arg2.charAt(arg2.length() - 1) == quotedChar && arg2.length() > 1) { + if (endIndex != i) build.append(' '); + build.append(arg2.substring(endIndex == i ? 1 : 0, arg2.length() - 1)); + break; + } else if (endIndex == i) { + build.append(arg2.substring(1)); + } else { + build.append(' ').append(arg2); + } + } + + if (endIndex < args.length) { + arg = build.toString(); + i = endIndex; + } + + // In case there is an empty quoted string + if (arg.isEmpty()) { + continue; + } + // else raise exception about hanging quotes? + } + argList.add(arg); + } + + // Then flags + + this.originalArgIndices = new ArrayList<>(argIndexList.size()); + this.parsedArgs = new ArrayList<>(argList.size()); + + if (parseFlags) { + for (int nextArg = 0; nextArg < argList.size(); ) { + // Fetch argument + String arg = argList.get(nextArg++); + suggestionContext = SuggestionContext.hangingValue(); + + // Not a flag? + if (arg.charAt(0) != '-' || arg.length() == 1 || !arg.matches("^-[a-zA-Z\\?]+$")) { + if (!isHanging) { + suggestionContext = SuggestionContext.lastValue(); + } + + originalArgIndices.add(argIndexList.get(nextArg - 1)); + parsedArgs.add(arg); + continue; + } + + // Handle flag parsing terminator -- + if (arg.equals("--")) { + while (nextArg < argList.size()) { + originalArgIndices.add(argIndexList.get(nextArg)); + parsedArgs.add(argList.get(nextArg++)); + } + break; + } + + // Go through the flag characters + for (int i = 1; i < arg.length(); ++i) { + char flagName = arg.charAt(i); + + if (valueFlags.contains(flagName)) { + if (this.valueFlags.containsKey(flagName)) { + throw new CommandException("Value flag '" + flagName + "' already given"); + } + + if (nextArg >= argList.size()) { + if (allowHangingFlag) { + suggestionContext = SuggestionContext.flag(flagName); + break; + } else { + throw new CommandException("No value specified for the '-" + flagName + "' flag."); + } + } + + // If it is a value flag, read another argument and add it + this.valueFlags.put(flagName, argList.get(nextArg++)); + if (!isHanging) { + suggestionContext = SuggestionContext.flag(flagName); + } + } else { + booleanFlags.add(flagName); + } + } + } + } else { + for (int i = 0; i < argList.size(); i++) { + String arg = argList.get(i); + originalArgIndices.add(argIndexList.get(i)); + parsedArgs.add(arg); + } + } + + this.suggestionContext = suggestionContext; + } + + public SuggestionContext getSuggestionContext() { + return suggestionContext; + } + + public String getCommand() { + return command; + } + + public boolean matches(String command) { + return this.command.equalsIgnoreCase(command); + } + + public String getString(int index) { + return parsedArgs.get(index); + } + + public String getString(int index, String def) { + return index < parsedArgs.size() ? parsedArgs.get(index) : def; + } + + public String getJoinedStrings(int initialIndex) { + initialIndex = originalArgIndices.get(initialIndex); + StringBuilder buffer = new StringBuilder(originalArgs[initialIndex]); + for (int i = initialIndex + 1; i < originalArgs.length; ++i) { + buffer.append(" ").append(originalArgs[i]); + } + return buffer.toString(); + } + + public String getRemainingString(int start) { + return getString(start, parsedArgs.size() - 1); + } + + public String getString(int start, int end) { + StringBuilder buffer = new StringBuilder(parsedArgs.get(start)); + for (int i = start + 1; i < end + 1; ++i) { + buffer.append(" ").append(parsedArgs.get(i)); + } + return buffer.toString(); + } + + public int getInteger(int index) throws NumberFormatException { + return Integer.parseInt(parsedArgs.get(index)); + } + + public int getInteger(int index, int def) throws NumberFormatException { + return index < parsedArgs.size() ? Integer.parseInt(parsedArgs.get(index)) : def; + } + + public double getDouble(int index) throws NumberFormatException { + return Double.parseDouble(parsedArgs.get(index)); + } + + public double getDouble(int index, double def) throws NumberFormatException { + return index < parsedArgs.size() ? Double.parseDouble(parsedArgs.get(index)) : def; + } + + public String[] getSlice(int index) { + String[] slice = new String[originalArgs.length - index]; + System.arraycopy(originalArgs, index, slice, 0, originalArgs.length - index); + return slice; + } + + public String[] getPaddedSlice(int index, int padding) { + String[] slice = new String[originalArgs.length - index + padding]; + System.arraycopy(originalArgs, index, slice, padding, originalArgs.length - index); + return slice; + } + + public String[] getParsedSlice(int index) { + String[] slice = new String[parsedArgs.size() - index]; + System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, 0, parsedArgs.size() - index); + return slice; + } + + public String[] getParsedPaddedSlice(int index, int padding) { + String[] slice = new String[parsedArgs.size() - index + padding]; + System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, padding, parsedArgs.size() - index); + return slice; + } + + public boolean hasFlag(char ch) { + return booleanFlags.contains(ch) || valueFlags.containsKey(ch); + } + + public Set getFlags() { + return booleanFlags; + } + + public Map getValueFlags() { + return valueFlags; + } + + public String getFlag(char ch) { + return valueFlags.get(ch); + } + + public String getFlag(char ch, String def) { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return value; + } + + public int getFlagInteger(char ch) throws NumberFormatException { + return Integer.parseInt(valueFlags.get(ch)); + } + + public int getFlagInteger(char ch, int def) throws NumberFormatException { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return Integer.parseInt(value); + } + + public double getFlagDouble(char ch) throws NumberFormatException { + return Double.parseDouble(valueFlags.get(ch)); + } + + public double getFlagDouble(char ch, double def) throws NumberFormatException { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return Double.parseDouble(value); + } + + public int argsLength() { + return parsedArgs.size(); + } + + public CommandLocals getLocals() { + return locals; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java index d5ba775a0..8497e3f6b 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java @@ -1,83 +1,83 @@ -/* - * 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.minecraft.util.commands; - -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; -import javax.annotation.Nullable; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class CommandException extends Exception { - - private List commandStack = new ArrayList<>(); - - public CommandException() { - super(); - } - - public CommandException(String message) { - super(message); - } - - public CommandException(String message, Throwable t) { - super(message, t); - } - - public CommandException(Throwable t) { - super(t); - } - - public void prependStack(String name) { - commandStack.add(name); - } - - /** - * Gets the command that was called, which will include the sub-command - * (i.e. "/br sphere"). - * - * @param prefix the command shebang character (such as "/") -- may be empty - * @param spacedSuffix a suffix to put at the end (optional) -- may be null - * @return the command that was used - */ - public String getCommandUsed(String prefix, @Nullable String spacedSuffix) { - checkNotNull(prefix); - StringBuilder builder = new StringBuilder(); - if (prefix != null) { - builder.append(prefix); - } - ListIterator li = commandStack.listIterator(commandStack.size()); - while (li.hasPrevious()) { - if (li.previousIndex() != commandStack.size() - 1) { - builder.append(" "); - } - builder.append(li.previous()); - } - if (spacedSuffix != null) { - if (builder.length() > 0) { - builder.append(" "); - } - builder.append(spacedSuffix); - } - return builder.toString().trim(); - } - -} +/* + * 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.minecraft.util.commands; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class CommandException extends Exception { + + private List commandStack = new ArrayList<>(); + + public CommandException() { + super(); + } + + public CommandException(String message) { + super(message); + } + + public CommandException(String message, Throwable t) { + super(message, t); + } + + public CommandException(Throwable t) { + super(t); + } + + public void prependStack(String name) { + commandStack.add(name); + } + + /** + * Gets the command that was called, which will include the sub-command + * (i.e. "/br sphere"). + * + * @param prefix the command shebang character (such as "/") -- may be empty + * @param spacedSuffix a suffix to put at the end (optional) -- may be null + * @return the command that was used + */ + public String getCommandUsed(String prefix, @Nullable String spacedSuffix) { + checkNotNull(prefix); + StringBuilder builder = new StringBuilder(); + if (prefix != null) { + builder.append(prefix); + } + ListIterator li = commandStack.listIterator(commandStack.size()); + while (li.hasPrevious()) { + if (li.previousIndex() != commandStack.size() - 1) { + builder.append(" "); + } + builder.append(li.previous()); + } + if (spacedSuffix != null) { + if (builder.length() > 0) { + builder.append(" "); + } + builder.append(spacedSuffix); + } + return builder.toString().trim(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java index 90fd29709..2a7850734 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java @@ -1,39 +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.minecraft.util.commands; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Indicates a list of permissions that should be checked. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface CommandPermissions { - - /** - * A list of permissions. Only one permission has to be met - * for the command to be permitted. - * - * @return a list of permissions strings - */ - String[] value(); - -} +/* + * 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.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates a list of permissions that should be checked. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface CommandPermissions { + + /** + * A list of permissions. Only one permission has to be met + * for the command to be permitted. + * + * @return a list of permissions strings + */ + String[] value(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java index d86d2f225..d58def95e 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java @@ -1,27 +1,27 @@ -/* - * 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.minecraft.util.commands; - -/** - * Thrown when not enough permissions are satisfied. - */ -public class CommandPermissionsException extends CommandException { - -} +/* + * 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.minecraft.util.commands; + +/** + * Thrown when not enough permissions are satisfied. + */ +public class CommandPermissionsException extends CommandException { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java index 5e50c6ab5..69f17f62e 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java @@ -1,34 +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.minecraft.util.commands; - -public class CommandUsageException extends CommandException { - - protected String usage; - - public CommandUsageException(String message, String usage) { - super(message); - this.usage = usage; - } - - public String getUsage() { - return usage; - } -} +/* + * 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.minecraft.util.commands; + +public class CommandUsageException extends CommandException { + + protected String usage; + + public CommandUsageException(String message, String usage) { + super(message); + this.usage = usage; + } + + public String getUsage() { + return usage; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Console.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Console.java index 3ab90906a..a57505ac3 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Console.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Console.java @@ -1,31 +1,31 @@ -/* - * 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.minecraft.util.commands; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This annotation indicates that a command can be used from the console. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface Console { - -} +/* + * 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.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This annotation indicates that a command can be used from the console. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Console { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Injector.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Injector.java index 0ac9fb166..e0e1ff0e1 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Injector.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Injector.java @@ -1,40 +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.minecraft.util.commands; - -import java.lang.reflect.InvocationTargetException; - -/** - * Constructs new instances. - */ -public interface Injector { - - /** - * Constructs a new instance of the given class. - * - * @param cls class - * @return object - * @throws IllegalAccessException thrown on injection fault - * @throws InstantiationException thrown on injection fault - * @throws InvocationTargetException thrown on injection fault - */ - Object getInstance(Class cls) throws InvocationTargetException, IllegalAccessException, InstantiationException; - -} +/* + * 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.minecraft.util.commands; + +import java.lang.reflect.InvocationTargetException; + +/** + * Constructs new instances. + */ +public interface Injector { + + /** + * Constructs a new instance of the given class. + * + * @param cls class + * @return object + * @throws IllegalAccessException thrown on injection fault + * @throws InstantiationException thrown on injection fault + * @throws InvocationTargetException thrown on injection fault + */ + Object getInstance(Class cls) throws InvocationTargetException, IllegalAccessException, InstantiationException; + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java index 2ca2c2d18..eab4b2cd8 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java @@ -1,28 +1,28 @@ -/* - * 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.minecraft.util.commands; - -public class MissingNestedCommandException extends CommandUsageException { - - public MissingNestedCommandException(String message, String usage) { - super(message, usage); - } - -} +/* + * 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.minecraft.util.commands; + +public class MissingNestedCommandException extends CommandUsageException { + + public MissingNestedCommandException(String message, String usage) { + super(message, usage); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java index ae0e5ae14..05002c7fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java @@ -1,50 +1,50 @@ -/* - * 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.minecraft.util.commands; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Indicates a nested command. Mark methods with this annotation to tell - * {@link CommandsManager} that a method is merely a shell for child - * commands. Note that the body of a method marked with this annotation - * will never called. Additionally, not all fields of {@link Command} apply - * when it is used in conjunction with this annotation, although both - * are still required. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface NestedCommand { - - /** - * A list of classes with the child commands. - * - * @return a list of classes - */ - Class[] value(); - - /** - * If set to true it will execute the body of the tagged method. - * - * @return true to execute the body of the annotated method - */ - boolean executeBody() default false; - -} +/* + * 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.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates a nested command. Mark methods with this annotation to tell + * {@link CommandsManager} that a method is merely a shell for child + * commands. Note that the body of a method marked with this annotation + * will never called. Additionally, not all fields of {@link Command} apply + * when it is used in conjunction with this annotation, although both + * are still required. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface NestedCommand { + + /** + * A list of classes with the child commands. + * + * @return a list of classes + */ + Class[] value(); + + /** + * If set to true it will execute the body of the tagged method. + * + * @return true to execute the body of the annotated method + */ + boolean executeBody() default false; + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java index 918ca6fd6..117d96963 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java @@ -1,24 +1,24 @@ -/* - * 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.minecraft.util.commands; - -public class UnhandledCommandException extends CommandException { - -} +/* + * 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.minecraft.util.commands; + +public class UnhandledCommandException extends CommandException { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java index 02dcd8e23..b6621c8e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java @@ -1,28 +1,28 @@ -/* - * 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.minecraft.util.commands; - -public class WrappedCommandException extends CommandException { - - public WrappedCommandException(Throwable t) { - super(t); - } - -} +/* + * 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.minecraft.util.commands; + +public class WrappedCommandException extends CommandException { + + public WrappedCommandException(Throwable t) { + super(t); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java index 8353db02e..b188adb4f 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java @@ -1,369 +1,369 @@ -/* - * 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.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * String utilities. - */ -public final class StringUtil { - - private StringUtil() { - } - - /** - * Trim a string if it is longer than a certain length. - * - * @param str the string - * @param len the length to trim to - * @return a new string - */ - public static String trimLength(String str, int len) { - if (str.length() > len) { - return str.substring(0, len); - } - - return str; - } - - /** - * Join an array of strings into a string. - * - * @param str the string array - * @param delimiter the delimiter - * @param initialIndex the initial index to start form - * @return a new string - */ - public static String joinString(String[] str, String delimiter, int initialIndex) { - if (str.length == 0) { - return ""; - } - StringBuilder buffer = new StringBuilder(str[initialIndex]); - for (int i = initialIndex + 1; i < str.length; ++i) { - buffer.append(delimiter).append(str[i]); - } - return buffer.toString(); - } - - /** - * Join an array of strings into a string. - * - * @param str the string array - * @param delimiter the delimiter - * @param initialIndex the initial index to start form - * @param quote the character to put around each entry - * @return a new string - */ - public static String joinQuotedString(String[] str, String delimiter, - int initialIndex, String quote) { - if (str.length == 0) { - return ""; - } - StringBuilder buffer = new StringBuilder(); - buffer.append(quote); - buffer.append(str[initialIndex]); - buffer.append(quote); - for (int i = initialIndex + 1; i < str.length; ++i) { - buffer.append(delimiter).append(quote).append(str[i]).append(quote); - } - return buffer.toString(); - } - - /** - * Join an array of strings into a string. - * - * @param str the string array - * @param delimiter the delimiter - * @return a new string - */ - public static String joinString(String[] str, String delimiter) { - return joinString(str, delimiter, 0); - } - - /** - * Join an array of strings into a string. - * - * @param str an array of objects - * @param delimiter the delimiter - * @param initialIndex the initial index to start form - * @return a new string - */ - public static String joinString(Object[] str, String delimiter, int initialIndex) { - if (str.length == 0) { - return ""; - } - StringBuilder buffer = new StringBuilder(str[initialIndex].toString()); - for (int i = initialIndex + 1; i < str.length; ++i) { - buffer.append(delimiter).append(str[i]); - } - return buffer.toString(); - } - - /** - * Join an array of strings into a string. - * - * @param str a list of integers - * @param delimiter the delimiter - * @param initialIndex the initial index to start form - * @return a new string - */ - public static String joinString(int[] str, String delimiter, int initialIndex) { - if (str.length == 0) { - return ""; - } - StringBuilder buffer = new StringBuilder(Integer.toString(str[initialIndex])); - for (int i = initialIndex + 1; i < str.length; ++i) { - buffer.append(delimiter).append(Integer.toString(str[i])); - } - return buffer.toString(); - } - - /** - * Join an list of strings into a string. - * - * @param str a list of strings - * @param delimiter the delimiter - * @param initialIndex the initial index to start form - * @return a new string - */ - public static String joinString(Collection str, String delimiter, int initialIndex) { - if (str.isEmpty()) { - return ""; - } - StringBuilder buffer = new StringBuilder(); - int i = 0; - for (Object o : str) { - if (i >= initialIndex) { - if (i > 0) { - buffer.append(delimiter); - } - - buffer.append(o); - } - ++i; - } - return buffer.toString(); - } - - /** - *

Find the Levenshtein distance between two Strings.

- * - *

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

- * - *

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

- * - *

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

- * - *
-     * StringUtil.getLevenshteinDistance(null, *)             = IllegalArgumentException
-     * StringUtil.getLevenshteinDistance(*, null)             = IllegalArgumentException
-     * StringUtil.getLevenshteinDistance("","")               = 0
-     * StringUtil.getLevenshteinDistance("","a")              = 1
-     * StringUtil.getLevenshteinDistance("aaapppp", "")       = 7
-     * StringUtil.getLevenshteinDistance("frog", "fog")       = 1
-     * StringUtil.getLevenshteinDistance("fly", "ant")        = 3
-     * StringUtil.getLevenshteinDistance("elephant", "hippo") = 7
-     * StringUtil.getLevenshteinDistance("hippo", "elephant") = 7
-     * StringUtil.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
-     * StringUtil.getLevenshteinDistance("hello", "hallo")    = 1
-     * 
- * - * @param s the first String, must not be null - * @param t the second String, must not be null - * @return result distance - * @throws IllegalArgumentException if either String input {@code null} - */ - public static int getLevenshteinDistance(String s, String t) { - if (s == null || t == null) { - throw new IllegalArgumentException("Strings must not be null"); - } - - /* - * The difference between this impl. and the previous is that, rather - * than creating and retaining a matrix of size s.length()+1 by - * t.length()+1, we maintain two single-dimensional arrays of length - * s.length()+1. The first, d, is the 'current working' distance array - * that maintains the newest distance cost counts as we iterate through - * the characters of String s. Each time we increment the index of - * String t we are comparing, d is copied to p, the second int[]. Doing - * so allows us to retain the previous cost counts as required by the - * algorithm (taking the minimum of the cost count to the left, up one, - * and diagonally up and to the left of the current cost count being - * calculated). (Note that the arrays aren't really copied anymore, just - * switched...this is clearly much better than cloning an array or doing - * a System.arraycopy() each time through the outer loop.) - * - * Effectively, the difference between the two implementations is this - * one does not cause an out of memory condition when calculating the LD - * over two very large strings. - */ - - int n = s.length(); // length of s - int m = t.length(); // length of t - - if (n == 0) { - return m; - } else if (m == 0) { - return n; - } - - int[] p = new int[n + 1]; // 'previous' cost array, horizontally - int[] d = new int[n + 1]; // cost array, horizontally - int[] _d; // placeholder to assist in swapping p and d - - // indexes into strings s and t - int i; // iterates through s - int j; // iterates through t - - char tj; // jth character of t - - int cost; // cost - - for (i = 0; i <= n; ++i) { - p[i] = i; - } - - for (j = 1; j <= m; ++j) { - tj = t.charAt(j - 1); - d[0] = j; - - for (i = 1; i <= n; ++i) { - cost = s.charAt(i - 1) == tj ? 0 : 1; - // minimum of cell to the left+1, to the top+1, diagonally left - // and up +cost - d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] - + cost); - } - - // copy current distance counts to 'previous row' distance counts - _d = p; - p = d; - d = _d; - } - - // our last action in the above loop was to switch d and p, so p now - // actually has the most recent cost counts - return p[n]; - } - - public static > T lookup(Map lookup, String name, boolean fuzzy) { - String testName = name.replaceAll("[ _]", "").toLowerCase(Locale.ROOT); - - T type = lookup.get(testName); - if (type != null) { - return type; - } - - if (!fuzzy) { - return null; - } - - int minDist = -1; - - for (Map.Entry entry : lookup.entrySet()) { - final String key = entry.getKey(); - if (key.charAt(0) != testName.charAt(0)) { - continue; - } - - int dist = getLevenshteinDistance(key, testName); - - if ((dist < minDist || minDist == -1) && dist < 2) { - minDist = dist; - type = entry.getValue(); - } - } - - return type; - } - - public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, char quoteClose) { - return parseListInQuotes(input, delimiter, quoteOpen, quoteClose, false); - } - - public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, - char quoteClose, boolean appendLeftover) { - List parsableBlocks = new ArrayList<>(); - StringBuilder buffer = new StringBuilder(); - for (String split : input) { - if (split.indexOf(quoteOpen) != -1 && split.indexOf(quoteClose) == -1) { - buffer.append(split).append(delimiter); - } else if (split.indexOf(quoteClose) != -1 && split.indexOf(quoteOpen) == -1) { - buffer.append(split); - parsableBlocks.add(buffer.toString()); - buffer = new StringBuilder(); - } else if (buffer.length() == 0) { - parsableBlocks.add(split); - } else { - buffer.append(split).append(delimiter); - } - } - if (appendLeftover && buffer.length() != 0) { - parsableBlocks.add(buffer.delete(buffer.length() - 1, buffer.length()).toString()); - } - - return parsableBlocks; - } - - /** - * Splits a string respecting enclosing quotes. - * - * @param input the input to split. - * @param delimiter the delimiter to split on. - * @param open the opening quote character. - * @param close the closing quote character. - * @return a list of split strings. - */ - public static List split(String input, char delimiter, char open, char close) { - if (input.indexOf(open) == -1 && input.indexOf(close) == -1) { - return Arrays.asList(input.split(String.valueOf(delimiter))); - } - int level = 0; - int begin = 0; - List split = new ArrayList<>(); - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); - if (c == delimiter && level == 0) { - split.add(input.substring(begin, i)); - begin = i + 1; - } else if (c == open) { - level++; - } else if (c == close) { - level--; - } - } - if (begin < input.length()) { - split.add(input.substring(begin)); - } - return split; - } -} +/* + * 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.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * String utilities. + */ +public final class StringUtil { + + private StringUtil() { + } + + /** + * Trim a string if it is longer than a certain length. + * + * @param str the string + * @param len the length to trim to + * @return a new string + */ + public static String trimLength(String str, int len) { + if (str.length() > len) { + return str.substring(0, len); + } + + return str; + } + + /** + * Join an array of strings into a string. + * + * @param str the string array + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(String[] str, String delimiter, int initialIndex) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(str[initialIndex]); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(str[i]); + } + return buffer.toString(); + } + + /** + * Join an array of strings into a string. + * + * @param str the string array + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @param quote the character to put around each entry + * @return a new string + */ + public static String joinQuotedString(String[] str, String delimiter, + int initialIndex, String quote) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(); + buffer.append(quote); + buffer.append(str[initialIndex]); + buffer.append(quote); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(quote).append(str[i]).append(quote); + } + return buffer.toString(); + } + + /** + * Join an array of strings into a string. + * + * @param str the string array + * @param delimiter the delimiter + * @return a new string + */ + public static String joinString(String[] str, String delimiter) { + return joinString(str, delimiter, 0); + } + + /** + * Join an array of strings into a string. + * + * @param str an array of objects + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(Object[] str, String delimiter, int initialIndex) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(str[initialIndex].toString()); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(str[i]); + } + return buffer.toString(); + } + + /** + * Join an array of strings into a string. + * + * @param str a list of integers + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(int[] str, String delimiter, int initialIndex) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(Integer.toString(str[initialIndex])); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(Integer.toString(str[i])); + } + return buffer.toString(); + } + + /** + * Join an list of strings into a string. + * + * @param str a list of strings + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(Collection str, String delimiter, int initialIndex) { + if (str.isEmpty()) { + return ""; + } + StringBuilder buffer = new StringBuilder(); + int i = 0; + for (Object o : str) { + if (i >= initialIndex) { + if (i > 0) { + buffer.append(delimiter); + } + + buffer.append(o); + } + ++i; + } + return buffer.toString(); + } + + /** + *

Find the Levenshtein distance between two Strings.

+ * + *

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

+ * + *

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

+ * + *

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

+ * + *
+     * StringUtil.getLevenshteinDistance(null, *)             = IllegalArgumentException
+     * StringUtil.getLevenshteinDistance(*, null)             = IllegalArgumentException
+     * StringUtil.getLevenshteinDistance("","")               = 0
+     * StringUtil.getLevenshteinDistance("","a")              = 1
+     * StringUtil.getLevenshteinDistance("aaapppp", "")       = 7
+     * StringUtil.getLevenshteinDistance("frog", "fog")       = 1
+     * StringUtil.getLevenshteinDistance("fly", "ant")        = 3
+     * StringUtil.getLevenshteinDistance("elephant", "hippo") = 7
+     * StringUtil.getLevenshteinDistance("hippo", "elephant") = 7
+     * StringUtil.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
+     * StringUtil.getLevenshteinDistance("hello", "hallo")    = 1
+     * 
+ * + * @param s the first String, must not be null + * @param t the second String, must not be null + * @return result distance + * @throws IllegalArgumentException if either String input {@code null} + */ + public static int getLevenshteinDistance(String s, String t) { + if (s == null || t == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + + /* + * The difference between this impl. and the previous is that, rather + * than creating and retaining a matrix of size s.length()+1 by + * t.length()+1, we maintain two single-dimensional arrays of length + * s.length()+1. The first, d, is the 'current working' distance array + * that maintains the newest distance cost counts as we iterate through + * the characters of String s. Each time we increment the index of + * String t we are comparing, d is copied to p, the second int[]. Doing + * so allows us to retain the previous cost counts as required by the + * algorithm (taking the minimum of the cost count to the left, up one, + * and diagonally up and to the left of the current cost count being + * calculated). (Note that the arrays aren't really copied anymore, just + * switched...this is clearly much better than cloning an array or doing + * a System.arraycopy() each time through the outer loop.) + * + * Effectively, the difference between the two implementations is this + * one does not cause an out of memory condition when calculating the LD + * over two very large strings. + */ + + int n = s.length(); // length of s + int m = t.length(); // length of t + + if (n == 0) { + return m; + } else if (m == 0) { + return n; + } + + int[] p = new int[n + 1]; // 'previous' cost array, horizontally + int[] d = new int[n + 1]; // cost array, horizontally + int[] _d; // placeholder to assist in swapping p and d + + // indexes into strings s and t + int i; // iterates through s + int j; // iterates through t + + char tj; // jth character of t + + int cost; // cost + + for (i = 0; i <= n; ++i) { + p[i] = i; + } + + for (j = 1; j <= m; ++j) { + tj = t.charAt(j - 1); + d[0] = j; + + for (i = 1; i <= n; ++i) { + cost = s.charAt(i - 1) == tj ? 0 : 1; + // minimum of cell to the left+1, to the top+1, diagonally left + // and up +cost + d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + + cost); + } + + // copy current distance counts to 'previous row' distance counts + _d = p; + p = d; + d = _d; + } + + // our last action in the above loop was to switch d and p, so p now + // actually has the most recent cost counts + return p[n]; + } + + public static > T lookup(Map lookup, String name, boolean fuzzy) { + String testName = name.replaceAll("[ _]", "").toLowerCase(Locale.ROOT); + + T type = lookup.get(testName); + if (type != null) { + return type; + } + + if (!fuzzy) { + return null; + } + + int minDist = -1; + + for (Map.Entry entry : lookup.entrySet()) { + final String key = entry.getKey(); + if (key.charAt(0) != testName.charAt(0)) { + continue; + } + + int dist = getLevenshteinDistance(key, testName); + + if ((dist < minDist || minDist == -1) && dist < 2) { + minDist = dist; + type = entry.getValue(); + } + } + + return type; + } + + public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, char quoteClose) { + return parseListInQuotes(input, delimiter, quoteOpen, quoteClose, false); + } + + public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, + char quoteClose, boolean appendLeftover) { + List parsableBlocks = new ArrayList<>(); + StringBuilder buffer = new StringBuilder(); + for (String split : input) { + if (split.indexOf(quoteOpen) != -1 && split.indexOf(quoteClose) == -1) { + buffer.append(split).append(delimiter); + } else if (split.indexOf(quoteClose) != -1 && split.indexOf(quoteOpen) == -1) { + buffer.append(split); + parsableBlocks.add(buffer.toString()); + buffer = new StringBuilder(); + } else if (buffer.length() == 0) { + parsableBlocks.add(split); + } else { + buffer.append(split).append(delimiter); + } + } + if (appendLeftover && buffer.length() != 0) { + parsableBlocks.add(buffer.delete(buffer.length() - 1, buffer.length()).toString()); + } + + return parsableBlocks; + } + + /** + * Splits a string respecting enclosing quotes. + * + * @param input the input to split. + * @param delimiter the delimiter to split on. + * @param open the opening quote character. + * @param close the closing quote character. + * @return a list of split strings. + */ + public static List split(String input, char delimiter, char open, char close) { + if (input.indexOf(open) == -1 && input.indexOf(close) == -1) { + return Arrays.asList(input.split(String.valueOf(delimiter))); + } + int level = 0; + int begin = 0; + List split = new ArrayList<>(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (c == delimiter && level == 0) { + split.add(input.substring(begin, i)); + begin = i + 1; + } else if (c == open) { + level++; + } else if (c == close) { + level--; + } + } + if (begin < input.length()) { + split.add(input.substring(begin)); + } + return split; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/NotABlockException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/NotABlockException.java index 583b10ea3..9201e39b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/NotABlockException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/NotABlockException.java @@ -1,52 +1,52 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit; - -/** - * Raised when an item is used when a block was expected. - */ -public class NotABlockException extends WorldEditException { - - /** - * Create a new instance. - */ - public NotABlockException() { - super("This item is not a block."); - } - - /** - * Create a new instance. - * - * @param input the input that was used - */ - public NotABlockException(String input) { - super("The item '" + input + "' is not a block."); - } - - /** - * Create a new instance. - * - * @param input the input that was used - */ - public NotABlockException(int input) { - super("The item with the ID " + input + " is not a block."); - } - -} +/* + * 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; + +/** + * Raised when an item is used when a block was expected. + */ +public class NotABlockException extends WorldEditException { + + /** + * Create a new instance. + */ + public NotABlockException() { + super("This item is not a block."); + } + + /** + * Create a new instance. + * + * @param input the input that was used + */ + public NotABlockException(String input) { + super("The item '" + input + "' is not a block."); + } + + /** + * Create a new instance. + * + * @param input the input that was used + */ + public NotABlockException(int input) { + super("The item with the ID " + input + " is not a block."); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java index 6a1a0cbd5..99398d3e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java @@ -1,83 +1,83 @@ -/* - * 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.worldedit.world.item.ItemType; - -/** - * Represents a stack of BaseItems. - * - *

This class may be removed in the future.

- */ -public class BaseItemStack extends BaseItem { - - private int amount = 1; - - /** - * Construct the object with default stack size of one, with damage value of 0. - * - * @param itemType The item type - */ - public BaseItemStack(ItemType itemType) { - super(itemType); - } - - /** - * Construct the object. - * - * @param itemType The item type - * @param amount amount in the stack - */ - public BaseItemStack(ItemType itemType, int amount) { - super(itemType); - this.amount = amount; - } - - /** - * Construct the object. - * - * @param id The item type - * @param tag Tag value - * @param amount amount in the stack - */ - public BaseItemStack(ItemType id, CompoundTag tag, int amount) { - super(id, tag); - this.amount = amount; - } - - /** - * Get the number of items in the stack. - * - * @return the amount - */ - public int getAmount() { - return amount; - } - - /** - * Set the amount of items in the stack. - * - * @param amount the amount to set - */ - public void setAmount(int amount) { - this.amount = amount; - } -} +/* + * 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.worldedit.world.item.ItemType; + +/** + * Represents a stack of BaseItems. + * + *

This class may be removed in the future.

+ */ +public class BaseItemStack extends BaseItem { + + private int amount = 1; + + /** + * Construct the object with default stack size of one, with damage value of 0. + * + * @param itemType The item type + */ + public BaseItemStack(ItemType itemType) { + super(itemType); + } + + /** + * Construct the object. + * + * @param itemType The item type + * @param amount amount in the stack + */ + public BaseItemStack(ItemType itemType, int amount) { + super(itemType); + this.amount = amount; + } + + /** + * Construct the object. + * + * @param id The item type + * @param tag Tag value + * @param amount amount in the stack + */ + public BaseItemStack(ItemType id, CompoundTag tag, int amount) { + super(id, tag); + this.amount = amount; + } + + /** + * Get the number of items in the stack. + * + * @return the amount + */ + public int getAmount() { + return amount; + } + + /** + * Set the amount of items in the stack. + * + * @param amount the amount to set + */ + public void setAmount(int amount) { + this.amount = amount; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java index 4238e5f6d..6dea98712 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -1,250 +1,250 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions; - -import com.boydti.fawe.object.collection.BlockVectorSet; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.regions.iterator.RegionIterator; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.storage.ChunkStore; - -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -public abstract class AbstractRegion extends AbstractSet implements Region { - - protected World world; - - public AbstractRegion(World world) { - this.world = world; - } - - @Override - public int size() { - return com.google.common.primitives.Ints.saturatedCast(getVolume()); - } - - @Override - public Vector3 getCenter() { - return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); - } - - /** - * Get the iterator. - * - * @return iterator of points inside the region - */ - @Override - public Iterator iterator() { - return new RegionIterator(this); - } - - @Override - public World getWorld() { - return world; - } - - @Override - public void setWorld(World world) { - this.world = world; - } - - @Override - public void shift(BlockVector3 change) throws RegionOperationException { - expand(change); - contract(change); - } - - @Override - public AbstractRegion clone() { - try { - return (AbstractRegion) super.clone(); - } catch (CloneNotSupportedException exc) { - return null; - } - } - - @Override - public List polygonize(int maxPoints) { - if (maxPoints >= 0 && maxPoints < 4) { - throw new IllegalArgumentException("Cannot polygonize an AbstractRegion with no overridden polygonize method into less than 4 points."); - } - - final BlockVector3 min = getMinimumPoint(); - final BlockVector3 max = getMaximumPoint(); - - final List points = new ArrayList<>(4); - - points.add(BlockVector2.at(min.getX(), min.getZ())); - points.add(BlockVector2.at(min.getX(), max.getZ())); - points.add(BlockVector2.at(max.getX(), max.getZ())); - points.add(BlockVector2.at(max.getX(), min.getZ())); - - return points; - } - - @Override - public long getVolume() { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return (max.getX() - min.getX() + 1L) - * (max.getY() - min.getY() + 1L) - * (max.getZ() - min.getZ() + 1L); - } - - /** - * Get X-size. - * - * @return width - */ - @Override - public int getWidth() { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return max.getX() - min.getX() + 1; - } - - /** - * Get Y-size. - * - * @return height - */ - @Override - public int getHeight() { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return max.getY() - min.getY() + 1; - } - - /** - * Get Z-size. - * - * @return length - */ - @Override - public int getLength() { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return max.getZ() - min.getZ() + 1; - } - - /** - * Get a list of chunks. - * - * @return a set of chunks - */ - @Override - public Set getChunks() { - final Set chunks = new HashSet<>(); - - final BlockVector3 minBlock = getMinimumPoint(); - final BlockVector3 maxBlock = getMaximumPoint(); - - final BlockVector2 min = BlockVector2.at(minBlock.getX() >> 4, minBlock.getZ() >> 4); - final BlockVector2 max = BlockVector2.at(maxBlock.getX() >> 4, maxBlock.getZ() >> 4); - - for (int X = min.getBlockX(); X <= max.getBlockX(); ++X) { - for (int Z = min.getBlockZ(); Z <= max.getBlockZ(); ++Z) { - if (containsChunk(X, Z)) { - chunks.add(BlockVector2.at(X, Z)); - } - } - } - - return chunks; - } - - @Override - public Set getChunkCubes() { - final Set chunks = new BlockVectorSet(); - - final BlockVector3 min = getMinimumPoint(); - final BlockVector3 max = getMaximumPoint(); - - for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { - for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { - if (!contains(BlockVector3.at(x, y, z))) { - continue; - } - - chunks.add(BlockVector3.at( - x >> ChunkStore.CHUNK_SHIFTS, - y >> ChunkStore.CHUNK_SHIFTS, - z >> ChunkStore.CHUNK_SHIFTS - )); - } - } - } - - return chunks; - } - - // Sub-class utilities - - protected final int getWorldMinY() { - return world == null ? 0 : world.getMinY(); - } - - protected final int getWorldMaxY() { - return world == null ? 255 : world.getMaxY(); - } - - @Override - public int hashCode() { - int worldHash = this.world == null ? 7 : this.world.hashCode(); - int result = worldHash ^ (worldHash >>> 32); - result = 31 * result + this.getMinimumPoint().hashCode(); - result = 31 * result + this.getMaximumPoint().hashCode(); - result = (int) (31 * result + this.getVolume()); - return result; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Region)) { - return false; - } - Region region = ((Region) o); - - if (Objects.equals(this.getWorld(), region.getWorld()) - && this.getMinimumPoint().equals(region.getMinimumPoint()) - && this.getMaximumPoint().equals(region.getMaximumPoint()) - && this.getVolume() == region.getVolume()) { - return true; - } - return false; - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions; + +import com.boydti.fawe.object.collection.BlockVectorSet; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.iterator.RegionIterator; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public abstract class AbstractRegion extends AbstractSet implements Region { + + protected World world; + + public AbstractRegion(World world) { + this.world = world; + } + + @Override + public int size() { + return com.google.common.primitives.Ints.saturatedCast(getVolume()); + } + + @Override + public Vector3 getCenter() { + return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); + } + + /** + * Get the iterator. + * + * @return iterator of points inside the region + */ + @Override + public Iterator iterator() { + return new RegionIterator(this); + } + + @Override + public World getWorld() { + return world; + } + + @Override + public void setWorld(World world) { + this.world = world; + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + expand(change); + contract(change); + } + + @Override + public AbstractRegion clone() { + try { + return (AbstractRegion) super.clone(); + } catch (CloneNotSupportedException exc) { + return null; + } + } + + @Override + public List polygonize(int maxPoints) { + if (maxPoints >= 0 && maxPoints < 4) { + throw new IllegalArgumentException("Cannot polygonize an AbstractRegion with no overridden polygonize method into less than 4 points."); + } + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + final List points = new ArrayList<>(4); + + points.add(BlockVector2.at(min.getX(), min.getZ())); + points.add(BlockVector2.at(min.getX(), max.getZ())); + points.add(BlockVector2.at(max.getX(), max.getZ())); + points.add(BlockVector2.at(max.getX(), min.getZ())); + + return points; + } + + @Override + public long getVolume() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return (max.getX() - min.getX() + 1L) + * (max.getY() - min.getY() + 1L) + * (max.getZ() - min.getZ() + 1L); + } + + /** + * Get X-size. + * + * @return width + */ + @Override + public int getWidth() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return max.getX() - min.getX() + 1; + } + + /** + * Get Y-size. + * + * @return height + */ + @Override + public int getHeight() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return max.getY() - min.getY() + 1; + } + + /** + * Get Z-size. + * + * @return length + */ + @Override + public int getLength() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return max.getZ() - min.getZ() + 1; + } + + /** + * Get a list of chunks. + * + * @return a set of chunks + */ + @Override + public Set getChunks() { + final Set chunks = new HashSet<>(); + + final BlockVector3 minBlock = getMinimumPoint(); + final BlockVector3 maxBlock = getMaximumPoint(); + + final BlockVector2 min = BlockVector2.at(minBlock.getX() >> 4, minBlock.getZ() >> 4); + final BlockVector2 max = BlockVector2.at(maxBlock.getX() >> 4, maxBlock.getZ() >> 4); + + for (int X = min.getBlockX(); X <= max.getBlockX(); ++X) { + for (int Z = min.getBlockZ(); Z <= max.getBlockZ(); ++Z) { + if (containsChunk(X, Z)) { + chunks.add(BlockVector2.at(X, Z)); + } + } + } + + return chunks; + } + + @Override + public Set getChunkCubes() { + final Set chunks = new BlockVectorSet(); + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { + for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + if (!contains(BlockVector3.at(x, y, z))) { + continue; + } + + chunks.add(BlockVector3.at( + x >> ChunkStore.CHUNK_SHIFTS, + y >> ChunkStore.CHUNK_SHIFTS, + z >> ChunkStore.CHUNK_SHIFTS + )); + } + } + } + + return chunks; + } + + // Sub-class utilities + + protected final int getWorldMinY() { + return world == null ? 0 : world.getMinY(); + } + + protected final int getWorldMaxY() { + return world == null ? 255 : world.getMaxY(); + } + + @Override + public int hashCode() { + int worldHash = this.world == null ? 7 : this.world.hashCode(); + int result = worldHash ^ (worldHash >>> 32); + result = 31 * result + this.getMinimumPoint().hashCode(); + result = 31 * result + this.getMaximumPoint().hashCode(); + result = (int) (31 * result + this.getVolume()); + return result; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Region)) { + return false; + } + Region region = ((Region) o); + + if (Objects.equals(this.getWorld(), region.getWorld()) + && this.getMinimumPoint().equals(region.getMinimumPoint()) + && this.getMaximumPoint().equals(region.getMaximumPoint()) + && this.getVolume() == region.getVolume()) { + return true; + } + return false; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java index ffe53d364..0aaac9184 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java @@ -1,336 +1,336 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions; - -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.regions.polyhedron.Edge; -import com.sk89q.worldedit.regions.polyhedron.Triangle; -import com.sk89q.worldedit.world.World; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import javax.annotation.Nullable; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class ConvexPolyhedralRegion extends AbstractRegion { - - /** - * Vertices that are contained in the convex hull. - */ - private final Set vertices = new LinkedHashSet<>(); - - /** - * Triangles that form the convex hull. - */ - private final List triangles = new ArrayList<>(); - - /** - * Vertices that are coplanar to the first 3 vertices. - */ - private final Set vertexBacklog = new LinkedHashSet<>(); - - /** - * Minimum point of the axis-aligned bounding box. - */ - private BlockVector3 minimumPoint; - - /** - * Maximum point of the axis-aligned bounding box. - */ - private BlockVector3 maximumPoint; - - /** - * Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center. - */ - private BlockVector3 centerAccum = BlockVector3.ZERO; - - /** - * The last triangle that caused a {@link #contains(BlockVector3)}} to classify a point as "outside". Used for optimization. - */ - private Triangle lastTriangle; - - /** - * Constructs an empty mesh, containing no vertices or triangles. - * - * @param world the world - */ - public ConvexPolyhedralRegion(@Nullable World world) { - super(world); - } - - /** - * Constructs an independent copy of the given region. - * - * @param region the region to copy - */ - public ConvexPolyhedralRegion(ConvexPolyhedralRegion region) { - this(region.world); - vertices.addAll(region.vertices); - triangles.addAll(region.triangles); - vertexBacklog.addAll(region.vertexBacklog); - - minimumPoint = region.minimumPoint; - maximumPoint = region.maximumPoint; - centerAccum = region.centerAccum; - lastTriangle = region.lastTriangle; - } - - /** - * Clears the region, removing all vertices and triangles. - */ - public void clear() { - vertices.clear(); - triangles.clear(); - vertexBacklog.clear(); - - minimumPoint = null; - maximumPoint = null; - centerAccum = BlockVector3.ZERO; - lastTriangle = null; - } - - /** - * Add a vertex to the region. - * - * @param vertex the vertex - * @return true, if something changed. - */ - public boolean addVertex(BlockVector3 vertex) { - checkNotNull(vertex); - - lastTriangle = null; // Probably not necessary - - if (vertices.contains(vertex)) { - return false; - } - - Vector3 vertexD = vertex.toVector3(); - - if (vertices.size() == 3) { - if (vertexBacklog.contains(vertex)) { - return false; - } - - if (containsRaw(vertexD)) { - return vertexBacklog.add(vertex); - } - } - - vertices.add(vertex); - - centerAccum = centerAccum.add(vertex); - - if (minimumPoint == null) { - minimumPoint = maximumPoint = vertex; - } else { - minimumPoint = minimumPoint.getMinimum(vertex); - maximumPoint = maximumPoint.getMaximum(vertex); - } - - - switch (vertices.size()) { - case 0: - case 1: - case 2: - // Incomplete, can't make a mesh yet - return true; - - case 3: - // Generate minimal mesh to start from - final BlockVector3[] v = vertices.toArray(new BlockVector3[0]); - - triangles.add((new Triangle(v[0].toVector3(), v[1].toVector3(), v[2].toVector3()))); - triangles.add((new Triangle(v[0].toVector3(), v[2].toVector3(), v[1].toVector3()))); - return true; - - default: - break; - } - - // Look for triangles that face the vertex and remove them - final Set borderEdges = new LinkedHashSet<>(); - for (Iterator it = triangles.iterator(); it.hasNext(); ) { - final Triangle triangle = it.next(); - - // If the triangle can't be seen, it's not relevant - if (!triangle.above(vertexD)) { - continue; - } - - // Remove the triangle from the mesh - it.remove(); - - // ...and remember its edges - for (int i = 0; i < 3; ++i) { - final Edge edge = triangle.getEdge(i); - if (borderEdges.remove(edge)) { - continue; - } - - borderEdges.add(edge); - } - } - - // Add triangles between the remembered edges and the new vertex. - for (Edge edge : borderEdges) { - triangles.add(edge.createTriangle(vertexD)); - } - - if (!vertexBacklog.isEmpty()) { - // Remove the new vertex - vertices.remove(vertex); - - // Clone, clear and work through the backlog - final List vertexBacklog2 = new ArrayList<>(vertexBacklog); - vertexBacklog.clear(); - for (BlockVector3 vertex2 : vertexBacklog2) { - addVertex(vertex2); - } - - // Re-add the new vertex after the backlog. - vertices.add(vertex); - } - - return true; - } - - public boolean isDefined() { - return !triangles.isEmpty(); - } - - @Override - public BlockVector3 getMinimumPoint() { - return minimumPoint; - } - - @Override - public BlockVector3 getMaximumPoint() { - return maximumPoint; - } - - @Override - public Vector3 getCenter() { - return centerAccum.toVector3().divide(vertices.size()); - } - - @Override - public void expand(BlockVector3... changes) throws RegionOperationException { - } - - @Override - public void contract(BlockVector3... changes) throws RegionOperationException { - } - - @Override - public void shift(BlockVector3 change) throws RegionOperationException { - Vector3 vec = change.toVector3(); - shiftCollection(vertices, change); - shiftCollection(vertexBacklog, change); - - for (int i = 0; i < triangles.size(); ++i) { - final Triangle triangle = triangles.get(i); - - final Vector3 v0 = vec.add(triangle.getVertex(0)); - final Vector3 v1 = vec.add(triangle.getVertex(1)); - final Vector3 v2 = vec.add(triangle.getVertex(2)); - - triangles.set(i, new Triangle(v0, v1, v2)); - } - - minimumPoint = change.add(minimumPoint); - maximumPoint = change.add(maximumPoint); - centerAccum = change.multiply(vertices.size()).add(centerAccum); - lastTriangle = null; - } - - private static void shiftCollection(Collection collection, BlockVector3 change) { - final List tmp = new ArrayList<>(collection); - collection.clear(); - for (BlockVector3 vertex : tmp) { - collection.add(change.add(vertex)); - } - } - - @Override - public boolean contains(BlockVector3 position) { - if (!isDefined()) { - return false; - } - - final BlockVector3 min = getMinimumPoint(); - final BlockVector3 max = getMaximumPoint(); - - if (!position.containedWithin(min, max)) { - return false; - } - - return containsRaw(position.toVector3()); - } - - private boolean containsRaw(Vector3 pt) { - if (lastTriangle != null && lastTriangle.above(pt)) { - return false; - } - - for (Triangle triangle : triangles) { - if (lastTriangle == triangle) { - continue; - } - - if (triangle.above(pt)) { - lastTriangle = triangle; - return false; - } - } - - return true; - } - - public Collection getVertices() { - if (vertexBacklog.isEmpty()) { - return vertices; - } - - final List ret = new ArrayList<>(vertices); - ret.addAll(vertexBacklog); - - return ret; - } - - public Collection getTriangles() { - return triangles; - } - - @Override - public AbstractRegion clone() { - return new ConvexPolyhedralRegion(this); - } - - @Override - public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) { - return false; - } -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.polyhedron.Edge; +import com.sk89q.worldedit.regions.polyhedron.Triangle; +import com.sk89q.worldedit.world.World; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ConvexPolyhedralRegion extends AbstractRegion { + + /** + * Vertices that are contained in the convex hull. + */ + private final Set vertices = new LinkedHashSet<>(); + + /** + * Triangles that form the convex hull. + */ + private final List triangles = new ArrayList<>(); + + /** + * Vertices that are coplanar to the first 3 vertices. + */ + private final Set vertexBacklog = new LinkedHashSet<>(); + + /** + * Minimum point of the axis-aligned bounding box. + */ + private BlockVector3 minimumPoint; + + /** + * Maximum point of the axis-aligned bounding box. + */ + private BlockVector3 maximumPoint; + + /** + * Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center. + */ + private BlockVector3 centerAccum = BlockVector3.ZERO; + + /** + * The last triangle that caused a {@link #contains(BlockVector3)}} to classify a point as "outside". Used for optimization. + */ + private Triangle lastTriangle; + + /** + * Constructs an empty mesh, containing no vertices or triangles. + * + * @param world the world + */ + public ConvexPolyhedralRegion(@Nullable World world) { + super(world); + } + + /** + * Constructs an independent copy of the given region. + * + * @param region the region to copy + */ + public ConvexPolyhedralRegion(ConvexPolyhedralRegion region) { + this(region.world); + vertices.addAll(region.vertices); + triangles.addAll(region.triangles); + vertexBacklog.addAll(region.vertexBacklog); + + minimumPoint = region.minimumPoint; + maximumPoint = region.maximumPoint; + centerAccum = region.centerAccum; + lastTriangle = region.lastTriangle; + } + + /** + * Clears the region, removing all vertices and triangles. + */ + public void clear() { + vertices.clear(); + triangles.clear(); + vertexBacklog.clear(); + + minimumPoint = null; + maximumPoint = null; + centerAccum = BlockVector3.ZERO; + lastTriangle = null; + } + + /** + * Add a vertex to the region. + * + * @param vertex the vertex + * @return true, if something changed. + */ + public boolean addVertex(BlockVector3 vertex) { + checkNotNull(vertex); + + lastTriangle = null; // Probably not necessary + + if (vertices.contains(vertex)) { + return false; + } + + Vector3 vertexD = vertex.toVector3(); + + if (vertices.size() == 3) { + if (vertexBacklog.contains(vertex)) { + return false; + } + + if (containsRaw(vertexD)) { + return vertexBacklog.add(vertex); + } + } + + vertices.add(vertex); + + centerAccum = centerAccum.add(vertex); + + if (minimumPoint == null) { + minimumPoint = maximumPoint = vertex; + } else { + minimumPoint = minimumPoint.getMinimum(vertex); + maximumPoint = maximumPoint.getMaximum(vertex); + } + + + switch (vertices.size()) { + case 0: + case 1: + case 2: + // Incomplete, can't make a mesh yet + return true; + + case 3: + // Generate minimal mesh to start from + final BlockVector3[] v = vertices.toArray(new BlockVector3[0]); + + triangles.add((new Triangle(v[0].toVector3(), v[1].toVector3(), v[2].toVector3()))); + triangles.add((new Triangle(v[0].toVector3(), v[2].toVector3(), v[1].toVector3()))); + return true; + + default: + break; + } + + // Look for triangles that face the vertex and remove them + final Set borderEdges = new LinkedHashSet<>(); + for (Iterator it = triangles.iterator(); it.hasNext(); ) { + final Triangle triangle = it.next(); + + // If the triangle can't be seen, it's not relevant + if (!triangle.above(vertexD)) { + continue; + } + + // Remove the triangle from the mesh + it.remove(); + + // ...and remember its edges + for (int i = 0; i < 3; ++i) { + final Edge edge = triangle.getEdge(i); + if (borderEdges.remove(edge)) { + continue; + } + + borderEdges.add(edge); + } + } + + // Add triangles between the remembered edges and the new vertex. + for (Edge edge : borderEdges) { + triangles.add(edge.createTriangle(vertexD)); + } + + if (!vertexBacklog.isEmpty()) { + // Remove the new vertex + vertices.remove(vertex); + + // Clone, clear and work through the backlog + final List vertexBacklog2 = new ArrayList<>(vertexBacklog); + vertexBacklog.clear(); + for (BlockVector3 vertex2 : vertexBacklog2) { + addVertex(vertex2); + } + + // Re-add the new vertex after the backlog. + vertices.add(vertex); + } + + return true; + } + + public boolean isDefined() { + return !triangles.isEmpty(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return minimumPoint; + } + + @Override + public BlockVector3 getMaximumPoint() { + return maximumPoint; + } + + @Override + public Vector3 getCenter() { + return centerAccum.toVector3().divide(vertices.size()); + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + Vector3 vec = change.toVector3(); + shiftCollection(vertices, change); + shiftCollection(vertexBacklog, change); + + for (int i = 0; i < triangles.size(); ++i) { + final Triangle triangle = triangles.get(i); + + final Vector3 v0 = vec.add(triangle.getVertex(0)); + final Vector3 v1 = vec.add(triangle.getVertex(1)); + final Vector3 v2 = vec.add(triangle.getVertex(2)); + + triangles.set(i, new Triangle(v0, v1, v2)); + } + + minimumPoint = change.add(minimumPoint); + maximumPoint = change.add(maximumPoint); + centerAccum = change.multiply(vertices.size()).add(centerAccum); + lastTriangle = null; + } + + private static void shiftCollection(Collection collection, BlockVector3 change) { + final List tmp = new ArrayList<>(collection); + collection.clear(); + for (BlockVector3 vertex : tmp) { + collection.add(change.add(vertex)); + } + } + + @Override + public boolean contains(BlockVector3 position) { + if (!isDefined()) { + return false; + } + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + if (!position.containedWithin(min, max)) { + return false; + } + + return containsRaw(position.toVector3()); + } + + private boolean containsRaw(Vector3 pt) { + if (lastTriangle != null && lastTriangle.above(pt)) { + return false; + } + + for (Triangle triangle : triangles) { + if (lastTriangle == triangle) { + continue; + } + + if (triangle.above(pt)) { + lastTriangle = triangle; + return false; + } + } + + return true; + } + + public Collection getVertices() { + if (vertexBacklog.isEmpty()) { + return vertices; + } + + final List ret = new ArrayList<>(vertices); + ret.addAll(vertexBacklog); + + return ret; + } + + public Collection getTriangles() { + return triangles; + } + + @Override + public AbstractRegion clone() { + return new ConvexPolyhedralRegion(this); + } + + @Override + public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) { + return false; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index dd5e7efe9..317fda0b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -1,430 +1,430 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions; - -import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.IChunk; -import com.boydti.fawe.beta.IChunkGet; -import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector2; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.geom.Polygons; -import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; -import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.world.World; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.Iterator; -import java.util.List; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Represents a cylindrical region. - */ -public class CylinderRegion extends AbstractRegion implements FlatRegion { - - private BlockVector2 center; - private Vector2 radius; - private Vector2 radiusInverse; - private int minY; - private int maxY; - private boolean hasY = false; - - /** - * Construct the region. - */ - public CylinderRegion() { - this((World) null); - } - - /** - * Construct the region. - * - * @param world the world - */ - public CylinderRegion(World world) { - this(world, BlockVector3.ZERO, Vector2.ZERO, 0, 0); - hasY = false; - } - - /** - * Construct the region. - * - * @param world the world - * @param center the center position - * @param radius the radius along the X and Z axes - * @param minY the minimum Y, inclusive - * @param maxY the maximum Y, inclusive - */ - public CylinderRegion(World world, BlockVector3 center, Vector2 radius, int minY, int maxY) { - super(world); - setCenter(center.toBlockVector2()); - setRadius(radius); - this.minY = minY; - this.maxY = maxY; - hasY = true; - } - - /** - * Construct the region. - * - * @param center the center position - * @param radius the radius along the X and Z axes - * @param minY the minimum Y, inclusive - * @param maxY the maximum Y, inclusive - */ - public CylinderRegion(BlockVector3 center, Vector2 radius, int minY, int maxY) { - super(null); - setCenter(center.toBlockVector2()); - setRadius(radius); - this.minY = minY; - this.maxY = maxY; - hasY = true; - } - - public CylinderRegion(CylinderRegion region) { - this(region.world, region.getCenter().toBlockPoint(), region.getRadius(), region.minY, region.maxY); - hasY = region.hasY; - } - - @Override - public Vector3 getCenter() { - return center.toVector3((maxY + minY) / 2); - } - - /** - * Sets the main center point of the region. - * - * @param center the center point - */ - public void setCenter(BlockVector2 center) { - this.center = center; - } - - /** - * Returns the radius of the cylinder. - * - * @return the radius along the X and Z axes - */ - public Vector2 getRadius() { - return radius.subtract(0.5, 0.5); - } - - /** - * Sets the radius of the cylinder. - * - * @param radius the radius along the X and Z axes - */ - public void setRadius(Vector2 radius) { - this.radius = radius.add(0.5, 0.5); - this.radiusInverse = Vector2.ONE.divide(radius); - } - - /** - * Extends the radius to be at least the given radius. - * - * @param minRadius the minimum radius - */ - public void extendRadius(Vector2 minRadius) { - setRadius(minRadius.getMaximum(getRadius())); - } - - /** - * Set the minimum Y. - * - * @param y the y - */ - public void setMinimumY(int y) { - hasY = true; - minY = y; - } - - /** - * Se the maximum Y. - * - * @param y the y - */ - public void setMaximumY(int y) { - hasY = true; - maxY = y; - } - - @Override - public BlockVector3 getMinimumPoint() { - return center.toVector2().subtract(getRadius()).toVector3(minY).toBlockPoint(); - } - - @Override - public BlockVector3 getMaximumPoint() { - return center.toVector2().add(getRadius()).toVector3(maxY).toBlockPoint(); - } - - @Override - public int getMaximumY() { - int worldMax = world != null ? world.getMaxY() - 1 : 255; - if (maxY > worldMax) { - return maxY = worldMax; - } - return maxY; - } - - @Override - public int getMinimumY() { - if (minY < 0) { - return minY = 0; - } - return minY; - } - - private static final BigDecimal PI = BigDecimal.valueOf(Math.PI); - - @Override - public long getVolume() { - return BigDecimal.valueOf(radius.getX()) - .multiply(BigDecimal.valueOf(radius.getZ())) - .multiply(PI) - .multiply(BigDecimal.valueOf(getHeight())) - .setScale(0, RoundingMode.FLOOR) - .longValue(); - } - - @Override - public int getWidth() { - return (int) (2 * radius.getX()); - } - - @Override - public int getHeight() { - return maxY - minY + 1; - } - - @Override - public int getLength() { - return (int) (2 * radius.getZ()); - } - - private BlockVector2 calculateDiff2D(BlockVector3... changes) throws RegionOperationException { - BlockVector2 diff = BlockVector2.ZERO; - for (BlockVector3 change : changes) { - diff = diff.add(change.toBlockVector2()); - } - - if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) { - throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.cylinder.error.even-horizontal")); - } - - return diff.divide(2).floor(); - } - - private BlockVector2 calculateChanges2D(BlockVector3... changes) { - BlockVector2 total = BlockVector2.ZERO; - for (BlockVector3 change : changes) { - total = total.add(change.toBlockVector2().abs()); - } - - return total.divide(2).floor(); - } - - /** - * Expand the region. - * Expand the region. - * - * @param changes array/arguments with multiple related changes - */ - @Override - public void expand(BlockVector3... changes) throws RegionOperationException { - center = center.add(calculateDiff2D(changes)); - radius = radius.add(calculateChanges2D(changes).toVector2()); - this.radiusInverse = Vector2.ONE.divide(radius); - for (BlockVector3 change : changes) { - int changeY = change.getBlockY(); - if (changeY > 0) { - maxY += changeY; - } else { - minY += changeY; - } - } - } - - /** - * Contract the region. - * - * @param changes array/arguments with multiple related changes - * @throws RegionOperationException - */ - @Override - public void contract(BlockVector3... changes) throws RegionOperationException { - center = center.subtract(calculateDiff2D(changes)); - Vector2 newRadius = radius.subtract(calculateChanges2D(changes).toVector2()); - radius = Vector2.at(1.5, 1.5).getMaximum(newRadius); - this.radiusInverse = Vector2.ONE.divide(radius); - for (BlockVector3 change : changes) { - int height = maxY - minY; - int changeY = change.getBlockY(); - if (changeY > 0) { - minY += Math.min(height, changeY); - } else { - maxY += Math.max(-height, changeY); - } - } - } - - @Override - public void shift(BlockVector3 change) throws RegionOperationException { - center = center.add(change.toBlockVector2()); - - int changeY = change.getBlockY(); - maxY += changeY; - minY += changeY; - } - - /** - * Checks to see if a point is inside this region. - */ - /* Slow and unnecessary - @Override - public boolean contains(BlockVector3 position) { - final int blockY = position.getBlockY(); - if (blockY < minY || blockY > maxY) { - return false; - } - - return position.toBlockVector2().subtract(center).toVector2().divide(radius).lengthSq() <= 1; - } - */ - - /** - * Checks to see if a point is inside this region. - */ - @Override - public boolean contains(int x, int y, int z) { - if (y < minY || y > maxY) { - return false; - } - return contains(x, z); - } - - @Override - public boolean contains(int x, int z) { - double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX(); - double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ(); - - return dx * dx + dz * dz <= 1; - } - - @Override - public boolean contains(BlockVector3 position) { - return contains(position.getX(), position.getY(), position.getZ()); - } - - /** - * Sets the height of the cylinder to fit the specified Y. - * - * @param y the y value - * @return true if the area was expanded - */ - public boolean setY(int y) { - if (!hasY) { - minY = y; - maxY = y; - hasY = true; - return true; - } else if (y < minY) { - minY = y; - return true; - } else if (y > maxY) { - maxY = y; - return true; - } - - return false; - } - - @Override - public Iterator iterator() { - return new FlatRegion3DIterator(this); - } - - @Override - public Iterable asFlatRegion() { - return () -> new FlatRegionIterator(CylinderRegion.this); - } - - /** - * Returns string representation in the format. - * "(centerX, centerZ) - (radiusX, radiusZ) - (minY, maxY)" - * - * @return string - */ - @Override - public String toString() { - return center + " - " + radius + "(" + minY + ", " + maxY + ")"; - } - - @Override - public CylinderRegion clone() { - return (CylinderRegion) super.clone(); - } - - @Override - public List polygonize(int maxPoints) { - return Polygons.polygonizeCylinder(center, radius, maxPoints); - } - - /** - * Return a new instance with the given center and radius in the X and Z - * axes with a Y that extends from the bottom of the extent to the top - * of the extent. - * - * @param extent the extent - * @param center the center position - * @param radius the radius in the X and Z axes - * @return a region - */ - public static CylinderRegion createRadius(Extent extent, BlockVector3 center, double radius) { - checkNotNull(extent); - checkNotNull(center); - Vector2 radiusVec = Vector2.at(radius, radius); - int minY = extent.getMinimumPoint().getBlockY(); - int maxY = extent.getMaximumPoint().getBlockY(); - return new CylinderRegion(center, radiusVec, minY, maxY); - } - - @Override - public void filter(final IChunk chunk, final Filter filter, final ChunkFilterBlock block, - final IChunkGet get, final IChunkSet set, boolean full) { - int bcx = chunk.getX() >> 4; - int bcz = chunk.getZ() >> 4; - int tcx = bcx + 15; - int tcz = bcz + 15; - if (contains(bcx, bcz) && contains(tcx, tcz)) { - filter(chunk, filter, block, get, set, minY, maxY, full); - return; - } - super.filter(chunk, filter, block, get, set, full); - } -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.geom.Polygons; +import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; +import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a cylindrical region. + */ +public class CylinderRegion extends AbstractRegion implements FlatRegion { + + private BlockVector2 center; + private Vector2 radius; + private Vector2 radiusInverse; + private int minY; + private int maxY; + private boolean hasY = false; + + /** + * Construct the region. + */ + public CylinderRegion() { + this((World) null); + } + + /** + * Construct the region. + * + * @param world the world + */ + public CylinderRegion(World world) { + this(world, BlockVector3.ZERO, Vector2.ZERO, 0, 0); + hasY = false; + } + + /** + * Construct the region. + * + * @param world the world + * @param center the center position + * @param radius the radius along the X and Z axes + * @param minY the minimum Y, inclusive + * @param maxY the maximum Y, inclusive + */ + public CylinderRegion(World world, BlockVector3 center, Vector2 radius, int minY, int maxY) { + super(world); + setCenter(center.toBlockVector2()); + setRadius(radius); + this.minY = minY; + this.maxY = maxY; + hasY = true; + } + + /** + * Construct the region. + * + * @param center the center position + * @param radius the radius along the X and Z axes + * @param minY the minimum Y, inclusive + * @param maxY the maximum Y, inclusive + */ + public CylinderRegion(BlockVector3 center, Vector2 radius, int minY, int maxY) { + super(null); + setCenter(center.toBlockVector2()); + setRadius(radius); + this.minY = minY; + this.maxY = maxY; + hasY = true; + } + + public CylinderRegion(CylinderRegion region) { + this(region.world, region.getCenter().toBlockPoint(), region.getRadius(), region.minY, region.maxY); + hasY = region.hasY; + } + + @Override + public Vector3 getCenter() { + return center.toVector3((maxY + minY) / 2); + } + + /** + * Sets the main center point of the region. + * + * @param center the center point + */ + public void setCenter(BlockVector2 center) { + this.center = center; + } + + /** + * Returns the radius of the cylinder. + * + * @return the radius along the X and Z axes + */ + public Vector2 getRadius() { + return radius.subtract(0.5, 0.5); + } + + /** + * Sets the radius of the cylinder. + * + * @param radius the radius along the X and Z axes + */ + public void setRadius(Vector2 radius) { + this.radius = radius.add(0.5, 0.5); + this.radiusInverse = Vector2.ONE.divide(radius); + } + + /** + * Extends the radius to be at least the given radius. + * + * @param minRadius the minimum radius + */ + public void extendRadius(Vector2 minRadius) { + setRadius(minRadius.getMaximum(getRadius())); + } + + /** + * Set the minimum Y. + * + * @param y the y + */ + public void setMinimumY(int y) { + hasY = true; + minY = y; + } + + /** + * Se the maximum Y. + * + * @param y the y + */ + public void setMaximumY(int y) { + hasY = true; + maxY = y; + } + + @Override + public BlockVector3 getMinimumPoint() { + return center.toVector2().subtract(getRadius()).toVector3(minY).toBlockPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return center.toVector2().add(getRadius()).toVector3(maxY).toBlockPoint(); + } + + @Override + public int getMaximumY() { + int worldMax = world != null ? world.getMaxY() - 1 : 255; + if (maxY > worldMax) { + return maxY = worldMax; + } + return maxY; + } + + @Override + public int getMinimumY() { + if (minY < 0) { + return minY = 0; + } + return minY; + } + + private static final BigDecimal PI = BigDecimal.valueOf(Math.PI); + + @Override + public long getVolume() { + return BigDecimal.valueOf(radius.getX()) + .multiply(BigDecimal.valueOf(radius.getZ())) + .multiply(PI) + .multiply(BigDecimal.valueOf(getHeight())) + .setScale(0, RoundingMode.FLOOR) + .longValue(); + } + + @Override + public int getWidth() { + return (int) (2 * radius.getX()); + } + + @Override + public int getHeight() { + return maxY - minY + 1; + } + + @Override + public int getLength() { + return (int) (2 * radius.getZ()); + } + + private BlockVector2 calculateDiff2D(BlockVector3... changes) throws RegionOperationException { + BlockVector2 diff = BlockVector2.ZERO; + for (BlockVector3 change : changes) { + diff = diff.add(change.toBlockVector2()); + } + + if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.cylinder.error.even-horizontal")); + } + + return diff.divide(2).floor(); + } + + private BlockVector2 calculateChanges2D(BlockVector3... changes) { + BlockVector2 total = BlockVector2.ZERO; + for (BlockVector3 change : changes) { + total = total.add(change.toBlockVector2().abs()); + } + + return total.divide(2).floor(); + } + + /** + * Expand the region. + * Expand the region. + * + * @param changes array/arguments with multiple related changes + */ + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + center = center.add(calculateDiff2D(changes)); + radius = radius.add(calculateChanges2D(changes).toVector2()); + this.radiusInverse = Vector2.ONE.divide(radius); + for (BlockVector3 change : changes) { + int changeY = change.getBlockY(); + if (changeY > 0) { + maxY += changeY; + } else { + minY += changeY; + } + } + } + + /** + * Contract the region. + * + * @param changes array/arguments with multiple related changes + * @throws RegionOperationException + */ + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + center = center.subtract(calculateDiff2D(changes)); + Vector2 newRadius = radius.subtract(calculateChanges2D(changes).toVector2()); + radius = Vector2.at(1.5, 1.5).getMaximum(newRadius); + this.radiusInverse = Vector2.ONE.divide(radius); + for (BlockVector3 change : changes) { + int height = maxY - minY; + int changeY = change.getBlockY(); + if (changeY > 0) { + minY += Math.min(height, changeY); + } else { + maxY += Math.max(-height, changeY); + } + } + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + center = center.add(change.toBlockVector2()); + + int changeY = change.getBlockY(); + maxY += changeY; + minY += changeY; + } + + /** + * Checks to see if a point is inside this region. + */ + /* Slow and unnecessary + @Override + public boolean contains(BlockVector3 position) { + final int blockY = position.getBlockY(); + if (blockY < minY || blockY > maxY) { + return false; + } + + return position.toBlockVector2().subtract(center).toVector2().divide(radius).lengthSq() <= 1; + } + */ + + /** + * Checks to see if a point is inside this region. + */ + @Override + public boolean contains(int x, int y, int z) { + if (y < minY || y > maxY) { + return false; + } + return contains(x, z); + } + + @Override + public boolean contains(int x, int z) { + double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX(); + double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ(); + + return dx * dx + dz * dz <= 1; + } + + @Override + public boolean contains(BlockVector3 position) { + return contains(position.getX(), position.getY(), position.getZ()); + } + + /** + * Sets the height of the cylinder to fit the specified Y. + * + * @param y the y value + * @return true if the area was expanded + */ + public boolean setY(int y) { + if (!hasY) { + minY = y; + maxY = y; + hasY = true; + return true; + } else if (y < minY) { + minY = y; + return true; + } else if (y > maxY) { + maxY = y; + return true; + } + + return false; + } + + @Override + public Iterator iterator() { + return new FlatRegion3DIterator(this); + } + + @Override + public Iterable asFlatRegion() { + return () -> new FlatRegionIterator(CylinderRegion.this); + } + + /** + * Returns string representation in the format. + * "(centerX, centerZ) - (radiusX, radiusZ) - (minY, maxY)" + * + * @return string + */ + @Override + public String toString() { + return center + " - " + radius + "(" + minY + ", " + maxY + ")"; + } + + @Override + public CylinderRegion clone() { + return (CylinderRegion) super.clone(); + } + + @Override + public List polygonize(int maxPoints) { + return Polygons.polygonizeCylinder(center, radius, maxPoints); + } + + /** + * Return a new instance with the given center and radius in the X and Z + * axes with a Y that extends from the bottom of the extent to the top + * of the extent. + * + * @param extent the extent + * @param center the center position + * @param radius the radius in the X and Z axes + * @return a region + */ + public static CylinderRegion createRadius(Extent extent, BlockVector3 center, double radius) { + checkNotNull(extent); + checkNotNull(center); + Vector2 radiusVec = Vector2.at(radius, radius); + int minY = extent.getMinimumPoint().getBlockY(); + int maxY = extent.getMaximumPoint().getBlockY(); + return new CylinderRegion(center, radiusVec, minY, maxY); + } + + @Override + public void filter(final IChunk chunk, final Filter filter, final ChunkFilterBlock block, + final IChunkGet get, final IChunkSet set, boolean full) { + int bcx = chunk.getX() >> 4; + int bcz = chunk.getZ() >> 4; + int tcx = bcx + 15; + int tcz = bcz + 15; + if (contains(bcx, bcz) && contains(tcx, tcz)) { + filter(chunk, filter, block, get, set, minY, maxY, full); + return; + } + super.filter(chunk, filter, block, get, set, full); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java index b2dc3ecf3..a9d33dd7f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java @@ -1,528 +1,528 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions; - -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; -import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.world.World; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * Represents a 2D polygonal region. - */ -public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { - - private List points; - private BlockVector2 min; - private BlockVector2 max; - private int minY; - private int maxY; - private boolean hasY = false; - - /** - * Construct the region. - */ - public Polygonal2DRegion() { - this((World) null); - } - - /** - * Construct the region. - * - * @param world the world - */ - public Polygonal2DRegion(World world) { - this(world, Collections.emptyList(), 0, 0); - hasY = false; - } - - /** - * Construct the region. - * - * @param world the world - * @param points list of points - * @param minY minimum Y - * @param maxY maximum Y - */ - public Polygonal2DRegion(World world, List points, int minY, int maxY) { - super(world); - this.points = new ArrayList<>(points); - this.minY = minY; - this.maxY = maxY; - hasY = true; - recalculate(); - } - - /** - * Make a copy of another region. - * - * @param region the other region - */ - public Polygonal2DRegion(Polygonal2DRegion region) { - this(region.world, region.points, region.minY, region.maxY); - hasY = region.hasY; - } - - /** - * Get the list of points. - * - * @return a list of points - */ - public List getPoints() { - return Collections.unmodifiableList(points); - } - - /** - * Recalculate the bounding box of this polygonal region. This should be - * called after points have been changed. - */ - protected void recalculate() { - if (points.isEmpty()) { - min = BlockVector2.ZERO; - minY = 0; - max = BlockVector2.ZERO; - maxY = 0; - return; - } - - int minX = points.get(0).getBlockX(); - int minZ = points.get(0).getBlockZ(); - int maxX = points.get(0).getBlockX(); - int maxZ = points.get(0).getBlockZ(); - - for (BlockVector2 v : points) { - int x = v.getBlockX(); - int z = v.getBlockZ(); - if (x < minX) { - minX = x; - } - if (z < minZ) { - minZ = z; - } - if (x > maxX) { - maxX = x; - } - if (z > maxZ) { - maxZ = z; - } - } - - int oldMinY = minY; - int oldMaxY = maxY; - minY = Math.min(oldMinY, oldMaxY); - maxY = Math.max(oldMinY, oldMaxY); - - minY = Math.min(Math.max(getWorldMinY(), minY), getWorldMaxY()); - maxY = Math.min(Math.max(getWorldMinY(), maxY), getWorldMaxY()); - - min = BlockVector2.at(minX, minZ); - max = BlockVector2.at(maxX, maxZ); - } - - /** - * Add a point to the list. - * - * @param position the position - */ - public void addPoint(BlockVector2 position) { - points.add(position); - recalculate(); - } - - /** - * Add a point to the list. - * - * @param position the position - */ - public void addPoint(BlockVector3 position) { - points.add(BlockVector2.at(position.getBlockX(), position.getBlockZ())); - recalculate(); - } - - @Override - public int getMinimumY() { - return minY; - } - - /** - * Set the minimum Y. - * - * @param y the Y - */ - public void setMinimumY(int y) { - hasY = true; - minY = y; - recalculate(); - } - - @Override - public int getMaximumY() { - return maxY; - } - - /** - * Set the maximum Y. - * - * @param y the Y - */ - public void setMaximumY(int y) { - hasY = true; - maxY = y; - recalculate(); - } - - @Override - public BlockVector3 getMinimumPoint() { - return min.toBlockVector3(minY); - } - - @Override - public BlockVector3 getMaximumPoint() { - return max.toBlockVector3(maxY); - } - - @Override - public long getVolume() { - long area = 0; - int i; - int j = points.size() - 1; - - for (i = 0; i < points.size(); ++i) { - long x = points.get(j).getBlockX() + points.get(i).getBlockX(); - long z = points.get(j).getBlockZ() - points.get(i).getBlockZ(); - area += x * z; - j = i; - } - - return BigDecimal.valueOf(area) - .multiply(BigDecimal.valueOf(0.5)) - .abs() - .setScale(0, RoundingMode.FLOOR) - .longValue() * (maxY - minY + 1); - } - - @Override - public int getWidth() { - return max.getBlockX() - min.getBlockX() + 1; - } - - @Override - public int getHeight() { - return maxY - minY + 1; - } - - @Override - public int getLength() { - return max.getBlockZ() - min.getBlockZ() + 1; - } - - @Override - public void expand(BlockVector3... changes) throws RegionOperationException { - for (BlockVector3 change : changes) { - if (change.getBlockX() != 0 || change.getBlockZ() != 0) { - throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.polygon2d.error.expand-only-vertical")); - } - int changeY = change.getBlockY(); - if (changeY > 0) { - maxY += changeY; - } else { - minY += changeY; - } - } - recalculate(); - } - - @Override - public void contract(BlockVector3... changes) throws RegionOperationException { - for (BlockVector3 change : changes) { - if (change.getBlockX() != 0 || change.getBlockZ() != 0) { - throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.polygon2d.error.contract-only-vertical")); - } - int changeY = change.getBlockY(); - if (changeY > 0) { - minY += changeY; - } else { - maxY += changeY; - } - } - recalculate(); - } - - @Override - public void shift(BlockVector3 change) throws RegionOperationException { - final double changeX = change.getX(); - final double changeY = change.getY(); - final double changeZ = change.getZ(); - - for (int i = 0; i < points.size(); ++i) { - BlockVector2 point = points.get(i); - points.set(i, BlockVector2.at(point.getX() + changeX, point.getZ() + changeZ)); - } - - minY += changeY; - maxY += changeY; - - recalculate(); - } - - @Override - public boolean contains(int targetX, int targetZ) { - boolean inside = false; - int npoints = points.size(); - int xNew; - int zNew; - int xOld; - int zOld; - int x1; - int z1; - int x2; - int z2; - long crossproduct; - int i; - - xOld = points.get(npoints - 1).getBlockX(); - zOld = points.get(npoints - 1).getBlockZ(); - - for (i = 0; i < npoints; ++i) { - xNew = points.get(i).getBlockX(); - zNew = points.get(i).getBlockZ(); - //Check for corner - if (xNew == targetX && zNew == targetZ) { - return true; - } - if (xNew > xOld) { - x1 = xOld; - x2 = xNew; - z1 = zOld; - z2 = zNew; - } else { - x1 = xNew; - x2 = xOld; - z1 = zNew; - z2 = zOld; - } - if (x1 <= targetX && targetX <= x2) { - crossproduct = ((long) targetZ - (long) z1) * (long) (x2 - x1) - - ((long) z2 - (long) z1) * (long) (targetX - x1); - if (crossproduct == 0) { - if ((z1 <= targetZ) == (targetZ <= z2)) { - return true; //on edge - } - } else if (crossproduct < 0 && (x1 != targetX)) { - inside = !inside; - } - } - xOld = xNew; - zOld = zNew; - } - - return inside; - } - - @Override - public boolean contains(BlockVector3 position) { - return contains(points, minY, maxY, position); - } - - /** - * Checks to see if a point is inside a region. - * - * @param points a list of points - * @param minY the min Y - * @param maxY the max Y - * @param pt the position to check - * @return true if the given polygon contains the given point - */ - public static boolean contains(List points, int minY, int maxY, BlockVector3 pt) { - if (points.size() < 3) { - return false; - } - int targetX = pt.getBlockX(); //wide - int targetY = pt.getBlockY(); //height - int targetZ = pt.getBlockZ(); //depth - - if (targetY < minY || targetY > maxY) { - return false; - } - - boolean inside = false; - int npoints = points.size(); - int xNew; - int zNew; - int x1; - int z1; - int x2; - int z2; - long crossproduct; - int i; - - int xOld = points.get(npoints - 1).getBlockX(); - int zOld = points.get(npoints - 1).getBlockZ(); - - for (i = 0; i < npoints; ++i) { - xNew = points.get(i).getBlockX(); - zNew = points.get(i).getBlockZ(); - //Check for corner - if (xNew == targetX && zNew == targetZ) { - return true; - } - if (xNew > xOld) { - x1 = xOld; - x2 = xNew; - z1 = zOld; - z2 = zNew; - } else { - x1 = xNew; - x2 = xOld; - z1 = zNew; - z2 = zOld; - } - if (x1 <= targetX && targetX <= x2) { - crossproduct = ((long) targetZ - (long) z1) * (long) (x2 - x1) - - ((long) z2 - (long) z1) * (long) (targetX - x1); - if (crossproduct == 0) { - if ((z1 <= targetZ) == (targetZ <= z2)) { - return true; //on edge - } - } else if (crossproduct < 0 && (x1 != targetX)) { - inside = !inside; - } - } - xOld = xNew; - zOld = zNew; - } - - return inside; - } - - /** - * Return the number of points. - * - * @return the number of points - */ - public int size() { - return points.size(); - } - - /** - * Expand the height of the polygon to fit the specified Y. - * - * @param y the amount to expand - * @return true if the area was expanded - */ - public boolean expandY(int y) { - if (!hasY) { - minY = y; - maxY = y; - hasY = true; - return true; - } else if (y < minY) { - minY = y; - return true; - } else if (y > maxY) { - maxY = y; - return true; - } - - return false; - } - - @Override - public Iterator iterator() { - return new FlatRegion3DIterator(this); - } - - @Override - public Iterable asFlatRegion() { - return () -> new FlatRegionIterator(Polygonal2DRegion.this); - } - - /** - * Returns string representation in the format - * "(x1, z1) - ... - (xN, zN) * (minY - maxY)" - * - * @return string - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - List pts = getPoints(); - Iterator it = pts.iterator(); - while (it.hasNext()) { - BlockVector2 current = it.next(); - sb.append("(").append(current.getBlockX()).append(", ").append(current.getBlockZ()).append(")"); - if (it.hasNext()) { - sb.append(" - "); - } - } - sb.append(" * (").append(minY).append(" - ").append(maxY).append(")"); - return sb.toString(); - } - - @Override - public Polygonal2DRegion clone() { - Polygonal2DRegion clone = (Polygonal2DRegion) super.clone(); - clone.points = new ArrayList<>(points); - return clone; - } - - @Override - public List polygonize(int maxPoints) { - if (maxPoints >= 0 && maxPoints < points.size()) { - throw new IllegalArgumentException("Cannot polygonize a this Polygonal2DRegion into the amount of points given."); - } - - return points; - } - - @Override - public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) { - for (int x = bx; x <= tx; x++) { - if (!contains(x, 0, bz)) { - return false; - } - } - for (int x = bx; x <= tx; x++) { - if (!contains(x, 0, tz)) { - return false; - } - } - for (int z = bz; z <= tz; z++) { - if (!contains(bx, 0, z)) { - return false; - } - } - for (int z = bz; z <= tz; z++) { - if (!contains(tx, 0, z)) { - return false; - } - } - return true; - } -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; +import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * Represents a 2D polygonal region. + */ +public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { + + private List points; + private BlockVector2 min; + private BlockVector2 max; + private int minY; + private int maxY; + private boolean hasY = false; + + /** + * Construct the region. + */ + public Polygonal2DRegion() { + this((World) null); + } + + /** + * Construct the region. + * + * @param world the world + */ + public Polygonal2DRegion(World world) { + this(world, Collections.emptyList(), 0, 0); + hasY = false; + } + + /** + * Construct the region. + * + * @param world the world + * @param points list of points + * @param minY minimum Y + * @param maxY maximum Y + */ + public Polygonal2DRegion(World world, List points, int minY, int maxY) { + super(world); + this.points = new ArrayList<>(points); + this.minY = minY; + this.maxY = maxY; + hasY = true; + recalculate(); + } + + /** + * Make a copy of another region. + * + * @param region the other region + */ + public Polygonal2DRegion(Polygonal2DRegion region) { + this(region.world, region.points, region.minY, region.maxY); + hasY = region.hasY; + } + + /** + * Get the list of points. + * + * @return a list of points + */ + public List getPoints() { + return Collections.unmodifiableList(points); + } + + /** + * Recalculate the bounding box of this polygonal region. This should be + * called after points have been changed. + */ + protected void recalculate() { + if (points.isEmpty()) { + min = BlockVector2.ZERO; + minY = 0; + max = BlockVector2.ZERO; + maxY = 0; + return; + } + + int minX = points.get(0).getBlockX(); + int minZ = points.get(0).getBlockZ(); + int maxX = points.get(0).getBlockX(); + int maxZ = points.get(0).getBlockZ(); + + for (BlockVector2 v : points) { + int x = v.getBlockX(); + int z = v.getBlockZ(); + if (x < minX) { + minX = x; + } + if (z < minZ) { + minZ = z; + } + if (x > maxX) { + maxX = x; + } + if (z > maxZ) { + maxZ = z; + } + } + + int oldMinY = minY; + int oldMaxY = maxY; + minY = Math.min(oldMinY, oldMaxY); + maxY = Math.max(oldMinY, oldMaxY); + + minY = Math.min(Math.max(getWorldMinY(), minY), getWorldMaxY()); + maxY = Math.min(Math.max(getWorldMinY(), maxY), getWorldMaxY()); + + min = BlockVector2.at(minX, minZ); + max = BlockVector2.at(maxX, maxZ); + } + + /** + * Add a point to the list. + * + * @param position the position + */ + public void addPoint(BlockVector2 position) { + points.add(position); + recalculate(); + } + + /** + * Add a point to the list. + * + * @param position the position + */ + public void addPoint(BlockVector3 position) { + points.add(BlockVector2.at(position.getBlockX(), position.getBlockZ())); + recalculate(); + } + + @Override + public int getMinimumY() { + return minY; + } + + /** + * Set the minimum Y. + * + * @param y the Y + */ + public void setMinimumY(int y) { + hasY = true; + minY = y; + recalculate(); + } + + @Override + public int getMaximumY() { + return maxY; + } + + /** + * Set the maximum Y. + * + * @param y the Y + */ + public void setMaximumY(int y) { + hasY = true; + maxY = y; + recalculate(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return min.toBlockVector3(minY); + } + + @Override + public BlockVector3 getMaximumPoint() { + return max.toBlockVector3(maxY); + } + + @Override + public long getVolume() { + long area = 0; + int i; + int j = points.size() - 1; + + for (i = 0; i < points.size(); ++i) { + long x = points.get(j).getBlockX() + points.get(i).getBlockX(); + long z = points.get(j).getBlockZ() - points.get(i).getBlockZ(); + area += x * z; + j = i; + } + + return BigDecimal.valueOf(area) + .multiply(BigDecimal.valueOf(0.5)) + .abs() + .setScale(0, RoundingMode.FLOOR) + .longValue() * (maxY - minY + 1); + } + + @Override + public int getWidth() { + return max.getBlockX() - min.getBlockX() + 1; + } + + @Override + public int getHeight() { + return maxY - minY + 1; + } + + @Override + public int getLength() { + return max.getBlockZ() - min.getBlockZ() + 1; + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + for (BlockVector3 change : changes) { + if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.polygon2d.error.expand-only-vertical")); + } + int changeY = change.getBlockY(); + if (changeY > 0) { + maxY += changeY; + } else { + minY += changeY; + } + } + recalculate(); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + for (BlockVector3 change : changes) { + if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.polygon2d.error.contract-only-vertical")); + } + int changeY = change.getBlockY(); + if (changeY > 0) { + minY += changeY; + } else { + maxY += changeY; + } + } + recalculate(); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + final double changeX = change.getX(); + final double changeY = change.getY(); + final double changeZ = change.getZ(); + + for (int i = 0; i < points.size(); ++i) { + BlockVector2 point = points.get(i); + points.set(i, BlockVector2.at(point.getX() + changeX, point.getZ() + changeZ)); + } + + minY += changeY; + maxY += changeY; + + recalculate(); + } + + @Override + public boolean contains(int targetX, int targetZ) { + boolean inside = false; + int npoints = points.size(); + int xNew; + int zNew; + int xOld; + int zOld; + int x1; + int z1; + int x2; + int z2; + long crossproduct; + int i; + + xOld = points.get(npoints - 1).getBlockX(); + zOld = points.get(npoints - 1).getBlockZ(); + + for (i = 0; i < npoints; ++i) { + xNew = points.get(i).getBlockX(); + zNew = points.get(i).getBlockZ(); + //Check for corner + if (xNew == targetX && zNew == targetZ) { + return true; + } + if (xNew > xOld) { + x1 = xOld; + x2 = xNew; + z1 = zOld; + z2 = zNew; + } else { + x1 = xNew; + x2 = xOld; + z1 = zNew; + z2 = zOld; + } + if (x1 <= targetX && targetX <= x2) { + crossproduct = ((long) targetZ - (long) z1) * (long) (x2 - x1) + - ((long) z2 - (long) z1) * (long) (targetX - x1); + if (crossproduct == 0) { + if ((z1 <= targetZ) == (targetZ <= z2)) { + return true; //on edge + } + } else if (crossproduct < 0 && (x1 != targetX)) { + inside = !inside; + } + } + xOld = xNew; + zOld = zNew; + } + + return inside; + } + + @Override + public boolean contains(BlockVector3 position) { + return contains(points, minY, maxY, position); + } + + /** + * Checks to see if a point is inside a region. + * + * @param points a list of points + * @param minY the min Y + * @param maxY the max Y + * @param pt the position to check + * @return true if the given polygon contains the given point + */ + public static boolean contains(List points, int minY, int maxY, BlockVector3 pt) { + if (points.size() < 3) { + return false; + } + int targetX = pt.getBlockX(); //wide + int targetY = pt.getBlockY(); //height + int targetZ = pt.getBlockZ(); //depth + + if (targetY < minY || targetY > maxY) { + return false; + } + + boolean inside = false; + int npoints = points.size(); + int xNew; + int zNew; + int x1; + int z1; + int x2; + int z2; + long crossproduct; + int i; + + int xOld = points.get(npoints - 1).getBlockX(); + int zOld = points.get(npoints - 1).getBlockZ(); + + for (i = 0; i < npoints; ++i) { + xNew = points.get(i).getBlockX(); + zNew = points.get(i).getBlockZ(); + //Check for corner + if (xNew == targetX && zNew == targetZ) { + return true; + } + if (xNew > xOld) { + x1 = xOld; + x2 = xNew; + z1 = zOld; + z2 = zNew; + } else { + x1 = xNew; + x2 = xOld; + z1 = zNew; + z2 = zOld; + } + if (x1 <= targetX && targetX <= x2) { + crossproduct = ((long) targetZ - (long) z1) * (long) (x2 - x1) + - ((long) z2 - (long) z1) * (long) (targetX - x1); + if (crossproduct == 0) { + if ((z1 <= targetZ) == (targetZ <= z2)) { + return true; //on edge + } + } else if (crossproduct < 0 && (x1 != targetX)) { + inside = !inside; + } + } + xOld = xNew; + zOld = zNew; + } + + return inside; + } + + /** + * Return the number of points. + * + * @return the number of points + */ + public int size() { + return points.size(); + } + + /** + * Expand the height of the polygon to fit the specified Y. + * + * @param y the amount to expand + * @return true if the area was expanded + */ + public boolean expandY(int y) { + if (!hasY) { + minY = y; + maxY = y; + hasY = true; + return true; + } else if (y < minY) { + minY = y; + return true; + } else if (y > maxY) { + maxY = y; + return true; + } + + return false; + } + + @Override + public Iterator iterator() { + return new FlatRegion3DIterator(this); + } + + @Override + public Iterable asFlatRegion() { + return () -> new FlatRegionIterator(Polygonal2DRegion.this); + } + + /** + * Returns string representation in the format + * "(x1, z1) - ... - (xN, zN) * (minY - maxY)" + * + * @return string + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + List pts = getPoints(); + Iterator it = pts.iterator(); + while (it.hasNext()) { + BlockVector2 current = it.next(); + sb.append("(").append(current.getBlockX()).append(", ").append(current.getBlockZ()).append(")"); + if (it.hasNext()) { + sb.append(" - "); + } + } + sb.append(" * (").append(minY).append(" - ").append(maxY).append(")"); + return sb.toString(); + } + + @Override + public Polygonal2DRegion clone() { + Polygonal2DRegion clone = (Polygonal2DRegion) super.clone(); + clone.points = new ArrayList<>(points); + return clone; + } + + @Override + public List polygonize(int maxPoints) { + if (maxPoints >= 0 && maxPoints < points.size()) { + throw new IllegalArgumentException("Cannot polygonize a this Polygonal2DRegion into the amount of points given."); + } + + return points; + } + + @Override + public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) { + for (int x = bx; x <= tx; x++) { + if (!contains(x, 0, bz)) { + return false; + } + } + for (int x = bx; x <= tx; x++) { + if (!contains(x, 0, tz)) { + return false; + } + } + for (int z = bz; z <= tz; z++) { + if (!contains(bx, 0, z)) { + return false; + } + } + for (int z = bz; z <= tz; z++) { + if (!contains(tx, 0, z)) { + return false; + } + } + return true; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java index fac5d055c..a6701cf98 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java @@ -1,36 +1,36 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions; - -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.util.formatting.text.Component; - -public class RegionOperationException extends WorldEditException { - - @Deprecated - public RegionOperationException(String msg) { - super(msg); - } - - public RegionOperationException(Component msg) { - super(msg); - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.util.formatting.text.Component; + +public class RegionOperationException extends WorldEditException { + + @Deprecated + public RegionOperationException(String msg) { + super(msg); + } + + public RegionOperationException(Component msg) { + super(msg); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java index 42cefdf05..7d003a041 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java @@ -1,90 +1,90 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions.polyhedron; - -import com.sk89q.worldedit.math.Vector3; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class Edge { - - private final Vector3 start; - private final Vector3 end; - - public Edge(Vector3 start, Vector3 end) { - checkNotNull(start); - checkNotNull(end); - - this.start = start; - this.end = end; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof Edge)) { - return false; - } - - Edge otherEdge = (Edge) other; - if ((this.start == otherEdge.end) && (this.end == otherEdge.start)) { - return true; - } - - if ((this.end == otherEdge.end) && (this.start == otherEdge.start)) { - return true; - } - - return false; - } - - @Override - public int hashCode() { - return start.hashCode() ^ end.hashCode(); - } - - - @Override - public String toString() { - return "(" + this.start + "," + this.end + ")"; - } - - /** - * Create a triangle from { this.start, this.end, vertex } - * - * @param vertex the 3rd vertex for the triangle - * @return a triangle - */ - public Triangle createTriangle(Vector3 vertex) { - checkNotNull(vertex); - return new Triangle(this.start, this.end, vertex); - } - - /** - * Create a triangle from { this.start, vertex, this.end }. - * - * @param vertex the second vertex - * @return a new triangle - */ - public Triangle createTriangle2(Vector3 vertex) { - checkNotNull(vertex); - return new Triangle(this.start, vertex, this.end); - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.polyhedron; + +import com.sk89q.worldedit.math.Vector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class Edge { + + private final Vector3 start; + private final Vector3 end; + + public Edge(Vector3 start, Vector3 end) { + checkNotNull(start); + checkNotNull(end); + + this.start = start; + this.end = end; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Edge)) { + return false; + } + + Edge otherEdge = (Edge) other; + if ((this.start == otherEdge.end) && (this.end == otherEdge.start)) { + return true; + } + + if ((this.end == otherEdge.end) && (this.start == otherEdge.start)) { + return true; + } + + return false; + } + + @Override + public int hashCode() { + return start.hashCode() ^ end.hashCode(); + } + + + @Override + public String toString() { + return "(" + this.start + "," + this.end + ")"; + } + + /** + * Create a triangle from { this.start, this.end, vertex } + * + * @param vertex the 3rd vertex for the triangle + * @return a triangle + */ + public Triangle createTriangle(Vector3 vertex) { + checkNotNull(vertex); + return new Triangle(this.start, this.end, vertex); + } + + /** + * Create a triangle from { this.start, vertex, this.end }. + * + * @param vertex the second vertex + * @return a new triangle + */ + public Triangle createTriangle2(Vector3 vertex) { + checkNotNull(vertex); + return new Triangle(this.start, vertex, this.end); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java index 761ea4d28..400fabb8b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java @@ -1,113 +1,113 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions.polyhedron; - -import com.sk89q.worldedit.math.Vector3; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class Triangle { - - private String tag = "Triangle"; - private final Vector3[] vertices; - private final Vector3 normal; - private final double maxDotProduct; - - /** - * Constructs a triangle with the given vertices (counter-clockwise). - * - * @param v0 first vertex - * @param v1 second vertex - * @param v2 third vertex - */ - public Triangle(Vector3 v0, Vector3 v1, Vector3 v2) { - checkNotNull(v0); - checkNotNull(v1); - checkNotNull(v2); - - vertices = new Vector3[] { v0, v1, v2 }; - - this.normal = v1.subtract(v0).cross(v2.subtract(v0)).normalize(); - this.maxDotProduct = Math.max(Math.max(normal.dot(v0), normal.dot(v1)), normal.dot(v2)); - } - - /** - * Returns the triangle's vertex with the given index, counter-clockwise. - * - * @param index Vertex index. Valid input: 0..2 - * @return a vertex - */ - public Vector3 getVertex(int index) { - return vertices[index]; - } - - /** - * Returns the triangle's edge with the given index, counter-clockwise. - * - * @param index Edge index. Valid input: 0..2 - * @return an edge - */ - public Edge getEdge(int index) { - if (index == vertices.length - 1) { - return new Edge(vertices[index], vertices[0]); - } - return new Edge(vertices[index], vertices[index + 1]); - } - - /** - * Returns whether the given point is above the plane the triangle is in. - * - * @param pt the point to test - * @return true if the point is below - */ - public boolean below(Vector3 pt) { - checkNotNull(pt); - return normal.dot(pt) < maxDotProduct; - } - - /** - * Returns whether the given point is above the plane the triangle is in. - * - * @param pt the point to test - * @return true if the point is above - */ - public boolean above(Vector3 pt) { - checkNotNull(pt); - return normal.dot(pt) > maxDotProduct; - } - - /** - * Set the triangle's tag. - * - * @param tag the tag - * @return this object - */ - public Triangle tag(String tag) { - checkNotNull(tag); - this.tag = tag; - return this; - } - - @Override - public String toString() { - return tag + "(" + this.vertices[0] + "," + this.vertices[1] + "," + this.vertices[2] + ")"; - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.polyhedron; + +import com.sk89q.worldedit.math.Vector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class Triangle { + + private String tag = "Triangle"; + private final Vector3[] vertices; + private final Vector3 normal; + private final double maxDotProduct; + + /** + * Constructs a triangle with the given vertices (counter-clockwise). + * + * @param v0 first vertex + * @param v1 second vertex + * @param v2 third vertex + */ + public Triangle(Vector3 v0, Vector3 v1, Vector3 v2) { + checkNotNull(v0); + checkNotNull(v1); + checkNotNull(v2); + + vertices = new Vector3[] { v0, v1, v2 }; + + this.normal = v1.subtract(v0).cross(v2.subtract(v0)).normalize(); + this.maxDotProduct = Math.max(Math.max(normal.dot(v0), normal.dot(v1)), normal.dot(v2)); + } + + /** + * Returns the triangle's vertex with the given index, counter-clockwise. + * + * @param index Vertex index. Valid input: 0..2 + * @return a vertex + */ + public Vector3 getVertex(int index) { + return vertices[index]; + } + + /** + * Returns the triangle's edge with the given index, counter-clockwise. + * + * @param index Edge index. Valid input: 0..2 + * @return an edge + */ + public Edge getEdge(int index) { + if (index == vertices.length - 1) { + return new Edge(vertices[index], vertices[0]); + } + return new Edge(vertices[index], vertices[index + 1]); + } + + /** + * Returns whether the given point is above the plane the triangle is in. + * + * @param pt the point to test + * @return true if the point is below + */ + public boolean below(Vector3 pt) { + checkNotNull(pt); + return normal.dot(pt) < maxDotProduct; + } + + /** + * Returns whether the given point is above the plane the triangle is in. + * + * @param pt the point to test + * @return true if the point is above + */ + public boolean above(Vector3 pt) { + checkNotNull(pt); + return normal.dot(pt) > maxDotProduct; + } + + /** + * Set the triangle's tag. + * + * @param tag the tag + * @return this object + */ + public Triangle tag(String tag) { + checkNotNull(tag); + this.tag = tag; + return this; + } + + @Override + public String toString() { + return tag + "(" + this.vertices[0] + "," + this.vertices[1] + "," + this.vertices[2] + ")"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java index c53401c25..9e6537787 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java @@ -1,274 +1,274 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.command.InsufficientArgumentsException; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.input.DisallowedUsageException; -import com.sk89q.worldedit.extension.input.NoMatchException; -import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.internal.expression.invoke.ReturnException; -import com.sk89q.worldedit.session.request.Request; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.io.file.FilenameException; -import com.sk89q.worldedit.world.block.BaseBlock; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * The context given to scripts. - */ -public class CraftScriptContext extends CraftScriptEnvironment { - - private final List editSessions = new ArrayList<>(); - private final String[] args; - - public CraftScriptContext(WorldEdit controller, - Platform server, LocalConfiguration config, - LocalSession session, Player player, String[] args) { - super(controller, server, config, session, player); - this.args = args; - } - - /** - * Get an edit session. Every subsequent call returns a new edit session. - * Usually you only need to use one edit session. - * - * @return an edit session - */ - public EditSession remember() { - EditSession editSession = controller.getEditSessionFactory() - .getEditSession(player.getWorld(), - session.getBlockChangeLimit(), session.getBlockBag(player), player); - Request.request().setEditSession(editSession); - editSession.enableStandardMode(); - editSessions.add(editSession); - return editSession; - } - - /** - * Get the player. - * - * @return the calling player - */ - public Player getPlayer() { - return player; - } - - /** - * Get the player's session. - * - * @return a session - */ - public LocalSession getSession() { - return session; - } - - /** - * Get the configuration for WorldEdit. - * - * @return the configuration - */ - public LocalConfiguration getConfiguration() { - return config; - } - - /** - * Get a list of edit sessions that have been created. - * - * @return a list of created {@code EditSession}s - */ - public List getEditSessions() { - return Collections.unmodifiableList(editSessions); - } - - /** - * Print a regular message to the user. - * - * @param message a message - */ - public void print(String message) { - player.printInfo(TextComponent.of(message)); - } - - /** - * Print an error message to the user. - * - * @param message a message - */ - public void error(String message) { - player.printError(TextComponent.of(message)); - } - - /** - * Print a raw message to the user. - * - * @param message a message - */ - public void printRaw(String message) { - player.print(TextComponent.of(message)); - } - - /** - * Checks to make sure that there are enough but not too many arguments. - * - * @param min a number of arguments - * @param max -1 for no maximum - * @param usage usage string - * @throws InsufficientArgumentsException if the arguments are not "sufficiently" good - */ - public void checkArgs(int min, int max, String usage) - throws InsufficientArgumentsException { - if (args.length <= min || (max != -1 && args.length - 1 > max)) { - throw new InsufficientArgumentsException(TranslatableComponent.of("worldedit.error.incorrect-usage", TextComponent.of(usage))); - } - } - - /** - * Immediately terminate execution of the script, but without a failure message. - * - * @implNote This exits by throwing an exception, which if caught will prevent - * the script from exiting - */ - public void exit() { - throw new ReturnException(null); - } - - /** - * Get an item from an item name or an item ID number. - * - * @param input input to parse - * @param allAllowed true to ignore blacklists - * @return a block - * @throws NoMatchException if no block was found - * @throws DisallowedUsageException if the block is disallowed - */ - public BaseBlock getBlock(String input, boolean allAllowed) throws WorldEditException { - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - context.setRestricted(!allAllowed); - context.setPreferringWildcard(false); - - return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null); - } - - /** - * Get a block. - * - * @param id the type Id - * @return a block - * @throws NoMatchException if no block was found - * @throws DisallowedUsageException if the block is disallowed - */ - public BaseBlock getBlock(String id) throws WorldEditException { - return getBlock(id, false); - } - - /** - * Get a list of blocks as a set. This returns a Pattern. - * - * @param list the input - * @return pattern - * @throws NoMatchException if the pattern was invalid - * @throws DisallowedUsageException if the block is disallowed - */ - public Pattern getBlockPattern(String list) throws WorldEditException { - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - return controller.getPatternFactory().parseFromInput(list, context); - } - - /** - * Get a list of blocks as a set. - * - * @param list a list - * @param allBlocksAllowed true if all blocks are allowed - * @return set - * @throws NoMatchException if the blocks couldn't be found - * @throws DisallowedUsageException if the block is disallowed - */ - public Set getBlocks(String list, boolean allBlocksAllowed) throws WorldEditException { - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - context.setRestricted(!allBlocksAllowed); - return controller.getBlockFactory().parseFromListInput(list, context); - } - - /** - * Gets the path to a file for opening. This method will check to see if the - * filename has valid characters and has an extension. It also prevents - * directory traversal exploits by checking the root directory and the file - * directory. On success, a {@code java.io.File} object will be - * returned. - * - *

Use this method if you need to read a file from a directory.

- * - * @param folder sub-directory to look in - * @param filename filename (user-submitted) - * @param defaultExt default extension to append if there is none - * @param exts list of extensions for file open dialog, null for no filter - * @return a file - * @throws FilenameException if there is a problem with the name of the file - */ - public File getSafeOpenFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException { - File dir = controller.getWorkingDirectoryFile(folder); - return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts); - } - - /** - * Gets the path to a file for saving. This method will check to see if the - * filename has valid characters and has an extension. It also prevents - * directory traversal exploits by checking the root directory and the file - * directory. On success, a {@code java.io.File} object will be - * returned. - * - *

Use this method if you need to read a file from a directory.

- * - * @param folder sub-directory to look in - * @param filename filename (user-submitted) - * @param defaultExt default extension to append if there is none - * @param exts list of extensions for file save dialog, null for no filter - * @return a file - * @throws FilenameException if there is a problem with the name of the file - */ - public File getSafeSaveFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException { - File dir = controller.getWorkingDirectoryFile(folder); - return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts); - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.InsufficientArgumentsException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.expression.invoke.ReturnException; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.FilenameException; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * The context given to scripts. + */ +public class CraftScriptContext extends CraftScriptEnvironment { + + private final List editSessions = new ArrayList<>(); + private final String[] args; + + public CraftScriptContext(WorldEdit controller, + Platform server, LocalConfiguration config, + LocalSession session, Player player, String[] args) { + super(controller, server, config, session, player); + this.args = args; + } + + /** + * Get an edit session. Every subsequent call returns a new edit session. + * Usually you only need to use one edit session. + * + * @return an edit session + */ + public EditSession remember() { + EditSession editSession = controller.getEditSessionFactory() + .getEditSession(player.getWorld(), + session.getBlockChangeLimit(), session.getBlockBag(player), player); + Request.request().setEditSession(editSession); + editSession.enableStandardMode(); + editSessions.add(editSession); + return editSession; + } + + /** + * Get the player. + * + * @return the calling player + */ + public Player getPlayer() { + return player; + } + + /** + * Get the player's session. + * + * @return a session + */ + public LocalSession getSession() { + return session; + } + + /** + * Get the configuration for WorldEdit. + * + * @return the configuration + */ + public LocalConfiguration getConfiguration() { + return config; + } + + /** + * Get a list of edit sessions that have been created. + * + * @return a list of created {@code EditSession}s + */ + public List getEditSessions() { + return Collections.unmodifiableList(editSessions); + } + + /** + * Print a regular message to the user. + * + * @param message a message + */ + public void print(String message) { + player.printInfo(TextComponent.of(message)); + } + + /** + * Print an error message to the user. + * + * @param message a message + */ + public void error(String message) { + player.printError(TextComponent.of(message)); + } + + /** + * Print a raw message to the user. + * + * @param message a message + */ + public void printRaw(String message) { + player.print(TextComponent.of(message)); + } + + /** + * Checks to make sure that there are enough but not too many arguments. + * + * @param min a number of arguments + * @param max -1 for no maximum + * @param usage usage string + * @throws InsufficientArgumentsException if the arguments are not "sufficiently" good + */ + public void checkArgs(int min, int max, String usage) + throws InsufficientArgumentsException { + if (args.length <= min || (max != -1 && args.length - 1 > max)) { + throw new InsufficientArgumentsException(TranslatableComponent.of("worldedit.error.incorrect-usage", TextComponent.of(usage))); + } + } + + /** + * Immediately terminate execution of the script, but without a failure message. + * + * @implNote This exits by throwing an exception, which if caught will prevent + * the script from exiting + */ + public void exit() { + throw new ReturnException(null); + } + + /** + * Get an item from an item name or an item ID number. + * + * @param input input to parse + * @param allAllowed true to ignore blacklists + * @return a block + * @throws NoMatchException if no block was found + * @throws DisallowedUsageException if the block is disallowed + */ + public BaseBlock getBlock(String input, boolean allAllowed) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setActor(player); + context.setWorld(player.getWorld()); + context.setSession(session); + context.setRestricted(!allAllowed); + context.setPreferringWildcard(false); + + return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null); + } + + /** + * Get a block. + * + * @param id the type Id + * @return a block + * @throws NoMatchException if no block was found + * @throws DisallowedUsageException if the block is disallowed + */ + public BaseBlock getBlock(String id) throws WorldEditException { + return getBlock(id, false); + } + + /** + * Get a list of blocks as a set. This returns a Pattern. + * + * @param list the input + * @return pattern + * @throws NoMatchException if the pattern was invalid + * @throws DisallowedUsageException if the block is disallowed + */ + public Pattern getBlockPattern(String list) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setActor(player); + context.setWorld(player.getWorld()); + context.setSession(session); + return controller.getPatternFactory().parseFromInput(list, context); + } + + /** + * Get a list of blocks as a set. + * + * @param list a list + * @param allBlocksAllowed true if all blocks are allowed + * @return set + * @throws NoMatchException if the blocks couldn't be found + * @throws DisallowedUsageException if the block is disallowed + */ + public Set getBlocks(String list, boolean allBlocksAllowed) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setActor(player); + context.setWorld(player.getWorld()); + context.setSession(session); + context.setRestricted(!allBlocksAllowed); + return controller.getBlockFactory().parseFromListInput(list, context); + } + + /** + * Gets the path to a file for opening. This method will check to see if the + * filename has valid characters and has an extension. It also prevents + * directory traversal exploits by checking the root directory and the file + * directory. On success, a {@code java.io.File} object will be + * returned. + * + *

Use this method if you need to read a file from a directory.

+ * + * @param folder sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt default extension to append if there is none + * @param exts list of extensions for file open dialog, null for no filter + * @return a file + * @throws FilenameException if there is a problem with the name of the file + */ + public File getSafeOpenFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException { + File dir = controller.getWorkingDirectoryFile(folder); + return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts); + } + + /** + * Gets the path to a file for saving. This method will check to see if the + * filename has valid characters and has an extension. It also prevents + * directory traversal exploits by checking the root directory and the file + * directory. On success, a {@code java.io.File} object will be + * returned. + * + *

Use this method if you need to read a file from a directory.

+ * + * @param folder sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt default extension to append if there is none + * @param exts list of extensions for file save dialog, null for no filter + * @return a file + * @throws FilenameException if there is a problem with the name of the file + */ + public File getSafeSaveFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException { + File dir = controller.getWorkingDirectoryFile(folder); + return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java index 54477cc72..3d3d3f258 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java @@ -1,32 +1,32 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting; - -import java.util.Map; -import javax.script.ScriptException; - -public interface CraftScriptEngine { - void setTimeLimit(int milliseconds); - - int getTimeLimit(); - - Object evaluate(String script, String filename, Map args) - throws ScriptException, Throwable; -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting; + +import java.util.Map; +import javax.script.ScriptException; + +public interface CraftScriptEngine { + void setTimeLimit(int milliseconds); + + int getTimeLimit(); + + Object evaluate(String script, String filename, Map args) + throws ScriptException, Throwable; +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java index f5265fe08..10684770d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java @@ -1,44 +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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting; - -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Platform; - -public abstract class CraftScriptEnvironment { - - protected WorldEdit controller; - protected Player player; - protected LocalConfiguration config; - protected LocalSession session; - protected Platform server; - - public CraftScriptEnvironment(WorldEdit controller, Platform server, LocalConfiguration config, LocalSession session, Player player) { - this.controller = controller; - this.player = player; - this.config = config; - this.server = server; - this.session = session; - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; + +public abstract class CraftScriptEnvironment { + + protected WorldEdit controller; + protected Player player; + protected LocalConfiguration config; + protected LocalSession session; + protected Platform server; + + public CraftScriptEnvironment(WorldEdit controller, Platform server, LocalConfiguration config, LocalSession session, Player player) { + this.controller = controller; + this.player = player; + this.config = config; + this.server = server; + this.session = session; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java index 947785cee..fc9f7e0bb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java @@ -1,77 +1,77 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting; - -import org.mozilla.javascript.Callable; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.ContextFactory; -import org.mozilla.javascript.Scriptable; - -public class RhinoContextFactory extends ContextFactory { - - protected int timeLimit; - - public RhinoContextFactory(int timeLimit) { - this.timeLimit = timeLimit; - } - - @Override - protected Context makeContext() { - RhinoContext cx = new RhinoContext(this); - try { - // Try to set ES6 compat flag (since 1.7.7) - Context.class.getDeclaredField("VERSION_ES6"); - cx.setLanguageVersion(RhinoContext.VERSION_ES6); - } catch (NoSuchFieldException e) { - // best we can do, compatible with 1.7R2 that many people probably use - cx.setLanguageVersion(Context.VERSION_1_7); - } - cx.setInstructionObserverThreshold(10000); - return cx; - } - - @Override - protected void observeInstructionCount(Context cx, int instructionCount) { - RhinoContext mcx = (RhinoContext) cx; - long currentTime = System.currentTimeMillis(); - - if (currentTime - mcx.startTime > timeLimit) { - throw new Error("Script timed out (" + timeLimit + "ms)"); - } - } - - @Override - protected Object doTopCall(Callable callable, Context cx, Scriptable scope, - Scriptable thisObj, Object[] args) { - RhinoContext mcx = (RhinoContext) cx; - mcx.startTime = System.currentTimeMillis(); - - return super.doTopCall(callable, cx, scope, thisObj, args); - } - - private static class RhinoContext extends Context { - long startTime; - - private RhinoContext(ContextFactory factory) { - super(factory); - } - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting; + +import org.mozilla.javascript.Callable; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Scriptable; + +public class RhinoContextFactory extends ContextFactory { + + protected int timeLimit; + + public RhinoContextFactory(int timeLimit) { + this.timeLimit = timeLimit; + } + + @Override + protected Context makeContext() { + RhinoContext cx = new RhinoContext(this); + try { + // Try to set ES6 compat flag (since 1.7.7) + Context.class.getDeclaredField("VERSION_ES6"); + cx.setLanguageVersion(RhinoContext.VERSION_ES6); + } catch (NoSuchFieldException e) { + // best we can do, compatible with 1.7R2 that many people probably use + cx.setLanguageVersion(Context.VERSION_1_7); + } + cx.setInstructionObserverThreshold(10000); + return cx; + } + + @Override + protected void observeInstructionCount(Context cx, int instructionCount) { + RhinoContext mcx = (RhinoContext) cx; + long currentTime = System.currentTimeMillis(); + + if (currentTime - mcx.startTime > timeLimit) { + throw new Error("Script timed out (" + timeLimit + "ms)"); + } + } + + @Override + protected Object doTopCall(Callable callable, Context cx, Scriptable scope, + Scriptable thisObj, Object[] args) { + RhinoContext mcx = (RhinoContext) cx; + mcx.startTime = System.currentTimeMillis(); + + return super.doTopCall(callable, cx, scope, thisObj, args); + } + + private static class RhinoContext extends Context { + long startTime; + + private RhinoContext(ContextFactory factory) { + super(factory); + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java index c6ba5ef7c..3e4bee75d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java @@ -1,98 +1,98 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.scripting; - -import com.google.common.io.CharStreams; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.scripting.compat.BabelScriptTranspiler; -import com.sk89q.worldedit.scripting.compat.ScriptTranspiler; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.ImporterTopLevel; -import org.mozilla.javascript.JavaScriptException; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; -import org.mozilla.javascript.WrappedException; - -import java.io.StringReader; -import java.util.Map; -import javax.script.ScriptException; - -public class RhinoCraftScriptEngine implements CraftScriptEngine { - - private static final ScriptTranspiler TRANSPILER = new BabelScriptTranspiler(); - private int timeLimit; - - @Override - public void setTimeLimit(int milliseconds) { - timeLimit = milliseconds; - } - - @Override - public int getTimeLimit() { - return timeLimit; - } - - @Override - public Object evaluate(String script, String filename, Map args) - throws ScriptException, Throwable { - String transpiled = CharStreams.toString(TRANSPILER.transpile(new StringReader(script))); - RhinoContextFactory factory = new RhinoContextFactory(timeLimit); - Context cx = factory.enterContext(); - cx.setClassShutter(new MinecraftHidingClassShutter()); - ScriptableObject scriptable = new ImporterTopLevel(cx); - Scriptable scope = cx.initStandardObjects(scriptable); - - for (Map.Entry entry : args.entrySet()) { - ScriptableObject.putProperty(scope, entry.getKey(), - Context.javaToJS(entry.getValue(), scope)); - } - try { - return cx.evaluateString(scope, transpiled, filename, 1, null); - } catch (Error e) { - throw new ScriptException(e.getMessage()); - } catch (RhinoException e) { - if (e instanceof WrappedException) { - Throwable cause = e.getCause(); - if (cause instanceof WorldEditException) { - throw cause; - } - } - - String msg; - int line = (line = e.lineNumber()) == 0 ? -1 : line; - - if (e instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException) e).getValue()); - } else { - msg = e.getMessage(); - } - - ScriptException scriptException = - new ScriptException(msg, e.sourceName(), line); - scriptException.initCause(e); - - throw scriptException; - } finally { - Context.exit(); - } - } - -} +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting; + +import com.google.common.io.CharStreams; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.scripting.compat.BabelScriptTranspiler; +import com.sk89q.worldedit.scripting.compat.ScriptTranspiler; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ImporterTopLevel; +import org.mozilla.javascript.JavaScriptException; +import org.mozilla.javascript.RhinoException; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.WrappedException; + +import java.io.StringReader; +import java.util.Map; +import javax.script.ScriptException; + +public class RhinoCraftScriptEngine implements CraftScriptEngine { + + private static final ScriptTranspiler TRANSPILER = new BabelScriptTranspiler(); + private int timeLimit; + + @Override + public void setTimeLimit(int milliseconds) { + timeLimit = milliseconds; + } + + @Override + public int getTimeLimit() { + return timeLimit; + } + + @Override + public Object evaluate(String script, String filename, Map args) + throws ScriptException, Throwable { + String transpiled = CharStreams.toString(TRANSPILER.transpile(new StringReader(script))); + RhinoContextFactory factory = new RhinoContextFactory(timeLimit); + Context cx = factory.enterContext(); + cx.setClassShutter(new MinecraftHidingClassShutter()); + ScriptableObject scriptable = new ImporterTopLevel(cx); + Scriptable scope = cx.initStandardObjects(scriptable); + + for (Map.Entry entry : args.entrySet()) { + ScriptableObject.putProperty(scope, entry.getKey(), + Context.javaToJS(entry.getValue(), scope)); + } + try { + return cx.evaluateString(scope, transpiled, filename, 1, null); + } catch (Error e) { + throw new ScriptException(e.getMessage()); + } catch (RhinoException e) { + if (e instanceof WrappedException) { + Throwable cause = e.getCause(); + if (cause instanceof WorldEditException) { + throw cause; + } + } + + String msg; + int line = (line = e.lineNumber()) == 0 ? -1 : line; + + if (e instanceof JavaScriptException) { + msg = String.valueOf(((JavaScriptException) e).getValue()); + } else { + msg = e.getMessage(); + } + + ScriptException scriptException = + new ScriptException(msg, e.sourceName(), line); + scriptException.initCause(e); + + throw scriptException; + } finally { + Context.exit(); + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java index 6248569dc..38c085e20 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java @@ -1,96 +1,96 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util; - -import com.sk89q.util.StringUtil; - -import java.io.File; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import javax.swing.JFileChooser; -import javax.swing.filechooser.FileFilter; - -public final class FileDialogUtil { - private FileDialogUtil() { - } - - public static File showSaveDialog(String[] exts) { - JFileChooser dialog = new JFileChooser(); - - if (exts != null) { - dialog.setFileFilter(new ExtensionFilter(exts)); - } - - int returnVal = dialog.showSaveDialog(null); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - return dialog.getSelectedFile(); - } - - return null; - } - - public static File showOpenDialog(String[] exts) { - JFileChooser dialog = new JFileChooser(); - - if (exts != null) { - dialog.setFileFilter(new ExtensionFilter(exts)); - } - - int returnVal = dialog.showOpenDialog(null); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - return dialog.getSelectedFile(); - } - - return null; - } - - private static class ExtensionFilter extends FileFilter { - private Set exts; - private String desc; - - private ExtensionFilter(String[] exts) { - this.exts = new HashSet<>(Arrays.asList(exts)); - - desc = StringUtil.joinString(exts, ","); - } - - @Override - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - String path = f.getPath(); - int index = path.lastIndexOf('.'); - if (index == -1 || index == path.length() - 1) { - return false; - } else { - return exts.contains(path.substring(index + 1)); - } - } - - @Override - public String getDescription() { - return desc; - } - } -} +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.util.StringUtil; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; + +public final class FileDialogUtil { + private FileDialogUtil() { + } + + public static File showSaveDialog(String[] exts) { + JFileChooser dialog = new JFileChooser(); + + if (exts != null) { + dialog.setFileFilter(new ExtensionFilter(exts)); + } + + int returnVal = dialog.showSaveDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return dialog.getSelectedFile(); + } + + return null; + } + + public static File showOpenDialog(String[] exts) { + JFileChooser dialog = new JFileChooser(); + + if (exts != null) { + dialog.setFileFilter(new ExtensionFilter(exts)); + } + + int returnVal = dialog.showOpenDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return dialog.getSelectedFile(); + } + + return null; + } + + private static class ExtensionFilter extends FileFilter { + private Set exts; + private String desc; + + private ExtensionFilter(String[] exts) { + this.exts = new HashSet<>(Arrays.asList(exts)); + + desc = StringUtil.joinString(exts, ","); + } + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + String path = f.getPath(); + int index = path.lastIndexOf('.'); + if (index == -1 || index == path.length() - 1) { + return false; + } else { + return exts.contains(path.substring(index + 1)); + } + } + + @Override + public String getDescription() { + return desc; + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java index a0e081e54..735a534f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -1,250 +1,250 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util; - -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.mask.SolidBlockMask; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; - -import javax.annotation.Nullable; - -/** - * This class uses an inefficient method to figure out what block a player - * is looking towards. - * - *

Originally written by toi. It was ported to WorldEdit and trimmed down by - * sk89q. Thanks to Raphfrk for optimization of toi's original class.

- */ -public class TargetBlock { - - private final Extent world; - - private int maxDistance; - private double checkDistance, curDistance; - private BlockVector3 targetPos = BlockVector3.ZERO; - private Vector3 targetPosDouble = Vector3.ZERO; - private BlockVector3 prevPos = BlockVector3.ZERO; - private Vector3 offset = Vector3.ZERO; - - // the mask which dictates when to stop a trace - defaults to stopping at non-air blocks - private Mask stopMask; - // the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker - private Mask solidMask; - - /** - * Constructor requiring a player, uses default values - * - * @param player player to work with - */ - public TargetBlock(Player player) { - this(player, 300, 0.2); - } - - /** - * Constructor requiring a player, max distance and a checking distance - * - * @param player Player to work with - * @param maxDistance how far it checks for blocks - * @param checkDistance how often to check for blocks, the smaller the more precise - */ - public TargetBlock(Player player, int maxDistance, double checkDistance) { - this(player, player.getWorld(), maxDistance, checkDistance); - } - - public TargetBlock(Player player, Extent extent, int maxDistance, double checkDistance) { - this.world = player.getWorld(); - this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), maxDistance, 1.65, checkDistance); - this.stopMask = new ExistingBlockMask(world); - this.solidMask = new SolidBlockMask(world); - } - - /** - * Set the mask used for determine where to stop traces. - * Setting to null will restore the default. - * - * @param stopMask the mask used to stop traces - */ - public void setStopMask(@Nullable Mask stopMask) { - if (stopMask == null) { - this.stopMask = new ExistingBlockMask(world); - } else { - this.stopMask = stopMask; - } - } - - /** - * Set the mask used for determine where to stop solid block traces. - * Setting to null will restore the default. - * - * @param solidMask the mask used to stop solid block traces - */ - public void setSolidMask(@Nullable Mask solidMask) { - if (solidMask == null) { - this.solidMask = new SolidBlockMask(world); - } else { - this.solidMask = solidMask; - } - } - - /** - * Set the values, all constructors uses this function - * - * @param loc location of the view - * @param xRotation the X rotation - * @param yRotation the Y rotation - * @param maxDistance how far it checks for blocks - * @param viewHeight where the view is positioned in y-axis - * @param checkDistance how often to check for blocks, the smaller the more precise - */ - private void setValues(Vector3 loc, double xRotation, double yRotation, int maxDistance, double viewHeight, double checkDistance) { - this.maxDistance = maxDistance; - this.checkDistance = checkDistance; - this.curDistance = 0; - xRotation = (xRotation + 90) % 360; - yRotation *= -1; - - double h = (checkDistance * Math.cos(Math.toRadians(yRotation))); - - offset = Vector3.at((h * Math.cos(Math.toRadians(xRotation))), - (checkDistance * Math.sin(Math.toRadians(yRotation))), - (h * Math.sin(Math.toRadians(xRotation)))); - - targetPosDouble = loc.add(0, viewHeight, 0); - targetPos = targetPosDouble.toBlockPoint(); - prevPos = targetPos; - } - - /** - * Returns any block at the sight. Returns null if out of range or if no - * viable target was found. Will try to return the last valid air block it finds. - * - * @return Block - */ - public Location getAnyTargetBlock() { - boolean searchForLastBlock = true; - Location lastBlock = null; - while (getNextBlock() != null) { - if (stopMask.test(world, targetPos)) { - break; - } else { - if (searchForLastBlock) { - lastBlock = getCurrentBlock(); - if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) { - searchForLastBlock = false; - } - } - } - } - Location currentBlock = getCurrentBlock(); - return (currentBlock != null ? currentBlock : lastBlock); - } - - /** - * Returns the block at the sight. Returns null if out of range or if no - * viable target was found - * - * @return Block - */ - public Location getTargetBlock() { - //noinspection StatementWithEmptyBody - while (getNextBlock() != null && !stopMask.test(world, targetPos)) ; - return getCurrentBlock(); - } - - /** - * Returns the block at the sight. Returns null if out of range or if no - * viable target was found - * - * @return Block - */ - public Location getSolidTargetBlock() { - //noinspection StatementWithEmptyBody - while (getNextBlock() != null && !solidMask.test(world, targetPos)) ; - return getCurrentBlock(); - } - - /** - * Get next block - * - * @return next block position - */ - public Location getNextBlock() { - prevPos = targetPos; - do { - curDistance += checkDistance; - - targetPosDouble = offset.add(targetPosDouble.getX(), - targetPosDouble.getY(), - targetPosDouble.getZ()); - targetPos = targetPosDouble.toBlockPoint(); - } while (curDistance <= maxDistance - && targetPos.getBlockX() == prevPos.getBlockX() - && targetPos.getBlockY() == prevPos.getBlockY() - && targetPos.getBlockZ() == prevPos.getBlockZ()); - - if (curDistance > maxDistance) { - return null; - } - - return new Location(world, targetPos.toVector3()); - } - - /** - * Returns the current block along the line of vision - * - * @return block position - */ - public Location getCurrentBlock() { - if (curDistance > maxDistance) { - return null; - } else { - return new Location(world, targetPos.toVector3()); - } - } - - /** - * Returns the previous block in the aimed path - * - * @return block position - */ - public Location getPreviousBlock() { - return new Location(world, prevPos.toVector3()); - } - - public Location getAnyTargetBlockFace() { - getAnyTargetBlock(); - Location current = getCurrentBlock(); - if (current != null) - return current.setDirection(current.toVector().subtract(getPreviousBlock().toVector())); - else - return new Location(world, targetPos.toVector3(), Float.NaN, Float.NaN); - } - - public Location getTargetBlockFace() { - getTargetBlock(); - if (getCurrentBlock() == null) return null; - return getCurrentBlock().setDirection(getCurrentBlock().toVector().subtract(getPreviousBlock().toVector())); - } - -} +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; + +import javax.annotation.Nullable; + +/** + * This class uses an inefficient method to figure out what block a player + * is looking towards. + * + *

Originally written by toi. It was ported to WorldEdit and trimmed down by + * sk89q. Thanks to Raphfrk for optimization of toi's original class.

+ */ +public class TargetBlock { + + private final Extent world; + + private int maxDistance; + private double checkDistance, curDistance; + private BlockVector3 targetPos = BlockVector3.ZERO; + private Vector3 targetPosDouble = Vector3.ZERO; + private BlockVector3 prevPos = BlockVector3.ZERO; + private Vector3 offset = Vector3.ZERO; + + // the mask which dictates when to stop a trace - defaults to stopping at non-air blocks + private Mask stopMask; + // the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker + private Mask solidMask; + + /** + * Constructor requiring a player, uses default values + * + * @param player player to work with + */ + public TargetBlock(Player player) { + this(player, 300, 0.2); + } + + /** + * Constructor requiring a player, max distance and a checking distance + * + * @param player Player to work with + * @param maxDistance how far it checks for blocks + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + public TargetBlock(Player player, int maxDistance, double checkDistance) { + this(player, player.getWorld(), maxDistance, checkDistance); + } + + public TargetBlock(Player player, Extent extent, int maxDistance, double checkDistance) { + this.world = player.getWorld(); + this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), maxDistance, 1.65, checkDistance); + this.stopMask = new ExistingBlockMask(world); + this.solidMask = new SolidBlockMask(world); + } + + /** + * Set the mask used for determine where to stop traces. + * Setting to null will restore the default. + * + * @param stopMask the mask used to stop traces + */ + public void setStopMask(@Nullable Mask stopMask) { + if (stopMask == null) { + this.stopMask = new ExistingBlockMask(world); + } else { + this.stopMask = stopMask; + } + } + + /** + * Set the mask used for determine where to stop solid block traces. + * Setting to null will restore the default. + * + * @param solidMask the mask used to stop solid block traces + */ + public void setSolidMask(@Nullable Mask solidMask) { + if (solidMask == null) { + this.solidMask = new SolidBlockMask(world); + } else { + this.solidMask = solidMask; + } + } + + /** + * Set the values, all constructors uses this function + * + * @param loc location of the view + * @param xRotation the X rotation + * @param yRotation the Y rotation + * @param maxDistance how far it checks for blocks + * @param viewHeight where the view is positioned in y-axis + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + private void setValues(Vector3 loc, double xRotation, double yRotation, int maxDistance, double viewHeight, double checkDistance) { + this.maxDistance = maxDistance; + this.checkDistance = checkDistance; + this.curDistance = 0; + xRotation = (xRotation + 90) % 360; + yRotation *= -1; + + double h = (checkDistance * Math.cos(Math.toRadians(yRotation))); + + offset = Vector3.at((h * Math.cos(Math.toRadians(xRotation))), + (checkDistance * Math.sin(Math.toRadians(yRotation))), + (h * Math.sin(Math.toRadians(xRotation)))); + + targetPosDouble = loc.add(0, viewHeight, 0); + targetPos = targetPosDouble.toBlockPoint(); + prevPos = targetPos; + } + + /** + * Returns any block at the sight. Returns null if out of range or if no + * viable target was found. Will try to return the last valid air block it finds. + * + * @return Block + */ + public Location getAnyTargetBlock() { + boolean searchForLastBlock = true; + Location lastBlock = null; + while (getNextBlock() != null) { + if (stopMask.test(world, targetPos)) { + break; + } else { + if (searchForLastBlock) { + lastBlock = getCurrentBlock(); + if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) { + searchForLastBlock = false; + } + } + } + } + Location currentBlock = getCurrentBlock(); + return (currentBlock != null ? currentBlock : lastBlock); + } + + /** + * Returns the block at the sight. Returns null if out of range or if no + * viable target was found + * + * @return Block + */ + public Location getTargetBlock() { + //noinspection StatementWithEmptyBody + while (getNextBlock() != null && !stopMask.test(world, targetPos)) ; + return getCurrentBlock(); + } + + /** + * Returns the block at the sight. Returns null if out of range or if no + * viable target was found + * + * @return Block + */ + public Location getSolidTargetBlock() { + //noinspection StatementWithEmptyBody + while (getNextBlock() != null && !solidMask.test(world, targetPos)) ; + return getCurrentBlock(); + } + + /** + * Get next block + * + * @return next block position + */ + public Location getNextBlock() { + prevPos = targetPos; + do { + curDistance += checkDistance; + + targetPosDouble = offset.add(targetPosDouble.getX(), + targetPosDouble.getY(), + targetPosDouble.getZ()); + targetPos = targetPosDouble.toBlockPoint(); + } while (curDistance <= maxDistance + && targetPos.getBlockX() == prevPos.getBlockX() + && targetPos.getBlockY() == prevPos.getBlockY() + && targetPos.getBlockZ() == prevPos.getBlockZ()); + + if (curDistance > maxDistance) { + return null; + } + + return new Location(world, targetPos.toVector3()); + } + + /** + * Returns the current block along the line of vision + * + * @return block position + */ + public Location getCurrentBlock() { + if (curDistance > maxDistance) { + return null; + } else { + return new Location(world, targetPos.toVector3()); + } + } + + /** + * Returns the previous block in the aimed path + * + * @return block position + */ + public Location getPreviousBlock() { + return new Location(world, prevPos.toVector3()); + } + + public Location getAnyTargetBlockFace() { + getAnyTargetBlock(); + Location current = getCurrentBlock(); + if (current != null) + return current.setDirection(current.toVector().subtract(getPreviousBlock().toVector())); + else + return new Location(world, targetPos.toVector3(), Float.NaN, Float.NaN); + } + + public Location getTargetBlockFace() { + getTargetBlock(); + if (getCurrentBlock() == null) return null; + return getCurrentBlock().setDirection(getCurrentBlock().toVector().subtract(getPreviousBlock().toVector())); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java index 65ecc3af2..f6e0ee892 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -1,270 +1,270 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import javax.annotation.Nullable; - -/** - * Tree generator. - */ -public class TreeGenerator { - - public enum TreeType { - TREE("Oak tree", "oak", "tree", "regular"), - BIG_TREE("Large oak tree", "largeoak", "bigoak", "big", "bigtree"), - REDWOOD("Spruce tree", "spruce", "redwood", "sequoia", "sequoioideae"), - TALL_REDWOOD("Tall spruce tree", "tallspruce", "bigspruce", "tallredwood", "tallsequoia", "tallsequoioideae"), - MEGA_REDWOOD("Large spruce tree", "largespruce", "megaredwood"), - RANDOM_REDWOOD("Random spruce tree", "randspruce", "randredwood", "randomredwood", "anyredwood") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - TreeType[] choices = { REDWOOD, TALL_REDWOOD, MEGA_REDWOOD }; - return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); - } - }, - BIRCH("Birch tree", "birch", "white", "whitebark"), - TALL_BIRCH("Tall birch tree", "tallbirch"), - RANDOM_BIRCH("Random birch tree", "randbirch", "randombirch") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - TreeType[] choices = { BIRCH, TALL_BIRCH }; - return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); - } - }, - JUNGLE("Jungle tree", "jungle"), - SMALL_JUNGLE("Small jungle tree", "smalljungle"), - SHORT_JUNGLE("Short jungle tree", "shortjungle") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - return SMALL_JUNGLE.generate(editSession, pos); - } - }, - RANDOM_JUNGLE("Random jungle tree", "randjungle", "randomjungle") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - TreeType[] choices = { JUNGLE, SMALL_JUNGLE }; - return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); - } - }, - JUNGLE_BUSH("Jungle bush", "junglebush", "jungleshrub"), - RED_MUSHROOM("Red mushroom", "redmushroom", "redgiantmushroom"), - BROWN_MUSHROOM("Brown mushroom", "brownmushroom", "browngiantmushroom"), - RANDOM_MUSHROOM("Random mushroom", "randmushroom", "randommushroom") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - TreeType[] choices = { RED_MUSHROOM, BROWN_MUSHROOM }; - return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); - } - }, - SWAMP("Swamp tree", "swamp", "swamptree"), - ACACIA("Acacia tree", "acacia"), - DARK_OAK("Dark oak tree", "darkoak"), - PINE("Pine tree", "pine") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - makePineTree(editSession, pos); - return true; - } - }, - RANDOM("Random tree", "rand", "random") { - @Override - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - TreeType[] choices = TreeType.values(); - return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); - } - }; - - /** - * Stores a map of the names for fast access. - */ - private static final Map lookup = new HashMap<>(); - private static final Set primaryAliases = Sets.newHashSet(); - - private final String name; - public final ImmutableList lookupKeys; - - static { - for (TreeType type : EnumSet.allOf(TreeType.class)) { - for (String key : type.lookupKeys) { - lookup.put(key, type); - } - if (type.lookupKeys.size() > 0) { - primaryAliases.add(type.lookupKeys.get(0)); - } - } - } - - TreeType(String name, String... lookupKeys) { - this.name = name; - this.lookupKeys = ImmutableList.copyOf(lookupKeys); - } - - public static Set getAliases() { - return Collections.unmodifiableSet(lookup.keySet()); - } - - public static Set getPrimaryAliases() { - return Collections.unmodifiableSet(primaryAliases); - } - - public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { - return editSession.getWorld().generateTree(this, editSession, pos); - } - - /** - * Get user-friendly tree type name. - * - * @return a name - */ - public String getName() { - return name; - } - - /** - * Return type from name. May return null. - * - * @param name name to search - * @return a tree type or null - */ - @Nullable - public static TreeType lookup(String name) { - return lookup.get(name.replace("_", "").toLowerCase(Locale.ROOT)); - } - } - - private TreeGenerator() { - } - - private static final Random RANDOM = new Random(); - - /** - * Makes a terrible looking pine tree. - * - * @param basePosition the base position - */ - private static void makePineTree(EditSession editSession, BlockVector3 basePosition) - throws MaxChangedBlocksException { - int trunkHeight = (int) Math.floor(Math.random() * 2) + 3; - int height = (int) Math.floor(Math.random() * 5) + 8; - - BlockState logBlock = BlockTypes.OAK_LOG.getDefaultState(); - BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState(); - - // Create trunk - for (int i = 0; i < trunkHeight; ++i) { - if (!setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock)) { - return; - } - } - - // Move up - basePosition = basePosition.add(0, trunkHeight, 0); - - // Create tree + leaves - for (int i = 0; i < height; ++i) { - setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock); - - // Less leaves at these levels - double chance = ((i == 0 || i == height - 1) ? 0.6 : 1); - - // Inner leaves - setChanceBlockIfAir(editSession, basePosition.add(-1, i, 0), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(1, i, 0), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(0, i, -1), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(0, i, 1), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(1, i, 1), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(-1, i, 1), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(1, i, -1), leavesBlock, chance); - setChanceBlockIfAir(editSession, basePosition.add(-1, i, -1), leavesBlock, chance); - - if (!(i == 0 || i == height - 1)) { - for (int j = -2; j <= 2; ++j) { - setChanceBlockIfAir(editSession, basePosition.add(-2, i, j), leavesBlock, 0.6); - } - for (int j = -2; j <= 2; ++j) { - setChanceBlockIfAir(editSession, basePosition.add(2, i, j), leavesBlock, 0.6); - } - for (int j = -2; j <= 2; ++j) { - setChanceBlockIfAir(editSession, basePosition.add(j, i, -2), leavesBlock, 0.6); - } - for (int j = -2; j <= 2; ++j) { - setChanceBlockIfAir(editSession, basePosition.add(j, i, 2), leavesBlock, 0.6); - } - } - } - - setBlockIfAir(editSession, basePosition.add(0, height, 0), leavesBlock); - } - - /** - * Looks up a tree type. May return null if a tree type by that - * name is not found. - * - * @param type the tree type - * @return a tree type or null - */ - @Nullable - public static TreeType lookup(String type) { - return TreeType.lookup(type); - } - - /** - * Set a block (only if a previous block was not there) if {@link Math#random()} - * returns a number less than the given probability. - * - * @param position the position - * @param block the block - * @param probability a probability between 0 and 1, inclusive - * @return whether a block was changed - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - private static > boolean setChanceBlockIfAir(EditSession session, BlockVector3 position, B block, double probability) - throws MaxChangedBlocksException { - return Math.random() <= probability && setBlockIfAir(session, position, block); - } - - /** - * Set a block only if there's no block already there. - * - * @param position the position - * @param block the block to set - * @return if block was changed - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - private static > boolean setBlockIfAir(EditSession session, BlockVector3 position, B block) throws MaxChangedBlocksException { - return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, block); - } -} +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * Tree generator. + */ +public class TreeGenerator { + + public enum TreeType { + TREE("Oak tree", "oak", "tree", "regular"), + BIG_TREE("Large oak tree", "largeoak", "bigoak", "big", "bigtree"), + REDWOOD("Spruce tree", "spruce", "redwood", "sequoia", "sequoioideae"), + TALL_REDWOOD("Tall spruce tree", "tallspruce", "bigspruce", "tallredwood", "tallsequoia", "tallsequoioideae"), + MEGA_REDWOOD("Large spruce tree", "largespruce", "megaredwood"), + RANDOM_REDWOOD("Random spruce tree", "randspruce", "randredwood", "randomredwood", "anyredwood") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { REDWOOD, TALL_REDWOOD, MEGA_REDWOOD }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + BIRCH("Birch tree", "birch", "white", "whitebark"), + TALL_BIRCH("Tall birch tree", "tallbirch"), + RANDOM_BIRCH("Random birch tree", "randbirch", "randombirch") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { BIRCH, TALL_BIRCH }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + JUNGLE("Jungle tree", "jungle"), + SMALL_JUNGLE("Small jungle tree", "smalljungle"), + SHORT_JUNGLE("Short jungle tree", "shortjungle") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + return SMALL_JUNGLE.generate(editSession, pos); + } + }, + RANDOM_JUNGLE("Random jungle tree", "randjungle", "randomjungle") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { JUNGLE, SMALL_JUNGLE }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + JUNGLE_BUSH("Jungle bush", "junglebush", "jungleshrub"), + RED_MUSHROOM("Red mushroom", "redmushroom", "redgiantmushroom"), + BROWN_MUSHROOM("Brown mushroom", "brownmushroom", "browngiantmushroom"), + RANDOM_MUSHROOM("Random mushroom", "randmushroom", "randommushroom") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { RED_MUSHROOM, BROWN_MUSHROOM }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + SWAMP("Swamp tree", "swamp", "swamptree"), + ACACIA("Acacia tree", "acacia"), + DARK_OAK("Dark oak tree", "darkoak"), + PINE("Pine tree", "pine") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + makePineTree(editSession, pos); + return true; + } + }, + RANDOM("Random tree", "rand", "random") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = TreeType.values(); + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }; + + /** + * Stores a map of the names for fast access. + */ + private static final Map lookup = new HashMap<>(); + private static final Set primaryAliases = Sets.newHashSet(); + + private final String name; + public final ImmutableList lookupKeys; + + static { + for (TreeType type : EnumSet.allOf(TreeType.class)) { + for (String key : type.lookupKeys) { + lookup.put(key, type); + } + if (type.lookupKeys.size() > 0) { + primaryAliases.add(type.lookupKeys.get(0)); + } + } + } + + TreeType(String name, String... lookupKeys) { + this.name = name; + this.lookupKeys = ImmutableList.copyOf(lookupKeys); + } + + public static Set getAliases() { + return Collections.unmodifiableSet(lookup.keySet()); + } + + public static Set getPrimaryAliases() { + return Collections.unmodifiableSet(primaryAliases); + } + + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + return editSession.getWorld().generateTree(this, editSession, pos); + } + + /** + * Get user-friendly tree type name. + * + * @return a name + */ + public String getName() { + return name; + } + + /** + * Return type from name. May return null. + * + * @param name name to search + * @return a tree type or null + */ + @Nullable + public static TreeType lookup(String name) { + return lookup.get(name.replace("_", "").toLowerCase(Locale.ROOT)); + } + } + + private TreeGenerator() { + } + + private static final Random RANDOM = new Random(); + + /** + * Makes a terrible looking pine tree. + * + * @param basePosition the base position + */ + private static void makePineTree(EditSession editSession, BlockVector3 basePosition) + throws MaxChangedBlocksException { + int trunkHeight = (int) Math.floor(Math.random() * 2) + 3; + int height = (int) Math.floor(Math.random() * 5) + 8; + + BlockState logBlock = BlockTypes.OAK_LOG.getDefaultState(); + BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState(); + + // Create trunk + for (int i = 0; i < trunkHeight; ++i) { + if (!setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock)) { + return; + } + } + + // Move up + basePosition = basePosition.add(0, trunkHeight, 0); + + // Create tree + leaves + for (int i = 0; i < height; ++i) { + setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock); + + // Less leaves at these levels + double chance = ((i == 0 || i == height - 1) ? 0.6 : 1); + + // Inner leaves + setChanceBlockIfAir(editSession, basePosition.add(-1, i, 0), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(1, i, 0), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(0, i, -1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(0, i, 1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(1, i, 1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(-1, i, 1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(1, i, -1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(-1, i, -1), leavesBlock, chance); + + if (!(i == 0 || i == height - 1)) { + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(-2, i, j), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(2, i, j), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(j, i, -2), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(j, i, 2), leavesBlock, 0.6); + } + } + } + + setBlockIfAir(editSession, basePosition.add(0, height, 0), leavesBlock); + } + + /** + * Looks up a tree type. May return null if a tree type by that + * name is not found. + * + * @param type the tree type + * @return a tree type or null + */ + @Nullable + public static TreeType lookup(String type) { + return TreeType.lookup(type); + } + + /** + * Set a block (only if a previous block was not there) if {@link Math#random()} + * returns a number less than the given probability. + * + * @param position the position + * @param block the block + * @param probability a probability between 0 and 1, inclusive + * @return whether a block was changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + private static > boolean setChanceBlockIfAir(EditSession session, BlockVector3 position, B block, double probability) + throws MaxChangedBlocksException { + return Math.random() <= probability && setBlockIfAir(session, position, block); + } + + /** + * Set a block only if there's no block already there. + * + * @param position the position + * @param block the block to set + * @return if block was changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + private static > boolean setBlockIfAir(EditSession session, BlockVector3 position, B block) throws MaxChangedBlocksException { + return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, block); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java index b0e48502f..34c6f92e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java @@ -1,23 +1,23 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util.io.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.util.io.file; import java.io.Closeable; import java.nio.file.Path; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java index e790f0d30..9c2678159 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java @@ -1,23 +1,23 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.util.io.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.util.io.file; import java.io.IOException; import java.nio.file.Files;